Qbasicnews.com
July 04, 2020, 08:15:58 AM *
Welcome, Guest. Please login or register.

Login with username, password and session length
News: Back to Qbasicnews.com | QB Online Help | FAQ | Chat | All Basic Code | QB Knowledge Base
 
   Home   Help Search Login Register  
Pages: [1]
  Print  
Author Topic: 2D sprite rotation and movement  (Read 3701 times)
steven_basic
Senior Member
**
Posts: 244


WWW
« on: February 15, 2005, 02:38:55 PM »

The following is an update to the sprite animation / movement code that used the rotozoomer in sdl_gfx to "animate" a sprite turning 360 degrees.  The sprite then will move in the direction it is facing based on some simple calculations.

However, simple or not, I seem to have run into a bit of a problem with the directional calculations
Code:

    ship1.x = ship1.x - (ship1.speed * sin((ship1.facing * 3.14159) / 180))
    ship1.y = ship1.y - (ship1.speed * cos((ship1.facing * 3.14159) / 180))

used to determine forward movement of the "ship".  I get good rotation of the sprite, but seem to only get forward movement in 8 directions only.  The result is a sprite rotated at say 60 degrees but only moving at a 45 degree angle (like its sliding).

I have attempted looking up calculations for sprite movement this way, but have not found anything outside of what I have come up with.

Any help on this?

To test the complete code use the following:

Code:

option explicit

'  include the sdl header in order to easily use the sdl.dll
'$include: "sdl/sdl.bi"
'$include: "sdl/sdl_image.bi"
'$include: "sdl/sdl_gfx_rotozoom.bi"

'  some defines to make code easier to read/maintain
#define FALSE 0
#define TRUE  NOT FALSE
#define SCREEN_WIDTH  640
#define SCREEN_HEIGHT 480

'  declare subs
declare sub screen_render()

'  define a sprite type to encapsulate the different variables used
'  to control our simple sprite
type gamesprite
  image as SDL_Surface ptr
  facing as double
  x as long
  y as long
  speed as long
end type
'  declare a variable for our sprite as a simple sprite type
dim shared ship1 as gamesprite
'  declare a variable for our main screen
dim shared screen1 as SDL_Surface ptr
'  declare a variable to track events (keyboard, etc.)
dim event as SDL_Event
'  declare a general use variable to catch returning information from called functions
dim result as unsigned integer
'  declare a "flag" for tracking gamestate
'  this level the state of the game is either TRUE or FALSE
dim gamestate as integer
dim keys as byte ptr

'  initialize video mode subsystem
result = SDL_Init(SDL_INIT_VIDEO)
'  check for success/failure
if result <> 0 then
  end 1
end if

'  create an sdl window
screen1 = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_ANYFORMAT )
'  check for success/failure
if screen1 = 0 then
  SDL_Quit
  end 2
end if

'  load bitmap image into "sprite"
ship1.image = IMG_Load("sdl_ship02.png")
'  check for success/failure
if ship1.image = 0 then
  SDL_Quit
  end 3
end if
'  set the transparent color in our sprite image
SDL_SetColorKey(ship1.image, SDL_SRCCOLORKEY, SDL_MapRGB(ship1.image->format, 255, 0, 255))

'  set beginning values for sprite information
ship1.facing = 0
ship1.x = 300
ship1.y = 200
ship1.speed = 1

'  set game state
gamestate = TRUE
'  enter main game loop
do
  '  process events
  while SDL_PollEvent( @event ) <> 0
    '  check for user exit
    if event.type = SDL_QUIT_ then
      gamestate = FALSE
    end if
    '  check user keypress
    if event.type = SDL_KEYDOWN then
      '  escape key to exit
      if event.key.keysym.sym = SDLK_ESCAPE then gamestate = FALSE
    end if
  wend
  '  get current keyboard state (keys held down)
  keys = SDL_GetKeyState(NULL)
  if keys[SDLK_UP] then

    '  Angle is changed from degrees to radians since QBasic SIN and COS functions operate with radians.
    '  Angle Radians = (ship1.facing * 3.14159) / 180
    ship1.x = ship1.x - (ship1.speed * sin((ship1.facing * 3.14159) / 180))
    ship1.y = ship1.y - (ship1.speed * cos((ship1.facing * 3.14159) / 180))

  end if
  if keys[SDLK_LEFT] then
    ship1.facing = ship1.facing + 1
    if ship1.facing > 359 then ship1.facing = 0
  end if
  if keys[SDLK_RIGHT] then
    ship1.facing = ship1.facing - 1
    if ship1.facing < 0 then ship1.facing = 359
  end if
  '  call screen render routine
  screen_render
loop until gamestate = FALSE
SDL_FreeSurface( ship1.image )
SDL_Quit
end

'  screen_render
'  subroutine to handle the graphics updates
sub screen_render()
  dim blitdst as SDL_Rect
  dim scratch as SDL_Surface ptr
  '  lock surface if needed
  if SDL_MUSTLOCK( screen1 ) then
    if SDL_LockSurface( screen1 ) < 0 then
      exit sub
    end if
  end if
  '  perform graphics updates here
  '  clear entire screen
  SDL_FillRect(screen1, 0, 0)
  scratch = rotozoomSurface( ship1.image, ship1.facing, 1, SMOOTHING_ON)
  '  set screen "outline" to recieve sprite frame from main bitmap
  blitdst.x = ship1.x - (scratch->w / 2)
  blitdst.y = ship1.y - (scratch->h / 2)
  blitdst.w = 31
  blitdst.h = 31
  ' draw the sprite
  SDL_BlitSurface(scratch, 0, screen1, @blitdst)
  '  end graphics updates
  '  unlock surface if needed
  if SDL_MUSTLOCK( screen1 ) then
    SDL_UnlockSurface( screen1 )
  end if
  '  force entire screen update
  SDL_UpdateRect( screen1, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT )
end sub
Logged

ature has its way of warning a person away from danger:  The distinct black and white coloration on a skunk, the chilling buzz of a rattlesanke, a redneck handing you his beer and saying "Watch this!"
steven_basic
Senior Member
**
Posts: 244


WWW
« Reply #1 on: February 15, 2005, 07:14:32 PM »

I have also tried this "precalc" setup for determining angle and movement velocity.  This code resembles one used in a VB game that controlled race cars around a track.  I merely cut out some of the "enhanced control" included in the calculations for tire quality and track condiditons.

This new code acts pretty much the same as the original.  It only moves in 45 degree increments.


Code:
'  SDL_SHIP
option explicit

'  include the sdl header in order to easily use the sdl.dll
'$include: "sdl/sdl.bi"
'$include: "sdl/sdl_image.bi"
'$include: "sdl/sdl_gfx_rotozoom.bi"

'  some defines to make code easier to read/maintain
#define FALSE 0
#define TRUE  NOT FALSE
#define SCREEN_WIDTH  640
#define SCREEN_HEIGHT 480
#define PI 3.14159265358979

'  declare subs
declare sub screen_render()


'  precalced tables
dim shared Sine(0 To 35) As double
dim shared Cosine(0 To 35) As double
const PIdiv18 = PI / 18

'  define a sprite type to encapsulate the different variables used
'  to control our simple sprite
type gamesprite
  image as SDL_Surface ptr
  facing as double
  speed as double
  x as long
  y as long
end type
'  declare a variable for our sprite as a simple sprite type
dim shared ship1 as gamesprite
'  declare a variable for our main screen
dim shared screen1 as SDL_Surface ptr
'  declare a variable to track events (keyboard, etc.)
dim event as SDL_Event
'  declare a general use variable to catch returning information from called functions
dim result as unsigned integer
'  declare a "flag" for tracking gamestate
'  this level the state of the game is either TRUE or FALSE
dim gamestate as integer
dim keys as byte ptr

'  initialize video mode subsystem
result = SDL_Init(SDL_INIT_VIDEO)
'  check for success/failure
if result <> 0 then
  end 1
end if

'  create an sdl window
screen1 = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, 32, SDL_ANYFORMAT )
'  check for success/failure
if screen1 = 0 then
  SDL_Quit
  end 2
end if

'  load bitmap image into "sprite"
ship1.image = IMG_Load("sdl_ship02.png")
'  check for success/failure
if ship1.image = 0 then
  SDL_Quit
  end 3
end if
'  set the transparent color in our sprite image
SDL_SetColorKey(ship1.image, SDL_SRCCOLORKEY, SDL_MapRGB(ship1.image->format, 255, 0, 255))

'  calculate sine / cosine tables
dim counter as long
for counter = 0 to 35
  sine(counter) = sin(counter * PIdiv18)
  print sine(counter); " : ";
  cosine(counter) = cos(counter * PIdiv18)
  print cosine(counter)
next

'  set beginning values for sprite information
ship1.facing = 0
ship1.x = 300
ship1.y = 200
ship1.speed = 1

'  set game state
gamestate = TRUE
'  enter main game loop
do
  '  process events
  while SDL_PollEvent( @event ) <> 0
    '  check for user exit
    if event.type = SDL_QUIT_ then
      gamestate = FALSE
    end if
    '  check user keypress
    if event.type = SDL_KEYDOWN then
      '  escape key to exit
      if event.key.keysym.sym = SDLK_ESCAPE then gamestate = FALSE
    end if
  wend
  '  get current keyboard state (keys held down)
  keys = SDL_GetKeyState(NULL)
  if keys[SDLK_UP] then

    '  Angle is changed from degrees to radians since QBasic SIN and COS functions operate with radians.
    '  Angle Radians = ship1.facing * 3.14159 / 180
'    ship1.x = ship1.x - (ship1.speed * (sin(ship1.facing * 3.14159 / 180)))
'    ship1.y = ship1.y - (ship1.speed * (cos(ship1.facing * 3.14159 / 180)))

    'work out the direction of travel
    ship1.x = (ship1.x - (ship1.speed * Sine(ship1.facing)))
    ship1.y = (ship1.y - (ship1.speed * Cosine(ship1.facing)))


  end if
  if keys[SDLK_LEFT] then
    ship1.facing = ship1.facing + 1
    if ship1.facing > 35 then ship1.facing = 0
  end if
  if keys[SDLK_RIGHT] then
    ship1.facing = ship1.facing - 1
    if ship1.facing < 0 then ship1.facing = 35
  end if
  '  call screen render routine
  screen_render
loop until gamestate = FALSE
SDL_FreeSurface( ship1.image )
SDL_Quit
end

'  screen_render
'  subroutine to handle the graphics updates
sub screen_render()
  dim blitdst as SDL_Rect
  dim scratch as SDL_Surface ptr
  '  lock surface if needed
  if SDL_MUSTLOCK( screen1 ) then
    if SDL_LockSurface( screen1 ) < 0 then
      exit sub
    end if
  end if
  '  perform graphics updates here
  '  clear entire screen
  SDL_FillRect(screen1, 0, 0)
  scratch = rotozoomSurface( ship1.image, ship1.facing * 10, 1, SMOOTHING_ON)
  '  set screen "outline" to recieve sprite frame from main bitmap
  blitdst.x = ship1.x - (scratch->w / 2)
  blitdst.y = ship1.y - (scratch->h / 2)
  blitdst.w = 31
  blitdst.h = 31
  ' draw the sprite
  SDL_BlitSurface(scratch, 0, screen1, @blitdst)
  '  end graphics updates
  '  unlock surface if needed
  if SDL_MUSTLOCK( screen1 ) then
    SDL_UnlockSurface( screen1 )
  end if
  '  force entire screen update
  SDL_UpdateRect( screen1, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT )
end sub
Logged

ature has its way of warning a person away from danger:  The distinct black and white coloration on a skunk, the chilling buzz of a rattlesanke, a redneck handing you his beer and saying "Watch this!"
Pages: [1]
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.21 | SMF © 2015, Simple Machines Valid XHTML 1.0! Valid CSS!