Going from running to standing?

Blitz3D Forums/Blitz3D Beginners Area/Going from running to standing?

Cubed Inc.(Posted 2011) [#1]
look whos backXD
I have been working on the basic mechanics of my game(running,jumping etc) and i'm kinda stuck with a problem with making my character switch stances.

ok, so I coded a system where when the arrow keys (in this case the right key) is pressed, he plays his running animations and when let go, he switches back to his standing animation. The problem is that while his running animation work properly when they are supposed to, his standing animation doesn't play properly and gets stuck in the first frame.

I think it is becuase it being apart of the main loop of the game, making his standing animation play repeatedly, causing it to never go beyond the first frame, but that's just what I think.

Could someone maybe look at my code and try to see why this problem could be happening?


This is the animation handling piece of the code( Movement is still very unpolished at this state )


Hope this post wasn't to much of a pain in the ass to readXD but I really could use some help with this right now.

Last edited 2011


_PJ_(Posted 2011) [#2]
Currently, I believe the above snippet is essentially the same as:

If (KeyDown(205))
	TESTX=TESTX+.4
	If (TESTX>5)
		TESTX=5
	End If
	seq=1
	animtype=1
	animspeed=.9
Else
	 TESTX=0 
	seq=2
	animtype=2
	animspeed=.3
EndIf


Animate TEST_MODEL1,animtype,animspeed,seq,10

RotateEntity TEST_MODEL1,0,TESTYAW,0

TranslateEntity TEST_MODEL1,TESTX,0,0


EXCEPT the use of KeyHit in the original code only updates when the key is pressed. If it's held down, as in KeyDown() then it will only return a TRUE (or non-zero) value on the initial press.


Kryzon(Posted 2011) [#3]
I noticed that you're having to use custom speeds for each sequence.
You might as well 'bake' these speeds in your animation software (by scaling the timeline for it to grow or shrink), so you just have to handle the sequences back in B3D and not their speed as well.
Then you know all sequences have 1.0 speed.


Cubed Inc.(Posted 2011) [#4]
Malice
So the problem is that while kirby's (ssbm model) running animation is updated only when the right key is hit, allowing it to only update once letting the animation play correctly, while the standing animation plays only when the TESTX variable equals 0, causing the standing animation to update constently and forever, keeping the animiation from going beyond the first frame.

whoo, that was a mouthful.

So basically it seems that my animation playing system is faulty. I'd be okay with rewriting it, but I don't know how I can keep the animation from playing correctly if it is in the game's main loop.


Kryzon(Posted 2011) [#5]
You need a better state machine.
isAnimating = Animating(TEST_MODEL1)

KeyRIGHT = KeyDown(205) ;Store the current values in variables so you can use them better.
KeyLEFT = KeyDown(203) ;Each KeyDown\KeyHit returns a value which is '1' or '0', so you can perform math on them like subtraction, addition etc.

If (KeyRight=1) And (KeyLeft=0) Then
	ANIM_State = 1 ;Just set up the state.
EndIF
If (KeyLeft=1) And (KeyRight=0) Then ;Only move left if the right key is unpressed.
	;[...]
EndIf

If (KeyRight + KeyLeft + [...]) = 0 Then ;If none of the keys are pressed (the sum of them equals zero).
	ANIM_State = 0 ;Idle animation
EndIf 


Select ANIM_State
	Case 0
		If Not isAnimating Then Animate TEST_MODEL1,1,1.0,SEQ_idle,10
	Case 1
		MoveEntity [...] ;Control movement and other properties here, not at the KeyDown condition.
		If Not isAnimating Then Animate TEST_MODEL1,1,1.0,SEQ_walkLeft,10
	Case 2
		[...]
End Select


Last edited 2011


Rob the Great(Posted 2011) [#6]
I haven't looked at your code, but I know what the problem is.

There's one command I use all the time to fix this problem:
Global standing = ExtractAnimSeq(entity,first_frame,last_frame) ;Name your running sequence
;Main Loop...
If AnimSeq(entity) <> standing
    Animate entity, standing
EndIf

You can use that little bit above in combination with any other key downs, mouse downs, ect., and this will stop the issue of repeatedly calling "Animate" on your entity, thus only showing the first frame of animation. Kryzon's method works as well, and it looks like his applies to the code you've supplied.


Kryzon(Posted 2011) [#7]
I always overlook AnimSeq; it's a great suggestion. It's definitely better than checking with Animating(), since you're comparing current sequences instead of animating or not.


Cubed Inc.(Posted 2011) [#8]
Kryzon
Your right. animseq is a great function.

With the use of it and ALOT of headaches, I was able to make the his animation cycles work properly when they should.



This was the section of code where animseq became a hero


I tried out your idea of using cases to store and use the animations, but I felt that it was a rather strange way to use the case function and I couldn't get it working right when I tried making my own version of it.

Despite me actually getting kirbys animations to work right, I still have some concerns.

Everything may seem fine now, but I just started to mechanics of my game. Kirby's animations work good, but he's moving in only one direction. Throughout the games steady progress, kirby will be able to do more things, such as jumping and attacking and other stuff.

My concern is that will my little code be able to take on more than just 2 animations? I know theres no way to now until the progress is actually made, but I really wouldn't want to end back in the forums with the SAME exact question, so what do you guys think?

Last edited 2011

Last edited 2011


Kryzon(Posted 2011) [#9]
That's why I recommended a more clean state system. You need to make it more modular because you're going to have lots of sequences and properties for a fully animated character, and it'll get very complex in the end.

With a clean, modular state machine you can very easily add new states. Not only this but it allows you to make sequences progress into one another:
Select animState
	Case JUMPING
		If AnimSeq(Player) <> animJumping Then Animate Player,1,1.0,animJumping,10
		playerY = playerY + jumpForce
		jumpForce = jumpForce - gravity
		If jumpForce < 0.1 Then animState = FALLING ;Change animation sequence and state when player stalls in the jump.
	Case FALLING
		If AnimSeq(Player) <> animFalling Then Animate Player,1,1.0,animFalling,10
		playerY = playerY + jumpForce
		jumpForce = jumpForce - gravity
		If EntityCollided(Player,3) Then animState = TOUCHDOWN ;When player reaches the ground or a platform, change his animation to "bounce" or "absorb the impact".

	;[...]
End Select

I think the Select is the most important part.


Warner(Posted 2011) [#10]
I find it more easy to control animations myself using SetAnimTime.
Suppose the model has only one long sequence. Then you can something along the lines of the following:
   if keydown(30) start_f = 0: stop_f = 30: spd_f# = 1
   if keydown(31) start_f = 31: stop_f = 34: spd_f# = 0.1

   frm# = frm# + spd_f#
   if frm < start_f then frm = start_f
   if frm > stop_f then frm = start_f
   SetAnimTime ent, frm



Cubed Inc.(Posted 2011) [#11]
Warner
I think the animtime technique would work for MD2 models but since i'm using b3d models it probably won't work as well.

Kryzon
I honestly now do see how using a module based animation system would work out better but the problem is that I don't understand it very well.

I tried writing my own version of the code according to yours but when your programming, it's impossible to do anything right if you simply don't know what your doing, for example, what does the <> supposed to represent in the code? I heard somewhere a while ago that it mean "neither" but i'm not sure and it's kinda confusing me.

Can you please explain the module animation system more? I just can't seem to understand it very well.


Tau_Aquilae(Posted 2011) [#12]
"<>" is not equal if i remember correctly (if not smack me over the head and correct me!)


Rob the Great(Posted 2011) [#13]
The <> symbol just means "not equal to", "not the same thing as", "different", or if you want to get real technical, "Less than or Greater than", which just means that the expression will be true only if the variable is different than the value listed. It's a nice operator in Blitz, but I can't think of any situation of the top of my head that couldn't be re-written with the "Not" command. For example,
Const x = 1
If x <> 1 ;When I type this line, I say under my breathe while I type "If x is not equal to 1"
   Print "This line will never get printed"
EndIf

could just as easily be written as
Const x = 1
If Not x = 1
   Print "This line will never get printed"
EndIf

Let me break down Kryzon's code for you. The select command is especially useful if you have a variable that is going to have a lot of different but specific values throughout your game. Think of the Select command as a giant list of "If" statements all contained in one block of code. Without the Select command, some code could look like this:
Global StateOfBeing$ = "Idle"
;Here, the player changes the StateOfBeing$ variable based on gameplay
If StateOfBeing$ = "Idle"
   ;Do some stuff here
EndIf
If StateOfBeing$ = "Jumping"
   ;Do some stuff here
EndIf
If StateOfBeing$ = "Attacking"
   ;Do some stuff here
EndIf
If StateOfBeing$ = "Defending"
   ;Do some stuff here
EndIf
;This could go on for a very long time, depending on how many states you have

All of those "If...EndIf" blocks can get a little ugly, so why not combine all of them using the Select command? Here's the same bit of code, but modified to use the Select command.
Global StateOfBeing$ = "Idle"
;Here, the player changes the StateOfBeing$ variable based on gameplay
Select StateOfBeing$
   Case "Idle"
      ;Do some stuff here
   Case "Jumping"
      ;Do some stuff here
   Case "Attacking"
      ;Do some stuff here
   Case "Defending"
      ;Do some stuff here
End Select
;This could go on for a very long time, depending on how many states you have

As you can see, the code appears cleaner, and you don't have to type so many "If...EndIf"s. What I get from Kryzon's example is that you should set up your animations using this process. I would even go as far as setting up a state of being string for Kirby, then perform all of your actions, such as movement, animation ect., based off of those state of beings. Here's a rough example of what the rundown might look like:
Graphics3D 640,480 ;set up gfx
SetBuffer BackBuffer() ;double buffering...

Const TYPE_KIRBY = 1 ;entity types for collisions
Const TYPE_LEVEL = 2 ;entity types for collisions

Global camera = CreateCamera() ;make a camera
MoveEntity camera,0,10,-10 ;move it up and backwards

Global level = CreatePlane() ;make a level
EntityType level,TYPE_LEVEL ;set the collision type

Global kirby = LoadAnimMesh("kirby.b3d") ;load kirby!
TranslateEntity kirby,0,1,0 ;move kirby off the ground
EntityType kirby,TYPE_KIRBY ;set the collision type
PointEntity camera,kirby ;makes for an easy 3rd person camera
EntityParent,camera,kirby ;makes for an easy 3rd person camera
Global kirbyanimstand = ExtractAnimSeq(kirby,1,10) ;This is how I load animation. You might use a different process
Global kirbyanimjump = ExtractAnimSeq(kirby,11,20) ;name each animation
Global kirbyanimrun = ExtractAnimSeq(kirby,21,30) ;name each animation

Global kirbysob$ = "standing" ;create a variable for Kirby's State of Being, set it to "standing"

Collisions TYPE_KIRBY,TYPE_LEVEL,2,3 ;set collisions

;MAIN LOOP
;----------------------------

While Not KeyDown(1)

   GetNewKirbySOB()   ;The function is below

   UpdateKirby()   ;The Function is below

   PointEntity camera,kirby

   UpdateWorld
   RenderWorld
   Flip

Wend

ClearWorld

End

;FUNCTIONS LIST
;---------------------------------

Function GetNewKirbySOB() ;Get's Kirby's new State of Being, changes kirbysob$ variable

   ;First, let's see if kirby should be running
   If kirbysob$ <> "jump" Or kirbysob$ <> "floating" ;kirby can only run or jump while on the ground
      If Not KeyDown(RIGHT_KEY) ;If we're not pushing the right key
         If Not KeyDown(LEFT_KEY) ;If we're not pushing the left key
            kirbysob$ = "standing"   ;Kirby should now be standing
         EndIf
      EndIf

      If KeyDown(RIGHT_KEY) ;If we're pushing the right key
         If Not KeyDown(LEFT_KEY) ;we can't push both keys at the same time
            kirbysob$ = "runright"  ;Kirby should now be running right
         EndIf
      EndIf

      If KeyDown(LEFT_KEY) ;If we're pushing the left key
         If Not KeyDown(RIGHT_KEY) ;we can't push both keys at the same time
            kirbysob$ = "runleft"   ;Kirby should now be running left
         EndIf
      EndIf

      If KeyDown(RIGHT_KEY) And KeyDown(LEFT_KEY) ;If we are pushing both keys
         kirbysob$ = "standing"   ;Just make Kirby stand
      EndIf

      ;Next, see if he should jump
      If KeyHit(SPACE_BAR)
         kirbysob$ = "jump"   ;Kirby should now leap off the ground
      EndIf

   EndIf

End Function

Function UpdateKirby() ;Make Kirby do new actions based on his new State of Being

   Select kirbysob$  ;Open a Select Command (like multiple "if"s)

      Case "standing" ;If Kirby should be standing
         If AnimSeq(kirby) <> kirbyanimstand ;If Kirby isn't already animated to stand
            Animate kirby,kirbyanimstand ;Animate Kirby to stand
         EndIf

      Case "runright" ;If Kirby should be running right
         If AnimSeq(kirby) <> kirbyanimrun ;If Kirby isn't already animated to run
            Animate kirby,kirbyanimrun ;Animate Kirby to run
         EndIf
         RotateEntity kirby,0,90,0 ;Turn Kirby to the right. At least, I think this is to the right?
         MoveEntity kirby,0,0,1 ;Run Kirby forward (to the right) 1 unit per loop

      Case "runleft" ;If Kirby should be running left
         If AnimSeq(kirby) <> kirbyanimrun ;If Kirby isn't already animated to run
            Animate kirby,kirbyanimrun ;Animate Kirby to run
         EndIf
         RotateEntity kirby,0,-90,0 ;Turn Kirby to the left. At least, I think this is to the left?
         MoveEntity kirby,0,0,1 ;Run Kirby forward (to the left) 1 unit per loop

      Case "jump" ;If Kirby should be jumping
         If AnimSeq(kirby) <> kirbyanimjump ;If Kirby isn't already animated to jump
            Animate kirby,kirbyanimjump ;Animate Kirby to jump
         EndIf
         TranslateEntity kirby,0,50,0 ;Shoot Kirby up in the air!
         kirbysob$ = "floating" ;After Kirby's in the air, float to the ground

      Case "floating" ;if Kirby should be floating
         TranslateEntity kirby,0,-1,0 ;Gravity...
         If EntityCollided(kirby,TYPE_LEVEL) ;If Kirby touches the ground
            kirbysob$ = "standing" ;Kirby should now be standing
         EndIf

      ;As always, feel free to add any more Cases here with actions to go along with each case

   End Select

End Function

Hopefully this helps. I can get a little lengthy with my explanations, so sometimes it's more confusing than helpful to read my responses. lol.
EDIT: I should also note that the above example was written from the top of my head, so it's untested and will not execute as it is now. It was more or less written for demonstration of concept, but with a couple of minor changes and an actual model to load with animation, it would (in theory), execute like it should.

Last edited 2011


Kryzon(Posted 2011) [#14]
Great break-down Rob.

@TaGames: using a 'Select...Case' allows you to have your code behave differently depending on the state of a certain variable (like that 'State of Being' that Rob proposed).
This is especially useful since each state might have different conditions you want to check. If we're dealing with the "Floating" state, you might want to check if the player touched the ground so we change to the "Idle" or "Running" states.
If the player is "Swimming", you might want to display an air-meter and start draining air from a counter, and while in this state check if the player ever leaves the water so you can hide the air-meter back and reset the air amount the player has.

Every 'Case' will specify how the characters should behave, and how you should interpret what the player is currently doing. With this in mind you might actually do this (in the same function):
[Store the current state of the keyboard keys in variables - like I showed in post #5]

[Head to the Select which will run\select the appropriate piece of code for the current state of being]

[Interpret the state of the keyboard keys accordingly and handle any other game elements based on the current state]
This allows you to implement states such as "insideCart", where Kirby gets into a cart and his commands and the camera behave differently. Or you have to aim a sniper rifle and the keyboard keys now instead of controlling the character itself are controlling the crosshair of the rifle.

The reason for keeping this system clean is that you won't be dealing with a simple demo where you can roughly patch things that don't work properly just to make things work - you'll have multiple levels and a multitude of states, and things can get out of hand pretty quickly if you don't start the clean route from the beginning (not only with this system but with anything else you code).


Cubed Inc.(Posted 2011) [#15]
thanks for the help and explaination. I've practically fallen in love with the module system kryzon insisted (finally learned how to do it thanks to robs explaination)

thanks for all the help guys:)