Now that we've seen lua, and used lua as a debugging aid, let's try out actual game scripts! Download the file:
Get the project compiling and running. If you run the program, you get a little cube that you can control with the arrow keys (hold space to move the cube faster). As before, you can bring up the lua console with the ~, and type in commands. One helpful command is print, which displays text on a seconday overlay -- try it out!
We have provided some of the "glue" to make scripting work within Ogre:
These files handle the debug console -- both input and output
These files handle the lua / C++ interface, as with the previous lua lecture. Note that the LuaWrapper loads in the ScriptManager.lua file on startup, and has a think method, which calls the lua function ScriptManagerThink
This file lives in Content/Scripts/, and is reproduced below:
-- Our quick and dirty script system. We maintain a global array of scripts. -- The Ogre Frame Listener calls our ScriptManagerThink function, which in turn -- calls the Think methods on all active scripts. -- A more robust scripting system would have an eaiser way of indexing scripts, and -- activating / deactivating / removing scripts. This is just quick and dirty enough -- to work for now. -- Our table of running scripts GlobalScripts = { } -- Method to add a script. function addScript(script) table.insert(GlobalScripts, script) end function ScriptManagerThink(time) for i, v in ipairs(GlobalScripts) do if v:Active() then v:Think(time) end end end -- Handy print method. Use print instead of debugOutput, to avoid crashes -- for nil values and non-string values. function print(x) debugOutput(tostring(x)) end ---------------------------- -- Script "Class" -- pretty straighforward for now, scripts have a Think method -- and an Active method by default, and nothing else ----------------------------- Script = {} function Script.Active(this) return this.isActive end function Script.Think(this, time) end function Script.create() local s = {} s.isActive = true s.Active = Script.Active; s.Think = Script.Think return s end -- A function to create a seeker object. We create an object, and then create a script to manipulate it function createSeeker(name, x, y, z) if name == nil then print("createSeeker: name required!") return end x = x or 0 y = y or 0 z = z or 0 print("Creating Seeker: ID = " .. name .. ", Location: " .. tostring(x) .. ", " .. tostring(y) .. ", " .. tostring(z)) createObject("MyCube.mesh", name) setPosition(name, x, y, z) local seekerScript = Script.create() seekerScript.Think = function(this, time) local pX, pY, pZ = getPosition("player") local mX, mY, mZ = getPosition(name) local deltaX, deltaY, deltaZ = pX-mX, pY-mY, pZ - mZ setVelocity(name, deltaX , deltaY, deltaZ) end addScript(seekerScript) end -- Note that the above script uses closures to keep track of the variable name. Instead, we could have -- used something more akin to instance variables: -- function createSeeker(name, x, y, z) -- x = x or 0 -- y = y or 0 -- z = z or 0 -- print("Creating Seeker: ID = " .. name .. ", Location: " .. tostring(x) .. ", " .. tostring(y) .. ", " .. tostring(z)) -- createObject("MyCube.mesh", name) -- setPosition(name, x, y, z) -- seekerScript = Script.create() -- seekerScript.objectName = name -- seekerScript.Think = function(this, time) -- local pX, pY, pZ = getPosition("player") -- local mX, mY, mZ = getPosition(name) -- local deltaX, deltaY, deltaZ = pX-mX, pY-mY, pZ - mZ -- setVelocity(this.objectName, deltaX , deltaY, deltaZ) -- end -- addScript(seekerScript) -- end -- A function to create a shy object. Shy objects want to always be a given distance away -- from a target. If no target is given, the target defaults to "player". If no distance -- is given, the distance defaults to 30 function createShyObject(name, distance, target, x, y, z) -- Fill me in! end
Now to work! In the Content/Scripts folder, open up the ScriptManager.lua file, and write the shyObject function