Object Based Physics Platformer TutorialHey guys, it occurred to me to write a tutorial about how to make an object-based system with real physics, to be used in platformers. This tutorial will cover objects, tilemapping, moving a player character, and forces interacting with objects.
NOTE: IT'S HIGHLY LIKELY I FARKED SOMETHING UP. PLEASE TELL ME IF I DID.
Part 0: ThinkingBefore you dive right in, think. What is your platformer going to feature? How is it going to be unique? What makes it stand out? Nobody wants another crap platformer claiming to be the best thing since sliced bread. Great places to start are flash games - some can be really unique and give you great ideas.
Next, start planning. Greyscale or not? How are you going to allocate your variables? Simple things like these will make a huge difference in the long run. Making sure you plan properly will save you a lot of rewrites in the future.
Part 1: The Real WorldSo what exactly happens in the real world? Things in the real world have three important attributes to determine their position: Their position, their velocity, and their acceleration. Acceleration is a constant value that changes the velocity by a set amount for a given amount of time. On Earth, this value is 9.8 meters per second squared. This means that for every second that passes, your velocity (in free fall) increases by 9.8 meters per second. Your velocity then increases your position, by an increasing amount each time.
Position Velocity Time
0 0 0
9.8 9.8 1
29.4 19.6 2
58.8 29.4 3
… … …
That’s good and all, but how do we apply this to a platformer?
Part 2: Inflation (The Good Kind)Axe has a problem - that is, it doesn’t calculate decimals. So if we try to use whole-pixel acceleration values, stuff will fall way to fast for the player’s reflexes to kick in. How do we prevent this? We inflate all the position values by 256 (or some other large number, but 256 is the most optimized for Axe. I think.) What does this mean? Basically, if a position value is, say, the 56th pixel on the screen, we inflate the position value to 56*256, then divide out 256 later on. This allows us to calculate non-integral acceleration values, which is very useful in Axe.
Part 3: Object SystemsFirst of all, the code below will not be optimized for tutorial purposes to make it easier to understand. For more optimized code on arrays check out Deep Thought’s tutorial:
http://clrhome.co.cc/tutorials/arrays/So let’s start! We first need a routine to set the number of objects to zero.
Lbl IN
0→O
Return
This is vital because if you don’t do this, you might end up with a For( loop that will last for a while. And you don’t want to have to pull your batteries. Next, we need a routine that will add objects.
All objects have a certain number of attributes. It’s always good to plan out what attributes your object will have before actually creating this routine. In this case, our objects will have 5 attributes: x position, y position, x velocity, y velocity, and size. You can add others as you see fit; in Graviter, I added attributes for gravity direction, gravity lock, and whether or not the object is held or independent. Tag had just a held attribute. Since this is just a basic tutorial, we’ll go with the basics.
In regards to size, we’re going to assume all objects are square boxes. You might have to get creative with spriting, but it saves us space and coding in the long run. You can make the height and length different in the future, but this tutorial won’t cover that.
Lbl AO
O+1→O*10-10+L₁→r6 //This line helps us not have to keep writing O*10-10+L₁ over and over again.
r1*256→{r6}r //The r after {r6} is the superscript r, located under angle (2nd+Apps).
r2*256→{r6+2}r
0→{r6+4}r
0→{r6+6}r
r3*256→{r6+8}r
Return
Notes: r1 is initial x position, r2 is initial y position, and r3 is size.
We use the superscript r to write to two bytes. This lets us go up to 65536 instead of 256 for just one byte. If you don’t get that, don’t worry.
Optimized using Deep Thought’s method, it would look like:
Lbl AO
r3*256→{0→{0→{r2*256→{r1*256→{O+1→O*5-5+L₁}r+1}r+1}r+1}r+1}r
Return
So. We have a routine to add objects. Now, we’re going to update them, in a glorious shower of awesomeness. Before we start, however, there’s something I should point out. There are a lot of ways to do hit detection. Depending on how your game is going to be run, you’ll want to choose one to suit your needs. If you want some tiles to be solid graphically but not detectable to the object, you’ll want to go with pointer or byte-masking detection. One of the fastest and easiest ways, however, is pixel detection. That’s what I’m going to demonstrate in this tutorial, and I’ll attach some additional code explaining the other methods.
Pixel detection does have some drawbacks, however. For example, it is difficult (though not impossible) to have tiles that are graphically solid.
We will now create the subroutine that will cause all the objects to become affected downwards by gravity.
Lbl UO
For(r5,1,O)
r5*10+L₁→r6
{r6+6}r+1→{r6+6}r //Increments the velocity by 1 for every frame. Inflated by 256, +1 for the velocity is kinda slow. I’d go with 4 or 5.
{r6+2}r+{r6+6}r→{r6+2}r //Adds the velocity to the positional value
End
Return
Alrightttt! Wasn’t that simple. If you run this code (Which I don’t recommend) it won’t look like it’s doing anything. Which is because we still need the main program, which will call all the subroutines in the order we want them.
We’re going to want something in the following order: Generate a map, initialize values, then have the code where the game is running. Something like:
sub(MAP)
sub(IN)
While 1
//Run game code, e.g. sub(UO),etc
End