Character Animation Control
Blitz3D Forums/Blitz3D Beginners Area/Character Animation Control
| ||
I'm having some frustrating problems with regard to controlling an MD2 character's animation sequences. The big problem seems to be with the jump animation. Can anyone help? My code looks like this: ;Called every frame Function UpdateCharacter(model) currentanimframe = MD2AnimateTime(model) Select(True) Case (KeyHit(57)) : If (currentanimframe < 67) Or (currentanimframe > 72) AnimateMD2 model, 3, 0.1, 67, 72, 2 ;JUMP ANIMATION (SPACE BAR) Case (KeyDown(200)) : If (currentanimframe < 40) Or (currentanimframe > 46) AnimateMD2 model, 1, 0.1, 40, 46, 2 ;RUN ANIMATION (FORWARD ARROW) Default : If (currentanimframe > 40) AnimateMD2 model, 1, 0.1, 0, 40, 2 ;DEFAULT IDLE ANIMATION End Select End Function Rogue Vector |
| ||
Rogue, I've not B3D at the moment, so I can't help you with code, but you may check the code located in the B3D samples folder; some of that sample deals with MD2 animation, and I'm sure you'll find it useful. If I recall fine, check the Reda directory. There's an example with a MD2 model which can run, fire and stay idle. Sergio. |
| ||
If I recall fine, check the Reda directory. There's an example with a MD2 model which can run, fire and stay idle. Reda directory? My B3D samples directory is 'Blitz3D\Samples\Blitz 3D Samples\' And there isn't a directory in there called Reda. Rogue Vector |
| ||
Uh, perhaps OpenDNA directory ? Again, under Blitz3D\Samples\Blitz 3D Samples\ Note that the example uses a .MD2 model, so if you do a search of *.MD2 from the main B3D samples directory, you should find it. I recall Reda because it's the name of the author of the example (Reda Borchart I guess) Anyway, looking at your code, I see that you use KeyHit for jump, and KeyDown for run animation. The running animation works because using keydown, you constantly animate the model, while using keyhit, you do this only once. Bare in mind that the model should constantly be animated, so to speak; is not enough to call once the animation statement, you have to do at each frame - and so you do with the running animation, thanks the use of keydown. So, you may better use a flag, and constantly set the animation as you do with the running one: const A_RUN = 1 const A_JUMP = 2 global anim ; ;character control anim = 0 if keydown(run_key) then anim = A_RUN if keydown(jump_key) then anim = A_JUMP ; ; ;in your main loop select anim case A_RUN If (currentanimframe < 40) Or (currentanimframe > 46) AnimateMD2 model, 1, 0.1, 40, 46, 2 ;RUN ANIMATION (FORWARD ARROW) case A_JUMP If (currentanimframe < 67) Or (currentanimframe > 72) AnimateMD2 model, 3, 0.1, 67, 72, 2 ;JUMP ANIMATION (SPACE BAR) end select Does he jump now ? :) Sergio. |
| ||
Here's my full code. Maybe someone could explain why it doesn't work. What's wrong with my logic here? You'll need to substitute an MD2 model file path AppTitle "Character Animation System", "Are you sure you want to quit?" Graphics3D 1024,768,16,0 SetBuffer BackBuffer() ;constants Const FPS = 30 ;globals Global index% = 0 Global ticks# = 0.0 Global elapsed# = 0.0 Global period# = 1000/FPS Global time# = MilliSecs() - period Global tween# = 0.0 Global model = 0 Global texture = 0 Global camera = 0 Global light = 0 Global modelfilepath$ = "system/media/MD2/alita/tris.md2" Global texturefilepath$ = "system/media/MD2/alita/alita.pcx" Global currentanimframe = 0 Global jumping = False Global crouching = True ;start program Initialise() ;main loop Repeat Repeat elapsed = MilliSecs() - time Until elapsed ticks = elapsed / period tween# = Float(elapsed Mod period)/ Float(period) For index = 1 To ticks time = time + period If (index = ticks) CaptureWorld() Update_Character() UpdateWorld() Next RenderWorld(tween) Flip Until KeyHit(1) ;shutdown program ClearWorld() End ;functions Function Initialise() camera=CreateCamera() PositionEntity camera,0,3,-4 light=CreateLight() PositionEntity light, 2, 6, -5 model = LoadMD2(modelfilepath) texture = LoadTexture(texturefilepath) ScaleEntity model, 0.07, 0.07, 0.07 EntityTexture model, texture PositionEntity model, 0, 1.7, 0 PointEntity camera, model PointEntity light, model EntityParent light, model AnimateMD2 model, 1, 0.1, 0, 40 ;DEFAULT IDLE ANIMATIION End Function Function Update_Character() currentanimframe = MD2AnimTime(model) Select(True) Case (KeyHit(57)) : jumping = True Case (KeyHit(46)) : crouching = True Case (KeyDown(200)) : If (currentanimframe < 40) Or (currentanimframe > 46) AnimateMD2 model, 1, 0.25, 40, 46, 2 ;FORWARD with UP ARROW Case (KeyDown(208)) : If (currentanimframe < 40) Or (currentanimframe > 46) AnimateMD2 model, 1, -0.25, 40, 46, 2 ;REVERSE with DOWN ARROW Default : If (currentanimframe > 40) AnimateMD2 model, 1, 0.05, 0, 40, 2 ;DEFAULT IDLE ANIMATIION End Select ;process animations If (jumping) AnimateMD2 model, 3, 0.1, 67, 72, 2 ;ONE-SHOT JUMP ANIMAION EndIf If (currentanimframe => 72) jumping = False If (currentanimframe > 40) AnimateMD2 model, 1, 0.05, 0, 40, 2 ;DEFAULT IDLE ANIMATIION EndIf End Function Regards, Rogue Vector |
| ||
I think I know what's up -- 'jumping' is set to True when you hit Space, so this...If (jumping) AnimateMD2 model, 3, 0.1, 67, 72, 2 ;ONE-SHOT JUMP ANIMAION EndIf ... is always called when the code gets here. Because Animate/MD2 restarts the animation, it doesn't get past the first frame. |
| ||
This fixes it (changes = *****)...Select(True) Case (KeyHit(57)) : AnimateMD2 model, 3, 0.1, 67, 72, 2: jumping = True ; ***** Case (KeyHit(46)) : crouching = True Case (KeyDown(200)) : If (currentanimframe < 40) Or (currentanimframe > 46) AnimateMD2 model, 1, 0.25, 40, 46, 2 ;FORWARD with UP ARROW Case (KeyDown(208)) : If (currentanimframe < 40) Or (currentanimframe > 46) AnimateMD2 model, 1, -0.25, 40, 46, 2 ;REVERSE with DOWN ARROW Default : If (jumping = 0) And (currentanimframe > 40) AnimateMD2 model, 1, 0.05, 0, 40, 2 ; ***** ;DEFAULT IDLE ANIMATIION End Select ;process animations ; If (jumping) ; ***** ; ***** ; ***** ; ***** ; EndIf ; ***** If (currentanimframe => 72) jumping = False If (currentanimframe > 40) AnimateMD2 model, 1, 0.05, 0, 40, 2 ;DEFAULT IDLE ANIMATIION EndIf |
| ||
When I ran this, it certainly fixed the problem with the JUMP animation - thanks by the way :) But, now the default IDLE animation doesn't work. ??? Rogue Vector |
| ||
Seems to be working here, even after doing the jump (and with debug on and "DebugLog currentanimframe" at the start of Update_Character I can see it's going from frame 0 to 40). I'm using the dragon model from "\samples\mak\dragon" BTW. Here's the full source as I currently have it -- see if it works for you... |
| ||
Thanks! Still having a problem with the Death animation sequence. It plays out normally, then tweens back to an earlier frame. Any ideas? The model file and texture can be downloaded from here: http://www.octanedigitalstudios.com/downloads/AnimationControl.zip Here's my latest code: AppTitle "Character Animation System", "Are you sure you want to quit?" Graphics3D 800,600,16,0 SetBuffer BackBuffer() Include "keyconstants.bb" ;constants Const FPS = 30 Const type_MD2 = 1000 Const type_B3D = 1001 Const type_3DS = 1002 ;globals Global index% = 0 Global ticks# = 0.0 Global elapsed# = 0.0 Global period# = 1000/FPS Global time# = MilliSecs() - period Global tween# = 0.0 Global model = 0 Global texture = 0 Global camera = 0 Global light = 0 Global modelfilepath$ = "tris.md2" Global texturefilepath$ = "alita.pcx" Global g_currentanimframe = 0 Global g_jumping = False Global g_dying = False Global g_character_is_dead = False ;start program Initialise() ;main loop Repeat Repeat elapsed = MilliSecs() - time Until elapsed ticks = elapsed / period tween# = Float(elapsed Mod period)/ Float(period) For index = 1 To ticks time = time + period If (index = ticks) CaptureWorld() Update_CharacterAnimation(model, type_MD2) UpdateWorld() Next RenderWorld(tween) Color 0,0,255: Text 5, 2, "Animation Frame: " + g_currentanimframe Color 255,255,255 Text 5, 20, "ARROW KEYS = FORWARDS \ BACK" Text 5, 35, "SPACE = JUMP" Text 5, 50, "C KEY + ARROW UP = CROUCH WALK" Text 5, 65, "D KEY = DEATH" If (g_character_is_dead=True) Color 255,0,0:Text 5, 80, "Character is dead!" EndIf Flip Until KeyHit(1) ;shutdown program ClearWorld() End ;functions Function Initialise() camera=CreateCamera() PositionEntity camera,0,3,-5 light=CreateLight() PositionEntity light, 2, 6, -5 model = LoadMD2(modelfilepath) texture = LoadTexture(texturefilepath) ScaleEntity model, 0.07, 0.07, 0.07 EntityTexture model, texture PositionEntity model, 0, 1.7, 0 PointEntity camera, model PointEntity light, model EntityParent light, model AnimateMD2 model, 1, 0.1, 0, 40, 4 ;DEFAULT IDLE ANIMATIION End Function Function Update_CharacterAnimation(v_model, v_model_type) g_currentanimframe = process_anim_frame(v_model, v_model_type);Get the current animation frame If (g_character_is_dead=False) Select(True) Case (KeyHit(KEY_D)) : process_dying(v_model, v_model_type) ; DEATH 1 with D Case (KeyHit(KEY_SPACE)) : process_jump(v_model, v_model_type) ; JUMP with SPACE BAR Case (KeyDown(KEY_C)) : process_crouching(v_model, v_model_type) ; CROUCH IDLE and CROUCH WALK with C key and/or ARROW KEYS Case (KeyDown(KEY_ARROWPAD_UP)) : process_run(v_model, v_model_type) ; RUN with UP ARROW Case (KeyDown(KEY_ARROWPAD_DOWN)) : process_run_backwards(v_model, v_model_type); RUN BACKWARDS with DOWN ARROW Default : If (g_dying=True) process_dying(v_model, v_model_type) ; CHARACTER IS DYING Else process_idle(v_model, v_model_type) ; DEFAULT IDLE ANIMATIION EndIf End Select If (g_currentanimframe = 72) g_jumping = False If (g_currentanimframe > 40) AnimateMD2 v_model, 1, 0.1, 0, 40, 4 ;DEFAULT IDLE ANIMATIION EndIf If (g_currentanimframe = 184) g_character_is_dead = True EndIf Else ;Character is dead - perform post mortem processes here EndIf End Function Function process_anim_frame%(v_model, v_model_type) If (v_model_type = type_MD2) Return MD2AnimTime(v_model) Else Return AnimTime(v_model) EndIf End Function Function process_idle(v_model, v_model_type) If (Not g_jumping) And (Not g_death) And (g_currentanimframe > 40) AnimateMD2 v_model, 1, 0.1, 0, 40, 4 ; DEFAULT IDLE ANIMATIION EndIf End Function Function process_jump(v_model, v_model_type) If (v_model_type = type_MD2) AnimateMD2 v_model, 3, 0.1, 67, 72, 4 g_jumping = True Else ;animate other model types here EndIf End Function Function process_run(v_model, v_model_type) If (KeyDown(KEY_C)=False) If (v_model_type = type_MD2) If (g_currentanimframe < 41) Or (g_currentanimframe > 46) AnimateMD2 v_model, 1, 0.25, 41, 46, 4 g_jumping = False EndIf Else ;animate other model types here EndIf EndIf End Function Function process_run_backwards(v_model, v_model_type) If (KeyDown(KEY_C)=False) If (v_model_type = type_MD2) If (g_currentanimframe < 41) Or (g_currentanimframe > 46) AnimateMD2 v_model, 1, -0.25, 41, 46, 4 g_jumping = False EndIf Else ;animate other model types here EndIf EndIf End Function Function process_crouching(v_model, v_model_type) Select(True) Case (KeyDown(KEY_ARROWPAD_UP)=True) : If (v_model_type = type_MD2);CROUCH WALK FORWARDS - UP ARROW If (g_currentanimframe < 155) Or (g_currentanimframe > 160) AnimateMD2 v_model, 1, 0.1, 155, 160, 4 g_jumping = False EndIf Else ;animate other model types here EndIf Case (KeyDown(KEY_ARROWPAD_DOWN)=True) : If (v_model_type = type_MD2);CROUCH WALK BACKWARDS - DOWN ARROW If (g_currentanimframe < 155) Or (g_currentanimframe > 160) AnimateMD2 v_model, 1, -0.1, 155, 160, 4 g_jumping = False EndIf Else ;animate other model types here EndIf Default : If (v_model_type = type_MD2);CROUCH IDLE If (g_currentanimframe < 136) Or (g_currentanimframe > 154) AnimateMD2 v_model, 1, 0.1, 136, 154, 4 g_jumping = False EndIf Else ;animate other model types here EndIf End Select End Function Function process_dying(v_model, v_model_type) If (v_model_type = type_MD2) If (g_currentanimframe < 179) Or (g_currentanimframe > 184) AnimateMD2 v_model, 3, 0.1, 179, 184, 1 EndIf g_jumping = False g_dying = True Else ;animate other model types here EndIf End Function Rogue Vector. |