Learning Game AI Programming with Lua
上QQ阅读APP看书,第一时间看更新

Creating a sandbox Lua script

With a basic sandbox application out of the way, we're going to create the basic Lua script that sets up the sandbox. First, create a new Sandbox.lua script within the script folder:

Create the Lua file as follows:

src/my_sandbox/script/Sandbox.lua

A sandbox Lua script must implement four global functions that the C++ code will call, and they are Sandbox_Cleanup, Sandbox_HandleEvent, Sandbox_Initialize, and Sandbox_Update:

Sandbox.lua:

function Sandbox_Cleanup(sandbox)
end

function Sandbox_HandleEvent(sandbox, event)
end

function Sandbox_Initialize(sandbox)
end

function Sandbox_Update(sandbox, deltaTimeInMillis)
end

With the basic hooks in place, modify your SandboxApplication class to create a sandbox based on your Lua script:

MySandbox.cpp:

void MySandbox::Initialize() {
    SandboxApplication::Initialize();

    ...
    CreateSandbox("Sandbox.lua");
}

Tip

Don't forget to recompile your sandbox application whenever a change is made to any of the C++ files.

Creating a floor

Now that your sandbox is initialized and hooked into Lua, we can start adding some basic geometry and lighting. The sandbox package exposed to Lua provides a CreatePlane function that will create a plane mesh specified by a width and length. A corresponding physics half-space will also be created and added into the physics simulation.

Tip

A physics half-space is a plane that expands infinitely in both the x and z directions.

Once a plane object has been created, we'll assign an Ogre material through the Core.SetMaterial function to give the plane a texture defined within media/materials/base.material.

Tip

The sandbox is set up to handle standard diffuse, specular, and normal mapped material types. New materials can be added to the media/materials/base.material file.

In this case we'll assign the Ground2 Ogre material to our newly created plane.

Sandbox.lua:

function Sandbox_Initialize(sandbox)
    local plane = Sandbox.CreatePlane(sandbox, 200, 200);
    Core.SetMaterial(plane, "Ground2");
end

If you run the sandbox at this point, you might expect to see the plane you created, but you'll see a black screen instead. Without any lighting in our sandbox, even though our plane had been created, we won't be able to see it yet.

Adding a light

Our plane isn't very exciting, as the sandbox has no lighting. The core package provides additional functions that create a directional light and assign diffuse and specular colors. The Core.CreateDirectionalLight function requires two parameters, the sandbox and a vector representing the direction of the light. Using a vector of (1, -1, 1) will create a light source that points diagonally in a downward direction.

Sandbox.lua:

function Sandbox_Initialize(sandbox)

    ...

    local directional = Core.CreateDirectionalLight(
        sandbox, Vector.new(1, -1, 1));

    --- Color is represented by a red, green, and blue vector.
    Core.SetLightDiffuse(
        directional, Vector.new(1.8, 1.4, 0.9));
    Core.SetLightSpecular(
        directional, Vector.new(1.8, 1.4, 0.9));
end

Tip

Note that the color of the diffuse and specular light values defined by Vector.new(red, green, blue) are set to values above one. This allows you to change the amount of light emitted.

Now that we have a light source, you can run your sandbox and look at the beautiful plane you created. To orient the camera, simply hold the right mouse button and drag the mouse in the direction in which you would like to point the camera. To navigate through the sandbox, we can move the camera around the world using the w, a, s, and d keys. Holding the Shift key while pressing any of the w, a, s, and d keys will move the camera significantly faster.

Adding a skybox

Looking into infinite blackness isn't very exciting; Sandbox.CreateSkyBox allows us to create a skybox defined by the six textures specified in the Ogre material (media/materials/skybox.material). If you're unfamiliar with skyboxes, they are essentially six-sided boxes with a different texture on each face of the box. As the camera moves around the sandbox, the skybox moves accordingly in order to give the illusion of an actual sky.

Tip

The sandbox comes with multiple skybox materials. Take a peek at the skybox.material file in any text editor to see other available skybox textures and how to create your own brand new skybox material.

Our Sandbox.CreateSkyBox function takes in three parameters: the sandbox itself, the name of the Ogre material, as well as a rotation vector. The rotation vector is represented in degrees and allows us to add an initial offset to our skybox. In this case, we can rotate the initial skybox by 180 degrees to have the sky textures match the directional light we created previously:

Sandbox.lua:

function Sandbox_Initialize(sandbox)

    ...

    Sandbox.CreateSkyBox(
        sandbox,
        "ThickCloudsWaterSkyBox",
        Vector.new(0, 180, 0));
end

Running the sandbox now will show a cloudy sky and a lit environment.

A new sandbox with a skybox and ground plane

Adding meshes to the sandbox

An Ogre mesh is simply a visual piece of geometry within the sandbox without any physics representation. To add an Ogre mesh to the sandbox, simply call Core.CreateMesh and pass in the location and filename of an Ogre mesh file.

Setting the position and rotation of a mesh can be done through the Core.SetPosition and Core.SetRotation functions:

Sandbox.lua:

function Sandbox_Initialize(sandbox)

    ...

    local mesh = Core.CreateMesh(
        sandbox, "models/nobiax_modular/modular_block.mesh");
    Core.SetPosition(mesh, Vector.new(0, 1, 0));
    Core.SetRotation(mesh, Vector.new(0, 45, 0));
end

The rotation function expects a vector of angles expressed in degrees. For example, Vector.new(0, 45, 0) will rotate the mesh 45 degrees around the y axis.

Creating sandbox objects

If you want an Ogre mesh to be simulated with physics, you can create a sandbox object instead. Sandbox.CreateObject will automatically generate a convex hull for any Ogre mesh and allow the object to be simulated with physics.

Note

As generating a physics representation for an arbitrary mesh happens at runtime, complex meshes might increase the load times of your sandbox. Internally, bullet physics creates a simplified convex hull that approximates the Ogre mesh instead of being an identical one-to-one mapping. Keep this in mind, as the physics representation of any Ogre mesh will always be an approximation and never an exact replica of the original mesh.

We can now convert the block mesh we created earlier to a full-fledged physically simulated object.

Sandbox.lua:

function Sandbox_Initialize(sandbox)

    ...

    local object = Sandbox.CreateObject(
        sandbox, "models/nobiax_modular/modular_block.mesh");
    -- Set the mass of the block in kilograms.
    Core.SetMass(object, 15);
    Core.SetPosition(object, Vector.new(0, 1, 0));
    Core.SetRotation(object, Vector.new(0, 45, 0));
end