A Game Engine: Integrating Lua

A Game Engine: Integrating Lua Eriksson Pontus Högskolan på Åland serienummer 13/2013 Informationsteknik Mariehamn 2013 ISSN 1458-1531 Examensar...
Author: Shanon Ramsey
4 downloads 3 Views 681KB Size
A Game Engine: Integrating Lua

Eriksson Pontus

Högskolan på Åland serienummer 13/2013

Informationsteknik

Mariehamn 2013 ISSN 1458-1531

Examensarbete Högskolan på Åland Utbildningsprogram: Författare: Arbetets namn: Handledare: Uppdragsgivare:

Informationsteknik Eriksson Pontus A Game Engine: Integrating Lua Eriksson-Granskog Agneta

Abstrakt:

Detta examensarbete undersöker hur man kan integrera skriptspråket Lua i en spelmotor. Spelmotorn är skriven i programmeringsspråket C++. Undersökningen utfördes genom att studera

läroböcker

och

artiklar



nätet

som

är

relevanta

till

integrationen.

Integrationsprocessen utfördes sedan enligt de metoder som tagits fram under undersökningen och laborationsrapporterna är anpassade att endast ta upp de ämnen som är direkt relevanta till integrationen.

Nivån på examensarbetet lämpar sig för personer som har goda programmeringskunskaper samt är bekanta med hur spelmotorer fungerar och är intresserade av hur man kan göra för att integrera ett skriptspråk i en spelmotor. Integrationen av skriptspråket kan även tillämpas i olika andra typer av applikationer.

Nyckelord (sökord):

Game Engine, Scripting Language, C++, Lua

Högskolans serienummer: ISSN:

Språk:

Sidantal:

2013:13

1458-1531

Engelska

34

Inlämningsdatum:

Presentationsdatum:

Datum för godkännande:

22.5.2013

17.5.2013

22.5.2013

Degree Thesis Högskolan på Åland / Åland University of Applied Sciences Study program: Author: Title: Academic Supervisor: Technical Supervisor:

Information Technology Eriksson Pontus A Game Engine: Integrating Lua Eriksson-Granskog Agneta

Abstract:

This degree thesis investigates how to integrate the scripting language Lua in a game engine. The game engine is written in the programming language C++. The investigation was done by studying textbooks for universities and articles on the internet that were relevant to the integration. The integration process was then carried out using the methods developed in the study and the lab reports are adapted to deal only with the issues that are directly relevant to the integration.

The level of the degree thesis is suitable for people with good programming skills that are also familiar with how game engines work and are interested in how to do to integrate a scripting language in a game engine. The integration of the scripting language can also be applied to various other types of applications.

Key words:

Game Engine, Scripting Language, C++, Lua

Serial number:

ISSN:

Language:

Number of pages:

2013:13

1458-1531

English

34

Handed in:

Date of presentation:

Approved on:

22.5.2013

17.5.2013

22.5.2013

TABLE OF CONTENTS 1.

2.

INTRODUCTION .................................................................................................... 3 1.1.

Subject ............................................................................................................... 3

1.2.

Intent .................................................................................................................. 3

1.3.

Methodology ...................................................................................................... 3

1.4.

Delimitation ....................................................................................................... 4

1.5.

Notation and Typographical Conventions ......................................................... 4

A GAME ENGINE................................................................................................... 5 2.1.

The Difference between a Game and its Engine ................................................ 5

2.2.

Architecture ....................................................................................................... 5

2.2.1.

Input Handling ............................................................................................ 5

2.2.2.

State Handling ............................................................................................ 6

2.2.3.

Audio Handling .......................................................................................... 6

2.2.4.

Video Handling .......................................................................................... 7

2.3.

3.

Modifiability and Flexibility.............................................................................. 8

2.3.1.

Making the Engine Configurable ............................................................... 8

2.3.2.

Replacing Existing Modules....................................................................... 9

2.3.3.

Integrating a Scripting Engine .................................................................... 9

2.3.4.

The Resource Manager ............................................................................. 10

INTEGRATING LUA ............................................................................................ 11 3.1.

Implementation ................................................................................................ 11

3.1.1.

The Role of Lua within the Engine .......................................................... 12

3.1.2.

Base for Communication .......................................................................... 14

3.1.3.

Creating a C++ Object from Lua .............................................................. 15

3.2.

Events with Lua ............................................................................................... 17

3.2.1.

The Event Manager in C++ ...................................................................... 20

3.2.2.

The Event Handler in Lua ........................................................................ 22

3.3.

Game Entities with Lua ................................................................................... 23

4.

IMPLEMENTATION PROCESS .......................................................................... 28 4.1.

Entities in C++ and Lua ................................................................................... 28

4.1.1.

Implementing the Base in C++ ................................................................. 28

4.1.2.

Implementing the Base in Lua .................................................................. 31

4.2.

The State Handler ............................................................................................ 33

4.3.

The Event Handler ........................................................................................... 34

5.

CONCLUSIONS .................................................................................................... 36

6.

REFERENCES ....................................................................................................... 37

1. INTRODUCTION 1.1. Subject For many years I have been interested in playing, developing and modifying games and in programming in general. Other than because it’s fun I also find game development to be a very interesting subject since it takes all common programming and development challenges but puts it at a more extreme level than most normal applications since a game engine has to process input, events, physics, sound and graphics at, what seems to the user, real-time. Because of this I thought that integrating a scripting language in an engine would be a perfect subject for a thesis while at the same time gathering knowledge and experience about game development for future projects.

1.2. Intent In the thesis I will bring up theory behind integrating and using the scripting language Lua (Celes, Figueiredo, & Ierusalimschy, 2006) in a game engine developed by using the programming language C++ (Stroustrup, 2000) as well as how the scripting language can be used to separate the game content from the game engine. I will make a basic implementation of a simple event system and the state handler in a game engine. The game engine will be created from scratch by using C++ and Lua and I will write lab reports on the implementation process and results.

1.3. Methodology •

Research and study about Lua and how it integrates with C++ using the Lua documentation as well as studying the use of different Lua libraries for integration with C++ on the web.



Study game engines and how they work from online articles and text books for universities.



Implement Lua in a game engine written in C++ using Microsoft Visual Studio 2010 and Notepad++ on Windows 7.



Write lab reports on the implementation process, issues encountered and the result.



Create diagrams and illustrations using Astah Community and Adobe Photoshop. 3

1.4. Delimitation In this thesis I will not go into detail about the actual C++ code with exception of snippets relevant to the content. Therefore there will not be any detailed information about common subsystems such as the memory manager, graphics engine, audio engine, input handling etc.

This thesis is written for people with a good understanding of programming and computer science and that are familiar with the C++ and Lua languages as well as having a basic understanding of how game engines work. Therefore it will not bring up any information regarding the syntax of each of the languages; neither will it go into detail about components in the game engine that is not directly related to the Lua implementation.

1.5. Notation and Typographical Conventions Figures of code snippets are syntax highlighted using Notepad++. The color scheme and the syntax are different depending on the language being used. Thus, the two languages are more clearly distinct and should therefore be easier to read.

Words or symbols written in regular paragraphs using the font Courier New are references to functions, variables, classes, objects, types, values or operators in either Lua or C++ (e.g. the function atan2 takes two arguments of type float or double).

4

2. A GAME ENGINE A game engine is an application framework for developing one or more games. The framework provides the core functionality that games use such as memory management and graphical presentation. (Gregory, 2009) (Ward, 2008)

2.1. The Difference between a Game and its Engine As mentioned in the section above, an engine only provides its framework and should therefore not contain any gameplay elements such as items, characters, vehicles. However, there are engines that are designed to only support one single game and these engines are therefore very much locked to that specific game. Reusing such an engine is very often not an option, as the gameplay content and game logic is sewn into the engine, unless you are developing a sequel based on the original game. In the worst cases it may even be difficult to add new content to the already existing game. (Gregory, 2009) (Ward, 2008)

2.2. Architecture The base structure of a game engine can be summarized into the famous main-loop that repeatedly catches input, updates state, plays audio and renders graphic until the game or application is closed. In fig. 1 we can see an unfinished, simplified main-loop that has been implemented using procedural style to provide clearer code for demonstration. (Wikipedia: Event loop, 2012) (Gregory, 2009) (Gold, 2004)

Figure 1: A Main Loop

2.2.1. Input Handling Input handling is the part of the loop that captures input from the user or any other external or internal source, depending on the design, and often registers local events based on the input that will be parsed and handled immediately or by the state engine. 5

Depending on the type of games that are being developed the frequency and accuracy at which the input is captured and handled may be high or low. For instance, a first person shooter (FPS) game that requires the user to react quickly and accurately may require that the input is handled more accurately and frequently than in a role-playing game (RPG) that quite often have a lot less user input. (Wikipedia: Game engine, 2012) (Wikipedia: Event loop, 2012) (Gregory, 2009)

2.2.2. State Handling The state handling is, depending on the design, the next part. As the name implies, state handling manages the state of the game which includes the game world and all of its entities, physics as well as the position and collision of objects. State handling is always, if we ignore the exceptions, locked at a specific frequency such as, for instance, 32 times per second depending on what the game requires. From my personal experience a simple 2D game may only be required to update once every 1/16th of a second.

The state handler often starts by parsing local events and correcting object positions while applying physical effects such as gravity. Then the world objects and entities as well as their animations are updated one step, an iteration, which itself may generate additional events that are either queued for the next iteration or handled immediately. (Wikipedia: Game engine, 2012) (Wikipedia: Event loop, 2012) (Gregory, 2009)

2.2.3. Audio Handling Audio handling is the part that handles the sound buffer and manages which sounds that are playing and at what channels, amplitude and other properties they have. Audio handling is usually run 60 times a second to ensure that the sound buffer is constantly provided with data to avoid glitches in the sound. It is the step run before rendering the graphics since the graphic rendering is the most calculation-heavy part in a modern game engine and could therefore spark delays, commonly referred to as lag. If the graphics were rendered before handling the audio the user may experience glitches in the sound that are a lot more noticeable than minor visual glitches in the graphics. (Wikipedia: Game engine, 2012) (Wikipedia: Event loop, 2012) (Gregory, 2009)

6

2.2.4. Video Handling Video handling is often the heaviest part of an engine performance wise. It has to perform a lot of various calculations almost instantly and in a 3D game it’s preferred that it updates at least once every 1/60th of a second and it is therefore important that the state handler prepares the graphical states, such as which animation, which animation frame, and which objects to render and where, so that the video handler can focus on its only task: to render the scene and the graphical user interface. Therefore a game engine often has two types of base objects: logical objects and visual objects. (Wikipedia: Game engine, 2012) (Wikipedia: Event loop, 2012) (Gregory, 2009) (Gold, 2004)

In fig. 2 we can see an interpretation of a logical class named Entity with a relation to a visual class named Actor. The diagram shows us that every logical object has one or more logical points and in this case we can presume that every logical object has a point that is the position of the object in the logical game world.

Figure 2: A simplified interpretation of separation between logical and visual components

Let’s presume that all visual objects are always linked to a logical object and will also translate the logical position of the object to a point in the visual space. By having this separation we may implement the engine so that the state handler updates the state, e.g. the position, of all logical objects which in some cases will push data to its visual object such as queuing animations. The video handling can therefore ignore all logical objects and only care about the visual ones which already contain a lot of the information that the video handler else may have had to calculate. (Gregory, 2009) (Gold, 2004)

7

2.3. Modifiability and Flexibility To design and develop a game engine that can be used for various games and maybe even games of different types we have to take a few things into deep consideration. (Wikipedia: Game engine, 2012) (Ward, 2008) (Gregory, 2009) (Gold, 2004)

1. The engine has to be configurable so that the developers easily can disable, enable and add features as well as changing various parameters that will affect how the game will be run. 2. The components that make up the game such as audio handling, video handling, etc. should be designed to be replaceable so that the developers, for instance, can make a 2D game a 3D game by replacing the video handler. 3. The engine should have the actual gameplay content separated from the rest of the engine which is typically done by embedding a scripting language such as Lua within the state handler. 4. The engine needs a resource manager that manages various types of resources such as textures, 3D models, images, sound files, etc.

2.3.1. Making the Engine Configurable There are two different types of configurations that should be considered: configurations on how the code will be compiled and configurations that decide how the game engine will run.

The compilation can be made configurable by simply creating a header file which includes various parameters that can be defined by the developers. These parameters are included into our source code which will be compiled differently depending on the existence and value of the parameters. Such a parameter could be a debug flag which compiles the game in debug mode if the flag is set or maybe there could be a flag that tells the engine to ignore mouse input in case we want to make a game that only use the keyboard or vice versa.

Configurations that affect how the game and engine will run can be made the same way as the compilation configurations but it would be even better if it was done by creating configuration files that the engine will parse at initialization, maybe even at runtime, and update the settings according to the configuration without even having to recompile 8

the code. Such settings are commonly the ones that the user can change from within the game by using a menu such as the screen resolution of the game and the mouse sensitivity. (Ward, 2008) (Gregory, 2009) (Gold, 2004)

2.3.2. Replacing Existing Modules To be able to replace a component such as the video handler easily we will want to design the video handler, or any other handler but in this example we’ll stick to replacing the video handler, as loose coupling (Wikipedia: Loose coupling, 2012) and as high cohesion (Wikipedia: High cohesion, 2012) as possible so we will be maintaining a nice balance between the two. (Shog9, 2008) (Cunningham & Cunningham, Inc., 2011) (Wikipedia: Cohesion, 2012) (Wikipedia: Coupling, 2012)

To put it in other words: we want modules to communicate through strict interfaces so that the calling module does not care whether or not the receiving module has implemented the called method or not and so that if it has implemented the method the calling module does not care what happens within that method as it should be shielded from outer scopes. (Shog9, 2008) (Cunningham & Cunningham, Inc., 2011)

“a loosely coupled system is one in which each of its components has, or makes use of, little or no knowledge of the definitions of other separate components.” – (Wikipedia: Loose coupling, 2012)

“..cohesion refers to the degree to which the elements of a module Figure 3: Pieces of a jigsaw puzzle

belong together. Thus, it is a measure of how strongly-related each piece of the functionality expressed by the source code of a software module is.” – (Wikipedia: Cohesion, 2012)

2.3.3. Integrating a Scripting Engine To separate gameplay and its content from the engine one common practice is to integrate a scripting language that takes care of the logical aspects of the game such as game rules, definition of game objects, artificial intelligence (AI) and more. While a scripting engine causes extra overhead it has a lot of advantages such as (Gregory, 2009):

9



Developers or modders can easily alter, remove and add additional logic and content to the game without having to recompile the whole engine.



The developers can implement a console in the engine for managing scripts and running snippets of scripts manually while the engine is running. The console can also be used to give instant feedback and information as seen in fig. 4.



If every gameplay element is implemented with scripting one can replace the whole engine with another as long as the scripting language is integrated the same way as in the previous engine.



The modding community will rejoice.

Figure 4: A snapshot of the console in Valve's game Half-Life

2.3.4. The Resource Manager The resource manager is a subsystem that preloads different types of resources such as textures, 3D models, audio files, etc. from external data files or libraries. The resource manager is therefore a lot like a database that contains every resource that is used by the game. Resource managers can be implemented as simple look-up dictionary or as a smart library that allocates and caches commonly used resources to fetch them faster at a request. If a resource doesn’t exist it is common that the resource manager returns a placeholder for that resource in addition to logging the missing resource. For instance, if a model is requested by the game and the model doesn’t exist the resource manager can return a ModelNotFound-model that can be a simple 3D primitive with a texture that sticks out from the rest of the models so that the error can easily be detected visually by developers and testers while it doesn’t prevent the game from running. (Gregory, 2009)

10

3. INTEGRATING LUA To integrate Lua within a C/C++ application it is common practice to use an existing library or implement a custom library which simplifies the development process by providing wrappers or additional functions and features while at the same time maintaining readability and simplicity. If we want to use a library we must first take into consideration the type of the application we are developing. Since we are developing a game engine the library we would want to use should be causing as little overhead as possible as we don’t want it to become a bottleneck in our game.

Here are four C++/Lua libraries that are available that I believe I may possibly be using in any of my future projects: •

oolua (http://code.google.com/p/oolua/)



CppLua (http://cpplua.sf.net/)



Luna (http://lua-users.org/files/wiki_insecure/users/lpalozzi/luna.tar.gz)



Lua++ (http://www.tecgraf.puc-rio.br/~celes/lua++/)

I decided not to use any of these libraries but instead to use the regular Lua C API so that I can improve my understanding and experience of the Lua-stack in C++ at firsthand without using wrappers or non-standard functions. In addition, the C++ code I provide will be using the regular Lua C API, unless it is specifically mentioned that it is using a specific library, which will make it possible to simply copy-paste the code and it should work with minor tweaks.

3.1. Implementation To bind C++ and Lua together in the game engine using the Lua C API we must create a virtual Lua-stack so that we can push data from C++ to Lua and vice-versa. It is also recommended to close the virtual Lua-stack when the application is finished or when we don’t need to use the stack anymore to free the dynamic memory that the stack was using as well as invoking the garbage collection methods. In fig. 5 we can see a code snippet of an application using a simple Lua implementation that does the following: 1. Opens a virtual Lua-stack. 2. Invokes the Init function in Lua from C++ when the application starts.

11

3. Application is running, various calls from and to Lua are probably happening here. 4. Invokes the Tidy function in Lua from C++ when the application stops. 5. Closes the virtual Lua-stack. In fig. 5, note that the Init and Tidy functions in Lua are defined by the developers and could be named whatever the developers prefer. Init and Tidy are just an example.

Figure 5: Simple example of an implementation of Lua in a C application

3.1.1. The Role of Lua within the Engine In the game engine; Lua will be used to provide the game logic and to handle two types of events: •

High-level events are created and handled in Lua and therefore only exists in Lua without the engine knowing.



Low-level events are detected within the engine and may be handled by the engine or transformed into a high-level event so it can be handled in Lua.

When the main-loop iterates the state handler in the engine, the engine will call the UpdateState function in Lua with the time difference since the last iteration, which will hereafter only be referred to as deltaTime, as argument. What happens in the UpdateState function is designed to be not much different than if it would have been implemented in an engine as C++ with the exception that it is in Lua.

12

In addition to handling events, Lua will also have to manage all various kinds of entities in the game. An entity is an instance of the Entity-class in C++ and will be represented in Lua as a CEntity-object which will have a reference to its counterpart in C++. Lua will also be responsible for providing a lot of the information about what visual assets that will be used and how (e.g. animation, location) since it will be managing actors which is an instance of the Actor-class in C++ and CActor-object in Lua. An Actor is responsible for the visual presentation of its owning Entity. In the engine I will implement the Entity-Actor relation as seen in fig. 6 which was designed based on the following observations: •

An Actor contains the information required to render the visual presentation of its owning Entity.



The Entity itself does not care how it is being rendered and only contains information related to the logical state of the game in the engine.



An Actor needs to know its owner so that it can access information required to render successfully. An example of such information is the position in the physical game world.



A CEntity does manipulate its CActor and therefore needs to know its CActor. For example, a CEntity may tell the CActor to play a specific animation.



An Entity does not need to manipulate its Actor, thus it does not need to know which Actor it owns.

Figure 6: Simplified illustration of the Entity-Actor relation in C++ and Lua and the references between.

13

3.1.2. Base for Communication A game engine with Lua or another scripting language implemented will have three different types of objects or variables, which will hereafter only be referred to as objects: •

Objects which exist only within C++



Objects which exist only within Lua or another scripting language of choice.



Shared objects which exist both in C++ and Lua or another scripting language of choice.

With the aforementioned types we will have to plan and make a decision regarding on how we want the memory management to work. The first two types are quite simple compared to the third; C++ objects will be managed in C++, Lua objects will be managed in Lua but shared objects will have memory allocated by both C++ and Lua. Thus, we must carefully design how the shared objects are supposed to work.

Like the other object types, the shared objects also have methods and properties with the difference being that the property or method may exist in C++, in Lua or in both. If we take an imaginary game entity, a monster in a role-playing game (RPG), it may have the following methods as seen in figures 7 and 8:

Figure 7: Method definition in C++ for the Entity-class.

Figure 8: Method definition in Lua for a CMonster-object.

14

The Entity::setPoint and Entity::getPoint methods are self-explanatory: they set and get the position of the Entity. The CMonster:isAngry-method returns true if the monster is angry and the CMonster:isFlatulent-method returns true if the monster is ready to use the CMonster:breakWind-method.

There is no Monster-class defined in C++ in our engine. The monster will be using the Entity-class as a base which will contain all general methods and properties that the engine requires to manage entities. It is in Lua that the monster-specific methods and properties are defined since they are not directly related to the engine itself. The problem that arises is that we have a monster entity that consists of two linked objects, one in C++ used by the engine and one in Lua defining the dynamic characteristics of the monster which is used by the game logic.

The role of the C++ object is, for instance, for the engine to separate local and remote (network) entities and update their local state accordingly as well as handling collision detection and similar features.

The role of the Lua object, as mentioned above, is to define the properties, methods and behavior of the actual game object and all of the different ways it can interact with the player or the environment (e.g. CMonster:attack).

These two objects not only have to coexist but we must design how the memory management will work. Since a game performs a lot of memory allocations, a custom memory manager may be required so that the memory heap doesn’t get fragmented (DeLoura, 2001). The path of least resistance, however, would be to simply ignore making a custom memory manager and let the Lua garbage collector do what it does which will result in a lot of allocation and reallocation during every game frame.

3.1.3. Creating a C++ Object from Lua One way to create a shared object from Lua can be easily done by creating a function in C++ which creates an object and returns a pointer to the object pointer. A code example can be seen in figures 9, 10 and 11. The reason why we want to return the pointer of a pointer is because we don’t want the garbage collector in Lua to collect our real pointer and destroy it. 15

Figure 9: Definition of a function in C++ that creates a shared object and returns a pointer to the pointer of the object.

Figure 10: Binding the function to Lua as CreateSharedObject.

Figure 11: Definition of the SharedObject in Lua

The CData property in the instance of the SharedObject contains the pointer that Lua will be using when accessing the C++ instance. To keep it simple, one way that we can add an additional method is by simply defining another C++ function that takes the CData as a Lua-argument and binds it to Lua. See figures 12, 13 and 14.

Figure 12: Definition of another function in C++ that manipulates a SharedObject.

16

Figure 13: Calling the L_DoSomethingInCppWithObject from a Lua method.

Figur 14: Create a SharedObject in Lua and then call the doSomething method.

While it may be uncomfortable to define a function for each method we want to be callable from Lua, it is a strict and effective way of providing availability to specifically chosen methods that we want to be available from Lua. If we think about all the methods that we want to be available from Lua we may come to the conclusion that it really doesn’t have to be that many since all of the game related content not required by the engine will be defined and visible in Lua only.

3.2. Events with Lua In a game engine several types of events will occur, such as: •

Input Events o From the user (e.g. keyboard, mouse) o From a stream (e.g. file system, network)



Gameplay related events o Collisions and physics o Game logic (e.g. a unit is issued an order)

Since the input is detected in C++ we will create these events in the engine itself and later pass them onto Lua, unless we for some reason want to drop the events. A short illustration of the life of an Event in C++ can be seen in fig. 15.

Figure 15: Illustration of the life of an Event in the Engine

17

To separate the game content from the actual engine we will want to move as much gameplay related logic from the engine as possible so at the first glance at the list above we may want to detect input events in C++ and all other events in Lua.

If we take a look at the collision events we may come to the conclusion that a lot of the actual collision detection is done by Point Inclusion Tests, Ray Intersection Tests, Moving Tests and more which is used for almost every game in almost every game engine with the only difference being on how it has been implemented (Sánchez-Crespo Dalmau, 2003). If we look more into the algorithms used to detect collisions we will realize that some of them require a lot of calculations and thus the collision detection may become a bottleneck unless we’re smart and only check entities that are likely to collide, such as dynamic entities in motion.

I will therefore design the Engine so that it will only check active, dynamic entities that are doing something that may cause a collision with another entity or the world. To detect a collision the engine will check various levels of collision which will look something like the following simple pseudocode seen in fig. 16:

Figure 16: Simple pseudocode of checking collision between two entities.

The idea is that we first check the collision against a collision type that is easy to calculate such as a Bounding Box or a Bounding Sphere. If there is a collision we will check the collision again using a more precise and more calculation heavy collision type until there is no more collision types or a collision type does not collide. Instead of iterating through each collision type of the second Entity every time we iterate through each collision type of the first Entity we may make it so that every Entity

18

has a set number of collision levels and therefore make it like the following more effective pseudocode seen in fig. 17 instead:

Figure 17: Altered pseudocode where the entities have the same number of collision levels.

A simplified diagram of the C++ Collision-classes and their relations can be seen in fig. 18. Even if we handle collision detection in C++ we will still probably want to push events down to Lua for additional handling so that the game logic can respond to collisions. We could even make additional custom collision detectors in Lua if needed and with this in mind it would be good to implement some kind of run-time or compile parameter that decides whether or not C++ should care about collisions.

Figure 18: Simplified diagram of the C++ Collision-classes and their relations.

19

3.2.1. The Event Manager in C++ To manage low-level events in C++ we will want to implement an event manager in the engine that queues instances of the Event-class and either handles the queued events by using callback functions or by passing them to the CEventHandler-object in Lua as a CEvent-object for the game logic to use as seen in fig. 15.

Different types of games may however require different types of input that may change depending on what state the game is in. So instead of detecting and passing all events down to Lua we could create some kind of filter for what event types that the event manager will pass down to Lua with the default being all events. We could implement it so it is using a filter that can be set by calling a function in the engine from Lua.

One example of where it could be useful is in a racing game where we disable the mouse events during a race but enable the mouse events again during a menu. By doing this the Lua CEventHandler does not have to process unnecessary mouse events should they be detected by the engine.

In fig. 19 we can see a simplified class diagram of the event manager.

Figur 19: Simplified class diagram of the event manager

20

An example on how we could fire an event from C++ to Lua by using the Luna(r) library can be seen in fig. 20 (Deadbeef Games, 2010). Pay attention though to the fact that the actors in fig. 20 are not in any way related to the Actor-class.

Figure 20: Fire an event from C++ to Lua using Luna(r).

The use of templates here may raise questions such as “why not use inheritance instead?” but it is required because of how the Luna library works. A more clean and developer friendly process of firing an event can be seen in fig. 21.

Figure 21: A cleaner way to fire an event from C++ to Lua using a different implementation.

Instead of using templates as in fig. 20 we use the regular Lua C API and use inheritance. It is designed so that all data required to an event will be treated as private members and the constructor is declared to require the data as arguments to ensure that the developers do not fire incomplete events. The Game Object ID shown in fig. 20 will be taken care of in the constructor of the event in fig. 21.

One downside of an approach like this is that if we do not implement setters for the required data we have to create a new event with the desired data to replace the old one that we want changed. It should be possible to set optional data after the creation either by implementing setters to private members or by accessing public members. Such an example is a key event where the required data is the identifier for the key and the optional data is what state it has as seen in fig. 22.

21

Figure 22: Setting the optional State-property of a key event using a setter.

While it may be true that the key state is also required in its own way it is a value that easily could be initialized to a default value such as KEYSTATE_UP. We could even make the state member a public member of boolean type and discard the setter method for faster access. It is however important that the events with optional data that may contain invalid values have setters that validate the value.

Another example of an optional property would be a collision event between two entities with the required data being the two entities involved in the collision and the optional data being the force of the collision and information on how to handle the collision.

3.2.2. The Event Handler in Lua While the event handler in Lua will be handling a lot of events that will be passed down from the engine it will also handle all of the events created from the game logic itself. Therefore we must be smart about how we will handle our events so that they do not occur in the wrong order or at the wrong time since the engine will be processing the high-level events before the state is updated as the events themselves may affect the state. We may want to attach a time stamp on some of the events passed down from C++ to Lua so that the event handler can handle the events as if they occurred when they actually did instead of when the event handler received them.

While it may not be much of a difference if the game is running nicely without any problems it may be very helpful if the client is having bad performance spikes and the user is trying to issue some commands such as pausing the game and then after a time the game continues running. If we pretend that the lag spike lasted for 2 seconsd and the game was seemingly frozen during that time, the commands without a time stamp would be treated up to 2 seconds later than when they actually occurred. But if the input events have a time stamp and we pretend that the user pressed the key that pauses the game after 1 second, the game would behave as if it had been running for a second and then be paused which is more likely to be expected by the user. 22

In fig. 23 we can see a simplified class diagram on how some of the events are going to be managed in Lua. The CEventHandler queues CEvent objects and passes them along to registered listeners that are interested in the event.

Figure 23: Simplified class diagram of how events are going to be managed in Lua.

3.3. Game Entities with Lua With only our Entity-class in C++ to represent the actual entities in the game it is very likely that we still want different types of entities such as: •

Static, non-interactive world objects (e.g. rocks).



Interactive, world objects that other entities can interact with (e.g. doors, levers).



Destructible, a combination of the former two with the only interaction being the ability to be damaged and destroyed if a certain force of certain type is applied.



Unit, living objects controlled by players or by AI.



Missile or Projectile, uncontrollable objects that have motion and possibly limited durability.

If we analyze each type of entity further we may come to the conclusion that the static and destructible entities only have a position, is facing an angle, have an actor to visually represent the object, a pathing map and collision. Because the role of the static object itself is only to look pretty and sometimes hinder the movement of other entities which have little to do with the actual game logic we could just add optional collisionproperties to the Entity-class and handle it only in the actual engine in C++ and not in 23

Lua. Since the destructible entities are identical to the static entities with the exception of the earlier mentioned properties which are related to the actual game logic we could make it so that the actual difference between the static entities and destructible entities are purely defined in Lua.

The interactive objects are interactive in a way that their state can be changed by other entities in the world. An example of interactive objects could be something as simple as a button or a door. In the case of the door we may also want it to be breakable if enough force is applied which in one way makes it a destructible entity, thus we could make the destructible object definition in Lua a subclass of the interactive object definition.

The units and missiles are also related to the game logic and should therefore be implemented in Lua with reference to an Entity. A simplified illustration of the one way to implement the different entities and their relations can be seen in fig. 24.

Figure 24: Illustration of one way the different entities and their relations can be implemented.

If we go deeper into the destructible entities we may also come to the conclusion that a destructible may have different states of being destroyed. A door in a first-person shooter (FPS) game could for instance have 7 different states: 1. The default state, it is a sturdy door with collision. 2. After the door has taken a specific amount of damage it may get an updated visual to give feedback to the players.

24

3. After additional damage it may update the visual further to show that it is more damaged than before. 4. After additional damage it may get a tiny hole in it by updating the visual. If we want it to be possible to shoot through the hole we may also want to update the collision data. 5. After additional damage the hole gets larger. Update visual and alter the collision data further. 6. After even more damage the hole is very large. Update visual again and alter the collision data further. 7. After some more damage the door is destroyed. Update the visual by playing a destroyed-animation. Disable the collision and also disable all interaction and possibly even queue for deletion after a delay.

With this state behavior in mind we will have to decide on how we will do the implementation. Should it be one object with a list of different state data or maybe it should be implemented using the state machine pattern or something similar? Since the logic itself has nothing to do with the actual engine we could keep it simple and make state objects in Lua with different preset properties when the different states are known beforehand, and have a variable that points to the current state. This way the properties related to the state can easily be changed just by pointing to another state. To avoid confusion, the destructible state-object in Lua will hereafter be referred to as the CPhysicalState object since it affects some of the physical properties of the entity. Depending on the design and the data it contains it may, and probably should, be called something else entirely.

This state behavior may at first seem to make the collision detection and handling a lot more complex, but if we make it possible for CEntity-objects to update their collision data in C++ at runtime it really doesn’t become that much more complex since the CPhysicalState-objects of the CEntity would contain the parameters required that would be passed to the engine to create a new collision type object. Thus we need to implement a simple factory (Broderick, 2009) for the collision type object in the engine.

25

If we design the CPhysicalState-object so that its proeprties is a table with callbacks we could do something as simple as in fig. 25 to apply all of the changes the new state brings.

Figure 25: Apply the new physical state to a CEntity.

A shortened and simplified CPhysicalState-object definition can be seen in fig. 26. Fig. 27 contains a simple example of how the physical states of the CShrinkableSphere-object can be defined.

Figure 26: Simplified CPhysicalState-object definition.

26

Figure 27: Simple definition of the CShrinkableSphere object definiton.

We should also keep in mind that since the engine will be responsible for some collision detection which could be quite heavy on the performance we could always add additional subclasses to the Entity-class or keep separate lists of entity objects which will be treated differently by the engine. The static world objects that do not change position could for instance never have to be checked for collision with the world but may have to be checked with dynamic entities such as a playable character or a projectile.

27

4. IMPLEMENTATION PROCESS In this chapter I will write about the implementation of the subsystems and functionality mentioned in chapter 3, more precisely and in the following order: •

Entities in C++ and Lua



The State Handler



The Event Handler

4.1. Entities in C++ and Lua 4.1.1. Implementing the Base in C++ As mentioned in chapter 3.1.2 there are shared objects. Instances of the Entity-class are such objects so I started by declaring the Entity-class as simple as possible to start with. The code of the declaration can be seen in fig. 28.

Figure 28: Basic declaration of the Entity-class.

This code is self-explanatory. We can create, destroy and set the position of an Entity as well as reading its current position. To give the entity a graphical presentation I also declared the Actor-class as simple as possible. The Actor-class declaration can be seen in fig. 29.

28

Figure 29: Basic declaration of the Actor-class.

I decided to make the m_owner member a reference to an Entity instead of a pointer and made the reference a required parameter to the constructor because I do not want it to be possible for actors to exist without an owning entity. So to create an entity in the game engine the following need to happen in the following order: 1. An instance of the Entity-class must be created. 2. An instance of the Actor-class must be created with a reference to the Entity-object. It is also vital that we delete the objects in the reverse order, meaning that the Actorobject must be freed before we can free the owning entities.

The function that we invoke from Lua to create an Entity in the engine is based on fig. 9 in chapter 3.1.3 but with some modifications to make it a template function so we can use it for other objects as well. To easily get the name of the type used by the template function I used the technique mentioned by Logan Capaldo (Capaldo, 2009). The function definition can be seen in fig. 30.

29

Figure 30: Templated function definition for creating shared objects.

Keep in mind that for us to be able to use the code in fig. 30 we must define the REGISTER_PARSE_TYPE for the type we wish to use (Capaldo, 2009) and when we bind the function to Lua we must bind it with the specific class as seen in fig. 31.

Figure 31: Bind the templated functions to Lua.

At this stage in the implementation two problems arose: the first problem was that the Actor object needs a reference to the Entity-object and with the current design it was not possible as the L_SharedObjectCreate-function did not make it possible to pass optional arguments to the object constructor. This was solved by creating a L_ActorCreate-function which takes an argument when called from Lua and used this argument to create a pointer to the Entity-object and then use the pointer to create the Actor-object and then finally returns the pointer of the pointer of the created Actor to Lua. The C++ code for the solution can be seen in fig. 32.

30

Figure 32: Definition of the function that creates an Actor-object and returns a pointer to its pointer to Lua.

The second problem was that we could not manipulate how our shared objects are handled in the memory by our engine. The L_SharedObjectCreate-function created objects but did not assign them to any type of memory manager or object manager. This problem was solved by overloading the new-operator to use a custom memory manager. A detailed guide of how to get started to write a custom memory manager can be found in (Sen & Kumar Kardam, 2008).

4.1.2. Implementing the Base in Lua With the base implemented in C++ I continued the implementation of entities and actors by writing the Lua object definitions based on fig. 11 in chapter 3.1.3. The definition of the CActor-object can be seen in fig. 33 and the definition of the CEntity-object can be seen in fig. 34.

Figure 33: Actor-definition.

31

Figure 34: Entity-definition.

Now that we have constructed the base for the entities and actors it is a great time to introduce a couple of methods and properties to both the CActor and CEntity object definitions. There are two types of properties that the objects can have: imaginary properties and regular properties. The difference is that the imaginary properties do not really exist in Lua but will be accessed in the same way that a regular Lua property is accessed. An implementation of the imaginary properties can be seen in fig. 35 which was inspired by John Calsbeek’s solution found at (Calsbeek, 2011). Although the same functionality could be achieved by defining getters and setters, this approach will result in a much more readable code in the long run.

To the CActor-definition we can start by adding something simple such as an imaginary scale property so that we can manipulate the scale of the models in the scene from Lua. To achieve this I implemented the imaginary property functionality for the CActor-objects and created the Actor::SetScale and Actor::GetScale static methods in C++ and bound them to Lua using the same technique as seen in fig. 10 in chapter 3.1.3.

To the CEntity-definition we can start by adding the getActor, getPoint, setPoint, getFacing and setFacing methods which was done by using the same technique as seen in figures 12, 13 and 14 in chapter 3.1.3.

32

Figure 35: Implementation of the imaginary properties for SomeObject.

4.2. The State Handler One of the pros of implementing a scripting language within a game engine can be seen by actually implementing the state handler. The StateHandler::update function takes the delta time (dt) since last run as an argument and passes it down to Lua by calling the UpdateClient function in Lua as seen in fig. 36. It was inspired by an example code in (Gregory, 2009). The UpdateServer is only required if we want our engine to provide support for multiplayer games over the network.

33

Figure 36: Basic implementation of the StateHandler::update-method.

In addition to the code above in fig. 36 I will also update the entities and do some collision detection before I update the state in Lua. This could be done in the UpdateServer-function depending on the game and the design but since I will not implement network support I will not be using the UpdateServer-function at all and it can therefore be discarded from the code.

4.3. The Event Handler I implemented the events in Lua based on fig. 23 in chapter 3.2.2 with some adjustments and finally ended up with a slightly different design. A simplified version of the altered design can be seen in fig. 37.

34

Figure 37: Basic class diagram of the event handling in Lua.

This new design allows different subscribers to be subscribed to different types of listeners at the same time. An example would be if we have a radio object and an empty box object. Both the radio and the box can subscribe to a listener that listens for explosion events since they both can be affected by an explosion. The radio is also subscribed to a listener that listens for communication events so that depending on the event it may start playing a sound. An illustration of the example can be seen in fig. 38.

Figure 38: Two entities subscribed to event listeners.

In addition to these global events there are also events between objects. One such even can be when a CUnit takes damage from another CUnit in an action game. These reactional events are implemented as normal methods that are instantly called when the event occurs. A simplified code snippet of such a method can be seen in fig. 39.

Figure 39: Basic implementation of a reactional event method.

35

5. CONCLUSIONS This study and its practical applications were focused on the integration of a scripting language in a game engine. In the thesis I have presented the theory behind the integration and use of the scripting language Lua in a C++ application as well as how it can be used to separate the game content from the game engine. I also made a basic implementation of an event system and state handler by using Lua in a game engine that was developed from scratch by using C++. I have also written lab reports on the implementation process and results.

The methodology I have used is research and study of the integration of Lua within a C++ application by looking at the documentation of the Lua C API. I also researched various Lua libraries by looking at their home page, documentation and some code examples online. Research about how game engines work was primarily based on the text book Game Engine Architecture (Gregory, 2009) but also from online articles. The game engine was developed in Microsoft Visual Studio 2010 by using C++ as the programming language and the scripting language integrated in the engine was Lua. All Lua scripts were written in Notepad++. The lab reports were written in OpenOffice Writer during the implementation process. The diagrams and illustrations provided in the thesis were made by using Astah Community or Adobe Photoshop.

In this thesis I have presented the parts of code that I found relevant to the content and either helpful or interesting for the reader. Implementations of common subsystems such as the memory management, handling of graphics, audio and input are not presented. The thesis is written for people with a good understanding of programming and computer science and that are familiar with the C++ and Lua languages as well as having a basic understanding of how game engines work. It therefore did not bring up any information regarding the syntax of each of the languages, neither does it go into detail about the components in the game engine that are not directly related to the Lua implementation.

After having implemented a scripting language within a game engine it would be interesting to develop a custom scripting language from scratch to utilize in possible future projects. 36

6. REFERENCES Broderick, C. (den 7 May 2009). Simple Factory vs. Factory Method vs. Abstract Factory. Hämtat från Quickshift Consulting: http://corey.quickshiftconsulting.com/1/post/2009/5/first-post.html den 12 April 2013 Calsbeek, J. (den 9 June 2011). How to directly map a Lua variable to a C++ variable? Hämtat från Stackoverflow: http://stackoverflow.com/questions/6297245/howto-directly-map-a-lua-variable-to-a-c-variable/6298077#6298077 den 12 April 2013 Capaldo, L. (den 28 June 2009). C++ Get name of type in template. Hämtat från Stackoverflow: http://stackoverflow.com/questions/1055452/c-get-name-oftype-in-template/1055563#1055563 den 12 April 2013 Celes, W., Figueiredo, L. H., & Ierusalimschy, R. (August 2006). Lua 5.1 Reference Manual. Hämtat från The Programming Language Lua: http://www.lua.org/manual/5.1/ September 2012 Cunningham & Cunningham, Inc. (2011). Coupling And Cohesion. Hämtat från Cunningham & Cunningham, Inc.: http://c2.com/cgi/wiki?CouplingAndCohesion den 18 September 2012 Deadbeef Games. (den 8 April 2010). Event Data from C++ to Lua using Luna(r). Hämtat från Deadbeef Games: http://deadbeefgames.com/blog/?p=111 den 17 January 2013 DeLoura, M. (2001). Game Programming Gems: Vol 2. Stamford, Connecticut, U.S.: Cengage Learning. Gold, J. (2004). Object-Oriented Game Development. Essex, England: Pearson Education, Ltd. Gregory, J. (2009). Game Engine Architecture. Natick, MA: A K Peters, Ltd. Sánchez-Crespo Dalmau, D. (2003). Core Techniques and Algorithms in Game Programming. Pearson Education, Ltd. Sen, A., & Kumar Kardam, R. (den 19 February 2008). Building your own memory manager for C/C++ projects. Hämtat från IBM: http://www.ibm.com/developerworks/aix/tutorials/au-memorymanager/aumemorymanager-pdf.pdf den 12 April 2013

37

Shog9. (den 2 September 2008). oop - Coupling and cohesion. Hämtat från Stackoverflow: http://stackoverflow.com/a/39988/930155 den 18 September 2012 Stroustrup, B. (2000). The C++ Programming Language: Special Edition. Murray Hill, New Jersey: Addison-Wesley Professional. Ward, J. (den 29 April 2008). What is a Game Engine? Hämtat från Game Career Guide: http://www.gamecareerguide.com/features/529/what_is_a_game_.php den 18 September 2012 Wikipedia: Cohesion. (2012). Cohesion (computer science). Hämtat från Wikipedia: http://en.wikipedia.org/wiki/Cohesion_%28computer_science%29 den 18 September 2012 Wikipedia: Coupling. (2012). Coupling (computer programming). Hämtat från Wikipedia: http://en.wikipedia.org/wiki/Coupling_%28computer_science%29 den 18 September 2012 Wikipedia: Event loop. (2012). Event loop. Hämtat från Wikipedia: http://en.wikipedia.org/wiki/Main_loop den 18 September 2012 Wikipedia: Game engine. (2012). Game engine. Hämtat från Wikipedia: http://en.wikipedia.org/wiki/Game_engine den 18 September 2012 Wikipedia: High cohesion. (2012). High cohesion. Hämtat från Wikipedia: http://en.wikipedia.org/wiki/High_cohesion den 3 November 2012 Wikipedia: Loose coupling. (2012). Loose coupling. Hämtat från Wikipedia: http://en.wikipedia.org/wiki/Loose_coupling den 3 November 2012

38