Character Animation Control

Blitz3D Forums/Blitz3D Beginners Area/Character Animation Control

Rogue Vector(Posted 2005) [#1]
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


semar(Posted 2005) [#2]
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.


Rogue Vector(Posted 2005) [#3]

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


semar(Posted 2005) [#4]
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.


Rogue Vector(Posted 2005) [#5]
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


BlitzSupport(Posted 2005) [#6]
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.


BlitzSupport(Posted 2005) [#7]
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 



Rogue Vector(Posted 2005) [#8]
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


BlitzSupport(Posted 2005) [#9]
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...




Rogue Vector(Posted 2005) [#10]
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.