I am going a bit mad trying to figure out how to make a simple 4 frame sprite animation run on a loop, and then transition to a different 4 frame animation loop after a button is pressed.
Simply - I am trying to make this Mario sprite look like it is walking forward when idle, or pressing forward, and then look like he is walking sideways when pressing left or right. I can make him animate on loop when idle, but I cannot figure out how to make it animate as a different sequence after a direction is pressed, and ensure the animation runs smooth (for example, I can get it to change to the new sequence, but holding the button down keeps the sequence locked into the first frame of the animation).
I hope that makes sense! Does anyone have a simple solution?
The simplest way I can think of is to put the 3 animations either in tables or in sequence within the sprite data, then use the current frame number on whichever one is needed. If the animations are all the same length, the frame number can be used directly. If not, the % operator can be used to translate based on the length of the current animation.
This is a nice palette, actually a lot better than the gb palette I tried to do once.
You made a simple error with t=0, but that's ok, keep on keepin on brotha
Changed 't=' statement in update_mario and added btn to _draw:
function _draw() cls() palt(9,true) print(t,10,10,10) print(delay,10,20,10) spo = btn(0) and 32 or 0 spr(sp + spo,64,64,2,2) end function update_mario() if t>=delay then sp+=2 t-=delay end if sp>=7 then sp=1 end end
So I implemented @roroyobert 's code for the button input and it works for moving left and right, but I still cannot figure out how to change the sequence for other buttons...
In this cart you can see I tried @kimiyoribaka 's suggestion of using tables to store the sprite numbers, and I thought if I could just reference the relevant table each time in the update_mario() function, then I could change the sprites that way. Alas it does not seem to work; either its not allowed to pass in tables to a function or I am writing it wrong... I am very much a beginner level coder I'm afraid!
I was also trying to make the sprite switch to the small mario when it passes through the tunnel but something weird happens there as well!
Okay, let me clarify a bit how it would work. To use those animation tables, you need a variable that stores references to them. In the commented out portion, it looks like the reference variable is named "table" but I don't see where that would be created. In addition, you need a way to keep track of which frame of animation is current that isn't based on the current sprite, as that's going to stop being a good comparison the moment you switch animations. Since I'm not good at gauging coding skill and you said you're a beginner, here's an explanation of each step:
Creating a reference to a table is done the same way you created it to begin with. Setting a variable to a table definition is, in reality, creating the table and then storing the first reference to it in the variable.
-- this causes animtable to reference the same table as animforward animtable = animforward -- assuming this code is after init() this would set i to 192 i = animtable
The variable for keeping track of mario's current frame just needs to be an integer with a value from 1 to 4 (assuming you're not doing variable lengths of animation).
-- this sets it to the beginning of the animation currentframe = 1 -- this is the code for updating the animation if (t>delay) then currentframe += 1 t -= delay end if (currentframe > 4) then currentframe = 1 end
From there, fetching the sprite is done the way you guessed.
mario.sp = animtable[currentframe]
Finally, to change the animation you would just switch which of the animation table animtable is equal to. Using the example of pressing the up arrow that'd be
if btn(⬆️) then animtable = animback self.y-=self.dy self.flipsprite=false end
though if you do it that way, you'll need to change it later to account for any variations (such as making mario small).
One other thing, if you plan to have other game objects also having their own animations running on their own, both animtable and currentframe would be better put in mario's values. In that case they'd be mario.animtable and mario.currentframe (or whatever name you prefer), or self.animtable and self.currentframe if self is currently referring to mario. When you call mario:update() and mario:draw(), you are actually passing mario as the first argument to the functions mario.update and mario.draw, so within those functions self is a reference to mario.
@kimiyoribaka Firstly, thank you so much for taking the time to write such a detailed response to my post. Its really amazing I am getting this help on this forum!
I follow everything you write, and I get why you change the update sprite variable to go from 1 to 4 instead of the sprite numbers as a way of switching between the different animations.
To my eyes, the code should work now, but I think I am missing where to place the the i = animtable (Btw I renamed the variable to 'a' because I refer to 'i' in the 'for' loops - does this matter at all?). I set the mario.sp variable to equal the animtable[currentframe]. The currentframe variable is updating, but the sprite number is not. What have I missed here? I feel like its so close!
Out of curiosity are you a programmer for a hobby or do this professionally? I have been trying to learn on and off for quite a while but its been very difficult to say the least!
Oh, sorry. The i = animtable was just for explaining how table references work. I was trying to demonstrate that animtable can be treated as equivalent to whichever table you set it to.
The reason the sprite isn't update appears to be because you set it to an initial value but never change it. In this case, the "sprite" itself is just an integer telling the sprite drawing function where it is on the sprite page. integers are not references in lua (it's mainly tables that do that) so that does need to be updated each time the frame changes. To do so, you can either put mario.sp = animtable[currentframe] at the end of the update_mario() function or put self.sp = animtable[currentframe] at the end of the update function where you have all the inputs checked, whichever you prefer.
I haven't managed to get a job in programming for various reasons (mainly due to just wanting to make indie games), so I guess I'm a hobbyist, but I've been doing different forms game programming/scripting for literally as long as I can remember (since like 8-years old I think?). If you do it enough, some aspect just start to make sense for any language/engine. I'm not good with a lot of the common paradigms and patterns though, since I'm mostly self-taught.
@kimiyoribaka Thanks for clarifying again, and now it works!!
Can't thank you enough for the help. This was meant to be a small demo scene that I thought would only take me a couple of days! A month later and here we are...
I didn't grow up with programming, but I love games and thought it was about time I learned how they are made. Its fun... incredibly frustrating at times, but like you said if you do it enough, things just start to click into place. We're lucky to have so many resources online to learn by ourselves (and I'm especially grateful for your forum posts here).
Thanks a ton! I'll be following your work.
[Please log in to post a comment]