Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Learning game AI programming with Lua
Learning game AI programming with Lua

Learning game AI programming with Lua: Leverage the power of Lua programming to create game AI that focuses on motion, animation, and tactics

eBook
$19.99 $28.99
Paperback
$48.99
Subscription
Free Trial
Renews at $19.99p/m

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Table of content icon View table of contents Preview book icon Preview Book

Learning game AI programming with Lua

Chapter 1. Getting Started with AI Sandbox

In this chapter, we will cover the following topics:

  • AI sandbox's project layout and compilation
  • Using the Lua integrated development environment, Decoda
  • Debugging Lua scripts and AI sandbox
  • Passing and receiving data from C++ to Lua and vice versa
  • C++ functions calling Lua functions
  • Lua functions calling C++ functions
  • Creating custom data types managed by C++ within Lua
  • An overview of AI sandbox C++ classes

Introduction to AI sandbox

AI sandbox is a framework that is designed to do away with the tedious job of application management, resource handling, memory management, and Lua binding, so that you can focus immediately on creating AI in Lua. While the sandbox does the dirty work of a small game engine, none of the internals of the sandbox are hidden. The internal code base is well documented and explained here so that you can expand any additional functionality your AI might require.

The design behind the sandbox is a culmination of open source libraries preassembled in order to rapidly prototype and debug Lua's scripted AIs. While C++ code maintains and manages the data of AI, Lua scripts manage AI's decision-making logic. With a clear separation of data and logic, the logic represented in Lua scripts can be rapidly iterated on without worrying about corrupting or invalidating the current state of AI.

Understanding the sandbox

Before diving head-first into creating AI, this chapter goes over the internals and setup of the sandbox. While the AI scripting will all take place in Lua, it is important to understand how Lua interfaces with the sandbox and what responsibilities remain in C++ compared to Lua.

The project layout

The sandbox is laid out to easily support individual applications while sharing the same media resources between them. A key project, which is demo_framework, provides all the common code used throughout the book. The only difference between each individual chapter's C++ code is the setup of which Lua sandbox script to execute. Even though the entire sandbox framework is available from the beginning of the book, each chapter will introduce new functionality within the sandbox incrementally:

bin
    x32/debug
    x32/release
    x64/debug
    x64/release
build (generated folders)
    projects
    Learning Game AI Programming.sln
decoda
lib (generated folders)
    x32/debug
    x32/release
    x64/debug
    x64/release
media
    animations
    fonts
    materials
    models
    packs
    particle
    programs
    shaders
    textures
premake
    premake
    SandboxDemos
src
    chapter_1_movement (example)
        include
        script
        src
    ogre3d (example)
        include
        src
    ...
tools
    decoda
    premake
vs2008.bat
vs2010.bat
vs2012.bat
vs2013.bat

Tip

Downloading the example code

You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.

Now we'll take a look at what each folder within the sandbox project contains:

  • The bin folder will contain all built executables, based on which build configuration is selected in Visual Studio. Both 32-bit and 64-bit versions of the sandbox can be built side by side without the need to rebuild the solution.

    Note

    While the sandbox can be built as both a 32-bit and 64-bit application, debugging Lua scripts is only supported in Decoda with 32-bit builds.

  • The build folder contains Visual Studio's solution file. The build/projects folder contains each individual Visual Studio project along with the solution. It is safe to delete the build folder at any time and regenerate the solution and project files with the vs2008.bat, vs2010.bat, vs2012.bat, or vs2013.bat batch files. Any changes made directly to the Visual Studio solution should be avoided, as regenerating the solution file will remove all the local changes.
  • The decoda folder contains the individual Decoda IDE project files that correspond to each chapter demo. These project files are not generated from build scripts.
  • The lib folder is an intermediate output folder where static libraries are compiled. It is safe to delete this folder, as Visual Studio will build any missing libraries during the next build of the sandbox.
  • The media folder contains all the shared assets used within the chapter demos. Assets used by the sandbox exist as both loose files and ZIP bundles.
  • The premake folder contains the build script used to configure the sandbox's solution and project files. Any desired changes to the Visual Studio solution or projects should be made in the Premake script.

    Note

    The Premake script will detect any additional C++ or Lua files within the project's folder structure. When adding a new Lua script or C++ files, simply rerun the build scripts to update the Visual Studio solution.

  • The src folder contains the source code for each open source library as well as the sandbox itself. Every project within the sandbox solution file will have a corresponding src folder, with separate folders for header files and source files. Chapter demos have an additional script folder that contains every Lua script for that particular chapter.

    Note

    Each open source library contains both a VERSION.txt and LICENSE.txt file, which states the version number of the open source library used as well as the license agreement that must be followed by all users.

  • The tools folder contains the installer for the Decoda IDE as well as the Premake utility program that is used to create the Visual Studio solution.

The Premake build

Premake is a Lua-based build configuration tool. AI sandbox uses Premake in order to support multiple versions of Visual Studio without the need to maintain build configurations across solutions and build configurations.

Executing the vs2008.bat batch file will create a Visual Studio 2008 solution within the build folder. Correspondingly, the vs2010.bat and vs2012.bat batch files will create Visual Studio 2010 and Visual Studio 2012 solutions of AI sandbox.

Compiling the sandbox with Visual Studio 2008/2010/2012/2013

Building the sandbox requires only one dependency, which is the DirectX SDK. Make sure that your system has the DirectX SDK installed, or download the free SDK from Microsoft at http://www.microsoft.com/en-us/download/details.aspx?id=6812.

The sandbox solution file is located at build/Learning Game AI Programming.sln once one of the vs2008.bat, vs2010.bat, vs2012.bat, or vs2013.bat batch files have been executed. The initial build of the sandbox might take several minutes to build all of the libraries the sandbox uses, and further builds will be much faster.

Open source libraries

Lua 5.1.5 is used by the sandbox instead of the latest Lua 5.2.x library. The latest build of the Decoda IDE's debugger only supports up to 5.1.x of Lua. Newer versions of Lua can be substituted into the sandbox, but Lua's debugging support will no longer function.

At the time of writing this, Ogre3D 1.9.0 is the latest stable build of the Ogre3D graphics library. A minimal configuration of Ogre3D is used by the sandbox, which only requires the minimum library dependencies for image handling, font handling, ZIP compression, and DirectX graphics support.

The included dependencies required by Ogre3D are:

  • FreeImage 3.15.4
  • FreeType 2.4.12
  • libjpeg 8d
  • OpenJPEG 1.5.1
  • libpng 1.5.13
  • LibRaw 0.14.7
  • LibTIFF 4.0.3
  • OpenEXR 1.5.0
  • Imbase 0.9.0
  • zlib 1.2.8
  • zzip 0.13.62

The sandbox was created with the DirectX SDK Version 9.29.1962, but any later version of DirectX SDK will work as well. Additional open source libraries providing debug graphics, input handling, physics, steering, and pathfinding are detailed as follows:

  • Ogre3D Procedural 0.2: This is a procedural geometry library that provides easy creation of objects such as spheres, planes, cylinders, and capsules used for debug- and prototyping-level creation within the sandbox.
  • OIS 1.3: This is a platform-agnostic library that is responsible for all the input handling and input device management used by the sandbox.
  • Bullet Physics 2.81-rev2613: This is the physics engine library that drives the AI movement and collision detection within the sandbox.
  • OpenSteer revision 190: This is a local steering library that is used to calculate steering forces of AI agents.
  • Recast 1.4: This provides the sandbox with runtime navigation mesh generation.
  • Detour 1.4: This provides A* pathfinding on top of generated navigation meshes.

Open source tools

Premake dev e7a41f90fb80 is a development build of Premake that is based on the Premake development branch. The sandbox's Premake configuration files utilize the latest features that are only present in the development branch of Premake.

Decoda 1.6 build 1034 provides seamless Lua debugging through an inspection of the sandbox's debug symbol files.

Lua IDE – Decoda

Decoda is a professional Lua integrated development environment (IDE) that was released as open source by Unknown Worlds Entertainment, makers of Natural Selection 2 (http://unknownworlds.com/decoda/).

Decoda takes a unique approach to Lua script debugging, which makes integrating with an application far superior to other Lua debuggers. Instead of using a networked-based approach where an internal Lua virtual machine must be configured to support debugging, Decoda uses the debug symbol files produced by Visual Studio in order to support Lua debugging. The key advantage of this approach is that it supports Lua debugging without requiring any changes to the original application. This key difference in Decoda allows for easy debug support in the sandbox's embedded Lua virtual machines.

Running AI sandbox inside Decoda

Begin by opening this chapter's Decoda project (decoda/chapter_1_movement.deproj). Each sandbox Decoda project is already set up to run the correct corresponding sandbox executable. To run the sandbox within Decoda, press Ctrl + F5, or click on the Start Without Debugging option from the Debug menu.

Setting up a new Decoda project

Setting up a new Decoda project only requires a few initial steps to point Decoda to the correct executable and debug symbols.

A new Decoda project can be configured with the following steps:

  1. Open the Settings menu under the Project menu, as shown in the following screenshot:
    Setting up a new Decoda project

    Accessing the Decoda project settings

  2. Set the Command textbox to point to the new sandbox executable.
  3. Set the Working Directory and Symbols Directory fields to the executable's directory.

    Note

    Decoda can only debug 32-bit applications where debug symbols are present. AI sandbox creates debug symbols in both Release and Debug build configurations.

The Project Settings screen can be seen as follows:

Setting up a new Decoda project

Setting the Decoda debug executable and working directory

Debugging Lua scripts

To begin debugging Lua scripts within the sandbox, press F5 within Decoda. F5 will launch the sandbox application and attach Decoda to the running process. Selecting Break from the Debug menu or setting a breakpoint over a running script will pause the sandbox for debugging.

Debugging Lua scripts

Debugging Lua scripts in Decoda

Decoda Watch window

If you're familiar with the Visual Studio Watch window, the Decoda Watch window is very similar. Type any variable within the Watch window to monitor that variable while debugging. Decoda also allows you to type in any arbitrary Lua statements within the Watch window. The Lua statement will be executed within the current scope of the debugger.

Decoda Watch window

Viewing local Lua variables in the Decoda Watch window

Decoda Call Stack window

The stack window shows you the currently executing Lua call stack. Double-click on any line to jump to the caller. The Watch window will be automatically updated based on the current scope specified by the call stack.

Decoda Call Stack window

Analyzing the Lua call stack in the Decoda Call Stack window

The Decoda Virtual Machines window

The Virtual Machines window shows you each of the Lua virtual machines the sandbox is running. In this case, there is a separate virtual machine for the sandbox and a separate virtual machine for each of the running agents.

The Decoda Virtual Machines window

Debugging multiple Lua virtual machines within Decoda

Simultaneous Lua and C++ debugging

To simultaneously debug both the C++ sandbox and any running Lua scripts, there are a few approaches available.

Visual Studio – Attach to Process

If the sandbox was launched from Decoda, you can always attach it to the running process from Visual Studio through the Debug menu's Attach to Process option.

Visual Studio – Attach to Process

Simultaneously debug the C++ sandbox when launching from Decoda

Decoda – Attach to Process

Decoda can also attach itself to a running process through the Debug menu. If the sandbox is run through Visual Studio, you can attach Decoda at any time in the same fashion that Visual Studio attaches it to the sandbox.

Decoda – Attach to Process

Simultaneously debug Lua scripts when launching the sandbox from Visual Studio

Decoda – Attach System Debugger

To automatically attach both Decoda and Visual Studio when the sandbox launches from Decoda, select the Attach System Debugger option from the Debug menu. Upon running the application from Decoda, Windows will prompt you to immediately attach a Just-In-Time (JIT) debugger.

Note

If your installed version of Visual Studio doesn't show up in the Just-In-Time debugger as a selectable option, enable JIT debugging for native applications from Visual Studio by navigating to Tools | Options | Debugging | Just-In-Time.

The following screenshot shows you the Debug option that we are accessing in order to attach the system debugger:

Decoda – Attach System Debugger

Automatically attach the Decoda debugger when launching the sandbox

Associating Lua scripts from code with Decoda

In order for Decoda to know which Lua file to associate the currently executing Lua script, the luaL_loadbuffer Lua API function must pass in the Lua filename as chunkName during the loading. The luaL_loadbuffer function is an auxiliary Lua helper function provided in lauxlib.h:

lauxlib.h

int luaL_loadbuffer(
    lua_State* luaVM, const char* buffer,
    size_t bufferSize, const char* chunkName);

The Lua virtual machine

The Lua virtual machine is represented by lua_State struct, which is defined in the lstate.h header file. Lua states are self-contained structures without the use for any global data, making them practical for threaded applications:

lstate.h

struct lua_State;

The sandbox runs multiple Lua virtual machines simultaneously. One main virtual machine is assigned to the sandbox itself, while each spawned agent runs its own separate virtual machine. The use of individual virtual machines comes to the sandbox at the cost of performance and memory but allows for iterating Lua scripts in real time on a per-agent basis.

The Lua stack

As Lua is a weakly typed language that supports functions that can receive an arbitrary amount of parameters as well as return an arbitrary number of return values, interfacing with C++ code is a bit tricky.

To get around the strong typing of C++, Lua uses a First In First Out (FIFO) stack to send and receive data from the Lua virtual machine. For example, when C++ wants to call a Lua function, the Lua function as well as the function parameters are pushed onto the stack and are then executed by the virtual machine. Any return values from the function are pushed back to the stack for the calling C++ code to handle.

The same process happens in reverse when the Lua code wants to call the C++ code. First, Lua pushes the C++ function onto the stack, followed by any parameters sent to the function. Once the code has finished executing, any return values are pushed back to the stack for the executing Lua script to handle.

The Lua stack

The Lua call stack indexing scheme

When interfacing with Lua, stack values can either be retrieved bottom-up, or top-down. The top element in the stack can be retrieved with an index of -1, while the bottom element of the stack can be retrieved with an index of 1. Additional elements can be retrieved by indexing -2, -3, 2, 3, and so on.

Note

Lua differs from most programming languages by index values beginning from 1 instead of 0.

Lua primitives

Lua has 8 basic primitives: nil, Boolean, number, string, function, userdata, thread, and table:

  • Nil: Here, a value corresponds to a null value in C.
  • Boolean: Here, values are equivalent to their C++ counterparts and represent either true or false.
  • Number: This internally represent doubles that Lua uses to store integers, longs, floats, and doubles.
  • String: This represents any sequence of characters.
  • Function: Lua also considers functions as a primitive, which allows you to assign functions to variables.
  • Userdata: This a special Lua type that maps a Lua variable to data managed by the C code.
  • Thread: A thread primitive is used by Lua to implement coroutines.
  • Table: This is an associative array that maps an index to a Lua primitive. A Lua table can be indexed by any Lua primitive.

Metatables

A metatable in Lua is a table primitive that allows custom functions to override common operations such as addition, subtraction, assignment, and so on. The sandbox uses metatables extensively in order to provide common functionality to the userdata that C++ manages.

To retrieve a metatable within Lua, use the getmetatable function on any object:

metatable getmetatable(object);

To set a metatable within Lua, use the setmetatable function that passes both the object to set and the metatable:

nil setmetatable(object, metatable);

Tip

As the sandbox heavily uses metatables for userdata, you can always use getmetatable on the userdata to see which operations a specific userdata type supports.

Metamethods

A metamethod is a particular entry within a metatable that is called when an overriden operation is being requested by Lua. Typically, all Lua metamethods will begin with two underscores at the beginning of the function's name.

To add a metamethod to a metatable, assign a function to the metatable indexed by the metamethod's name. For example:

local metatable = getmetatable(table);
metatable.__add = function(left, right)
    return left.value + right.value;
end
setmetatable(table, metatable);

Userdata

Userdata is an arbitrary block of data whose lifetime is managed by Lua's garbage collector. Whenever a code creates userdata to push into Lua, a block of memory managed by Lua is requested from lua_newuserdata:

lua.h

void* lua_newuserdata(lua_State* luaVM, size_t userdataSize);

While the sandbox makes extensive use of userdata, the construction and destruction of the allocated memory is still handled within the sandbox. This allows for Lua scripts to be easily iterated without worrying about Lua's internal memory management. For instance, when an agent is exposed to Lua through userdata, the only memory that Lua manages for the agent is a pointer to the agent. Lua is free to garbage collect the pointer at any time and has no effect on the agent itself.

C/C++ calling Lua functions

The sandbox hooks into the Lua script through three predefined global Lua functions: Sandbox_Initialize, Sandbox_Cleanup, and Sandbox_Update. When the sandbox is first attached to the corresponding Lua script, the Sandbox_Initialize function is called. Each update tick of the sandbox will also invoke the Sandbox_Update function in the Lua script. When the sandbox is being destroyed or reloaded, the Sandbox_Cleanup function will have an opportunity to perform any script-side cleanup.

In order for C++ to call a Lua function, the function must be retrieved from Lua and pushed onto the stack. Function parameters are then pushed on top of the stack, followed by a call to lua_pcall, which executes the Lua function. The lua_pcall function specifies the number of arguments the Lua function receives, the number of expected return values, and specifies how to handle errors:

lua.h

int lua_pcall(
   lua_State* luaVM, int numberOfArguments,
   int numberOfResults, int errorFunction);

For example, the Agent_Initialize Lua script function is called in the AgentUtilities class in the following manner:

Agent.lua

function Agent_Initialize(agent)
    ...
end

First, the Lua function is retrieved from Lua by name and pushed onto the stack. Next, the agent itself is pushed as the only parameter to the Agent_Initialize function. Lastly, lua_pcall executes the function and checks whether it succeeded successfully; otherwise, an assertion is raised by the sandbox:

AgentUtilities.cpp

void AgentUtilities::Initialize(Agent* const agent)
{
    // Retrieves the lua virtual machine the agent script is
    // running on.    lua_State* luaVM = agent->GetLuaVM();

    lua_getglobal(luaVM, "Agent_Initialize");

    // Agent_Initialize accepts one parameter, an Agent.
    AgentUtilities::PushAgent(luaVM, agent);

    // Execute the Agent_Initialize function and check for 
    // success.
    if (lua_pcall(luaVM, 1, 0, 0) != 0)
    {
        assert(false);
    }
}

Lua calling C/C++ functions

Exposing C++ functions to Lua takes place through a process called function binding. Any bound functions exposed to Lua become accessible either as a global function or as a function available through a package. Packages in Lua are similar to namespaces in C++ and are implemented as a global table within Lua.

Function binding

Any function exposed to Lua must fit the lua_CFunction declaration. A lua_CFunction declaration takes in the Lua virtual machine and returns the number of return values pushed onto the Lua stack:

lua.h

typedef int (*lua_CFunction) (lua_State *L);

For example, the C++ GetRadius function exposed in the sandbox is declared in the LuaScriptBindings.h header file in the following manner:

LuaScriptBindings.h

int Lua_Script_AgentGetRadius(lua_State* luaVM);

The actual function implementation is defined within the LuaScriptBindings.cpp file and contains the code for retrieving and pushing values back to the stack. The GetRadius function expects an agent pointer as the first and only parameter from Lua and returns the radius of the agent. The Lua_Script_AgentGetRadius function first checks the stack for the expected parameter count and then retrieves the userdata off the stack through a helper function within the AgentUtilities class. An additional helper function performs the actual work of calculating the agent's radius and pushes the value back onto the stack:

LuaScriptBindings.cpp

int Lua_Script_AgentGetRadius(lua_State* luaVM)
{
    if (lua_gettop(luaVM) == 1)
    {
        Agent* const agent = AgentUtilities::GetAgent(
            luaVM, 1);

        return AgentUtilities::PushRadius(luaVM, agent);
    }
    return 0;
}

To bind the function to Lua, we define a constant array that maps the function's name within Lua to the C function that should be called. The array of function mappings must always end with a null luaL_Reg type struct. Lua uses a null luaL_Reg type struct as a terminator when processing the function map:

AgentUtilities.cpp

const luaL_Reg AgentFunctions[] =
{
    { "GetRadius", Lua_Script_AgentGetRadius },
    { NULL, NULL }
};

The actual function binding to the Lua virtual machine takes place in the luaL_register helper function. The register function binds the table of function names to their corresponding C callback function. The package name is specified at this step and will be associated with each function within the mapping:

AgentUtilities.cpp

void AgentUtilities::BindVMFunctions(lua_State* const luaVM)
{
    luaL_register(luaVM, "Agent", AgentFunctions);
}

Note

If NULL is passed in as the package name, Lua requires that a table be at the top of the Lua stack. Lua will add the C functions to the Lua table at the top of the stack.

Creating custom userdata

While the sandbox uses userdata to pass around agents and the sandbox itself, another use of userdata is to add basic primitives into the sandbox. These primitives are completely controlled by Lua's garbage collector.

The vector primitive added into the sandbox is a good example of using userdata that is completely controlled by Lua. As a vector is essentially a struct that only holds three values, it is a great choice for Lua to completely maintain the creation and destruction of the data. What this means to the C++ code interacting with Lua vectors is that code should never hold on to the memory address returned from Lua. Instead, the code should copy values retrieved from Lua and store them locally.

Looking at the vector data type

Elevating a vector into a basic Lua primitive means supporting all the expected operations users would like to perform on a vector variable in Lua. This means that vectors should support the addition, subtraction, multiplication, indexing, and any other basic operators supported by Lua.

To accomplish this, the vector data type uses metamethods to support basic arithmetic operators, as well as supporting the dot operator for the ".x", ".y", and ".z" style syntax:

LuaScriptUtilities.cpp

const luaL_Reg LuaVector3Metatable[] =
{
    { "__add", Lua_Script_Vector3Add },
    { "__div", Lua_Script_Vector3Divide },
    { "__eq", Lua_Script_Vector3Equal },
    { "__index", Lua_Script_Vector3Index },
    { "__mul", Lua_Script_Vector3Multiply },
    { "__newindex", Lua_Script_Vector3NewIndex },
    { "__sub", Lua_Script_Vector3Subtract },
    { "__tostring", Lua_Script_Vector3ToString },
    { "__towatch", Lua_Script_Vector3ToWatch },
    { "__unm", Lua_Script_Vector3Negation },
    { NULL, NULL }
};

LuaScriptUtilities.h

#define LUA_VECTOR3_METATABLE "Vector3Type"

To support this functionality from the code, we need to let Lua know what type of userdata it is working with when we allocate memory. The LuaScriptUtilities header defines the metatable name of the vector type:

LuaScriptUtilities.cpp

void LuaScriptUtilities::BindVMFunctions(lua_State* const luaVM)
{
    ...

    luaL_newmetatable(luaVM, LUA_VECTOR3_METATABLE);
    luaL_register(luaVM, NULL, LuaVector3Metatable);

    ...
}

When binding C++ functions to the Lua virtual machine, an additional step is added to support vectors. The luaL_newmetatable function creates a new metatable, associating the table with the vector userdata type. Immediately after the metatable is created and pushed onto the Lua stack, a call to luaL_register adds the metamethods listed in LuaVector3Metatable to the metatable:

LuaScriptUtilities.cpp

int LuaScriptUtilities::PushVector3(
    lua_State* const luaVM, const Ogre::Vector3& vector)
{
    const size_t vectorSize = sizeof(Ogre::Vector3);

    Ogre::Vector3* const scriptType =
        static_cast<Ogre::Vector3*>(
            lua_newuserdata(luaVM, vectorSize));

    *scriptType = vector;

    luaL_getmetatable(luaVM, LUA_VECTOR3_METATABLE);
    lua_setmetatable(luaVM, -2);
    return 1;
}

Whenever a vector is created in Lua, memory is allocated from lua_newuserdata and the vector metatable is retrieved from Lua and assigned to the userdata. This allows Lua to know what type of userdata it is dealing with and what functions are supported on the userdata.

The demo framework

The demo framework follows a very simple update, initialization, and cleanup design shared throughout many of the classes within the sandbox.

The following is a class overview of the BaseApplication.h header:

The demo framework

The BaseApplication abstract class overview

The BaseApplication class has the main responsibility to configure the application window, process input commands, as well as configure and interface with Ogre3D. The Cleanup, Draw, Initialize, and Update functions are stub functions with no implementation within the BaseApplication class itself. Classes that inherit from BaseApplication can overload any of these functions in order to plug in their own logic:

  • In a derived class, the Initialize function is called once at the start of the application after Ogre has been initialized.
  • The Cleanup function is called when the application requests to be shut down right before Ogre itself gets cleaned up.
  • The Draw call is executed right before the graphics processing unit (GPU) renders the current application frame.
  • The Update function is called immediately after the GPU has queued up all the rendering calls in order to process the current frame. This allows the GPU to work simultaneously as the CPU begins to prepare the next draw frame.

Ogre

Ogre3D handles the general update loop and window management of the sandbox. BaseApplication implements the Ogre::FrameListener interface in order to implement both the Update and Draw calls of the sandbox:

The following is a class overview of the OgreFrameListener.h header:

Ogre

The Ogre3D FrameListener interface functions

The second interface, which is Ogre::WindowEventListener, enables the sandbox to receive specific callbacks to window events, such as the window movement, resizing, closing, closed, and window focus change:

The following is a class overview of the OgreWindowEventListener.h header:

Ogre

The Ogre3D WindowEventListener interface functions

Note

Both interfaces specify functions that are called from Ogre's main thread, so no race conditions exist to handle events.

Object-Oriented Input System

The Object-Oriented Input System (OIS) library is responsible for all the keyboard and mouse handling within the sandbox. The BaseApplication class implements both OIS interfaces in order to receive calls for key presses, mouse presses, and mouse movements. Once the BaseApplication class receives these events, it sends these events to the sandbox in turn.

The following is a class overview of the OISKeyboard.h header:

Object-Oriented Input System

The Ogre3D KeyListener interface functions

The following is a class overview of the OISMouse.h header:

Object-Oriented Input System

SandboxApplication

The main AI sandbox class, which is SandboxApplication, inherits from the BaseApplication class that implements the Cleanup, Draw, Initialize, and Update functions. The CreateSandbox function creates an instance of a sandbox and hooks up the Lua script specified by the filename parameter.

The following is a class overview of the SandboxApplication.h header:

SandboxApplication

The SandboxApplication implementation of the BaseApplication abstract class

Sandbox

The sandbox class represents the sandbox data as well as handling calls into the Lua sandbox script. The creation of a sandbox requires an Ogre SceneNode instance to situate the sandbox in the world. The sandbox's SceneNode instance acts as the parent to any additional geometry SceneNodes used for rendering; this also includes the AI agents within the sandbox.

The following is a class overview of the Sandbox.h header:

Sandbox

The sandbox class overview

Agent

The agent class encapsulates the agent data and performs function calls to the corresponding Lua script assigned to the agent from the LoadScript function. A SceneNode is required to construct an agent instance to maintain an orient and position the agent within the world.

The following is a class overview of the Agent.h header:

Agent

The agent class overview

Utility classes

AI sandbox heavily uses the utility pattern to separate logic and data. While both the sandbox and agent classes store their own relevant data, any manipulation of the data that interacts with the Lua virtual machine is handled through a utility class. This design separates the need for the agent and sandbox classes to know about the intricacies of interacting with the Lua stack. Instead, the Lua stack manipulation and data manipulation is left as the responsibility of a utility class.

For example, the AgentUtilities class handles all actions that are performed on an AI agent from Lua, while the SandboxUtilities class handles all actions that can be performed on the sandbox from Lua.

Any general purpose or miscellaneous interactions with the Lua virtual machine are handled by the LuaScriptUtilities class.

Lua binding

The LuaScriptBindings.h header file describes every C++ function that is exposed to the Lua virtual machine from the sandbox. You can always reference this file as the AI sandbox application programming interface (API). Each function contains a description, function parameters, return values, and examples of how the function should be called from Lua.

Summary

So far, we went over the basic structure of AI sandbox and learned how code interacts with the Lua VM. Key concepts such as debugging Lua scripts and understanding the project layout will be fundamental when we move forward and start building new AI examples for your own sandbox.

In the next chapter, we'll cover how to create an AI representation within the sandbox and apply movement forces to the agent. Once we have a basic AI up and running, we'll build upon the foundation and add squad movement, collision avoidance, and path following.

Left arrow icon Right arrow icon

Description

If you are a game developer or a general programmer who wishes to focus on programming systems and techniques to build your game AI without creating low-level interfaces in a game engine, then this book is for you. Knowledge of C++ will come in handy to debug the entirety of the AI sandbox and expand on the features present within the book, but it is not required.

What you will learn

  • Create an animation state machine to drive AI animations within Lua
  • Build and find paths on navigation meshes
  • Write and debug Lua scripts within a fullscale Lua IDE
  • Develop decision logic with behavior trees, state machines, and decision trees to build modular, reusable AI
  • Manage short and longterm knowledge representation with blackboard data structures
  • Add sensory perception to give AIs the ability to see and hear
  • Develop highlevel tactics with multiple AIs based on influence maps
Estimated delivery fee Deliver to Argentina

Standard delivery 10 - 13 business days

$12.95

Premium delivery 3 - 6 business days

$40.95
(Includes tracking information)

Product Details

Country selected
Publication date, Length, Edition, Language, ISBN-13
Publication date : Nov 28, 2014
Length: 352 pages
Edition : 1st
Language : English
ISBN-13 : 9781783281336
Category :
Languages :

What do you get with Print?

Product feature icon Instant access to your digital eBook copy whilst your Print order is Shipped
Product feature icon Paperback book shipped to your preferred address
Product feature icon Download this book in EPUB and PDF formats
Product feature icon Access this title in our online reader with advanced features
Product feature icon DRM FREE - Read whenever, wherever and however you want
Estimated delivery fee Deliver to Argentina

Standard delivery 10 - 13 business days

$12.95

Premium delivery 3 - 6 business days

$40.95
(Includes tracking information)

Product Details

Publication date : Nov 28, 2014
Length: 352 pages
Edition : 1st
Language : English
ISBN-13 : 9781783281336
Category :
Languages :

Packt Subscriptions

See our plans and pricing
Modal Close icon
$19.99 billed monthly
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Simple pricing, no contract
$199.99 billed annually
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts
$279.99 billed in 18 months
Feature tick icon Unlimited access to Packt's library of 7,000+ practical books and videos
Feature tick icon Constantly refreshed with 50+ new titles a month
Feature tick icon Exclusive Early access to books as they're written
Feature tick icon Solve problems while you work with advanced search and reference features
Feature tick icon Offline reading on the mobile app
Feature tick icon Choose a DRM-free eBook or Video every month to keep
Feature tick icon PLUS own as many other DRM-free eBooks or Videos as you like for just $5 each
Feature tick icon Exclusive print discounts

Frequently bought together


Stars icon
Total $ 136.97
L÷VE for Lua Game Programming
$32.99
Learning game AI programming with Lua
$48.99
Lua Game Development Cookbook
$54.99
Total $ 136.97 Stars icon

Table of Contents

10 Chapters
1. Getting Started with AI Sandbox Chevron down icon Chevron up icon
2. Creating and Moving Agents Chevron down icon Chevron up icon
3. Character Animations Chevron down icon Chevron up icon
4. Mind Body Control Chevron down icon Chevron up icon
5. Navigation Chevron down icon Chevron up icon
6. Decision Making Chevron down icon Chevron up icon
7. Knowledge Representation Chevron down icon Chevron up icon
8. Perception Chevron down icon Chevron up icon
9. Tactics Chevron down icon Chevron up icon
Index Chevron down icon Chevron up icon

Customer reviews

Rating distribution
Full star icon Full star icon Full star icon Full star icon Half star icon 4.3
(3 Ratings)
5 star 33.3%
4 star 66.7%
3 star 0%
2 star 0%
1 star 0%
Jimmy franco Dec 10, 2014
Full star icon Full star icon Full star icon Full star icon Full star icon 5
This book is amazing , I recomend that you buy it and buy as a gift for all ur friends it's so informational and I must say I enjoyed reading it .
Amazon Verified review Amazon
CPallini Dec 24, 2014
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
The book uses Lua scripting for implementing AI on a 3D game.Lua executes in a C++ framework (the sandbox) on the top of open source libraries like Ogre3D.Pros: - Lua scripting in a C++ framework is a very happy choice. - Focus is on practical AI. - The sandbox C++ code looks solid and is full accessible. - The companion code works out of the box.Cons: - In my opinion, the code/text ratio in the book is too high, more explanations would have been welcomed. To sum up, this is a good book, backed up by solid code (and good open source libraries) and you can actually script AI in a 3D game. Please note, in order to enjoy the book, you have to download the companion source code.
Amazon Verified review Amazon
Mr. Gibbins Jul 22, 2019
Full star icon Full star icon Full star icon Full star icon Empty star icon 4
This book is informative but hard to get you're head around unless you run lua on in c++ environment, if like me you don't have access to the c++ environment because the game engine doesn't allow you access then it's quite hard to figure out how to use the I formation provided with the system they use.
Amazon Verified review Amazon
Get free access to Packt library with over 7500+ books and video courses for 7 days!
Start Free Trial

FAQs

What is the delivery time and cost of print book? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela
What is custom duty/charge? Chevron down icon Chevron up icon

Customs duty are charges levied on goods when they cross international borders. It is a tax that is imposed on imported goods. These duties are charged by special authorities and bodies created by local governments and are meant to protect local industries, economies, and businesses.

Do I have to pay customs charges for the print book order? Chevron down icon Chevron up icon

The orders shipped to the countries that are listed under EU27 will not bear custom charges. They are paid by Packt as part of the order.

List of EU27 countries: www.gov.uk/eu-eea:

A custom duty or localized taxes may be applicable on the shipment and would be charged by the recipient country outside of the EU27 which should be paid by the customer and these duties are not included in the shipping charges been charged on the order.

How do I know my custom duty charges? Chevron down icon Chevron up icon

The amount of duty payable varies greatly depending on the imported goods, the country of origin and several other factors like the total invoice amount or dimensions like weight, and other such criteria applicable in your country.

For example:

  • If you live in Mexico, and the declared value of your ordered items is over $ 50, for you to receive a package, you will have to pay additional import tax of 19% which will be $ 9.50 to the courier service.
  • Whereas if you live in Turkey, and the declared value of your ordered items is over € 22, for you to receive a package, you will have to pay additional import tax of 18% which will be € 3.96 to the courier service.
How can I cancel my order? Chevron down icon Chevron up icon

Cancellation Policy for Published Printed Books:

You can cancel any order within 1 hour of placing the order. Simply contact customercare@packt.com with your order details or payment transaction id. If your order has already started the shipment process, we will do our best to stop it. However, if it is already on the way to you then when you receive it, you can contact us at customercare@packt.com using the returns and refund process.

Please understand that Packt Publishing cannot provide refunds or cancel any order except for the cases described in our Return Policy (i.e. Packt Publishing agrees to replace your printed book because it arrives damaged or material defect in book), Packt Publishing will not accept returns.

What is your returns and refunds policy? Chevron down icon Chevron up icon

Return Policy:

We want you to be happy with your purchase from Packtpub.com. We will not hassle you with returning print books to us. If the print book you receive from us is incorrect, damaged, doesn't work or is unacceptably late, please contact Customer Relations Team on customercare@packt.com with the order number and issue details as explained below:

  1. If you ordered (eBook, Video or Print Book) incorrectly or accidentally, please contact Customer Relations Team on customercare@packt.com within one hour of placing the order and we will replace/refund you the item cost.
  2. Sadly, if your eBook or Video file is faulty or a fault occurs during the eBook or Video being made available to you, i.e. during download then you should contact Customer Relations Team within 14 days of purchase on customercare@packt.com who will be able to resolve this issue for you.
  3. You will have a choice of replacement or refund of the problem items.(damaged, defective or incorrect)
  4. Once Customer Care Team confirms that you will be refunded, you should receive the refund within 10 to 12 working days.
  5. If you are only requesting a refund of one book from a multiple order, then we will refund you the appropriate single item.
  6. Where the items were shipped under a free shipping offer, there will be no shipping costs to refund.

On the off chance your printed book arrives damaged, with book material defect, contact our Customer Relation Team on customercare@packt.com within 14 days of receipt of the book with appropriate evidence of damage and we will work with you to secure a replacement copy, if necessary. Please note that each printed book you order from us is individually made by Packt's professional book-printing partner which is on a print-on-demand basis.

What tax is charged? Chevron down icon Chevron up icon

Currently, no tax is charged on the purchase of any print book (subject to change based on the laws and regulations). A localized VAT fee is charged only to our European and UK customers on eBooks, Video and subscriptions that they buy. GST is charged to Indian customers for eBooks and video purchases.

What payment methods can I use? Chevron down icon Chevron up icon

You can pay with the following card types:

  1. Visa Debit
  2. Visa Credit
  3. MasterCard
  4. PayPal
What is the delivery time and cost of print books? Chevron down icon Chevron up icon

Shipping Details

USA:

'

Economy: Delivery to most addresses in the US within 10-15 business days

Premium: Trackable Delivery to most addresses in the US within 3-8 business days

UK:

Economy: Delivery to most addresses in the U.K. within 7-9 business days.
Shipments are not trackable

Premium: Trackable delivery to most addresses in the U.K. within 3-4 business days!
Add one extra business day for deliveries to Northern Ireland and Scottish Highlands and islands

EU:

Premium: Trackable delivery to most EU destinations within 4-9 business days.

Australia:

Economy: Can deliver to P. O. Boxes and private residences.
Trackable service with delivery to addresses in Australia only.
Delivery time ranges from 7-9 business days for VIC and 8-10 business days for Interstate metro
Delivery time is up to 15 business days for remote areas of WA, NT & QLD.

Premium: Delivery to addresses in Australia only
Trackable delivery to most P. O. Boxes and private residences in Australia within 4-5 days based on the distance to a destination following dispatch.

India:

Premium: Delivery to most Indian addresses within 5-6 business days

Rest of the World:

Premium: Countries in the American continent: Trackable delivery to most countries within 4-7 business days

Asia:

Premium: Delivery to most Asian addresses within 5-9 business days

Disclaimer:
All orders received before 5 PM U.K time would start printing from the next business day. So the estimated delivery times start from the next day as well. Orders received after 5 PM U.K time (in our internal systems) on a business day or anytime on the weekend will begin printing the second to next business day. For example, an order placed at 11 AM today will begin printing tomorrow, whereas an order placed at 9 PM tonight will begin printing the day after tomorrow.


Unfortunately, due to several restrictions, we are unable to ship to the following countries:

  1. Afghanistan
  2. American Samoa
  3. Belarus
  4. Brunei Darussalam
  5. Central African Republic
  6. The Democratic Republic of Congo
  7. Eritrea
  8. Guinea-bissau
  9. Iran
  10. Lebanon
  11. Libiya Arab Jamahriya
  12. Somalia
  13. Sudan
  14. Russian Federation
  15. Syrian Arab Republic
  16. Ukraine
  17. Venezuela