Rollerball Tutorial

Penguin Shooter Example

Use the arrow keys to run around in the scene. Press the right mouse button to fire and hold the left mouse button to look in different directions.

Open This Pocket In A New Window

My First Game Tutorial

In this example you'll learn how to:

  • Create Objects
  • Manipulate the Camera
  • Capture User Input
  • Apply Forces to Objects
  • Capture Collision Events
  • Write a Main Loop

The demo at the top shows the finished example.

To the left are the individual steps to build this demo. Under each step is the new code for that step.

Simply copy the code underneath each step into your script, and by the end, you'll have the finished demo.
The complete code for this tutorial is at the very bottom of this page for your reference.

Open Script Directory

First, launch the builder.
You will keep all lua files that your game uses in your Script Directory.
To access this directory, click Folders->Open Local Directory.

 

Create New File

To start, create a new file called examplePenguinScript.lua
Open this file in your favorite text editor (We recommend Notepad++).

 

Print Output

Inside this file, you'll want to create a new onSceneStart function.
This special function is always called when a game first starts.
For now, you'll just print out the text "Hello World".
The exact code is located below, at the bottom of Step 1.
Save this file, then go back to the builder.

 

Set Script

To specify that you want to use your new script file, open the Global Properties (the top button on the right).
Under the Script tab, you can see that the attached script is already set to a default.
Specify the name of your script. Be sure to include your username.
For example, "yourusername/examplePenguinScript.lua" (without the quotes).

 

Test

Now, to test this pocket, click Debug->Begin Test.
In the new window that pops up you can see your pocket as it runs, but you also have access to the Debug Console.
Click the Debug Console button on the right and you can view your pocket's output.
You should see the words "Hello World" near the bottom to indicate that your script is running.
Congrats, you've gotten everything set up.
From here on out, all you have to do is save changes to your script and click reload on the test page to see the changes.

( Wild Pockets Manual : More details about setting up your scripts. )


    -- onSceneStart is called first to start the game
function onSceneStart()
 
-- Output to the debug console
print ("Hello World")
end

EventMaps

The first thing that you'll want to do is to capture the users input so they can interact with your game.
The pushFPSCamera function uses EventMaps to capture user input and in turn move the Camera around.
You'll notice that the first thing it does is to create a new map by calling fpskeymap = EventMap.new 
Then it assigns functions to keys using the setEvent method on the new keymap.
A key name is prepended by the state that you want to respond to. 
Possible states incule keyPressed, keyReleased and keyDown (keyDown fires every 10ms).
Finally once the map is build, it's pushed onto the EventHandler stack via the push function.
When a key is pressed, the top of the EventHandler stack is consulted, if the key is handled by that map it is, otherwise it digs deeper down the
stack.

( Wild Pockets Manual : More details about events. )

Camera Functions

In addition to eventMaps, you'll notice that the Camera is manipulated here.
The default Camera comes with a bunch of useful functions (though if you'd like more detailed control, consult our manual).
The Camera.setEye method defines the point in space where the Camera is located.
The Camera.setFocus method fines the point in space where the Camera is looking.
In addition the Camera.moveLeft, moveUp, etc functions manipulate the Cameras eye and focus.
The Camera.beginRotate function pushes a new EventMap onto the stack that tracks the users mouse and rotates the Camera accordingly.
To stop the rotation Camera.endRotate pops that EventMap.
Now you should be able to test your pocket and find that you can look around with the right mouse button and move with the arrow keys.

( Wild Pockets Manual : More details about the camera. )


    -- onSceneStart is called first to start the game
function onSceneStart()
 
-- Output to the debug console
print ("Hello World")

        -- Add camera controls
    pushFPSCamera()
        -- Set initial camera position
    Camera.setEye(vec(0,10,5))
    Camera.setFocus(vec(0,0,2))
end
-- This function will add an eventMap that control the camera
function pushFPSCamera()
 
    -- Create a new event map
    fpskeymap = EventMap:new()
   
    -- Add callback functions to specific input events
    fpskeymap:setEvent("scrollWheel",function(d) Camera.zoomIn(d/200) end)
    fpskeymap:setEvent("keyPress-rightMouse",function() Camera.beginRotate(150) end)
    fpskeymap:setEvent("keyRelease-rightMouse",function() Camera.endRotate() end)
 
    fpskeymap:setEvent("keyDown-left",function() Camera.moveLeft(0.1) end)
    fpskeymap:setEvent("keyDown-right",function() Camera.moveRight(0.1) end)
    fpskeymap:setEvent("keyDown-up",function() if EventHandler.keyIsDown("shift") then  Camera.moveUp(0.1) else Camera.moveForward(0.1) end end)
    fpskeymap:setEvent("keyDown-down",function() if EventHandler.keyIsDown("shift") then  Camera.moveDown(0.1) else Camera.moveBackward(0.1) end end)
 
 
    -- Add the eventmap to the stack
    EventHandler.push(fpskeymap)
end

spawnTarget Function

Lets go ahead and add stuff to our scene now.
As a first step lets spawn some targets to shoot at with a new function called spawnTarget.
In this function you can create a new object with SceneManager.createObject by passing it the filename of the object to create.
The createObject function will return a handle to the object.
With this handle you can set the position with setPosition to a random point 20 meters above the ground.
You can also give it the keyword “target” to make it easier to find later on.

 

Loops

You can use a simple for loop to call the spawnTarget function 6 times in the onSceneStart function.
After you’ve done this you can hit test and see the new targets appear.

 


    -- onSceneStart is called first to start the game
function onSceneStart()
 
-- Output to the debug console
print ("Hello World")
        -- Add camera controls
    pushFPSCamera()
 
        -- Set initial camera position
    Camera.setEye(vec(0,10,5))
    Camera.setFocus(vec(0,0,2))
   
        -- Create six targets
    for i=1,6 do
        spawnTarget()
    end
end
    -- Create a new target
function spawnTarget()
 
        -- Create the target and position it randomly
    local target = SceneManager.createObject("asmedberg/bobblePenguin")
    target:setPosition(vec(math.random(-10,10),math.random(-10,10),20))
   
        -- Apply the keyword target
    target:addKeywords("target")
 
end

New Event Map

First, in your onSceneStart function you’ll want to push a new EventMap to capture the user clicking the left mouse button.
Have this event call the fire function which we will create next.

Fire Function

The new fire function will do 3 things, create the projectile, apply a force to throw it and delete it after 5 seconds.
First create the projectile by calling SceneManager.createObject.
Then set the objects position to the position of the Cameras eye.
Next set the objects scale to 0.3 (or however big you want your projectiles to be)

Apply Force

To make the projectile fly forwards, you can call applyForce on it and pass that function a vector.

The Mouse.getRay function will return a vector that is pointing in the direction of the mouse, so all you have to do is multiply that vector by the amount of force you want and use that in the applyForce function.
We’ll also set the color of the projectile to a random color.
The setColor function takes a color which is defined by 3 or 4 numbers between 0 and 1. RGBA

( Wild Pockets Manual : More details about forces. )

Timer

In order to make the projectile disappear after 5 seconds we can schedule  a function to be run later with Timer.later.
Just
pass the function that you want to call, in this case calling delete on
the projectile, and the number of seconds later to call it.
Now you should be able to test your pocket and shoot colored balls into the scene.

( Wild Pockets Manual : More details about the timer and scheduling functions. )

 


    -- onSceneStart is called first to start the game
function onSceneStart()
 
-- Output to the debug console
print ("Hello World")
        -- Add camera controls
    pushFPSCamera()
 
        -- Set initial camera position
    Camera.setEye(vec(0,10,5))
    Camera.setFocus(vec(0,0,2))
   
        -- Add an event map to handle firing projectiles
    map = EventMap.new()
    map:setEvent("keyPress-leftMouse",fire)
    EventHandler.push(map)
   
        -- Create six targets
    for i=1,6 do
        spawnTarget()
    end
   
end
    -- Launch a projectile
function fire()
 
        -- Create the object
    local projectile = SceneManager.createObject("ecanaan/lowpoly_sphere")
   
        -- Position the object on the camera
    projectile:setPosition(Camera.getEye())
    projectile:setScale(0.3)
   
        -- Apply a force in the direction of the mouse
    projectile:applyForce(Mouse.getRay() * 50000)
   
        -- Apply a random color to the new projectile
    projectile:setColor(Color.new(math.random(0,100)/100,math.random(0,100)/100,math.random(0,100)/100))
   
        -- Schedule this projectile to be removed after 5 seconds
    Timer.later( function() delete(projectile) end , 5)
end

Set The Collision Handler

Now we definitely want to have the projectiles that we’re firing interact with the targets.
To add a collision handler to the projectiles, when they are created call setCollisionHandler on the projectile and pass it the function that you want to be called when it collides with something.

Phases

The function that is called from a collision event takes three arguments, the object, what its colliding with and what phase of the collision its on.
The start phase is when the object first touches even before any physics apply.
The middle phase is called every frame that the objects are still touching.
And the end phase is called when the objects stop colliding.
In this example we’ll want the end phase, simply because we want the paintball to apply a force before anything happens.

Coloring The Target

The next thing we’ll check is if the thing the paintball hit has the keyword “target” on it (To avoid coloring the ground).
If so, then we’ll simply set the color of the thing hit to the paintballs color, then delete the paintball.
You should be able to paint the targets now if you refresh your test pocket.

( Wild Pockets Manual : More details about collision handlers. )


    -- Launch a projectile
function fire()
 
        -- Create the object
    local projectile = SceneManager.createObject("ecanaan/lowpoly_sphere")
   
        -- Position the object on the camera
    projectile:setPosition(Camera.getEye())
    projectile:setScale(0.3)
   
        -- Apply a force in the direction of the mouse
    projectile:applyForce(Mouse.getRay() * 50000)
   
        -- Apply a random color to the new projectile
    projectile:setColor(Color.new(math.random(0,100)/100,math.random(0,100)/100,math.random(0,100)/100))
   
        -- Apply a collision handler to the new projectile
    projectile:setCollisionHandler(collision)
   
        -- Schedule this projectile to be removed after 5 seconds
    Timer.later( function() delete(projectile) end , 5)
end
function collision(self, other, phase)
 
    -- Only execute this code after the collision has been dealt with
    if phase == "end" then
   
        -- Only affect targets
        if other:hasKeyword("target") then
       
            -- Transfer color and remove the projectile
            other:setColor(self:getColor())
            delete(self)
        end
    end
end

Setting up a Main Loop

You may have noticed that the penguins fly off into the distance after a while.
To prevent this we’ll use a main loop to keep them close to the center of the world.
If you use a Timer.every you can schedule a function to be run every frame, or every so often.
The first argument to Timer.every is the function you want to run, the second is the number of seconds between executions.
A duration of 0 is special cased to run once every frame.

Attraction

In your main loop function you can get a list of SceneObjects that contain the keyword “target”.
Using a for loop to loop through this list you can apply a force to each that will push them slightly back towards the center.
Since this runs every frame, the penguins will have a tendency to be pulled back to the middle of the pocket.

Finished

Congrats!  You have built a basic pocket that creates objects, captures users
input, moves the camera, handles collisions and uses a main loop.

 


    -- onSceneStart is called first to start the game
function onSceneStart()
 
-- Output to the debug console
print ("Hello World")
        -- Add camera controls
    pushFPSCamera()
 
        -- Set initial camera position
    Camera.setEye(vec(0,10,5))
    Camera.setFocus(vec(0,0,2))
   
        -- Add an event map to handle firing projectiles
    map = EventMap.new()
    map:setEvent("keyPress-leftMouse",fire)
    EventHandler.push(map)
   
        -- Create six targets
    for i=1,6 do
        spawnTarget()
    end
   
        -- Start the function that will draw the targets to the center
    Timer.every(attractTargets,0)
end
function attractTargets()
 
    -- Loop through every target
    for k,v in pairs(SceneManager.getByKeyword("target")) do
   
        -- Apply a force directly opposite of the targets position
        v:applyForce(v:getPosition() * -10)
    end
end

Complete Code For 'My First Game' Penguin Shooter :

 


-- ExampleCode_PenguinShooter.lua --
 
    -- onSceneStart is called first to start the game
function onSceneStart()
 
-- Output to the debug console
print ("Hello World")
        -- Add camera controls
    pushFPSCamera()
 
        -- Set initial camera position
    Camera.setEye(vec(0,10,5))
    Camera.setFocus(vec(0,0,2))
   
        -- Add an event map to handle firing projectiles
    map = EventMap.new()
    map:setEvent("keyPress-leftMouse",fire)
    EventHandler.push(map)
   
        -- Create six targets
    for i=1,6 do
        spawnTarget()
    end
   
        -- Start the function that will draw the targets to the center
    Timer.every(attractTargets,0)
end
 
    -- Launch a projectile
function fire()
 
        -- Create the object
    local projectile = SceneManager.createObject("ecanaan/lowpoly_sphere")
   
        -- Position the object on the camera
    projectile:setPosition(Camera.getEye())
    projectile:setScale(0.3)
   
        -- Apply a force in the direction of the mouse
    projectile:applyForce(Mouse.getRay() * 50000)
   
        -- Apply a random color to the new projectile
    projectile:setColor(Color.new(math.random(0,100)/100,math.random(0,100)/100,math.random(0,100)/100))
   
        -- Apply a collision handler to the new projectile
    projectile:setCollisionHandler(collision)
   
        -- Schedule this projectile to be removed after 5 seconds
    Timer.later( function() delete(projectile) end , 5)
end
 
    -- Create a new target
function spawnTarget()
 
        -- Create the target and position it randomly
    local target = SceneManager.createObject("asmedberg/bobblePenguin")
    target:setPosition(vec(math.random(-10,10),math.random(-10,10),20))
   
        -- Apply the keyword target
    target:addKeywords("target")
 
end
 
function collision(self, other, phase)
 
    -- Only execute this code after the collision has been dealt with
    if phase == "end" then
   
        -- Only affect targets
        if other:hasKeyword("target") then
       
            -- Transfer color and remove the projectile
            other:setColor(self:getColor())
            delete(self)
        end
    end
end
 
-- This function will add an eventMap that control the camera
function pushFPSCamera()
 
    -- Create a new event map
    fpskeymap = EventMap:new()
   
    -- Add callback functions to specific input events
    fpskeymap:setEvent("scrollWheel",function(d) Camera.zoomIn(d/200) end)
    fpskeymap:setEvent("keyPress-rightMouse",function() Camera.beginRotate(150) end)
    fpskeymap:setEvent("keyRelease-rightMouse",function() Camera.endRotate() end)
 
    fpskeymap:setEvent("keyDown-left",function() Camera.moveLeft(0.1) end)
    fpskeymap:setEvent("keyDown-right",function() Camera.moveRight(0.1) end)
    fpskeymap:setEvent("keyDown-up",function() if EventHandler.keyIsDown("shift") then  Camera.moveUp(0.1) else Camera.moveForward(0.1) end end)
    fpskeymap:setEvent("keyDown-down",function() if EventHandler.keyIsDown("shift") then  Camera.moveDown(0.1) else Camera.moveBackward(0.1) end end)
 
 
    -- Add the eventmap to the stack
    EventHandler.push(fpskeymap)
end
 
function attractTargets()
 
    -- Loop through every target
    for k,v in pairs(SceneManager.getByKeyword("target")) do
   
        -- Apply a force directly opposite of the targets position
        v:applyForce(v:getPosition() * -10)
    end
end