Order now AGK Bitesize

Lesson Two - An introduction to AGK Physics

by Steven Holding

In this tutorial we will take a look at the physics system incorporated into AGK. Using this system we can recreate a realistic set of physical reactions and quickly create an effective game engine with very little coding. Arguably the most widely known 2D physics based game is "Angry Birds" and we can easily code a similar basic game engine in AGK physics, even in a "Bitesize" tutorial. We'll start by positioning some ordinary sprites where we want them, for the time being we'll confine them to the limits of our screen but it's worth increasing the size of our screen first to give us a little more visible room.

Start by creating a new project and then open the "setup.agc" file. Edit line 13 so that it says "width=1024". Also edit line 16 so that it says "height=600". Then open the "main.agc" file and change the display aspect (line 6) like this:

SetDisplayAspect( 1024.0 / 600.0 )

Now we have a larger, wider screen to play with let's add some dynamic sprites to knock down. Add the following code after the display aspect line:

rem lower level
for s=1 to 4
    spr = createSprite(0)
    setSpriteVisible(spr,0)
    setSpriteSize(spr,1,20)
    setSpritePosition(spr,70 + s*5,80)
   
    rem turn physics on!
    setSpritePhysicsOn(spr,2)
   
    if s<4
        spr = createSprite(0)
        setSpriteVisible(spr,0)
        setSpriteSize(spr,5,1.5)
        setSpritePosition(spr,70.5 + s*5,79.25)
       
        rem turn physics on!
        setSpritePhysicsOn(spr,2)
    endif
next

You will notice that we create a sprite, set its size and set its position. Then we "set sprite physics on". The "2" means we are creating a "dynamic" sprite which will react to hitting other physics sprites. We are also setting each sprite's visibility to zero; this is because we will be viewing this exercise in debug mode to avoid the need for any media. We turn debug mode on by adding this line before our game loop:

SetPhysicsDebugOn()

Here is what you should see when you compile and run the code so far:

AGK - Angry Birds Physics

There are three settings (1 to 3) which are "static", "dynamic" and "kinematic". Static sprites will not be affected by other sprites or forces (such as gravity), but will act as a physical barrier to other sprites. Dynamic sprites will react to collisions with static / dynamic / kinematic sprites as well as forces. Kinematic sprites are similar to static sprites but can have their linear and angular velocity set / edited. During a collision, a kinematic sprite will not divert from it's course.

We will now create a static sprite which will represent an obstacle in our scene. Add this code after the last line we added:

rem obstacle
spr = createSprite(0)
setSpriteVisible(spr,0)
setSpriteSize(spr,2,15)
setSpritePosition(spr,50,85)
rem turn physics on!
setSpritePhysicsOn(spr,1)

You may notice when you run the code that static sprites are shown in green in debug mode:

AGK - Angry Birds Physics

Now we need something to throw at our dynamic sprites! Another dynamic object would be ideal so let's use a circular object and position it where we would like to throw it from.

rem circular object
spr = createSprite(0)
setSpriteVisible(spr,0)
setSpriteSize(spr,2,-1)
setSpritePosition(spr,5,95)
rem turn physics on!
setSpritePhysicsOn(spr,2)
setSpriteShapeCircle(spr,0,0,1)
rock = spr

I have assigned the name "rock" for this sprite as we will need to make sure we are looking at the correct sprite in a short while.

AGK - Angry Birds PhysicsWe also have a new command "setSpriteShapeCircle". Physics-enabled sprites require a "shape" to define their bounds. The "0,0" parameters are the offset of the shape from the sprite's centre and the "1" is the radius of the circle (1 percent of the width of the screen). Sprites can be circular, rectangular (including square) or polygon shaped. Polygon (or irregular) shapes can be automatically created by AGK based on your sprite image or defined by you (for more complex shapes) but for now we will stick with simple shapes. Your circular sprite should look like the image here.

All we need to do now is to make it possible to throw our sprite over the obstacle to try to hit our targets. This can be done in a number of ways but perhaps the simplest is to just drag the sprite. We can create "joints" in AGK which are similar to connections we make in real life. A "revolute" joint for example is similar to loosely bolting two lengths of wood together so that they can "hinge".

For the purpose of this exercise a "mouse" joint is similar to a revolute joint fixed to a point in world space and can be used to "grab" objects with the mouse. We will use input from the mouse to pick up and throw our object as follows. Read through the following subroutine and add it after the loop.

mouseGrab:
    rem get the pointer/mouse position
    px# = getPointerX()
    py# = getPointerY()
    
    rem find out if the pointer/mouse has JUST been pressed
    if getPointerPressed()=1
     
        rem check position of rock
        if getSpriteX(rock)<20 and getSpriteY(rock)>80
       
            rem check if the "rock" is under the mouse
            if getSpriteHitTest(rock,px#,py#)=1
               
                rem it is so let's pick it up
                mouseJoint = createMouseJoint(rock,px#,py#,10000)
               
            endif
           
        else
           
            rem reset the "rock" position
            setSpritePosition(rock,5,95)
           
            rem stop the "rock" from moving
            setSpritePhysicsVelocity(rock,0,0)
            setSpritePhysicsAngularVelocity(rock,0)
           
        endif
       
    else
       
        rem check if the mouse joint exists
        if mouseJoint>0
           
            rem check if the pointer/mouse is still being pressed
            if getPointerState()=1
               
                rem it is so let's update the position of the joint
                rem so the "rock" will follow but only if the mouse
                rem not too far from the start, in which case it is
                rem thrown by deleting the joint!
                if px#<20 and py#>80
   
                    rem update the mouse joint position
                    setJointMouseTarget(mouseJoint,px#,py#)
                   
                else
                   
                    rem delete the mouse joint
                    deleteJoint(mouseJoint)
                    mouseJoint=0
                   
                endif
               
            else
               
                rem delete the mouse joint
                deleteJoint(mouseJoint)
                mouseJoint=0
               
            endif
           
        endif
       
    endif
 
return

This subroutine will check for the rock being clicked on by the mouse and create a mouse joint if it is. If the mouse is released (or too far from the start position) then the rock is thrown by deleting the joint. If the rock is not in its start position when the mouse is pressed it will be "reset" back to the start position.

For this code to run you will need to add "gosub mouseGrab:" in the loop as follows:

rem A Wizard Did It!
do
    gosub mouseGrab:
   
    Sync()
loop

AGK BitesizeTry running the code and see how it works. This is a very simple start to an "Angry Birds" style game, by adding media and checking the collision data stored by AGK we could quickly get something closer to what would be required for the full engine but hopefully this example gives you a better idea how to use just a few commands to make a simple game engine using AGK physics.

The full code and a compiled version of this month's example can be downloaded here. As an extra challenge, why not try to build a more complex structure to demolish, using the simple techniques learned in this tutorial.