Drawing different images (select...case help)

BlitzMax Forums/BlitzMax Beginners Area/Drawing different images (select...case help)

Zacho(Posted 2011) [#1]
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


H&K(Posted 2011) [#2]
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


Zacho(Posted 2011) [#3]
Wow! I haven't seen a post like this!! Thanks so much I will take a look at this


Zacho(Posted 2011) [#4]
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


H&K(Posted 2011) [#5]
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)


Who was John Galt?(Posted 2011) [#6]
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


Zacho(Posted 2011) [#7]
Oh yes, I know its a bit sloppy, i will clean it up soon. Thanks for the help guys!!


Zacho(Posted 2011) [#8]
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?


Brucey(Posted 2011) [#9]
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)


Midimaster(Posted 2011) [#10]
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)


Czar Flavius(Posted 2011) [#11]
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.


Zacho(Posted 2011) [#12]
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:




Zacho(Posted 2011) [#13]
Fixed that but now working on holding "jump" animation while in air....


Zacho(Posted 2011) [#14]
Fixed =D

I will be sure to come back with more questions when I hit them.


Czar Flavius(Posted 2011) [#15]
You can use Default in a Select. This will trigger if no Cases are matched. It's a bit like Else in If.


Zacho(Posted 2011) [#16]
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


col(Posted 2011) [#17]
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


Zacho(Posted 2011) [#18]
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!


Zacho(Posted 2011) [#19]


^ to know what works while i rework code


Jesse(Posted 2011) [#20]
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.


col(Posted 2011) [#21]
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


Zacho(Posted 2011) [#22]
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


col(Posted 2011) [#23]
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


Zacho(Posted 2011) [#24]
Yes, yes you are right, but its fixed, check it out! Ill work on the images code next:




col(Posted 2011) [#25]
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


Zacho(Posted 2011) [#26]
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


col(Posted 2011) [#27]
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


Zacho(Posted 2011) [#28]
ahhh, see I didn't know you could do that... THanks for the clever math =)


col(Posted 2011) [#29]
Hehe. That isnt the clever math :-)

using

Function Logic ()
	DIRECTION = STANCE Mod 2
EndFunction

is the clever bit :-)


Zacho(Posted 2011) [#30]
Whats Mod? I havent seen that before


col(Posted 2011) [#31]
'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


Zacho(Posted 2011) [#32]
^ 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....


Zacho(Posted 2011) [#33]
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...


Zacho(Posted 2011) [#34]
Nevermind again, I found and fixed my problem


col(Posted 2011) [#35]
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.