Index:

  • Gravity
  • Trigonometry
  • Cellular Automata
  • Virtual Pixel Testing
  • Single Segmented Rope Physics

    GRAVITY:

    One of the most basic Physics concepts that you might want to implement in a game is gravity. Whether it be in a platformer, a pinball game, or something else, gravity is a common need. So to start off, we need to ask ourselves, what it gravity? Gravity acts on all objects on earth, and pulls the objects towards the surface, we all know that. But its not merely as simple as decreasing the players position by 1 each frame, things don't fall that way*, as they fall they get faster and faster. This phenomenom is known as acceleration and is the concept behind gravity and all accelerating physics.

    Acceleration is measured in X Meters per second per second. That is to say, every second, your velocity will increase by X Meters per second. Since we live in the game world, it would be more somthing like X pixels per frame per frame. That is to say, every frame, your velocity will increase by X pixels per frame. Lets say your position starts at 0 and your velocity starts at -3 and you are in an empty world with 1 P/F/F acceleration (2 pixels per frame per frame). This chart shows your position, velocity, and acceleration for a few frames.

    Code:
    Frame	Position	Velocity	Acceleration
    0	0		-3		1
    1	-3		-2		1
    2	-5		-1		1
    3	-6		0		1
    4	-6		1		1
    5	-5		2		1	
    6	-3		3		1
    7	0		4		1
    8	4		5		1		
    9	9		6		1
    10	15		7		1

    The code for this would look something like

    Code:
    0->X
    -3->V
    1->A
    
    While 1
    Output(1,1,X)
    X+V->X
    V+A->V
    End

    Notice that even when the velocity is positive, the position can still be negative, and vica versa. But you can see that the position starts off moving downwards, stops at -6, then starts moving upwards again. Acceleration stays constant througout the entire simulation. If you want to get really technical, you can go into how velocity is the derivative of position blah blah blah, but you dont need to know that in a game.

    HOW TO USE IT:

    Implementing acceleration is simple, especialy if your acceleration is constant. You only need a single variable for your position and one for your velocity. If you want changing acceleration you could add a variable for that too.

    Also note that X velocity is INDEPENDANT of Y velocity. That is to say, if your character has a velocity in the X direction, and has gravity affecting it, since gravity is only in the Y direction (unless your game is uber cool) the Y acceleration will only affect the Y velocity will only affect the Y position. Try this example program for size:

    Code:
    ZStandard
    ZInteger
    AxesOff
    Clrdraw
    0->X
    0->Z
    0->A
    0->B
    
    While 1
    PtOff(X,Z,2
    X+A->X
    Z+B->Z
    PtOn(X,Z,2
    getKey->K
    A+(K=26)-(K=24)->A
    B+(K=25)-(K=34)->B
    End

    Its a fun example of the power of acceleration, see if you can add gravity to it! You might have some interesting results.

    WHAT TO WATCH OUT FOR:

    Acceleration is not always applied, for example when you are standing on a platform, both your velocity and your acceleration are 0. More on this will be covered in the next section 'Collisions'

    Back to the top

    OK here is a quick (kinda) lesson on trig and the wonders of Triangles! Unplanned, so its coming before collisions.

    ************

    Trigonometry

    ************

    NOTE: put your calc in degrees mode!

    Trig is one of those things that can be very usefull in games, but is actualy fairly difficult to figure out without some good instruction. That is where this tutorial is going to try to help.

    Trigonometry is the mathematics of trianlges. Take this triangle for instance.

    Code:
          |\
          | \
      a   |  \ C    (hypotenuse)
    (leg) |   \
          |    \
          +-----
             b (leg)

    It is a right triangle because the angle between side A and side B is 90 degrees. This is the only type of trignale we will discuss in this tutorial, and usualy it is the only one you will need.

    In addition to having 3 sides, there are also 3 angles. AB, AC, and BC. You can also call them by the sides that are *opposite* to that angle, so angle AB would be angle C. We already established that angle AB is 90 degrees. This triangle is a RIGHT triangle, because it has one right (90 degree) angle, and Right Triangles are your friend.

    For starters, here is the pythagorean theorem:

    A^2 + B^2 = C^2

    Hmmm interesting, for all Right Trignales, the sum of each leg squared, equals the hypotenuse squared. (remember, the legs are the two sides that make the right angle) What this means for us is that for any right triangle, if we are given 2 sides, we can find the other with this equation. This is a way to calculate the distance to a point, as you can use the 2 legs as the X and Y distances to a point.

    Code:
                  B
                  /|
    	     / |    The distance from A to B is the hypotenuse of a right triangle, with X and Y
    	    /  |    as the legs. 
    	   /   | Y
    	  /    |    Distance^2 = X^2 + Y^2     Take the square root, and we have:
    	 /     |	
    	A------+    Distance = SQRT(X^2 + Y^2)	
                X

    Now, we have worked with the sides, what about the angles? The angles between two sides is the ammount of rotation between them:

    Code:
      |
      |          \                         /
      |           \                       /
      |            \                     / 
      | 90 degrees  \   135 degrees     /  45 degrees 
      |              \                 /
      +---------      --------        ---------

    Somtimes we want to rotate a sprite or an object around a point. Like this:

    Code:
    ZStandard
    ZInteger
    AxesOff
    ClrDraw
    For(F,0,360,5
    Pt-On(29cos(F),29sin(F
    End

    What??? How did i just do that? Well the answer lies in trig, and in right triangles. You may not think that triangles have much to do with circles, but in fact, they have everything to do with eachother. A circle contains all the points a certain radius from a center point. So given a radius, there are different X,Y points that lie onto a circle. Does this look farmiliar? Look again at the distance formula:

    Distance = SQRT(X^2 + Y^2)

    If we say that Distance is the radius, this distance equation becomes the equation of a circle! :O

    It gives us an euqation, where if we have a radius (distance) and an X or Y value, we can find the other coordinate.

    Try solving the distance equation for Y

    Distance = SQRT(X^2 + Y^2)
    Distance^2 = X^2 + Y^2
    Distance^2 - X^2 = Y^2
    SQRT(Distance^2 - X^2) = Y
    
    Y = SQRT(Distance^2 - X^2)

    Try putting this into Y1 in your calculator, set Distance to 5 lets say, and graph it! You get a circle! (or half of one anyway... stupid functions...)

    Wow, thats really cool, we can get a circle without doing any trig at all!

    Now comes the final challenge, using the above equation, we can find all of the points on a circle, given the radius, but what if we want a singe point? We already have the radius, but we do not have any other variables to determine which point to use. We need another, and that is the angle. A circle goes accross 360 degrees or angle, starting at the rightmost point at 0 degrees and rotating accross the circle counterclockwise until it gets to 360 degrees, where it started.

    Now it is time to introduce Sin, Cos, and Tan. These functions pertain to triangles and their angles, and are all very usefull. For right triangles, you only take the sin, cos, or tan of angles that are NOT the Right

    Angle

    So for this triable they would be AC and BC

    Code:
          |\			Sin of an angle equals the opposite leg over the hypotenuse
          | \				Sin(BC) = A/C	Sin(AC) = B/C
      a   |  \ C    (hypotenuse)	Cos of an angle equals the adjecent leg over the hypotenuse
    (leg) |   \				Cos(BC) = B/C	Sin(AC) = A/C
          |    \			Tan of an angle equals the opposite over the adjecent
          +-----				Tan(BC) = A/B	Tan(AC) = B/A
             b (leg)

    These trigonometric equations give us some interesting power. If we know Hypotenuse C and Angle BC, we can find leg A.

    Sin(BC) = A/C
    Sin(BC)*C = A
    A = Sin(BC)*C

    And we can also find leg B as well

    Cos(BC) = B/C
    Cos(BC)*C = B
    B = Cos(BC)*C

    Do you know what this meants? Given a distance, and an angle, we can find the coordinates of that point!

    Code:
               B
              /|
    	     / |  
    	    /  |    
    	   /   | Y
    	  /    |  
    	 /     |	
    	A------+    
                X

    Given the angle at A, and the distance AB, we can calculate the distances X and Y, which are the coordinates of Point B.

    X = R*Cos(A)
    Y = R*Sin(B)

    Its that simple! And for all angles, point B will be a distance of R form the center, which is the *exact* definition of a circle! Given an angle and a radius, using these two equations we can find a specific point on a circle.

    This program shows how the triangles fit into the circle as it travels around the circle:

    Code:
    ZStandard
    ZInteger
    AxesOff
    ClrDraw
    Degree
    0->F
    
    Circle(0,0,30
    While 1
    Line(0,0,A,B,0	//hypotenuse
    Line(0,0,A,0,0	//right leg
    Line(A,0,A,B,0  //left leg
    29Cos(F)->A //find the coordinates of the next point on the circle
    29Sin(F)->B
    Line(0,0,A,B
    Line(0,0,A,0
    Line(A,0,A,B
    F+5->F
    End

    Back to top

    Cellular Automata

    Cellular Automata is described by a grid of pixels, where each pixel has a certain amount of rules determining what happens to it. The Game Of Life is a great example of this type of simulation, but how can this be used for physics? Using pixel based rules is a great way to simulate large scale effects that would normally be difficult to program. Things like fluid dynamics, sand, fire, and acid, sounds complicated? Well all of these things are possible with cellular automata, and will be covered in this tutorial on how to use pixel rules to simulate all of your effects needs.

    We are going to base our tutorial off of the water simulation, since that is a simulation that will cover the basics of everything else to come. Water sounds like an extremely difficult thing to implement on a calculator; itís so dynamic and hard to define! How would you even go about storing the data? Well cellular automata provides a great method for us to solve this. First, we need to come up with our expectations:

    1) The water must be affected by gravity
    2) Water must flow

    Now that we have our expectations, we need to find some rules that we can apply to our pixels. In our simulation, each pixel will represent a small part of water, and each pixel will move corresponding to our rules. I would like to introduce a 3rd rule:

    3) Pixels cannot intersect eachother!

    This is very important! If one pixel moves itself onto another pixel, those pixels merge and become a single pixel, and we will lose a small piece of water. This is fine if thatís what you want, but we want our water to stay at a constant volume, we donít want to lose any pieces of water. So no matter what, if a pixel moves, it must always move to an empty space!

    With this, we can devise some simple rules:

    Code:
    Rule #		Condition				Action
    1		Space below empty			Move down
    2		Spaces to the sides empty		Move either left or right
    3		Single empty space to a side		Move into that empty space

    These rules are followed top to bottom. This means that first rule 1 is checked, if the condition is satisfied, we do the action. If not, we move onto the next rule and continue. If no conditions are satisfied, the pixel stays where it is and we move onto the next pixel.

    Thatís it! Those are the rules! Simple rules right? And yet they can yield surprisingly advanced responsesÖ.

    Pretty impressive eh? Letís look at some other sample rules that we could apply:

    Sand:
    Code:
    Rule #		Condition					Action
    1		Space below empty				Move down
    2		Space to the bottom-right/left empty		Move to that empty space
    
    
    Fire:
    Code:
    Rule #		Condition					Action
    1		Space above is empty				Move up
    2		Space above is filled				Move left/right
    3		rand<.05					End life of this pixel
    
    
    Acid:
    Code:
    Rule #		Condition					Action
    1		Space below is not Acid			Move down
    2		Spaces to the sides is not acid		Move either left or right
    3		Single non-Acid space to a side		Move into that empty space

    Note that these are not the only way to achieve the effects desired, this is not a precise art, and many different rules can be applied to achieve many different effects, the best way to find out what works is to try everything yourself!

    How To Use It:

    Well thatís nice, how do I implement this in my program? Well, it would be tempting to rely on pixel commands alone, but a more elegant solution is to have a list of pixel locations, and to loop through them. This allows for better speed and a larger area of simulation.

    Here is some sample code in Axe format:

    Code:
    For(F,0,N				For N+1 Pixels 
    D*2+L1->L				Find their location in L1
    {L}->X					X location in first Byte
    {L+1}->Y				Y location in second bytes
    Pxl-Off(X,Y
    
    If Pxl-Test(X,Y+1)			If ground below is solid
      Rand^2*2-1->A				Choose a random direction
      !If Pxl-Test(X+A,Y		If that direction is empty
        X+A->X					Move there
      Else!If Pxl-Test(X-A,Y	Else, if the opposite direction is empty
        X-A->X					Move there instead
      End
    Else
      Y+1->Y					If all else fails and ground below is empty, move down
    End
    
    Pxl-On(X,Y
    X->{L}
    Y->{L+1}
    End

    Note that this code wonít work by itself; you still need a way to put the pixels into L1, and to remove them. You will also need to create the environment and everything, but this I leave up to you.

    What to look out for:

    I presented an option to store the pixels in an array, which takes a fair amount of memory. It is tempting to just work off of the screen as a buffer, and loop through every pixel on it, but there is an inherent problem with this. Not only does it limit the size of your screen, but the fact that you are either going to pass through the screen left to right, or right to left, introduces a bias into the simulation that might make fluids tend to flow left, or for smoke to drift right. The results are unpredictable, and unless you know that the rules you introduce will not interfere, and that you have a small enough space to keep speed up, you should stick with the pixel buffer.

    Back to the top

    Virtual Pixel Testing

    We all know about the basic command Pxl-Test() right? It tests a pixel on the screen/buffer and returns whether or not the pixel is on or off. This seems simple enough, but actually can be used to provide some fairly quick alternatives to using matrix based collision detection. Not only are we eliminating the need to a matrix, but by simply drawing to the screen, we have already generated the data we will need for collision. Eliminating the Matrix, as well as the time needed to spend writing to it, mean that pxl-testing is a formidable way to speed up your Basic or Axe game!

    But, there are some issues with this. What happens when your game requires tiles that might not be solid black? We run into problems fast if we have complicated graphics, and have to resort to complex trickery in order to get collision to work. One option is to have a single pixel in each tile of a tilemap be the indicator on whether or not the tile is filled or not, but this is hardly a perfect solution. What if we wanted to be able to detect alternate things? Like for instance certain tiles might slow down your character, or make them enter a swimming animation. Certainly we canít assign properties to all of the pixels of a sprite, that would be both slow and limiting in the graphics we could choose. The solution lies in Virtual Pixel Testing.

    A virtual pixel test is a test that behaves like a pixel test, but returns a value that doesnít have to do with the pixels color. Instead, it has to do with any attributes that the pixel has. If we make this simple, we can have the virtual test determine whether or not the pixel is solid or not, independent of its color. We could even expand this to return a value that relates to something like friction or temperature. But how to implement such a function? In this tutorial, I am going to be focusing on Tile Based Virtual Pixels, and Mask Based Virtual Pixels.

    Tile Based Virtual Testing:

    Say you have a tilemap, for any sort of game, sidescroller, top down, platform, you name it. Chances are some of your tiles are going to need to be solid. Now up until now, you have might gone by using some tricky byte testing mixed with modular arithmetic, wishing it were as simple as using a pxl-test() command. Well, using virtual tests, it can be just as simple:

    Code:
    Lbl TST
    {r2/8*W + (r1/8)+L1}
    Return

    Given a byte based matrix array located in L1, that represents a tilemap with width W, this function will return the tile number associated with any given pixel. Note that r2/8*W is essential, r2*W/8 would not work.

    This simple function, coupled with clever ordering of your tiles, can make for very simple collision checking. When you design your game, order the tiles so that all the solid ones come first, followed by all of the empty tiles. This way, checking for a solid tile is as simple as a comparison test.

    Code:
    Lbl TST
    {r2/8*W + (r1/8)+L1}
    Return

    Where r1 is the X position, r2 is the Y position, N is the tile number where your empty tiles start, and L1 is the location of your matrix data buffer.

    Using this routine will allow you to test a pixel and either get the tile number associated with that pixel (which could tell you any number of things) or test whether or not the tile is solid. Using this information for accurate physics is now easier, and will be addressed in a later chapter.

    Masked Virtual Buffer Testing:

    This is all fine and dandy for tile based physics, but what about tiles that are not square? Say you were making a sonic game, and you needed ramps and loops and things like that? How could you modify this code such that it would work correctly? The answer lies in Masks.

    All a mask is, is an alternate sprite that tells you where your main sprite is solid. If this is your normal sprite:

    Code:
    -------O
    ------OO
    -----O-O
    ----O--O
    ---OOOOO
    --O----O
    -O-----O
    OOOOOOOO

    A simple ramp like sprite, then this is your sprite mask:

    Code:
    -------O
    ------OO
    -----OOO
    ----OOOO
    ---OOOOO
    --OOOOOO
    -OOOOOOO
    OOOOOOOO

    Note that your regular sprite can be any design it wants to be, and your mask is black where it is solid and white where it is not. The code for testing this is as follows:

    Code:
    Lbl MSK
    {r2^8+{r2/8*W+(r1/8)+L1}+Str1}e r1
    Return

    Where r1 is your X position, r2 is your Y position, W is the width of your tilemap (in tiles), L1 is the location of your matrix data buffer, and Str1 is the start of your Mask Sprite table.

    Your mask sprite table is identical to your sprite table, but instead of normal sprites, it includes the masked sprites. This code will return the value of the bit in the mask sprite where your pixel is located, which can make for pixel based physics and terrain, in a tile based world.

    What to watch out for:

    Make sure that instead of using a variable W, use a constant! Also try to make sure it is a power of 2, as this makes for very quick and simple multiplication. You can further speed up both subroutines by changing the /8 into /2/2/2, although this will create an increase in size. Also, the e in the mask operation is the euler's constant e found on the divide button.

    Also note that all of the code in this lesson is based on the assumption that your pixel coordinates are based off of the upper left hand corner of your matrix, and that your matrix follows the left-to-right moving-down standard. It also assumes you are using 8x8 sprites, although 16x16 sprites would not be difficult to accommodate.

    Back to the top

    Single Segmented Rope Physics

    The situation is always the same, you are making your physics puzzle game that may or may not be a platformer, you want to add in a new game element, but you can't think of anything to add! Maybe you want to add in some sort of rope element, but how in the world could we do this fast and efficiently? Well this tutorial is going to teach you how to make a Single Segmented Force Based Rope Physics engine That might sound complicated but lets break it down:

    1) Single Segmented

    What single segmented means is that your rope will consist of only a single segment. What this means is that we will only simulate the start and end of the rope, none of the stuff in the middle where the rope bends or whatnot. Since one end of the rope is going to be fixed to a wall, in this tutorial we will only be simulating the object that is attached to the end of the rope. When you go to display the rope however, you don't have to simply draw a line between the anchor and the object, you can get creative and do fancy things, but that is outside this tutorial.

    2) Force Based

    There are many types of physics engines, and when combining them to create complicated effects, weird things can start to happen. If one part of the physics engine devoted to rope physics moves an object without checking the other parts, it might accidentally move it into a wall or another object! For this reason, the only thing this physics engine will do is impart forces onto the object, it will not move them. We are also going to be assuming this rope is infinitely strong, and we will be ignoring the mass of the object. By using only a force based engine, this gives us the highest possibility that this code will be able to be implemented into your existing engine.

    3) The Conecpt

    So what happens to an object that is attached to a string? What forces are exerted on it? Before we can answer those questions, we need to decide how to define the string itself. It needs an anchor point, and a length, so we will use three variables X,Y and L, to represent these. We also need to use certain variables from our object, such as its position (I,J) and velocity (A,B).

    Whenever the distance D from the object to the anchor is less than the length, we know that the rope is not going to be taught, and therefor cannot be imparting any force on the ball. We could calculate the distance using the pythagorean theorem:

    Code:
    Sqrt((X-I)^2+(Y-J)^2)=D

    But that uses a square root, and those are slow and sad. Instead, we are going to square both sizes of the equation, since squaring is fast and happy!

    Code:
    (X-I)*2+(Y-J)^2=D^2

    So now when we compare D to L, we will actually be comparing D^2 to L^2. The size difference doesnt matter, since are only seeing if D is greater than L. If you are using a x256 precision engine (which you should be ) you can use this piece of code to find the distance in pixels (not x256!)

    Code:
    abs(X-I)->r1*^r1+(abs(Y-J)->r1*^r1)->D

    So now we can tell if the object is pulling the string taught, or if it is letting it slack. Obviously if it is slack (D=L) that we start needing to apply a force.

    When a ball is moving out of the allowable ring of movement that the string allows, the first thing we need to do is eliminate the velocity that is taking it outside the ring. This does not mean setting the velocity to 0. This does also not mean we negate the velocity. Imagine this: The ball is falling straight down with the string above it. When the string pulls taught, the ball will be yanked back up again and lose almost all velocity very quickly. But if you drop it from an angle, off to the side, it will lose a little speed, but most of it will be transfered into a pendulum motion. In a sense, all of the velocity that is directed out of the ring is being removed, and anything that is in line with the ring (tangential, its the motions it moves in when it swings) is kept. Now this is a bit tricky to do, so bear with me here:

    I-X//L->N
    J-Y//L->O

    This finds the Normal Vector of the string. The math behind it isn't that important except that you know that it points in the same direction as the string, from base to object. This will be important in determining how much velocity to remove, and from what direction to remove it from. The string is the only thing that can take velocity from the object, and as such, it can only affect the object in the same direction the string is pointing. The significance of this is that any change in the velocity of the object will be a multiple of this Normal Vector! All that is left is to find this coefficient!

    That coefficient just so happens to be the dot product of the objects velocity and the ropes normal vector.

    A**N + (B**O)*-1->K

    Yeah, this isn't the 100% right dot product. Technically speaking we would have to multiply two Normal Vectors, and AB is not normal. But since we are going to be multiplying by AB anyways, we just combine the steps by not dividing and multiplying by AB I put this in a spoiler just because its pretty involved vector physics and not needed for the tutorial. Similarly, multiplying by -1 isn't something that is done in a dot product, but is done later twice so i moved it back here so we only had to do it once

    Now we need to do a quick test. On the off chance that the ball is outside L, but actually moving *towards* the rope, K will be positive, and you don't want to affect the ball in this case.

    Code:
    If K<<0

    Now all that is left to do is to add the velocity to the object!

    Code:
    K**N+A->A
    K**O+B->B

    Note that this will remove all velocity that is taking the ball outside the ring of string; stop it dead. Sometimes this is undesired, so you can make it pull a little bit more and give the string a little "bounce"

    Code:
    K**N*3//2+A->A
    K**O*3//2+B->B

    And thats it! You are done! This is what the final result should look like when you piece all this together: (Note that L^2 has been precomputed and put into M)

    Code:
    If abs(X-I)->r1*^r1+(abs(Y-J)->r1*^r1)I-X//L->N
    J-Y//L->O
    A**N+(B**O)*-1->K
    If K<<0
    K**N*3//2+A->A
    K**O*3//2+B->B
    End
    End

    And this is what it should look like when implemented into a simple program!

    Back to the top