Help with Animations for KeyHit?
BlitzMax Forums/BlitzMax Beginners Area/Help with Animations for KeyHit?
| ||
| Basically I am trying to make a Frogger game and I want it to go up when I press the up key and when I hit up it goes into one animation(legs extend) and to do the next animation I have to hit the up key again(legs retract) the code is "" If KeyHit(Key_Up) Player.y = Player.y - 20 DifficultyCursor.y = DifficultyCursor.y - 132 player.frame = player.frame + 1 If player.frame >1 player.frame = 0 EndIf Endif" How can I make it to where it will do the two frames, frame 1 is 0 and frame 2 is 1. Also the difficulty cursor part is for a difficulty selection before starting the game. EDIT : I know that it will either be frame 1 or frame 0 how do i make it to where it will do both frame 0 and frame 1 when hitting up. |
| ||
| You need to learn how to use a state machine in your code. It's a way to change the behaviour of your game based on the value of a variable. - https://www.scirra.com/tutorials/1139/how-to-simplify-your-ai-code-with-finite-state-machines - http://howtomakeanrpg.com/a/state-machines.html On one game state (like a game menu), pressing the up key changes the difficulty level. On another game state (gameplay), pressing the up key changes the character state of the character from (whatever they're doing) to "moving". In the state processing code of the character you check to see what state the character is on (idle, moving, jumping etc.), and if it's in the "moving" state then you play the apropriate animation. |
| ||
| Would the state machine make it do the full animation when i move the character? |
| ||
| You are free to program the state machine to do what you want on each state (such as changing frames of an animation), this is how you get different behaviours. Please read those articles, they explain how it can help you. To make a simple finite state machine you need to write code such as this: Method processCharacterState() Select state Case STATE_IDLE 'All the stuff you need to check on this idle state: '- Check if the idle animation is being played, and if not, change to it. '- Check if enough time has passed to advance the frame of the current animation (which is "idle"). '- Check the keyboard keys being pressed, see if the character needs to change to another state (like, to jump or start moving). '- Check for collisions against the level and enemies. Case STATE_MOVING 'All the stuff you need to check on this moving state: '- Check if the correct moving animation is being played based on the character direction, and if not, change to it. '- Check if enough time has passed to advance the frame of the current animation (which is "moving, to a certain direction"). '- Check the keyboard keys being pressed to see if you need to change back to idle state or jump or keep moving. '- Check for collisions against the level and enemies. 'If there are no collisions against the level, not even the ground, for example, the character should go to state STATE_FALLING where you apply gravity. End Select End Method |
| ||
| So do I need to download it? |
| ||
| No, it's a software design pattern, it's the way you structure your program. |
| ||
| Oh okay,thanks but I was just really wondering how to do animations. |
| ||
If you only have an animation with two frames, you could use a simply timestamp to reset the frame:Type TPlayer Field X%, Y%, Frame%, AnimTime%, Frog:Timage Method Jump() Frame=1 AnimTime=MilliSecs()+500 Y = Y - 20 End Method Method Draw() If AnimTime<MilliSecs() Frame=0 EndIf DrawImage Frog,X,Y,Frame End Method End Type Repeat Cls If KeyHit(Key_Up) Player.Jump EndIf Player.Draw() Flip Until KeyHit(KEY_ESCAPE) |
| ||
| If I was to have it be 3 frames I would just add Frame = 1 underneath frame =0?Thank you for the answer though. |
| ||
You could just increase the frame each time your timer went to 0.If AnimTime < Millisecs() Frame :+ 1 AnimTime = Millisecs() + 500 'variant 1 if Frame = 4 then Frame = 0 'only Frame 0-3 would happen 'variant 2 Frame = Frame mod 4 'leading to 1 = 1, 2 = 2 ..., 4 = 0, 5 = 1, ... Endif bye Ron |
| ||
| Thanks,And for the first part could I put Field X%, Y%, Field Frame%, Field AnimTime%, Field Frog:Timage |
| ||
| Because at the top of my code I have Type TObject Field x,y Field image:TImage Field frame EndType |
| ||
It does not matter ,if you write...Type TObject Field X%, Y%, Frame%, AnimTime%, Image:Timage...or ... Type TObject Field x:Int, y:Int Field frame:Int Field AnimTime:Int Field image:TimageBut you should always define the variables, f.e. as INTEGER or FLOAT (good programming style) To use more than two frames you should do it like this: Type TObject Field X%, Y%, Frame%, AnimTime%, Frog:Timage Method Jump() Frame=1 AnimTime=MilliSecs()+500 Y = Y - 20 End Method Method Draw() If ( Frame>0 ) AND ( AnimTime<MilliSecs() ) Frame=Frame +1 AnimTime = Millisecs() + 500 If Frame=3 Then Frame=0 EndIf DrawImage Frog,X,Y,Frame End Method End Type this stopps the animation, when the frog is returned to Frame 0 |
| ||
| Thanks, I usually do define them as an integer.But what is the purpose of % After some of the defined variables ( AnimTime% ) |
| ||
| its the same... an old school version of ":INT" |
| ||
| Oh okay thanks.Also what does Method do exactly? |
| ||
| Method is a function that only applies to the object/type. E.g. Type TMultiplicationTable Field number:Int Method ShowTable() Local i:Int For i = 1 To 10 DebugLog(number * i) Next End Method End Type Local table:TMultiplicationTable = New TMultiplicationTable table.number = 3 table.ShowTable() table.number = 7 table.ShowTable() |
| ||
| You can compare the scope of METHOD versus FUNCTION with the type's variable scope GLOBAL versus FIELD: If you create a member (instance) of a type it has its own variables called FIELDS. The type in total instead uses GLOBAL variables. Analog to this a METHOD is a "function", which is only avaiable to the member (instance). The METHOD is used (written) like a field: with a point behind the member. Global FrogA:TObject=New TObject Global FrogB:TObject=New TObject FrogA.X=3 FrogB.Jump() Type TObject Field X%, Y%, Frame%, AnimTime%, Frog:Timage Method Jump() Frame=1 AnimTime=MilliSecs()+500 Y = Y - 20 End Method .... End Type As you can see FrogA and FrogB are two members of the TObject. Only FrogA's X would become 3. Only FrogB would jump in this code. Another advantage: All fields can be accessed directly inside the METHOD: You can also see, that inside the method the fields of FROGB like FRAME can be used without adding the word "FROGB". There is a second possibility of writing methods, which may help you to understand. Same code like above: Method Jump() Self.Frame=1 Self.AnimTime=MilliSecs()+500 Self.Y = Self.Y - 20 End Method .... |
| ||
A Method is like a Function with the added parameter "instance" (or "object")
Type TMyObject
Field name:string
Method PrintName(andNumber:int = 0)
print name + andNumber
End Method
End Type
Function PrintName(obj:TMyObject, andNumber:int = 0)
if obj then print obj.name + andNumber
End Function
'alternative - if you want to have both ways
Function PrintNameAlternative(obj:TMyObject, andNumber:int = 0)
if obj then obj.PrintName(andNumber)
End Function
global test:TMyObject = new TMyObject
test.name = "test"
test.PrintName(5)
PrintName(test, 6)
PrintNameAlternative(test, 7)
bye Ron |
| ||
| Do I have to call a method like I would for a function(as in putting the name of it in the main loop? |
| ||
| The syntax for calling a method and a function is explained well in this BlitzMax guide: http://www.truplo.com/blitzmaxbeginnersguide/wave10.html |
| ||
as you need an member (instance) of the type, you can only call the method with the instance's name in front:Global FrogA:TObject=New TObject
Repeat
FrogA.Jump()
....
Until...
Function CheckAll()
....
FrogA.Jump()
End FunctionAlso very comfortable is to add all Objects to a list and the call each Object within a FOR/NEXT loop: Global FrogA:TObject=New TObject
Global FrogB:TObject=New TObject
Global List:TList=New TList
List.AddLast FrogA
List.AddLast FrogB
For local locFrog:TObject= EachIn List
locFrog.Jump()
Next
Until...
Function CheckAll()
Frog.Jump()
End Function |
| ||
| Why would I need to add the animation code in a method? |
| ||
| You dont need to. One can do pretty much the same thing with bare functions. The strength of Methods come into play when you start building type hierarchies by extending other types, where an extended type can override the behavior of its parent. Something like what Midimaster posted, that Jump method can do something different for each type without the need for a second identifier tag and If-Else/Select-Case over it. |
| ||
| Oh okay thanks. |
| ||
| So I used the code that Midimaster posted " Type TObject Field X%, Y%, Frame%, AnimTime%, Frog:Timage Method Jump() Frame=1 AnimTime=MilliSecs()+500 Y = Y - 20 End Method Method Draw() If ( Frame>0 ) AND ( AnimTime<MilliSecs() ) Frame=Frame +1 AnimTime = Millisecs() + 500 If Frame=3 Then Frame=0 EndIf DrawImage Frog,X,Y,Frame End Method End Type ' And it for some reason isn't making the animations happen,why is that? |
| ||
| Depends on how you call it i guess.. Heres an example using what you posted: |
| ||
| What does "SetGraphicsDriver GLMax2DDriver()" do? |
| ||
| It is not necessary, remove it. Here is the same code with a more realistic jump: |
| ||
| So I use the code that grable posted,but changed it to show the image I am trying to use and iit makes the player go up but it doesn't show the animations,why is that?Here is the code,it is the entire code,there is nothing else in it " SuperStrict Graphics 800,600,0 Global Frog:Tobject = New Tobject Frog.X = 400 Frog.Y = 300 Repeat If KeyHit(Key_Up) Then Frog.jump() Frog.Draw() Flip Cls Frog.image = LoadAnimImage ("Frogger 2.0 AnimTest.bmp",30,28,0,6) DrawImage Frog.image,Frog.X,Frog.Y Until KeyHit(Key_Escape) Or AppTerminate() End Type Tobject Field X:Int,Y:Int,Frame:Int,AnimTime:Int,image:TImage,Frog:Int Method Jump() Frame = 1 AnimTime=MilliSecs()+500 Y = Y - 100 EndMethod Method Draw() If ( Frame >0 ) And ( AnimTime<MilliSecs() ) Frame = Frame + 1 AnimTime = MilliSecs() + 500 If Frame = 3 Then Frame = 0 Y :+ 100 EndIf EndIf EndMethod EndType " |
| ||
| I would guess the 500msec are to long and the y-100 to big to see the animation. The loading of the images should be before the REPEAT loop. Does the images really contain 6 frames? There is no need to have another DrawImage inside the REPEAT loop. Because you already call the FROG.DRAW method, which will also draw the frog. Try this and report, what happened: |
| ||
| Thanks for the reply,the reason it has 6 images is because I was making it for more than just going up the first 3 were for going up and the next three were for going left,but what happens with the game is that it goes up,then down an to the right but doesn't load the other animations. EDIT:With the way I tried to make the animations,the first three images were for the frog to go up and the next three were so it can go left,so in the game it would be up would make it go up then left would make it go left. |
| ||
| Thanks for the reply,the reason it has 6 images is because I was making it for more than just going up the first 3 were for going up and the next three were for going left,but what happens with the game is that it goes up,then down an to the right but doesn't load the other animations. EDIT:With the way I tried to make the animations,the first three images were for the frog to go up and the next three were so it can go left,so in the game it would be up would make it go up then left would make it go left. |
| ||
| so do a first check about the frames are existing and the dimensions are ok. Test this as a new project (save it in the same folder like your original game) and report back Download my image guitarl2.png and add it to this folder. SuperStrict
Graphics 800,600,0
Local YourImage:TImage = LoadAnimImage ("Frogger 2.0 AnimTest.bmp",30,28,0,6)
Local MidiImage:TImage = LoadAnimImage ("GuitarL2.png",25,30,0,6)
SetColor 255,255,255
Repeat
Cls
For Local i%=0 To 5
DrawImage YourImage, i*50, 100, i
DrawImage MidiImage, i*50, 200, i
Next
Flip 1
Until KeyHit(KEY_ESCAPE)
|
| ||
| So I did what you said and it shows all 6 of your images side by side,going from the first to the last,and above yours is all 6 of my images side by side. |
| ||
so the image is OK and the frames are well dimensioned. Did you forget to add the FRAME% parameter in the DRAWIMAGE command?DrawImage Frog.image, Frog.X, Frog.Y, Frog.Frame or if you put the drawing into the method Draw: Method Draw() If ( Frame>0 ) And ( AnimTime<MilliSecs() ) ..... EndIf DrawImage Image, X, Y, Frame .... |
| ||
| I didn't use Frog.Frame,I did just have it be frame:Int.Was that the problem? |
| ||
In your post #30 you wrote:DrawImage Frog.image,Frog.X,Frog.Yhere you forgot the Frame parameter! And you defined Frame as a field of TObject. So you have to use it as a property of the objects: Frog.FrameIt is is the same like X and Y So please try the code in my post #31. It should work. |
| ||
| But your post at 31 doesn't have frog.frame? |
| ||
| Never mind I used the code at 31 and it worked,thank you.But the weird thing is that it doesn't have frog.frame,instead it is "DrawImage Image, X,Y, Frame" |
| ||
| Yes, this is because a Method is already "inside" of each object (member) of a type: No need to additional write the objects name to the field variables. So your Method DrawImage() is inside the Frog-Object: No need to additional write "Frog." to the field variables like X, Y or Frame. (Look: You will also find no Frog.X in my code) What you could do inside a method is to add "Self." to all field variables. But it is unnecessary: Method Draw() If ( Self.Frame>0 ) And ( Self.AnimTime<MilliSecs() ) Self.Frame=Self.Frame +1 Self.AnimTime = MilliSecs() + 200 If Self.Frame=3 Then Self.Frame=0 Self.Y :+ 15 Self.X :+ 15 EndIf EndIf DrawImage Self.Image, Self.X,Self.Y, Self.Frame End Method |
| ||
| What exactly would adding self to everything do? |
| ||
| Nothing! It is only a second possibility to write the code. Some prefer to add "self.". I prefer only to write the field names. |
| ||
| "Self" is needed inside a method if you want to acquire the object itself that the method was called on, the "Frog" in your case. If you don't need a reference the object itself, only to members of it (like in the code in #41 above), you can still add "Self." in front of their names. If there's a local variable of the same name as the member, this will make sure you get the member and not the local var, otherwise it's optional. |
| ||
| Oh okay thanks.But now I have a new problem with it,all of the animations work perfectly if I make it to where the only thing that you can do is that animation(for key up,down,left right)but when I include them all in the code,the only one that works how it is supposed to work is key_up and the rest just go through all the animations nonstop until it goes past the last animation(in this case it is number 12) the code will be in the next reply. |
| ||
Graphics 800,600,0
Local Frog:TObject = New TObject
Frog.X = 400
Frog.Y = 250
Frog.image = LoadAnimImage ("Frogger 2.0 AnimTest.bmp",30,28,0,12)
Repeat
If KeyHit(Key_Up) Then Frog.Up()
If KeyHit(Key_Left) Then Frog.Left()
If KeyHit(Key_Right) Then Frog.Right()
If KeyHit(Key_Down) Then Frog.Down()
Frog.Draw()
Flip
Cls
Until KeyHit(KEY_ESCAPE) Or AppTerminate()
End
Type TObject
Field X%, Y%, Frame%, AnimTime%, Image:TImage
Method Up()
Frame = 1
AnimTime=MilliSecs()+200
Y = Y - 20
End Method
Method Left()
Frame = 5
AnimTime=MilliSecs()+200
X = X - 20
End Method
Method Right()
Frame = 7
AnimTime=MilliSecs()+200
X = X + 20
EndMethod
Method Down()
Frame = 10
AnimTime=MilliSecs()+200
Y = Y + 20
EndMethod
Method Draw()
'Up
If ( Frame>0 ) And ( AnimTime<MilliSecs() )
Frame=Frame + 1
AnimTime = MilliSecs() + 200
If Frame=3 Then
Frame=0
EndIf
EndIf
'Left
If ( Frame>4 ) And ( AnimTime<MilliSecs() )
Frame=Frame + 1
AnimTime = MilliSecs() + 200
If Frame=6 Then
Frame=3
EndIf
EndIf
'Right
If (Frame >6) And (AnimTime<MilliSecs() )
Frame = Frame + 1
AnimTime = MilliSecs() + 200
If Frame = 9 Then
Frame = 6
EndIf
EndIf
'Down
If (Frame >9) And (AnimTime<MilliSecs() )
Frame = Frame + 1
AnimTime = MilliSecs() + 200
If Frame > 11 Then
Frame = 9
EndIf
EndIf
DrawImage Image, X,Y, Frame
End Method
End Type
|
| ||
| your code looks good, but you need to change the order of conditions in the method Draw(). An example will show you the problem: You press KEY_DOWN and FRAME will become 10. When the code now comes to Draw() the first condition will be fullfilled! Method Draw() 'Up If ( Frame>0 ) And ( AnimTime<MilliSecs() ) 10 is greater than 0. So the code wil jump into the first condition ("up") . this is not what you want. You can change the order of condition. Now the highest values are on the top: Method Draw() 'Down If (Frame >9) And (AnimTime<MilliSecs() ) ... 'Right If (Frame >6) And (AnimTime<MilliSecs() ) ... 'Left If ( Frame>4 ) And ( AnimTime<MilliSecs() ) ... 'Up If ( Frame>0 ) And ( AnimTime<MilliSecs() ) ... Now a 10 will jump into "Down". And a 7 into "Right"... But now you will have the next problem. At the end of a "Down" sequence the FRAME will become 9. And this fulfilles the condition for "Right", because 9 is greater than 6. The best way is not to use FRAME for decisions any more, but add a new field ACTION%, which knows, that an animation is running. |
| ||
Okay so now I have a new problem lol,when I run the program it says "Missing function parameter 'Direction' on the part where it says "If KeyHit(Key_Up) Then Frog.Up()"I have no idea on how to fix it,please help.Edit : Here is the entire code of the program Graphics 800,600,0
Local Frog:TObject = New TObject
Frog.X = 400
Frog.Y = 250
Frog.image = LoadAnimImage ("Frogger 2.0 AnimTest.bmp",30,28,0,12)
Repeat
If KeyHit(Key_Up) Then Frog.Up()
If KeyHit(Key_Left) Then Frog.Left()
If KeyHit(Key_Right) Then Frog.Right()
If KeyHit(Key_Down) Then Frog.Down()
Frog.Draw()
Flip
Cls
Until KeyHit(KEY_ESCAPE) Or AppTerminate()
End
Type TObject
Field X%, Y%, Frame%, AnimTime%, Image:TImage, Action%
Method Up (Direction%)
Action=1 '************** add this to all four methods!
Frame = 1
AnimTime=MilliSecs()+200
Y = Y - 20
End Method
Method Down(Direction%)
Action=1
Frame = 1
AnimTime=MilliSecs()+200
Y = Y - 20
End Method
Method Left(Direction%)
Action=1
Frame = 1
AnimTime=MilliSecs()+200
Y = Y - 20
End Method
Method Right (Direction%)
Action=1
Frame = 1
AnimTime=MilliSecs() + 200
Y = Y - 20
End Method
Method Draw()
If Action>0
Frame=Frame + 1
AnimTime = MilliSecs() + 200
If Frame=3 Then
Frame=0
Action=0
ElseIf Frame=6 Then
Frame=3
Action=0
ElseIf Frame = 9 Then
Frame = 6
Action=0
ElseIf Frame =12 Then
Frame = 9
Action=0
EndIf
EndIf
DrawImage Image, X,Y, Frame
End Method
End Type
|
| ||
| Your functions declare a param "Direction%" - but when calling "bla.Up()" you do not provide one. Either define "default params": Method Right(Direction%=0) or provide a param bla.Up(0) But the best is: just remove that param from the method/function definition at all - as within that methods you do not use that param-variable at all. bye Ron |
| ||
| So instead of If KeyHit(Key_Down) Then Frog.Down() use method right(Direction%= 0)??? |
| ||
| For your current code: If KeyHit(Key_Down) Then Frog.Down(1) (the 1 could be any number as you do not work with the variable within the method "Down()") If you changed "Method Down(Direction%)" to "Method Down()" you would not need to adjust the "If KeyHit..."-lines. bye Ron |
| ||
Okay so I got it to work,thanks to Derron and Midimaster,but the weird thing is,when I press up it does 1 and 3,if i press left 3 and 5 and so on for down and right,basically it doesn't do the middle animation,only the first and last.Here is the code Graphics 800,600,0
Local Frog:TObject = New TObject
Frog.X = 400
Frog.Y = 250
Frog.image = LoadAnimImage ("Frogger 2.0 AnimTest.bmp",30,28,0,12)
Repeat
If KeyHit(Key_Up) Then Frog.Up(1)
If KeyHit(Key_Left) Then Frog.Left(1)
If KeyHit(Key_Right) Then Frog.Right(1)
If KeyHit(Key_Down) Then Frog.Down(1)
Frog.Draw()
Flip
Cls
Until KeyHit(KEY_ESCAPE) Or AppTerminate()
End
Type TObject
Field X%, Y%, Frame%, AnimTime%, Image:TImage, Action%
Method Up (Direction%)
Action=1 '************** add this to all four methods!
Frame = 0
AnimTime=MilliSecs()+200
Y = Y - 20
End Method
Method Left(Direction%)
Action=4
Frame = 4
AnimTime=MilliSecs()+200
X = X - 20
End Method
Method Right (Direction%)
Action=7
Frame = 6
AnimTime=MilliSecs() + 200
X = X + 20
End Method
Method Down(Direction%)
Action=9
Frame = 9
AnimTime=MilliSecs()+200
Y = Y + 20
End Method
Method Draw()
If Action>0
Frame=Frame + 1
AnimTime = MilliSecs() + 200
If Frame=3 Then 'UP
Frame = 0
Action=0
ElseIf Frame=6 Then 'LEFT
Frame=3
Action=0
ElseIf Frame = 9 Then 'RIGHT
Frame = 6
Action=0
ElseIf Frame =12 Then 'DOWN
Frame = 9
Action=0
EndIf
EndIf
DrawImage Image, X,Y, Frame
End Method
End Type
|
| ||
| sorry, my mistakes! 1. "Direction%" is not necessary... I had an idea, tested it, discarded it, but forgot to remove the parameter "Direction%" from the code. Sorry! Wrong: Type TObject Right: Repeat If KeyHit(Key_Up) Then Frog.Up() If KeyHit(Key_Left) Then Frog.Left() If KeyHit(Key_Right) Then Frog.Right() If KeyHit(Key_Down) Then Frog.Down() ... Type TObject Method Up() 2. I removed "If Animtime<Millisecs()". But it is necessary. Sorry, I wrote the code in #47 without testing it. Wrong: Method Draw() Right: Method Draw() If ( Action>0 ) And ( AnimTime<MilliSecs() ) Frame=Frame + 1 AnimTime = MilliSecs() + 200 So this would be correct: |
| ||
| There is honestly no reason to apologize since you have helped me with the code and the knowledge of coding.But hat completely fixed it,after 53 posts it was finally resolved,thank you so much for your help,anyone and everyone who helped me out with this endeavor.I would have never have been able to do it without the people who told me what to do and gave me the code,mainly to Midimaster,I honestly had no idea on how to do it as I have never attempted animations before. Now I have just one final question,when I impliment it into the code of the real game,that I have finished except for the animations,when I go to do collisions with other objects what do I do? I sort of have an idea but I am pretty sure that I am wrong here is the code that I had set up without the animations " If ImagesCollide(Frog.image,Frog.x,Frog.y,0,car.image,car.x,car.y,0) score = score - 1 'Bring Frog back to starting location Frog.x = 300 Frog.y = 550 EndIf And what I think would be to replace the 0 that is after Frog.y with the number of total animations which in the case of the frog animation would be 12 and to add Action,but I am pretty sure that is wrong. |
| ||
The number behind Frog.Y is not the total number of animation frames, but the current frame, which is visible at this moment. In case of the frog it is "Frog.Frame". If Car is a image without animation "0" is correct.If ImagesCollide( Frog.image, Frog.x, Frog.y, Frog.Frame, car.image, car.x, car.y, 0 ) score = score - 1 'Bring Frog back to starting location Frog.x = 300 Frog.y = 550 Frog.Action=0 EndIfDon't forget to set Action to 0! |
| ||
| okay thanks. |
| ||
| I feel the need to say some things. I think you're being unhelpful to yourself by trying to program something like a game, which is not a trivial thing, without going through some basic study of the language you're using. For example, you wrote: it says "Missing function parameter 'Direction' (...) I have no idea on how to fix it Parameters to functions are a fundamental concept in programming, you shouldn't go ahead without knowing how to use these.I posted this earlier, I recommend that you read through this. It's a simple guide to programming in BlitzMax: http://www.truplo.com/blitzmaxbeginnersguide/wave1.html You can find more in the BlitzMax tutorial section: http://www.blitzbasic.com/Community/topics.php?forum=112 - - - - - - Some comments on the code being posted: - That 'action' variable is only being used to control whether to update the animation or not, and this type of use is ideal for a boolean value. So instead of assigning several different values to 'action' as it is (which is misleading since those different values are not doing anything), use it in an "on" or "off" way like a boolean variable and rename it like a proper boolean, with the naming being "the question that is answered by the value of the boolean": Field isMoving:Byte Method Draw() If isMoving And ( AnimTime < MilliSecs() ) Frame=Frame + 1 AnimTime = MilliSecs() + 200 If Frame = 3 Then 'UP Frame = 0 isMoving = False ElseIf Frame= 6 Then 'LEFT Frame=3 isMoving = False ElseIf Frame = 9 Then 'RIGHT Frame = 6 isMoving = False ElseIf Frame = 12 Then 'DOWN Frame = 9 isMoving = False EndIf EndIf 'DrawText Frame,X,Y DrawImage Image, X,Y, Frame End Method - You mentioned having trouble with changing the animations and frames, and I understand why. There's a lot of repetition going on in that Draw() method, for changing frames and checking whether the frame limits have been reached. It's a lot of places where something could go wrong. You can help yourself here by using a separate class whose sole responsibility is to update frames and check for reaching the end of animations. You use a separate class because you can then write all the logic once and use instances of that class to control different frame sequences (up, down, left etc.) -- this is where knowing how to code in BlitzMax helps, you need to know how to use custom types. Type FrameSequence Field startFrame:Int Field endFrame:Int Field frame:Int Field _isFinished:Byte Method begin() frame = startFrame _isFinished = False End Method Method advanceFrame() frame :+ 1 If frame > endFrame Then frame = startFrame _isFinished = True EndIf End Method Method getFrame:Int() Return frame End Method Method isFinished:Byte() Return _isFinished End Method End Type (...) 'To be used like this for example: Method Up() currentSequence = upSequence currentSequence.begin() End Method Method Draw() If isMoving And ( animTime < MilliSecs() ) Then animTime = Millisecs() currentSequence.advanceFrame() If currentSequence.isFinished() Then currentSequence = idleSequence currentSequence.begin() EndIf EndIf DrawImage image, x, y, currentSequence.getFrame() End MethodSee how simple and literal things get? If you read that code a few weeks from now when you don't remember anything about it, it'll be much easier to understand how it works. |
| ||
| double post |