Slope Physics TutorialWell basically I hate slope physics. So in order to help myself figure out what the hell is going on here, I’m going to write a tutorial! Makes perfect sense. Let’s get started. First, a little background. If you are relatively well-versed with physics in an Axe environment, you can skip this part.
Part 1: Gravity.First off let’s introduce the concept of gravity. Universal force that acts downwards. All objects fall at the same rate; or rather they all accelerate at the same rate. According to Newton, Force=mass*acceleration. More force=more acceleration. In real life, the acceleration of gravity is about 9.8 meters/second/second. Which makes sense: meters/second is a measure of speed, so meters/second/second is a measure of acceleration.
In our game world, we’ll set gravity to whatever quantity we want.
Part 2: Integer MathWell, we’ve got no decimals. That is certainly a problem. Well, to simulate decimals, we can inflate all our values by a certain number. The standard is 256, although theoretically you could use any value. How does this work?...Let’s go with an example. Let’s do a simulation of an object being affected by gravity!
We want the y position to accelerate every time, so let’s set up the following code with gravity being 1 pixel:
0->Y
Repeat getKey(15)
ClrDraw
Y+1->Y
Pxl-On(5,Y)
DispGraph
End
Wait, but that’s way too fast! Let’s try the same example, but with inflation of values by 256
0->Y
Repeat getKey(15)
ClrDraw
Y+1->Y
Pxl-On(5,Y/256)
DispGraph
End
See? Each time you add 1, it’s like you’re adding 1/256th of a pixel….Anyway, let’s move on to…
Part 3: The SlopeSo now, let’s draw a diagram of all the forces acting on an object on a slope. Forces are vectors; in other words, they are numbers with direction. And they can be split into different components.
Remember, sin is opposite/hypotenuse, and cos is adjacent/hypotenuse.
Now, we can see that the force dragging an object down a hill is equal to the force of gravity times the sine of the angle. Remember that F=ma, so the force of gravity is mg. In games, unless you’re planning to change the mass, I would set it to 1 for simplicity’s sake. So we get F=g. Easy enough. The force that pulls you down the hill is equivalent to gsinθ, with the direction of θ. The Fn up there is called the normal force. Basically, it just cancels out the y-component of gravity, which is why we don't talk about them much.
Notating VectorsWe can either express vectors in component, or in magnitude+direction formats. In games, it is more common to store vectors as components, so let’s start with that.
The problem is, how do you increment your objects’ velocity diagonally? Well, let’s move on to some more trig….
And there you have it. Every frame, increment x velocity by gsinθcosθ and y velocity by gsinθsinθ
But wait…Is it really that simple?
Part 5: Applying this concept in an Axe environmentHere is the tricky part. Axe sets us up with a great coding environment designed on speed and efficiency. Unfortunately, this means no decimals. Which is a HUGE problem.
Axe’s sine and cosine functions are a little bit different from your traditional sine and cosine functions. First of all, they use a system of
binary degrees Basically, one period or revolution is 256. You can use the conversion factor of 32/45 to convert from traditional degrees to binary degrees, or a factor of 128/π to convert from radians.
Degrees | Radians | Circle | Binary Degrees
0 | 0 | 0 | 0
45 | π/4 | 1/8 | 32
90 | π/2 | 1/4 | 64
180 | π | 1/2 | 128
270 | 3π/2 | 3/4 | 292
360 | 2π | 1 | 256
But that’s not the end of our problems. Since there are no decimals, Axe’s sine and cosine functions have an amplitude of -127 to +128 (or something like that, I don’t remember the exact limits). Take a look:
Degrees | sin | cos | Axe sin | Axe cos
0 | 0 | 1 | 0 | 128
30 | .5 | .87 | 64 | 93
45 | .71 | .71 | 53 | 53
90 | 1 | 0 | 128 | 0
180 | 0 | -1 | 0 | 65409
270 | -1 | 0 | 65409 | 0
Basically, the decimals that the traditional sine and cosine values output are multiplied by 256, rounded off, and then have the value 128 subtracted from them.
So how do we apply this in Axe?
G*sin(θ)//128*sin(θ)//128 || G*cos(θ)//128*sin(θ)//128
It’s messy, but at least it works.
Part 6: Wait! How do I figure out the angle?Ah, I thought you’d never ask.
Well, there are a few ways to do this. In traditional math and physics, we have this handy tool called the inverse tangent function. Unfortunately, we don’t get that in axe so....
Method 1: Tilemap.Yay! Everybody loves tilemapping. Fast, easy, etc. Basically, all you have to do here is give each tile an angle associated with it. Then, if you detect that your player is *on* the tile, apply the slope physics. I would use pixel testing for collision here.
How do you figure out what tile you’re standing on? Well first, make sure you’re standing on something….If not, apply gravity. Otherwise….
{Y/8+8*(map width)+(X/8)+(pointer to map location)}
should give you the tile you are standing on
Method 2: Pixel based methodThis method is a bit more complex. Basically, we shall look at the two pixels directly below us to determine the angle of the slope.
(The numbers in parentheses are binary degrees) Then, we’ll store this information in a lookup table (LUT) since we don’t get a tan^-1 function….
Data(51+64,45+64,32+64)
Data(0,32,45,51)->GDB1
I believe that this method works because the lines on the screen are all pixelated anyway. The total slope physics generated will all average each other out.
Note: This method can be easily adapted to memory reads instead of pixel tests if for some reason you have pixel heights stored in memory. Also, it may be easier for some to store the precomputed sin and cos values instead of the angle, for possible increased accuracy or speed.
.Note- make sure this runs before your sprite is drawn on screen
0->{L1}^^r
For(B,0,1)
For(A,0,7)
If pxl-Test(X+B,Y+A-3)
A-3->{B+L1}
End
End
End
{{L1}-{L1+1}+GDB1}
.^^this returns the angle value
Part 7: Multiple or Dynamic SlopesAll right, now we know how to deal with one slope. But what about slopes that change direction and stuff? Here is the time to use the other notation for vectors: magnitude-angle.
Basically, it’s relatively straightforward. Remember how the acceleration on the ball on the slope was Gsin θ? Well, changing the velocity with magnitude-angle notation is *almost* as simple as just adding gsinθ to the speed (S). Then, you have to store theta somewhere as the angle. To retrieve the x and y velocities, we can break the speed back into components: X speed=Scos θ and the Y speed= Ssin θ
However, one tricky part is that the
acceleration angle and the velocity angles are not the same. Do not rely on using the same angle for both of them, as that will turn out…not so pretty. Here’s an example of what it might look like…
Correcting this problem, we get this
(Credit to Runer112 on the concept on how to make this hilly terrain)
…And that’s all I have for now
As I learn more, I’ll add more; Future additions include collision with an angled surface, and flying and other random stuff. Happy programming!