Drawing different images (select...case help)
BlitzMax Forums/BlitzMax Beginners Area/Drawing different images (select...case help)
| ||
I am trying to remake a platformer and have a quick question on displaying different images. So its like a megaman game... you can run left and right, jump, shoot, shoot while jumping, climb, shoot while climbing etc. The question I have is what paramaters do I show which image? Do I use 50 flags and if flag 3 and 8 are not null, show this image. I know there is an easier way and maybe select...case can help me? I am looking for your input |
| ||
Your post is mixing and matching concepts, its really not going to get you any useful answer http://www.blitzbasic.com/Community/posts.php?topic=95110 (You may gleem info from the above and other, then come back and ask a more specific question) ie How do I know which direcion mario to draw etc Last edited 2011 |
| ||
Wow! I haven't seen a post like this!! Thanks so much I will take a look at this |
| ||
Okay, here is my specific question: can I use select case with a variable within a type that can be directly accessed to draw an image?Type Man Field stance Rem 1 = idle 2 = jump 3 = run right 4 = run left 5 = shoot endrem end type With the select case code: Function Draw () Select stance Case 1 DrawImage megaIdle:TImage,player.x,player.y,player.frame Case 2 DrawImage megaJump:TImage,player.x,player.y,player.frame Case 3 DrawImage megaRR:TImage,player.x,player.y,player.frame Case 4 DrawImage megaRL:TImage,player.x,player.y,player.frame End Select EndFunction And this would happen if I did something like: Function Movement () If KeyDown (KEY_RIGHT) player.stance = 3 player.x:+2 ElseIf KeyDown (KEY_LEFT) player.stance = 4 player.x:-2 EndIf Would this be viable? Last edited 2011 |
| ||
Would this be viable? Very much so.(+-2 seems a bit far per frame) You Could say ADD .1 everyframe stance is 3, Ans have 20substances per direction. But yep nail on the head (The numbers in first code box, make them Global Const) |
| ||
Looks good to me, Zacho. Use some consts to make your code more readable. e.g: (untested) const STANCE_IDLE=1 const STANCE_JUMP=2 select (stance) case (STANCE_IDLE) ...etc....Edit... beaten to it by H&K. Last edited 2011 |
| ||
Oh yes, I know its a bit sloppy, i will clean it up soon. Thanks for the help guys!! |
| ||
Oh wait, another quick question... its out of topic but how can I delay the frame rate within a function (I want to make the sprites flip frames much much slower) without slowing down the game, is that possible? |
| ||
Easier to create a new topic for new questions... ;-) Anyhoo... how about creating a counter, which you decrement, when it reaches zero, move onto the next frame? ... Const flipDelay:Int = 5 Const maxIndex:Int = 7 Field count:Int = 0 Field imageIndex:Int = 0 ... Method update() If Not count Then imageIndex :+ 1 If imageIndex > maxIndex Then imageIndex = 0 End If count = flipDelay End If count :- 1 End Method or something like that... Another option is to run the delay off the clock/delta time, so that you are relying on time rather than the frame rate of your game (frame rate is not always guaranteed to be constant) |
| ||
you could use individual timers for animation speed: Each actor has a personal time variable, which ticks with a individual step rate. Only if this time is lower than the current computer time Millisecs() the animation step can rise. Every time the step rises, the time will be adjusted 200 msecs into the future. Here is a symbolic example: Repeat If Player.StepTime<Millisecs() Then Player.StepTime = Millisecs() + 200 Player.Step = (Player.Step +1) Mod Player.MaxSteps Endif DrawAnimatedImage Image[Player.Stance] , Player.X , Player.Y , Player.Step Flip Forever(where... Step = the current animation frame MaxSteps = the number of frames of this animation 200 = the step rate: every 200msecs) |
| ||
you can make stand, move, attack Global images for each type of character. Load these once at game start. Then each type has a currentimage field of type TImage. In the update phase, based on the select case, make the currentimage equal one of the globals. Then in the draw phase you only need one draw statement, using currentimage. You might need to store the number of frames in globals as well and copy this into a field too. |
| ||
Thanks guys! I actually found a timer for bullets in another game I made and successfully imported it to work with frames, so I don't need any more help with the animations ;D. Here's the code if you are curious:Global StartTime:Int = MilliSecs() .... Function Frames () Local CurrTime:Int = MilliSecs() If CurrTime - StartTime > 150 player.frame:+1 StartTime = CurrTime EndIf If player.frame > 2 player.frame = 0 EndIf EndFunction And here's another question about the Select...Case question I originally asked ;D. I want my idle pose to be displayed if nothing else in my game isnt happening (ie player isnt jumping or moving,etc). I have some finicky code at the moment which works after I jump (I go back into idle position) but not after I run right or left. I am thinking one big select...case function but I have some doubts: |
| ||
Fixed that but now working on holding "jump" animation while in air.... |
| ||
Fixed =D I will be sure to come back with more questions when I hit them. |
| ||
You can use Default in a Select. This will trigger if no Cases are matched. It's a bit like Else in If. |
| ||
Yes, I was aware of that, I think I have that in my code... Thanks =) Fixing up my code and soon-to-be adding in bullet animations or working on the stage next |
| ||
Hiya, Can I suggest a little rework with your logic of handling the movement. I suggest to completely separate the code for handling the keys away from the code that handles the movement and break it down to the smallest sections. In pseudo code something like :- HandleKeys() 'Set necessary flags for movement / image. HandleMovement() 'You 'could' change flags again here if you wanted/needed. Draw() This way you can set the falling/jumping/stance flags according to keys being pressed or idle if none, then in the movement code adjust the characters position, also if the character image needs changing because of the player re-acting with the game level ( falling ) then the image can be changed accordingly again. You may need to introduce another flag to set whether facing left or right to use to select the correct image to display, but it would make the code a lot easier to follow logically in the long run. As the game code grows it will need to be as easy to follow logically as possible. Its quite surprising how you quickly become swamped with trying to follow the codes logic instead of working on the game features. EDIT :- If you going to introduce bullets etc then my suggestion above will more than likely be necessary. For eg :- You will need to know which direction the character is facing to start firing bullets in the correct direction. Last edited 2011 |
| ||
Hmmm... thats a very good idea col. I will definetly (and am) be cleaning up my code, thats an interesting way of putting it, I will look into it. I am in the process of un-clogging all of my code now anyway so I am sure it will help! |
| ||
^ to know what works while i rework code |
| ||
One of the biggest problems I see, is with the absolute file location in the LoadImage function. If for some reason you want to try it out in a different computer, it will not work. The basic structure should be a main folder where your game executable is, one or several sub folders where your assets(graphics, sounds and data files) should be. and accessed like this from with in the game source: LoadAnimImage("images/myImage.png",32,32,0,8) images is a folder inside the game folder that holds all of the images. this way you can just move the game folder to any computer and it will just work. the way you have it will only be able to run in the computer it was made. Not bad if that is what you want though. |
| ||
I'm not into posting too much code unless someone is really struggling ( which you're not ), so I'll just give a quick example with pseudo code of what I mean with breaking everything down to smaller sections... For the HandleKeys function a suggestion of logic could be :- As you can see it doesn't repeat the same checks and its easy to follow. You can even write 'SetPlayerToFaceRight' in a new function to make the code even easier to follow, but be aware that breaking it down too much can eventually make it more difficult to follow. Then in the HandleMovement function you simply write code to... well... handle the movement including setting the jumping and falling images according to the flags set. Don't take the above code literally, like I say it's just a brainstorm of logic only, not actual code. Good luck. Last edited 2011 |
| ||
Spoke to soon :o... I have a question about your three functions, I have refixed my code but have something like this at the moment. I did what you suggested and have three separate functions but am having trouble with the movement. Before, I had the player move when the corresponding key was hit, and it detected direction pretty well... now I do not know how to call movement through a function, I either get my player sliding across the screen in one direction or not moving at all: I think I am mixing up something here but I cannot see it |
| ||
I think so too. The idea now is that everything is broken now to smaller sections and they need to be handled separately. You could use the movement function as is but you need to either pass in the direction as a function variable, or use a global variable, or write a separate movement function to handle moving left and another movement function to handle moving right. EDIT :- Imagine the logic at this small of a level - The player is looking right...user presses right...check player is looking right...if so move player else if player not looking right make the player look right... That logic can then loop back over itself and covers if the player is looking left,right or idle and the user presses right. First time its run it will check the player direction and if its not facing right then it set a flag to display the right facing image, ( every other time this code is run and the user is pressing right key and the player is already facing right ) if the player is already facing right then set a flag to actually move the player. You then do the same but for facing and moving the player left. Last edited 2011 |
| ||
Yes, yes you are right, but its fixed, check it out! Ill work on the images code next: |
| ||
Getting there :-) Select Case would be best used in your Logic function. And you only really need to call Movement() once, at the end of the Keys() function outside of any If statements. It will work as you have it. Just pointing it out, can save your fingers from typing :-) Last edited 2011 |
| ||
If select case would work in logic, where should i put my code to draw the sprites? Do i just merge the two, is that what you are saying? Last edited 2011 |
| ||
No need to merge them, I mean Keys() Logic() Draw() also Function Logic() Select STANCE Case 1,3,5,7,9,11,13 DIRECTION = 1 Case 2,4,6,7,10,12,14 DIRECTION = 0 EndSelect EndFunction There are optimisations that can be done here using clever math, but save that until you have the concept. EDIT :- Also theres no real need to have ElseIf here - If DIRECTION = 1 player.x:+1 ElseIf DIRECTION = 0 player.x:-1 EndIf as DIRECTION is either 1 or 0, so If DIRECTION = 1 player.x:+1 Else player.x:-1 EndIf would be ok in this part Last edited 2011 |
| ||
ahhh, see I didn't know you could do that... THanks for the clever math =) |
| ||
Hehe. That isnt the clever math :-) using Function Logic () DIRECTION = STANCE Mod 2 EndFunction is the clever bit :-) |
| ||
Whats Mod? I havent seen that before |
| ||
'Mod' is a standard math function meaning Modulus. Its the whole number remainder after the calculation. In the example 'DIRECTION = STANCE Mod 2', in laymans terms it means... 'DIRECTION' = the remainder after 'STANCE' is divided by '2' In the case of STANCE = 1... 1 divide 2 will give 1 as a result, and STANCE = 0... 0 divide 2 will give 0 as the result. EDIT :- As you are using the DIRECTION variable as either 1 or 0, you can use that little optimisation. Don't worry about optimising anything until you have finished the game though. As you will need your code as easy to read as possible remember. Last edited 2011 |
| ||
^ Now THAT is fancy!! I think I will pass until I get my code close to working :p Another question (Hope I aren't asking too too many :o) My code is working pretty solid until I am trying to return to an idle pose. I can no longer stop like I did in my messy-code. Does anyone see anything fishy? '*********** 'Main Loop '*********** While Not KeyHit(KEY_ESCAPE) Cls Logic () Keys () 'Keyboard input Draw () UpdateFrame () Flip Wend Function Keys () If KeyDown (KEY_LEFT) player.savedX = player.x If DIRECTION = 1 STANCE = IDLE_LEFT Else STANCE = RUN_LEFT EndIf Movement () EndIf If KeyDown (KEY_RIGHT) player.savedX = player.x If DIRECTION = 0 STANCE = IDLE Else STANCE = RUN_RIGHT EndIf Movement () EndIf EndFunction Function Movement () If DIRECTION = 1 player.x:+1 ElseIf DIRECTION = 0 player.x:-1 EndIf EndFunction Function Draw () Select STANCE Case (IDLE) DrawImage megaIdle:TImage,player.x,player.y,player.frame Case (IDLE_LEFT) DrawImage megaIdleL:TImage,player.x,player.y,player.frame Case (RUN_RIGHT) DrawImage megaRR:TImage,player.x,player.y,player.frame Case (RUN_LEFT) DrawImage megaRL:TImage,player.x,player.y,player.frame End Select EndFunction Function Logic() If Not KeyDown (KEY_RIGHT) And player.savedX < player.x DIRECTION = 1 'STANCE = IDLE EndIf If Not KeyDown (KEY_LEFT) And player.savedX > player.x DIRECTION = 0 'STANCE = IDLE_LEFT EndIf Select STANCE Case 1,3,5,7,9,11,13 DIRECTION = 1 Case 2,4,6,7,10,12,14 DIRECTION = 0 EndSelect EndFunction Function UpdateFrame () 'TIMERS Local IDLE_TIMER:Int = MilliSecs() Local RUN_TIMER:Int = MilliSecs() DrawText "timer: " + (IDLE_TIMER - START_TIME),11,11 '*********** 'IDLE FRAMES '*********** If STANCE = IDLE If IDLE_TIMER - START_TIME > 1040 player.frame:+1 START_TIME = IDLE_TIMER EndIf EndIf If STANCE = IDLE_LEFT If IDLE_TIMER - START_TIME > 1040 player.frame:+1 START_TIME = IDLE_TIMER EndIf EndIf '*********** 'RUNNING FRAMES '*********** If STANCE = RUN_RIGHT 'Or STANCE + RUN_LEFT If RUN_TIMER - START_TIME > 150 player.frame:+1 START_TIME = RUN_TIMER EndIf EndIf If STANCE = RUN_LEFT If RUN_TIMER - START_TIME > 150 player.frame:+1 START_TIME = RUN_TIMER EndIf EndIf If player.frame > 2 player.frame = 0 EndIf EndFunction I can bet you its in logic but I don't know what.... |
| ||
by the way, player.savedX is a field in my type that "originally" stored a variable so I could return to normal pose but it doesnt fit in here obviously... |
| ||
Nevermind again, I found and fixed my problem |
| ||
First theres no need to check for KeyDown(...) ( or Not KeyDown() as the case is ) in the Logic() function. Use Logic() to only check flags set by the Keys() function, and use the Keys() only to check for the keys and set the flags. Looks like you'll need a flag to allow for STANDINGSTILL? maybe in the DIRECTION, Use DIRECTION = 1 for right, DIRECTION = -1 for left, DIRECTION = 0 for stationary. You can also use these values in the movement code too, if you think about it :-) On a different note - do you know how to use the Debugger features of the MaxIDE ? You can use it to step through your code one code statement at a time and look at all of your variables to what them changing. If you're not using it then you're missing out on an invaluable tool! Start a new thread if you need help with it. |