April 25, 2024, 03:43:44 PM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Sprite Animation Speed

Started by J B Wood (Zumwalt), January 03, 2007, 12:34:28 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

J B Wood (Zumwalt)

What is the best way to handle animation speed?
I have 21 frames of animation in a single image, 8 images which relate to 8 angles.
When playing a sprite frame, right now in testing I am playing 1 frame per game loop.
This isn't going to work long term.
What is the best solution to that problem?

Ionic Wind Support Team

time based relative movement with a delta value is what I use.  See any of my examples for how I calculate 'flAdjust'.  The asteroids demo should give you wgat you are looking for.
Ionic Wind Support Team

J B Wood (Zumwalt)


J B Wood (Zumwalt)

Ok, taking the asteriods as an example, I got me a horde of bats.
Now, I know what the code is doing on the viewing angle and how you are spinning the rocks.
However, how do I make the bats viewing angle match that of there facing on start?
I mean to say rather, the bats load in at a random viewing angle and random trajectory. I want there viewing angle to match there facing trajectory.

This way they appear to be facing the way they are flying.

Ionic Wind Support Team

That would depend on their orientation in the file.  Angles are expressed in radians or degrees and converted by 180/PI.  Using simple triangle math you can determine the current rotation angle.  Easier to show on paper of couse but draw a bat, draw a line through the bats trajectory and then two lines interecting that trajectory to form a right angle of a triangle.  Then mumble the phrase SOHCAHTOA to jar the neurons loose that learned angles in school ;)

The only thing you need then is the formula for the length of a line, given two points in 2D space.  That line forms the hypontenuse of the triangle and is the line you drew in your head from the current XY position of the sprite to an arbetrary point in space along the trajectory.

Paul.
Ionic Wind Support Team

Ionic Wind Support Team

Since I am feeling a little generous I will give you a little shortcut used by 2D programmers to determine the angle of a line, knowing both of the lines points in 2d space then:

theta = atan2(y2-y1,x2-x1)

atan2 is a function in the C library which you can link to, or create a little sub which does the same:

SUB myatan2(double y, double x)
double theta
   if x > 0 then  theta = atand(y/x)
   if x < 0 then  theta = atand(y/x) -180
   if x = 0
     if y > 0 then theta = 90
     if y < 0 then theta = -90
     if y = 0 then print "error"
  end if 
RETURN theta
ENDSUB


The code returns the angle of the line in degrees.

Paul.
Ionic Wind Support Team

J B Wood (Zumwalt)

January 04, 2007, 06:40:43 AM #6 Last Edit: January 04, 2007, 06:49:18 AM by Jonathan (zumwalt) Wood
I got through math in school and haven't gone back to it sense :)
Not much of a choice now it seems.
The bat faces east (3 o'clock on a clock face) in its file.
So that angle I presume is 90.
However, based on how you described it, if I have the bat facing 12 o'clock instead of 3 o'clock, my angle is a direct corolation to what the code is at the moment. Which would mean a literal degree for facing and wouldn't have to do to much math to get the moment and the facing to align, atleast this is my assumption.

edit:
Had to alter your code slightly since it was a cross language post:


SUB myatan2(y as double, x as double),double
def theta as double
   if x > 0 then  theta = atand(y/x)
   if x < 0 then  theta = atand(y/x) -180
   if x = 0
     if y > 0 then theta = 90
     if y < 0 then theta = -90
     if y = 0 then print "error"
  end if 
RETURN theta
ENDSUB

J B Wood (Zumwalt)

January 04, 2007, 06:59:52 AM #7 Last Edit: January 04, 2007, 07:19:27 AM by Jonathan (zumwalt) Wood
This code works, as long as your image is facing 3 o'clock that is (or 90 degrees)

CONST DIK_UP = 0xC8 /* UpArrow on arrow keypad */
CONST DIK_LEFT = 0xCB /* LeftArrow on arrow keypad */
CONST DIK_RIGHT = 0xCD /* RightArrow on arrow keypad */
CONST DIK_DOWN = 0xD0 /* DownArrow on arrow keypad */

DECLARE IMPORT,GetSystemMetrics(item:int),int
TYPE floatPoint
DEF x:float
DEF y:float
ENDTYPE

TYPE OBJECT
def Loc:floatPoint
def ViewAngle:FLOAT
def FixedAngle:FLOAT
def Direction:floatPoint
def id:int
def tt:double
def tf:int   
def BoxBoundry:int
def Shieldup:int
def Active:int
def Amount:int
def SpriteID:POINTER       
def SPEED:FLOAT
ENDTYPE

TYPE bat_objects
def BatL[50]:OBJECT
ENDTYPE

def bats:bat_objects
def batEast as pointer
def lBats as int
DEF mElapsed,mTimer,mFrameTimer,mFPS,mFPSCounter,border,caption,music,getready,gameover,showscores,gethighscore:INT
DEF mAdjust:FLOAT
DEF command,hsname:STRING

'change this to 1 for full screen mode
full_screen = 0

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
SCREEN_BPP = 8
ROTATE_STEP = 10
RETRO = 0.26f
FRICTION = 0.995f
lBats=50

DEF playwin:WINDOW

IF full_screen = 0
caption = GetSystemMetrics(4)
border = GetSystemMetrics(5)
OPENWINDOW playwin,0,0,SCREEN_WIDTH+(border*2),SCREEN_HEIGHT+caption+(border*2),@NOAUTODRAW|@MINBOX,0,"Gone Batty",&winproc
IF ATTACHSCREEN(playwin,SCREEN_WIDTH,SCREEN_HEIGHT,FALSE) < 0
MESSAGEBOX 0, "Could not attach screen","Error"
END
ENDIF
ELSE
IF CREATESCREEN(SCREEN_WIDTH,SCREEN_HEIGHT,16,&winproc) < 0
MESSAGEBOX 0, "Could not open screen","Error"
END
ENDIF
ENDIF
batEast = loadsprite(GETSTARTPATH+"bat\\bat_000_0000.bmp",128,128,25,TRUE)

SPRITEMASKCOLOR batEast,RGB(0,0,255)
SPRITEDRAWMODE batEast,@TRANSROTOZOOM
FRONTPEN BackBuffer,RGB(0,0,255)
DRAWMODE BackBuffer,@TRANSPARENT
CONST DIK_SPACE = 0x39
fps = 0
clr = RGB(0,0,0)
batFrame=1

InitGame()
DO
FILLSCREEN clr
if batFrame >= 21 then
batFrame=1
end if
SpriteFrame batEast, batFrame
play()
fps = FLIP 1
batFrame=batFrame+1
wait 1
'OK this is how this works....
'Lets say our target FPS is 30,we calculate the FPS and the time
'each frame takes. mElapsed is the counter (in milleseconds)
'for every frame
'30 FPS = (1/30) * 1000ms = 33.334
'45 FPS = (1/45) * 1000ms = 22.223
'60 FPS = (1/60) * 1000ms = 16.667
'So no matter what the actual frame rate is our 'perceived' rate
'will always look the same.
    mElapsed = MILLISECS() - mTimer
    mTimer = MILLISECS()
mAdjust = mElapsed / FLT(59)
UNTIL KEYDOWN(1)
freesprite batEast
CLOSESCREEN
IF full_screen = 0 THEN CLOSEWINDOW playwin
END

SUB winproc
SELECT @MESSAGE
CASE @IDCREATE
IF full_screen = 0 THEN CENTERWINDOW playwin
ENDSELECT
RETURN
end sub

SUB TranslatePoint( Dest:floatPOINT, Src:floatPOINT, Angle:int)
def Radians,sine,cosine:float
Radians = Angle * 0.01745f
sine = fsin( Radians )
cosine = fcos( Radians )
Dest.x = Src.x * cosine - Src.y * sine
Dest.y = Src.x * sine + Src.y * cosine
RETURN
ENDSUB

SUB TranslateObject(object:OBJECT)
SPRITEANGLE Object.SpriteID,(Object.ViewAngle * -0.01745f)
RETURN
ENDSUB

SUB DrawObject(object:OBJECT)
DEF i:int
MOVESPRITE Object.SpriteID,Object.Loc.x-Object.BoxBoundry,Object.Loc.y-Object.BoxBoundry
DRAWSPRITE Object.SpriteID
IF Object.Shieldup :' & (Object.id = 0))
Circle BackBuffer,Object.Loc.x, Object.Loc.y, Object.BoxBoundry+2
ENDIF
RETURN
ENDSUB

SUB MoveObject(object:OBJECT)
Object.Loc.x = Object.Loc.x+ (Object.Direction.x * mAdjust * Object.SPEED)
Object.Loc.y = Object.Loc.y+ (Object.Direction.y * mAdjust * Object.SPEED)
IF  Object.Loc.x < 0
Object.Loc.x = Object.Loc.x + SCREEN_WIDTH
ENDIF
IF Object.Loc.x > SCREEN_WIDTH
Object.Loc.x = Object.Loc.x - SCREEN_WIDTH
ENDIF
IF Object.Loc.y < 0
Object.Loc.y = Object.Loc.y + SCREEN_HEIGHT
ENDIF
IF Object.Loc.y > SCREEN_HEIGHT
Object.Loc.y = Object.Loc.y - SCREEN_HEIGHT
ENDIF
RETURN
ENDSUB

SUB InitGame()
'Large Bats!
for z=0 TO lbats-1
bats.BatL[z].SpriteID = batEast
bats.BatL[z].BoxBoundry = 32
bats.BatL[z].Active = 0
bats.BatL[z].id = 1
bats.BatL[z].FixedAngle = rand(359)
bats.BatL[z].ViewAngle = rand(359)
bats.BatL[z].Loc.x = rand((SCREEN_HEIGHT-1))
bats.BatL[z].Loc.y = rand((SCREEN_WIDTH-1))
bats.BatL[z].Direction.x = 0
bats.BatL[z].Direction.y = 0
bats.BatL[z].Amount = lbats
bats.BatL[z].Active=1
bats.BatL[z].SPEED = RND(0.5,3.0)
next z
endsub

SUB Play
def Radians as float
def loop as int
LOCKSPRITE batEast
LOCKBUFFER
for loop = 0 to lbats-1
if bats.BatL[loop].Active then
Radians = bats.BatL[loop].FixedAngle * 0.01745f
      bats.BatL[loop].Direction.x = fsin( Radians ) * 1.75f
      bats.BatL[loop].Direction.y = fcos( Radians ) * 1.75f
bats.BatL[loop].ViewAngle = myatan2(bats.BatL[loop].Direction.y,bats.BatL[loop].Direction.x)
MoveObject(bats.BatL[loop])
      TranslateObject(bats.BatL[loop])
      DrawObject(bats.BatL[loop])
end if
next loop
UNLOCKBUFFER
UNLOCKSPRITE batEast
endsub

SUB myatan2(y as double, x as double),double
def theta as double
   if x > 0 then  theta = atand(y/x)
   if x < 0 then  theta = atand(y/x) -180
   if x = 0
     if y > 0 then theta = 90
     if y < 0 then theta = -90
     if y = 0 then print "error"
  end if 
RETURN theta
ENDSUB


I have added the image file for educational purposes only.
(note I have a (C) at the bottom of the image with my name)

J B Wood (Zumwalt)

Now that I have all of that testing out of the way, on to phase 2, give the bats something to avoid, walls and such.
Phase 3, some basic AI, collision is easy enough.. will have to use part of the AI code to detect LOS, add some brightness values to the room, well, with bats doesn't matter since they work off of sonar.

Lots to do.

pistol350

Hi Jonathan !
I am one of those who are looking forward to see the end of this project.
What's new about the phase 2 ?
Regards,

Peter B.

J B Wood (Zumwalt)

Slightly on hold :) I got distracted on a larger project.
The larger project includes the AI component, so it is still being refined.
The battle system for humanoid hit locations is complete with point variations.
This is one of those issues where I have to much on my plate at one time...
I'll see if I can pull out the AI module for movement and post that. Its pretty deep.

pistol350

Keep up  ;)
Looking forward to see more  ;D
Regards,

Peter B.