Getting Physical

Here’s where things get interesting, I will be referring to Daniel Shiffman’s work over at shiffman.net, he’s done excellent work on simple physics for programming, most of his work is done in P5.JS but it should be easily adaptable to any language.

 

First we will create a vector that contains the objects position and set it to the center of the screen, in this case we’ll be using the foreground image from the previous code as our object, but it could really be anything.

[pastacode lang=”cpp” manual=”vec2%20position%3B%0A%0Aposition.setX(SCREEN_WIDTH%20%2F%202)%3B%0Aposition.setY(SCREEN_HEIGHT%20%2F%202)%3B” message=”” highlight=”” provider=”manual”/]

 

Now that we have the position covered we’ll modify the rendering code to use the X and Y member variables of the vector position instead of the mouse cursor locations. rerunning the program we see no changes, this is good! Now to make it move we need to update it’s location at every frame by a certain amount, that amount will be it’s velocity, velocity is just a change in position over time.

We’ll Add another vector called velocity and assign it an arbitrary value of 5 to get started by using the member function setMag():

[pastacode lang=”cpp” manual=”vec2%20velocity%3B%0A%0Avelocity.setMag(5)” message=”” highlight=”” provider=”manual”/]

 

Now in the render loop, we use the add() function we created for vec2 to add the velocity to the position each frame: position.add(velocity);

Running the program we see that our image has disappeared, I’m thinking it’s just moving too fast so I’m going to reduce the velocity by an order of magnitude to .5. Still no good, let’s go a few more orders of magnitude, nope, something is definitely wrong, let’s see what happened here. I’m going to add std::cout << position.getX() << std::endl before and after the velocity is added in my code so I can see what is happening.

It looks like the program is running so fast we don’t get to see the results, I’ll add a delay to the code with SDL_Delay(100) to artificially slow it down, later on we’ll look into frame rate limiting to make this more automatic and less wasteful of CPU cycles, but this will do for now.

With the delay in place I can see that the starting position.x is 320 and then it goes to -nan, looks like a bug!

Further investigation and a few more lines printed to console shows that there is an error in the vec2 class, it has allowed us to create an empty vector!  We’ll need to modify the class to include default values if none are specified in the function call.

Adding the following constructors to the class should resolve the issue:

[pastacode lang=”cpp” manual=”vec2%3A%3Avec2()%0A%7B%0A%20%20%20%20this-%3Ex%20%3D%201%3B%0A%20%20%20%20this-%3Ey%20%3D%201%3B%0A%7D%0A%0Avec2%3A%3Avec2(int%20x%2C%20int%20y)%0A%7B%0A%20%20%20%20this-%3Ex%20%3D%20x%3B%0A%20%20%20%20this-%3Ey%20%3D%20y%3B%0A%7D” message=”” highlight=”” provider=”manual”/]

 

This should allow us to create a vector object and populate it with any values we want and, if we don’t specify any values for it, it should default to one for both Y and Y. Commenting out the setMag() function call we can see that the object is now slowly creeping down to the bottom left of the screen just as we would expect for an object moving at 1 pixel per frame! If I remove the delay we see that the object moves at a steady but fairly leisurely pace, slower than I would have expected for something with no frame rate limiting. Looking back in the code I recall that we set the renderer to sync to monitor vsync, which is 60hz, let’s disable it and see what happens.

As expected the object shot off the screen faster than could be seen, this is good, it means that we don’t really need to worry about frame rate limiting at this stage in the game, though timers will be useful for determining just how long a frame took to render, that way we can tell how much time we have to calculate everything else.

Let’s make it bounce when it hits a wall now, instead of just disappearing into the ether:

[pastacode lang=”cpp” manual=”if%20(position.getX()%20%3E%3D%20SCREEN_WIDTH%20-%20iW%20%7C%20position.getX()%20%3C%3D%200)%0A%7B%0A%20%20%20%20velocity.setX(velocity.getX()%20*-1)%3B%0A%7D%0Aif%20(position.getY()%20%3E%3D%20SCREEN_HEIGHT%20-%20iH%7C%20position.getY()%20%3C%3D%200)%0A%7B%0A%20%20%20%20velocity.setY(velocity.getY()%20*-1)%3B%0A%7D%0A” message=”” highlight=”” provider=”manual”/]

 

This simple collision code will test to see if the image is at or past the window boundaries and, if so, invert the velocity, effectively reversing it’s direction. Note also that we are subtracting the images width and height from the greater than comparison, because the object is location at a point, we need to look beyond that point to the width or height of the image to be sure it doesn’t appear to pass out of the window.

Modifying the render code will make things render correctly: renderTexture(image, renderer, position.getX(), position.getY())

All we’ve done here is omit the centering of the image on the render location, this simplifies the collision code.

 

One last simple change we can make for today is to increment and decrement the velocity with keypresses using the event handler from earlier:

[pastacode lang=”cpp” manual=”case%20SDLK_a%3A%0A%20%20%20%20velocity.setX(velocity.getX()%20%2B%201)%3B%0A%20%20%20%20velocity.setY(velocity.getY()%20%2B%201)%3B%0A%20%20%20%20break%3B%0A%0Acase%20SDLK_z%3A%0A%20%20%20%20velocity.setX(velocity.getX()%20-%201)%3B%0A%20%20%20%20velocity.setY(velocity.getY()%20-%201)%3B%0A%20%20%20%20break%3B%0A” message=”” highlight=”” provider=”manual”/]

There is an interesting bug here where the direction of the velocity is not taken into account when incrementing and decrementing which causes the object to appear to have acceleration in some instances, fun!

That’s it for today, hopefully more tomorrow!

Leave a Reply

Your email address will not be published.