Help with my game (currently for animations)

I’m making a super smash bros clone and so far, everything is going great, I made a custom splash screen and finished all of the menus. The problem is the actual game, this is only my third one, and it’s a very ambitious one. Currently, I have a sprite and 2 platform images on the screen, and I’ve been following on @Pharap 's 2d platformer demo, and I got some basic movement right now. Although, for my game, it’s not very fitting and performs very badly. Right now, my 3 questions are this:

  1. How can I create a better movement system? Something more smash bros like.

  2. How can I create hitboxes for the platforms, and make it so that the player will always be victim to gravity, and fall, unless on any of the three platforms.

  3. How can I create an animation? Currently I only know how to draw single frames, and for a game like this, animations are extremely important.

Thanks!

  1. Learn how (rigid body) physics works
    • (Or at least a simplified version. Physics simulations can get brain-meltingly complicated.)
    • Note in particular: speed and velocity, scalars and vectors, vectors, force, gravity and weight vs mass.
      • (Yes, suddenly all that crap you ignored in physics and maths at school is relevant. If they’d told me I needed to know that stuff to make video games I might have actually listened in class.)
    • Of course, you can cut corners and cheat, but it likely won’t look ‘right’
    • Speaking of which, you’ll probably have to using either floating point or fixed point numbers instead of integers to get the physics to behave properly.
  2. Study Smash Bros. clips to try to guess what’s going on
    • (Some people have disassembled various incarnations of Smash Bros., but unless you can read assembly that’s not really going to help you much.)
  3. Try things until something works
  4. Give up and settle for something simpler
    • Smash Bros.'s movement mechanics are very likely more complex than you probably think they are because of things like wall clinging, velocity changing based on damage percentage and the ability to occasionally defy gravity.
    • At a bare minimum, I’m certain that most Smash Bros. games actually give each character a state machine and their behaviour differs depending on which state they’re in (e.g. wall clinging, in the air, on the ground, tripped over).

That depends on whether you’re going to be representing your world as a grid of tiles or an array of rectangles/other shapes.

If your world is going to consist of a list of rectangles then congratulations, you already have your hitboxes.

If you’re going to represent your world as a grid of tiles then you can derive a hitbox for a tile as { tileX * tileWidth, tileY * tileHeight, tileWidth, tileHeight }, where tileX and tileY are the indices into the grid and tileWidth and tileHeight are the dimensions of the sprites you are using to represent the tiles.

(If you’re using a grid of tiles then you can actually avoid creating a hitbox in the first place because there’s a cheaper way to determine which tile contains a particular point.)

You probably should have started with a simpler game to get used to how to do basic collisions first, but…

In a virtual world, solidness means that an entity (object, player character, NPC, piece of fruit, whatever) cannot travel in a particular direction.

The way that is achieved is by looking at where an entity is attempting to travel, determining if it’s actually allowed to move there and then either cancelling the movement or instead moving the entity to the closest point that it would be allowed to move to.

For example, instead of doing:

if(arduboy.justPressed(A_Button))
{
	x += movement;
}

You might have something more like:

if(arduboy.justPressed(A_Button))
{
	auto destination = x + movement;
	
	if(canMoveTo(destination, y))
		x = destination;
}

In my 2D platformer demo, I do that sort of thing with updateEntityPosition:

(In this case the player actually has a diamond shaped collision area instead of a rectangular one. I can’t entirely remember why. I think it was to make it more difficult to land on platforms, or to simplify the logic somehow.)

The Sprites class has a parameter for the frame index.
If your images are in the right format then you can just use that index to select the frame.
With that you can apply various different effects, and the code needed to create an effect will depend on what kind of effect you want to create.

Here is some demo code:


By the way, instead of maintaining an sfxToggle variable and then checking it every time you make a sound, you might want to look at the Arduboy2Audio functions:
https://mlxxxp.github.io/documents/Arduino/libraries/Arduboy2/Doxygen/html/classArduboy2Audio.html

If you toggle the audio with arduboy.audio.toggle() (or Arduboy2Audio::toggle()) then ArduboyTones will automatically be enabled or disabled. (That’s also why you’re supposed to feed the arduboy.audio.enabled function to the ArduboyTones constructor - it allows it to react to the sound being toggled on and off properly.)

1 Like

How could I do this? I know floating points are decimals from my time using Unity, but what are fixed point numbers? Just like when the player falls, instead of snapping up when jumping, is there a way I can do a similar thing, so the player sort of…falls upward?

My version is going to be pretty simple, just basic physics, and a short/ranged attack, and some attacks combined with movement, like how in any version of smash bros, you can use your ranged/special attack with up for example, for a different attack. For the damage percentage, I might use a variable as the “knockback ammount” and a counter for the damage, and the higher the damage counter gets to say, 200, then the knockback variable will increase, and the enemies/player will have increased knockback. I’m also aware you can jump through platforms, but when you fall onto a platform, it is solid. I’m not too sure how I will add the hitboxes, so I’m not too sure if I will add that feature or not.

Currently, my world just has 3 images, 3 platforms, all rectangles of course. So let’s say I always include a downforce on my player, how can I check to see if my player is currently on a platform, then cancel that force?

Technically they’re actually binary. They have a binary point instead of a decimal point. The computer just does some special wizardry to print them in decimal format for us poor humans.

For floating points, use float instead of int. And ideally read a tutorial about them.
(And if you’re really dedicated or wondering why you keep ending up with random 0.000001s added to things, watch this video.)

They’re like floating point numbers, but the binary point doesn’t move.around. That means the range of values they represent is more limited, but they’re generally cheaper and for that limited range they’re a lot more accurate.

I’m guessing you’d probably need to introduce acceleration on top of velocity and position so the velocity can steadily increase.
I avoided adding acceleration to my platformer demo to keep life simple, and because maths makes my head hurt.

Ironically, that’s actually not too far from the truth. If you were in space, where there’s no gravity and negligable friction, you could technically ‘fall’ in any direction. When you jump up, you are effectively falling upwards for a very brief time, but eventually gravity wins (with a little help from air resistance).

If the knockback is dependent on the damage then you could avoid storing the knockback value by simply calculating it as and when it’s required.

It’s a lot easier to derive something as needed than it is to try to keep two variable synchronised when one depends on the other.

Which means you’d have to change your collision logic depending on the direction the character is travelling in, which is slightly more complicated than just letting character hit their head on the ceiling.

Well, yes and no. They’re only rectangles if you tell the computer that they are. You could say they’re spheres or grids of smaller rectangles and as long as the code is right the computer won’t complain.

But rectangles is probably what you want, so that’s neither here nor there…

There’s lots of ways you could approach it.

If you want to prevent entities from bumping into things sideways then really you should be looking at taking the player’s current position and velocity, figuring out where the player is about to move to and then if that new position would cause the entity to be inside of something you should either stop the entity moving or move the entity as close as they can get to that thing (there’s lots of ways to do that, but moving the entity 1 pixel at a time until it can move no further is probably the best).

If you wanted to ignore sideways collisions then you could trace a line down from the entity’s feet to determine if there’s a platform below it and how close it is to the platform, and allow it to move up until the point where it’s just touching the platform. That would be a lot simpler and cheaper.


If you want code demonstrating any of this it’ll have to wait until tomorrow (unless someone else wants to volunteer some).

In the mean time, you might want to start getting used to the Rect struct or maybe make a Platform struct. (Assuming you’re sticking with platforms rather than having a tile-based world.)

Also, I have no clue what smash mode is supposed to be, but consider this:

enum class SmashMode : uint8_t
{
	Mode20,
	Mode50,
	Mode100,
};
1 Like

That’s supposed to be the game mode. In some of the Smash Bros games, there are some game modes where you try to defeat a certain amount of enemies as fast as you can. In one version, I think there was something like 100 man smash. I remember on the Nintendo 64 version, the second level was one where there were 20 or so Yoshi’s, and you had to defeat them all as fast as you could.

I’ve only ever played Melee and Brawl, so to me it will forever be “mult-man melee”.

1 Like

Currently I have a basic gravity force and solid ground code, which uses a boolean toggle.

void handleInput()
{
  if (arduboy.pressed(LEFT_BUTTON))
  {
    playerEntity.xVelocity -= movementSpeed;
  }

  if (arduboy.pressed(RIGHT_BUTTON))
  {
    playerEntity.xVelocity += movementSpeed;
  }

  if (isOnSolid == false && playerEntity.y > 0)
  {
    playerEntity.yVelocity += gravitySpeed;
  }

  int16_t playerX = (playerEntity.x + playerEntity.xVelocity);
  int16_t playerY = (playerEntity.y + playerEntity.yVelocity);

  Sprites::drawOverwrite(playerX, playerY, playerSideways, 0);

  Rect playerRect (playerX, playerY, 9, 9);

  Rect platform1Rect (platformX1, platformY1, 100, 18);

  if (arduboy.collide(playerRect, platform1Rect))
  {
    isOnSolid = true;
  }
}

My problem is that after you collide/land on a platform, the bool stays on, even if you no longer are on that platformer, so the gravity won’t be able to work anymore. Is there a way I can make it so that if the player is not on a platform, the bool stays off, and is only on if the player is on a platform? Another thing, if you were below the platform, and collided with it from the bottom, the gravity would stop and you would just stay and float where you are, perhaps there is a better way to make the solid platforms? Thanks.

I am not sure what your game looks like but here we go …

When you detect a collision with the platform object then you should also check to see what your yVelocity value is. If you are going up (you have hit the platform with your head) and you want the player to continue going up to the top of the arc and then fall naturally, you should not set the isOnSolid variable.

If you continue to go up and then fall down and collide with the platform a second time ( you are now standing on it) and yVelocity is positive (meaning going down) then you would set the isOnSolid variable to true;

1 Like

Part of your problem is that your definition of ‘player is on solid ground’ is actually ‘player is intersecting with platform’. That basically means that the player’s feet or could be several pixels into the platform before you consider them ‘on solid ground’, which isn’t what you want.

You are at least looking at where the player is about to move to rather than where the player currently is, but you’re not updating the player’s position if they’re allowed to move, and the logic is too oversimplified to be useful.

What you want is probably something more like this:

void handleInput()
{
  if (arduboy.pressed(LEFT_BUTTON))
  {
    playerEntity.xVelocity -= movementSpeed;
  }

  if (arduboy.pressed(RIGHT_BUTTON))
  {
    playerEntity.xVelocity += movementSpeed;
  }

  if (!isOnSolid)
  {
    playerEntity.yVelocity += gravitySpeed;
  }
}

// Keep updating separate to input handling!
void updatePlayer()
{
  // auto infers the type
  auto playerX = (playerEntity.x + playerEntity.xVelocity);
  auto playerY = (playerEntity.y + playerEntity.yVelocity);
  
  // Presume the player is not on solid ground
  isOnSolid = false;
  
  // Only run these checks if the player is actually falling downwards
  if(playerEntity.yVelocity > 0)
  {  
    // Figure out the coordinates of the player's left, right and base
    auto playerBase = (playerY + playerHeight);
    auto playerLeft = playerX;
    auto playerRight = (playerX + playerWidth);
  
    // Figure out the coordinates of all sides of the platform
    auto platformTop = platform1Y;
    auto platformBase = (platform1Y + platform1Height);
    auto platformLeft = platform1X;
    auto platformRight = (platform1X + platform1Width);
  
    // Determine if the player's left or right side is in range of the platform
    bool leftOverlaps = ((playerLeft >= platformLeft) && (playerLeft <= platformRight);
    bool rightOverlaps = ((playerRight >= platformLeft) && (playerRight <= platformRight));
  
    // Determine if the player's base is below the platform
    bool baseOverlaps = ((playerBase >= platformTop) && ((playerBase <= platformBase));
  
    // If the player's base intersects the platform
    if((leftOverlaps || rightOverlaps) && baseOverlaps)
    {
      // Move the player to the point where they're just touching the platform
      playerY = (platformTop - playerHeight);

      // Register the player as now being on solid ground
      isOnSolid = true;
    }
  
    // The above code should be repeated for every platform
    // which means that platforms should be kept in an array,
    // and the above code should be placed inside a loop
  }
  
  // Now that all collisions have been resolved,
  // the player's actual position can finally be updated
  playerEntity.x = playerX;
  playerEntity.y = playerY;
}

// Keep drawing separate from updating!
void drawPlayer()
{
  Sprites::drawOverwrite(playerEntity.x, playerEntity.y, playerSideways, 0);
}

(Completely untested.)

That’s what the playerEntity.yVelocity > 0 check is for - you only want to start colliding with platforms if the player is falling, not when the player is jumping.

With real world physics you wouldn’t do that, the player would just bump their head on the block above, so this is a case where you’re actually having to defy physics to get the proper effect.


That’ll handle the collisions at least.

The fact gravity is being constantly added every frame that the player isn’t on the ground doesn’t seem right because it means the player’s y velocity will just constantly increase every frame until it reaches some ridiculous value, but I’m not sure how to go about correcting that offhand.

Also, strictly speaking gravity should always apply, regardless of whether the player is on a platform or not. Disabling it when the player is on a solid surface seems like a bit of a hack. Though as long as it doesn’t cause any unexpected problems it’s probably fine.

1 Like

Thanks guys! One question I asked before was how to use floating points for the variables like movementSpeed and gravitySpeed, but whenever I change them to a float and make the value a decimal (ex: 1.5, 0.5 etc), it just doesn’t work. If I make movement speed 0.5 for example, the player just doesn’t move. Am I maybe doing something wrong?

Also, @pharap, I noticed

this code makes the player super fast, I removed it, and everything functions the same, minus the super speed, is this code really necessary?

That sounds like you’re still using integers in places where integers shouldn’t be.

If you try to convert a value of 0.5 to an integer, you get 0 - the fractional part is discarded. Thus when you start mixing floats and integers, you have to be careful about what you’re doing, lest you end up discarding important information when you shouldn’t be discarding it.

This is one of the reasons I’ve been using auto. Given:

int a = 5;
int b = 6;
auto c = a + b;

c is inferred to be of type int, but if you were to change a or b to float, c would automatically change to type float, because the type is inferred from the result of a + b:

float a = 5.6;
float b = 6.55;
auto c = a + b;
// c is a float with a value of 12.15

However, if you’d declared c as int and then forgot to update it to float, c would be an int with a value of 12 - the fractional part would be discarded.

float a = 5.6;
float b = 6.55;
int c = a + b;
// c is an int with a value of 12 - the .15 is discarded

That all said, unless you post the code that “isn’t working”, I can only guess what’s going wrong, I can’t say for definite.

If you adapted* my code correctly then it shouldn’t function properly without those two lines. Those are the only two lines that modify playerEntity.x and playerEntity.y. Without those lines, the player never moves. Thus you must be doing something somewhere that makes the player move.

* I purposely used some variables that you didn’t have and renamed some others, e.g. platform1Y instead of platformY1. There’s a good reason for this that will hopefully make sense later.

I just realised that I forgot to change the drawing code to use playerEntity.x and playerEntity.y, so I have rectified that.

It will at the moment because gravitySpeed is currently 1, and this is being called every frame, so the velocity will increase by 1 each frame.

There’s still a few steps you’ll have to go through before everything is working properly. Even without the full gamut of Smash Bros. mechanics, doing proper physics is quite involved. You’ll likely need to incorporate acceleration, delta time and either floating points or fixed points before all is said and done.

If you were just making a platformer then you could probably afford to cut corners, but you’re probably going to need that other stuff if you’re going to have characters flying around the arena.


I’ve briefly looked into this. I think part of what’s missing is that gravity should probably affect acceleration rather than velocity, and the other half is that in the real world an object achieves ‘terminal velocity’ because there’s a drag force to counteract the gravity, and at present the game has no drag force.

Again, there’s possibly some kind of corner-cutting way to avoid having to worry about drag, but it might take a bit of trial and error to find something suitable.

1 Like

I see. Here is my code currently:

I changed both movementSpeed and gravitySpeed to a float, and changed their values to 1.5. This time it works, but the decimal value (.5) is only being added when subtracting the velocity. So for example, when pressing LEFT, you are subtracting the xVelocity, and when going RIGHT, you are increasing the xVelocity. So basically, the .5 extra is only being used when going LEFT, similarly to falling, the yVelocity increases, therefore the extra .5 in gravity speed won’t be added. I am really confused by what’s happening.

EDIT: Changed xVelocity & yVelocity to floats as well, it now works as expected :slightly_smiling_face:

1 Like

How do I do that? currently my jumping code is

  if (arduboy.justPressed(UP_BUTTON))
  {
    while (playerEntity.yVelocity >= -14)
    {
    playerEntity.yVelocity -= jumpSpeed;
    }
  }

But I’m unsure how to add acceleration, and right now the player instantly teleports up to -14.

Thus my earlier prediction was correct:

I might have to do a bit of research and testing before I can give you a definitive answer on that.

So far this article looks the most promising, albeit a tad more academic and involved than necessary (you can ignore all the the Runge-Kutte stuff, that’s far more realism than you’re going to need):

The key points at the moment are that you’d need something equivalent to:

velocity += acceleration * dt;
position += velocity * dt;

Acceleration is supposed to be derived as acceleration = force / mass, but I’m not sure if your characters really need mass. For now, omitting / mass would be fine because it would be equivalent to your entities having a mass of 1.

Either way, note that gravity is a force, so when you do introduce acceleration, however that needs to be done, you’ll have to change your code so that gravity affects acceleration rather than velocity.

Also, note that acceleration, velocity and force are all vectors (i.e. they have both an x and a y component). You might want to read up on those. (Or, if you prefer videos, see here and here.)

I’ll have to explain the dt bit tomorrow (unless someone else wants to volunteer in my absence), but that’s the ‘delta time’ that I mentioned.

The short version is that at the moment your physics simulation is actually running 60 times faster than it ought to because you’re doing 1 second’s worth of adjustments 60 times per second. The delta time is supposed to reduce the work so you move things at a speed that’s appropriate to the update rate (60 updates per second).

(Edit: Actually, as of your last commit it’s 40, not 60, but I suspect you might have done that in an attempt to slow things down. Ideally your game should run at 60fps if it can afford to.)

That’s because you’re using a while.

The while will keep running until the condition evaluates to false, and the computer will do nothing else in the mean time - no frames will be drawn, no other code will be touched.

(With a few exceptions - music will still play for reasons that probably aren’t worth going into right now.)

1 Like

The thing is though, nothing I do makes it so that the player slowly goes upwards. If for example I make an if loop:

if (arduboy.justPressed(UP_BUTTON) && yVelocity >= -20)
{
  yVelocity -= jumpSpeed //jumpSpeed is basically thrust
}

Then this code only executes one time, and if for example jumpSpeed = 2.0, my player will only go up 2 pixels, the code won’t continue. Am I missing something?

Think about the lines of code you posted. What is the if statement that conditions the movement doing? Why does it only happen once?

If you want it to happen many times what conditions would it have, if any?

Pressing the button should indicate that you want the player to jump. The code to actually move the player will happens over a period of time (frames).

1 Like

Again, without knowing the context and what else you’ve changed, I can only guess.

I would presume that either the gravity becomes so large that -jumpSpeed isn’t powerful enough to cancel it out, or it’s somehow related to where in the code you’re putting that excerpt.


Ok, I finally got chance to actually compile and run the game today.

From what I’ve seen, there are several problems so far:

  • You are drawing the character with playerX and playerY, when you should be using playerEntity.x and playerEntity.y
    • As I mentioned earlier, originally I forgot to make that change in the code I posted before
  • You aren’t updating playerEntity.x and playerEntity.y with the values of playerX and playerY
  • When the player is on a solid platform, the effect of gravity needs to be cancelled out
    • Not just stopped, but actually cancelled out, otherwise jumping won’t have enough force to propel the player upwards
  • There’s currently no code for initiating a jump
  • There’s a very slight bug in that collision code I posted - isOnSolid = false should happen inside the if(playerEntity.yVelocity > 0) block, otherwise the player falls through the platform when velocity becomes 0.
  • If the player moves too fast the collision code won’t stop them falling through the platform because they’re effectively teleporting past the platform
    • I’ve worked out a way to fix this
  • There’s no friction, so when you move the player entity right or left they don’t stop moving
  • Gravity is being continually added to the velocity each frame
  • 1 second worth of simulation is being run every frame

As I mentioned before, if the aim was to have platformer like physics then you could potentially cheat a bit, but to have Smash Bros. like physics you’re probably going to have to do it properly, which means you’ve still got a lot of work to go before everything is working properly (e.g. delta time, acceleration…).

On the one hand I think this would go quicker if I just fixed a load of this for you and then made a PR since I (mostly) know what I’m doing.

On the other hand, I think if I did that then you wouldn’t learn as much, and im particular you probably wouldn’t understand how everything works and interacts, which might cause you problems later on.

It depends whether you care more about finishing the game or actually learning how to make games, how to program, and/or how games work.


By fixing a small number of the above issues, I got jumping working:

Smash_Bros_Arduboy.ino.hex (45.4 KB)

I had to:

  • Adjust the collision code to prevent the ‘bullet through paper’ problem
  • Move isOnSolid = false; to its correct position
  • Correct the player drawing code
  • Add the code that updates playerEntity.x and playerEntity.y
  • Add some code to initiate a jump
  • Zero out the player’s y velocity when the player is standing on a solid platform

If you’re happy to accept a PR then I can prepare a PR with the changes. Otherwise I can explain the changes one by one.

Now that that’s fixed things look a little more promising, so I’m wondering if you might be able to get away with not having acceleration, but you will definitely need delta timing at some point.


To very briefly explain the idea of delta time again:

At the moment you’re effectively simulating a second’s worth of movement, 60 times a second, so the simulation is running 60 times faster than it should be. ("ell, 40 at the minute, but it should be 60.) With delta time, instead of doing a whole second’s worth of simulation you do 1/60th of a second’s worth of simulation by multiplying certain values (mainly velocities and accelerations, I think) by the amount of time that has passed between frames - i.e. ~1/60 in this case.

(It would be even more important with an uncapped frame rate, because with an uncapped framerate the time between frames can vary.)

1 Like

I think this is part of you mis-understanding. Are you expecting the if to operate (loop) many times?

I’d like that, thanks :slightly_smiling_face:.

Yeah, I mean the gravity if-loop always repeats and keeps on adding value to the y velocity, so why not this one?

In my code (without updating playerEntity x & y, the player just stops moving when you stop pressing the button).

Well its not a loop in itself.

It will only execute the once as the condition of justPressed() will only be true once (unless you keep clicking the button).

1 Like