Add gravity to an animated graphic

Hello There, I have an animated rotating 3d looking cube. It is going to be a logo for a shmup. Anyways I want it to animate off the screen with realistic gravity as it continues to rotate. I find geometry not hard but realistic gravity examples like Pharaphs Physix confusing for some reason, especially since I have an animation going on at the same time:

#include <Arduboy2.h>

int horizSpin = 64;
int vertSpin1 = 88;
int vertSpin2 = 40;
int SpinRad = 38;

Arduboy2 arduboy;

void setup() {

  arduboy.begin();
}

void loop() {
  arduboy.clear();
  for (int i = 60; i > 0; i--) {
    arduboy.fillRect(0, 0, 128, 64, BLACK);
    arduboy.fillCircle(horizSpin, vertSpin1, (SpinRad / 2) - 1 , BLACK);

    float SpinAng = i * 6;
    SpinAng = SpinAng / 57.296;
    float SpinAng2 = SpinAng + 90 / 57.296;

    int a = (horizSpin + (sin(SpinAng) * (SpinRad / 2)));
    int b = (vertSpin1 - (cos(SpinAng) * (SpinRad / 2))) / 2;
    int c = (horizSpin - (sin(SpinAng) * (SpinRad / 2)));
    int d = (vertSpin1 + (cos(SpinAng) * (SpinRad / 2))) / 2;
    int a1 = (horizSpin + (sin(SpinAng2) * (SpinRad / 2)));
    int b1 = (vertSpin1 - (cos(SpinAng2) * (SpinRad / 2))) / 2;
    int c1 = (horizSpin - (sin(SpinAng2) * (SpinRad / 2)));
    int d1 = (vertSpin1 + (cos(SpinAng2) * (SpinRad / 2))) / 2;
    int e = (horizSpin + (sin(SpinAng) * (SpinRad / 2)));
    int f = (vertSpin2 - (cos(SpinAng) * (SpinRad / 2))) / 2;
    int g = (horizSpin - (sin(SpinAng) * (SpinRad / 2)));
    int h = (vertSpin2 + (cos(SpinAng) * (SpinRad / 2))) / 2;
    int e1 = (horizSpin + (sin(SpinAng2) * (SpinRad / 2)));
    int f1 = (vertSpin2 - (cos(SpinAng2) * (SpinRad / 2))) / 2;
    int g1 = (horizSpin - (sin(SpinAng2) * (SpinRad / 2)));
    int h1 = (vertSpin2 + (cos(SpinAng2) * (SpinRad / 2))) / 2;

    arduboy.drawLine(a, b, a1, b1, WHITE);
    arduboy.drawLine(a1, b1, c, d, WHITE);
    arduboy.drawLine(c, d, c1, d1, WHITE);
    arduboy.drawLine(c1, d1, a, b, WHITE);
    arduboy.drawLine(e, f, e1, f1, WHITE);
    arduboy.drawLine(e1, f1, g, h, WHITE);
    arduboy.drawLine(g, h, g1, h1, WHITE);
    arduboy.drawLine(g1, h1, e, f, WHITE);
    arduboy.drawLine(a, b, e, f, WHITE);
    arduboy.drawLine(g, h, c, d, WHITE);
    arduboy.drawLine(a1, b1, e1, f1, WHITE);
    arduboy.drawLine(g1, h1, c1, d1, WHITE);
    arduboy.display();
  }

Thanks to you all.
Max

2 Likes

@Maxm,

When you post code in this forum, please enclose it in markdown code tags:

Start with a line containing three backticks followed by cpp .
Insert your code starting on the following line.
On the line following you code, put another three backticks.
The backtick character is commonly on the key below the Esc key at the top left of the keyboard. If you can’t find it on your keyboard, you can copy and past from the tags here:

```cpp
The first line of your code
More code
The last line of your code
```

I’ve added the tags to your post above but please do it yourself in the future.

Ok yes I will. I missed the instructions. Thank you for doing that.

1 Like

The Flappy Ball game uses binary fixed point arithmatic to calculate and move the animated the “ball” due to gravity. It’s not too well documented but you might be able to follow the code.

I wrote the fixed point code specifically for Flappy Ball but @Pharap has written a library for it that you may be able to use:

Ok. Thank you but I can’t parse that, it looks like exquisite engineering, but beyond me. There are some simple games with good gravity, like Lunar Lander type games, but I don’t understand how to adapt the gravity logic to handle an existing animation in with the games loop.

Ok, my first question: are you expecting this to be a rotation by 90 degrees?

The basic idea is that every ‘rigid body’ has:

  • A position
  • A velocity
  • A mass

Bear in mind that velocities are vectors - they have direction as well as speed.
(More about vectors here.)

Where:

  • The position of the rigid body determines where it is in the world
  • The velocity of the rigid body determines how much it moves by each second
  • The mass of the rigid body reduces the effectiveness of external forces applied to the rigid body

Applying a force divides the force by the rigid body’s mass and then adds that to the velocity, as per real world physics.
I.e. Newton’s second law of motion (F = ma, or force = mass * acceleration) is reversed to get a = F / m, or acceleration = force / mass, and acceleration is applied to the object’s velocity.

Gravity is a force that is applied once per frame.
(It probably ought to be once per second to be truly realistic,
but I’m taking quite a lot of other liberties as well to keep things simple.)

Rotation is ignored because simulating proper rotation gets into the realm of quite difficult maths and it was just supposed to be a simple demo.
A proper rigid body simulation would take that into account,
as well as doing collision checks on the rectangles.


Of course, even if you get gravity working, to get a screen to rotate offscreen you’d need to give it sufficient momentum and bounce, which realistically means you’re probably better off just trying to make an animation rather than trying to implement realisic physics.

If you were making a physics-driven game then using proper physics makes sense, but for the sake of an animated logo you might as well just precalculate several keyframes and interpolate between them.
Linear interpolation is easiest to implement, but won’t be very smooth.
For some more interesting interpolation methods, see here.

It’s difficult to understand because templates are very ‘meta’,
but it’s actually quite easy to use if you can understand how fixed points work.

Have a read of A Fixed Point Primer, particularly the “How Do Fixed Points Work?” section and it should hopefully give you an idea of how they work (they’re easier to understand than floats, especially if you think of them as a kind of mixed fraction where the fraction denominator is a power of two) at which point you should be able to use them more or less how you’d use a float:

Q8x8 number = 0.5;
number *= 5; // number is now 2.5
number += 7.5; // number is now 10.0

If you want to print it or use it where an integer is expected then you have to do a bit extra, like:

// If number is 10.5, prints 10
arduboy.println(number.getIntegerPart());
// Ought to give the same result as above
arduboy.println(static_cast<uint8_t>(number));
// Would print 10.5
arduboy.println(static_cast<float>(number));

Lastly a word of advice:
Since you’re passing the same values to sin and cos - cache the result in a variable.
The compiler (probably) can’t do that for you because it can’t prove that sin and cos have no side effects, and sin and cos are particularly expensive functions.

That and you might want to use an array for your vertices.
Possibly an array of Point just to make things even clearer.

1 Like

Oh, I think I might be able to follow this, Pharap like float but not infinite or open-ended. I need to read the primer first though, then incorporate your Library. Do you have an example of an object in one of your programs that accelerates this way?

Not sure what you mean by ‘open-ended’, but indeed there is no designated infinity value.
(That would greatly complicate matters.)

I think @MLXXXp was mentioning the library more as an aid to understanding Flappy Ball’s code, not necessarily suggesting that you use it.

In what way?


By the way, you didn’t answer my question:

Also I didn’t notice your reply sooner because you used the blue reply button at the bottom instead of using the reply on my post or @-mentioning me (e.g. @Pharap). If you do one of those I’ll get a notification that you’ve responded.

(You may want to read this post to understand the forum better.)

Answering the question, yes thats what I think. If it’s an error I never thought so, since the cube spins the way I need it to.

As for an example I meant like an object accelerating, like a missile or something.

It shouldn’t work because sin and cos expect angles in radians, not degrees.

Degrees go from 0 to 360, with 180 being a half turn.
Radians go from 0 to 2*Pi, with Pi being a half turn.
(Though personally I prefer tau to pi. Tau = 2*Pi.)

When you say ‘acceleration’, do you mean an object moving at a constant speed (an initial velocity with no acceleration) or an object with increasing speed (constant acceleration)?

In an environment with no friction, constant acceleration soon mounts up and reaches ridiculous speeds.

The simplest possible demonstration of constant velocity with no acceleration would be something like:

#include <Arduboy2.h>

Arduboy2 arduboy;

float positionX = (WIDTH / 2);
float positionY = (HEIGHT / 2);
float velocityX = 1.0f;
float velocityY = 0.25f;

void setup()
{
	arduboy.begin();
}

void loop()
{
	if(!arduboy.nextFrame())
		return;

	arduboy.pollButtons();

	arduboy.clear();

	// Note: not taking actual time into account
	positionX += velocityX;
	positionY += velocityY;

	arduboy.fillRect(positionX - 4, positionY - 4, 8, 8, WHITE);

	arduboy.display();
}

Hence:
Accelerate.ino.hex (20.9 KB)

Hmm, well it does work. Not sure whether to be happy about that or not. Dude, thank you for the example of constant velocity. Yes I see what you mean that constant acceleration would get silly fast, But I meant acceleration to a point, like you see it gain speed from a standstill and it plateaus.

I’m still not quite sure what you’re aiming for.

The best I can guess from that is something like this:

#include <Arduboy2.h>

Arduboy2 arduboy;

float positionX = 8;
float positionY = (HEIGHT - 8);
float velocityX = 0.0f;
float velocityY = 0.0f;

void setup()
{
	arduboy.begin();
}

uint8_t counter = 0;

void loop()
{
	if(!arduboy.nextFrame())
		return;

	arduboy.pollButtons();

	arduboy.clear();

	if(counter < 15)
	{
		velocityX += 0.05f;
		velocityY += -0.01f;
		++counter;
	}

	positionX += velocityX;
	positionY += velocityY;

	arduboy.fillRect(positionX - 4, positionY - 4, 8, 8, WHITE);

	arduboy.display();
}

Accelerate.ino.hex (21.3 KB)

Maybe if you drew the path that you want the cube to take?

Like I said before, having proper physics for the sake of an intro animation would be overkill, so unless this is actually part of a game mechanic you’re probably barking up the wrong tree to an extent.

Another cool example. Imagine a drop of water dripping off an icicle, still at first then falls free and slowly picks up speed to some maximum. That’s how I picture the spinning cube sitting there rotating in a fixed position, then it slowly slides down, picking up speed, falling at an increasing rate until it is off screen. I feel like I am wearing out my welcome, already. I hope that makes sense. I would like to describe things better when I ask questions, to be respective of your time.

Sounds like a great intro … I wonder if you will have any memory left over for a game?

As if THAT was important!

3 Likes

Exactly! Who want a game if the intro is awesome right? :wink:

1 Like

Perhaps you ought to draw a diagram, I’m really not understanding what you’re imagining from your description.

(Not least because I just keep thinking of the GameCube intro animation.)

I think the goal is to simply have the cube fall down and disappear off the bottom of the screen, accelerating due to the force of gravity (while rotating as it does now), as if it were held at its initial position and then released. The desired value for acceleration may be quite low, so that it takes a fair amount of time to slowly increase speed while falling.

For the short distance the cube falls, I don’t think a terminal velocity due to atmospheric resistance needs to be a factor.

Yes Mr. Scott that’s exactly it. Thank you. I think I would use Va = 1/2gt. Let’s say for arguments sake that is correct. What gets me is how do I incorporate an existing animation?

Like most typical sketches, you should be using a fixed rate, frame based system for your timing. The nextFrame() function is used for this, as @Pharap has done in his posted examples. For each frame you calculate the new position of the cube based on whatever acceleration formula you’ve chosen. You then calculate the new view of the cube and draw it at the new position. You repeat this until the cube is entirely off screen, then you somehow switch to the next stage of your program.

This is a basic skeleton:

#include <Arduboy2.h>

Arduboy2 arduboy;

// Whatever global variables you need go here

void setup()
{
  arduboy.begin();
  arduboy.setFrameRate(60); // 60 frames per second is the default.
                            // A different rate may be better
  // arduboy.setFrameDuration(); is available if you prefer to work
  //                             in milliseconds per frame
}

void loop()
{
  // Wait until it's time for the next frame
  if (!arduboy.nextFrame())
  {
    return;
  }

  arduboy.clear();

  // If the next cube position would be entirely off screen,
  // switch to the next game state.
  // Depending on how it's determined, this test may be better
  // at the end end of the loop.

  // Calculate the next cube position. If acceleration is slow,
  // fixed point math may make things smoother and easier.
  // Another technique to slow things down would be to only
  // calculate new positions every nth frame.
  if (arduboy.everyXFrames(4)) // on every 4th frame
  {
    // Calculate next cube position
  }

  // Calculate the next view of the cube and draw it at the new position.

  arduboy.display();
}
1 Like