Skip to content

Archive

Tag: Game Engine

Since we’re already using blender as a level editor, I got a little curious about BGE and decided to check it out.

What is it?

The blender game engine (BGE) is part of Blender, it allows creating games using Blender. Games can run as standalone executables on a PC or Mac. I think there may be a plugin to run this in browsers as well.

I’m not sure whether there is an iOS compatible engine that supports BGE or not. You could look into SiO2 or GameKit.
If you made your own engine (whether 2D or 3D), exporting BGE graphs should be a big piece of cake (somewhat time consuming, but not difficult).

How it works

You can read the comprehensive introduction (see older links, below), I’m not very used to (this approach to) visual programming so this is how I explained it to myself.

The blender game engine uses sensors, controllers and actuators. Soberly, this is an event driven architecture. For each object you define trigger conditions causing events to be generated, then link the conditions to scripts affecting the stage of game objects.

  • sensor: sensors generate events, for example dedicated sensors detect keyboard or collision events.
  • actuator: actuators change the state of the world, for example make an object move or play an animation.
  • controller: read on.
In Blender’s logic editor, each object has a tab for sensors, actuators and controllers, so BGE is also object oriented. In practice we attach behavior to a game object by creating a graph, so a basic linked graph will look like this in the blender UI:
.
[sensor] => [controller] => [actuator]
example:
[right arrow key] => [AND] => [motion actuator]  
.
So we could make a game actor move to the right by linking a keyboard sensor (right arrow key) to a motion actuator, right? So what’s this AND controller in the middle?
Controllers provide a way to integrate inputs from several sensors. For example if we have sensors A and B and we want actuator X to apply only when both A and B are firing, we can use a simple AND controller. Yes, basic controllers are ‘logic gates’. Naturally this scales up – you can write your own logic expressions, or use scripts if you need more elbow room.

Links

2.5x/2.6x

  • Tutorials (Blender Noob To Pro on wikibooks – search ‘Game engine’)
  • Where to start BGE Python (blenderArtists.org)
  • 2.6x API docs
  • 2.6x GameObjectSettings  - These APIs aren’t used to access game objects while a BGE game is running, instead they can be used to inspect/modify game properties (including actuators/sensors/controllers).
    Blender 2.5x and later stores this under an object’s game property; 2.6x added APIs to inspect linkages between sensors, controllers and actuators.
    Situations where this gets useful:
    • You want to setup game objects programmatically
    • You want to export logic bricks using a py script.

Older links (but still useful to understand how stuff works)

All in all, there’s no game engine until you see that game engine supporting a couple of separate executables. Paradoxically, even if you’re working on ‘just one game’, it’s better to have a game engine and it’s better to have two or three executables than one.

I don’t exactly remember when I started piecing things out. It took a few weeks already and I’m not done yet. Now I have a bunch of static libraries:

  1. utilities. This doesn’t do much. Sound and string utilities, a tiny parser and some support for talkback. I put there essential things that I’d see running in any game I make. I
  2. shell. An MVC template for game containers. It provides basic support for stuff people do when they’re not playing: starting a new game, checking out ‘more games’, mailing support and the like. In other words, the ‘little extras’ that indies don’t think about when they start making a game. This is meant to be reusable and can be customized easily.
  3. rendering engine. this is directly derived from Antistar code. This library knows how to import stuff from blender (via ox3ich/qwagga) and render scenes using OpenGL ES 1.0
  4. game engine. derived from Antistar code, its scope is narrow compared with open source and commercial counterparts. Includes support for walking, game physics, qualified actors and items etc…

Aside, I also have the following:

  • Unit testing for all my libraries. It’s not that I use it that much (less than I should) but I want to have it handy when I need it (seriously, I do have more than zero tests, and for solo work it’s a lot more valuable than version control, which gives me chronical pains and zero rewards).
  • Two sandboxes. The sandboxes are used to play-test and develop features. One sandbox targets core3d (for your eyes only), the other targets a3dsfx to try out game features. I consider that the sandboxes are a big improvement over messing with level design ‘just for testing’, then finding that nothing’s where it should.
  • 3 game projects. Antistar, and other stuff I may or may not be working on.

How did it happen?

It all happened mainly because I thought the Antistar project took way too long, and I’m getting better at designing smaller games. I managed to kickstart a mini-project, and the good news is, I’m not working on it now (somebody else is). The mini project spawned the shell, utilities and a rather tiny game engine for 2D stuff (not quoted above).

Then it looked like the mini project might take a while. So I started looking at the 3D content in Antistar, thinking I’m much better at 3D graphics than 2D. So I extracted the rendering library and spawned another mini project (not something I’m too concerned about). And finally I pulled a3dsfx from the antistar equation, because I wanted a sandbox for that.

Is it good?

It depends how you look at it. From a short term perspective, it’s wasteful. Building with unstable libraries (most of them are) is much slower. Creating standalone libraries requires breaking undesirable dependencies. None of this hurt a lot (which still shows the code massively improved since last year), but it takes time.

If we look ahead a little, I think it’s great. I’ve been rushing forward, then thrashing forward, I wrote code that’s valuable to me, and code that takes that long to write shouldn’t be used in just one product.
A static library gives ‘strong separation’. Yes, I could import whatever headers I fancy. But no, I don’t, and I don’t feel like it.

Aside, although I’m not evenly committed to the side projects I started, going through the motions helped me look at things in a different light. As a result I already improved my rendering engine and blender scene support. This clearly brought improvements that will support the next Antistar release.

Integrations

Another thing that’s coming up with the static libraries and the sandboxes is ‘easy to use integrations’. So now I have the following:

  • World3D – this is basically a no fuss blender scene viewer.
  • Stage3D – also a scene loader, but it relies on conventions to extract terrain, physics, actors, items and such.

What’s next?

I’m still validating Stage3D using the sandbox. Separating the game engine from the game itself is a little bit like making an omelette (break an egg) but it makes game logic clearer and more manageable.

Yeah, whatever…

In my previous article I’ve suggested a few scripting statements that could be used to specify interactions between actors and the board. In this post I am investigating a solution to bind these statements to the action graph in my underlying API.

Implementing interactions

If you followed the previous articles, you already know how ‘pseudo-scripted’ statements get into the action graph. First an object tree representing the script is created. I have added the following classes to support this:

  • InteractionDef – Defines an interaction as associating an EventDef with several responses.
  • EventDef – Base class for interaction events
    • ActorEventDef – Occurs when an occur performs a specified action.
    • EnvironmentEventDef – Occurs when an actor occupies/enters a given tile
    • CollisionEventDef – Occurs when an actor collides with an actor or prop.
  • ActorResponseDef – A passive reaction (typically rendered as an actor animation)
  • CapacityModifierDef – Used to capture disabling/enabling a capacity
  • RoleModifierDef – Used to capture disabling/enabling a role
  • PropertyModifierDef – Used to capture an increase/decrease to a property

The class hierarchy  could be a little more structured. Also, it seems that we may easily compress the same hierarchy later by considering similar node types. However, this is enough to render the current set of scripting statements provided by the Script class.

The next step is to feed those into the Interpreter class that will actually setup the action graph. I decided to provide ad-hoc classes to render interactions to the action graph. Compared to the design I earlier produced to model actor decisions, classes for interaction are more specialized – many of these nodes just can’t be put anywhere in the graph. This is more a change in the design than something that is specific to the problem being solved, so I guess I would take an opportunity to clean the overall design of the action graph API a little later on – it seems that using more particular types helps keep the action graph small and simplifies some of the design while offering straightforward optimization hooks. On the other hand, large, structured nodes offer less opportunities for reuse.

The class hiearchy for this looks like this:

  • AffectMap – a list of affect bindings, i.e. event/response pairs (subclass of Action)
  • AffectBinding – a list of event/response pairs
  • AffectCondition – specialized subclasses implement interaction events
  • Affect – specialized subclasses realize actor responses.

All reflex maps (see previous articles) should be processed before affect maps. Notwithstanding, it’s OK to use several reflex maps, either for each actor or for the same actor.

Unlike with ReflexMap, I decided to hold an Actor instance directly in the map and pass it to binding, condition and affect method calls, this prevents these ‘support classes’ from implementing Action, but saves memory (no need to store Actor pointers in each node) and  seems, overall, a better choice.

With this, my original draft for a behavior programming API and pseudo scripting interface is complete. Next time I’ll write a small test suite for this and hopefully I’ll then find time to discuss the overall design.

Interacting with tiles and props

In the data model supporting my engine, I distinguish three base classes:

  • Actors
  • Cells – cells are ’tiles’ on the game board. A cell defines a terrain (an id representing grass, sand, etc…), the solid property which determines whether an actor can go through the cell, a prop
  • Props. A prop is an accessory associated with a cell. This could be use for trees, walls, etc…

For performance reasons, it might be better for actors not to interact with cells and props. Also we could work around the problem using actors. I leave this question as an implementation detail. For now, I want to consider a few scenarios which might require interacting with the stage and props:

  • There used to be games based on a ‘color all tiles’ concept. We’d like to change the environment property of a tile given preconditions.
  • Suppose an actor picks a key and uses it to open a door. I would tend to define the door as a prop, and the key as either a prop or an actor.
  • Now suppose an actor activates a lever, this might open a door as well, or change something else

a. Specifying tile and prop interactions

Let’s see how this can be specified using our pseudo-scripting. I add the following methods to the Script class:

-(void)let:(act)reaction when:(tag)kind doing:(act)action within:(float)range has:(tag)object;
-(void)let:(act)reaction when:(tag)kind within:(float)range has:(tag)object;
-(void)let:(act)reaction when:(tag)kind is:(tag)status;
-(void)let:(act)reaction when:(tag)kind within:(float)range is:(tag)status;

This doesn’t require redefining the statement class, all that is new so far is that we can add conditions over the target that triggers an action – carrying an item or bearing a given status. So I extend the Statement class accordingly.

I have added methods checking for statuses and items to the Actor class; the actor class forwards hasStatus:(tag)status and hasItem:(tag)item to the hasTag:(tag)tg method; I don’t allocate new pointers at this point – I’ll be relying on an actor subclass if I need more flexibility.

b. Enabling tile and prop interaction

At this point, scripts using the new statement could work, but they would only work with actors:

  • The Interpreter doesn’t recognize tiles and props as type-binding targets
  • Tiles and props don’t have tags associated to them anyway

I modify Interpreter to allow type-binding using tiles. I won’t define per-tile tags. Each tile has an integer coding the kind of terrain used for the tile. I map these ids to tags in the Board class. Maybe later I can extend board to tag special tiles irrespective of terrain if needed.

The interpreter works by associating a TargetSelector to a Decision. Decision is tightly bound to the Actor class, so I define a BoardDecision class for tiles. TargetSelector only requires an actor’s location, so I updated this class to support tiles as well.

For now BoardDecision only recognizes changes to the solid/empty state of a tile (can actors pass through?) and wholesale changes to terrain type.

Finally, I decide I won’t support prop interactions after all. using an Actor as substitute for a prop is much easier.

Picking, dropping, exchanging and snatching objects

I still don’t have anything to support picking and dropping objects. Maybe a good place to implement picking is within BasicActorUpdates:

  • If an actor is on a tile with a pickable object, they can automatically pick an object with a suitable ‘auto-pick’ tag
  • If an actor is on a tile with a pickable, and they use a PICK action, they will also pick that object.

There are many issues related to picking, dropping, exchanging and snatching (forcefully acquiring) objects. To get started, however, I will only use the following statements, adding them to the script class:

-(void)drop:(tag)item at:(tag)location;
-(void)pick:(tag)item at:(tag)location;
-(void)pick:(tag)item;
-(void)give:(tag)item to:(tag)receiver;
-(void)steal:(tag)kind from:(tag)owner;

This allows a game designer to specify basic flows for goods collection, storage and exchange. Note that all of these are high level actions compared to what I have defined so far – given the opportunity, a character is expected to effect these actions, moving to reach the target when detected.

These actions all break down into a couple of actions, one to reach the target and one to effect the corresponding ‘material transfer’ (give/take/pick an object). This is reflected in my implementation of the new Script methods:

  • Each of the above functions generates an approach: statement as already defined by the Script class.
  • A required/desired item condition is attached to the generated statement.
  • A lower priority statement is added to specify the actual transfer.

I have tied up a quick implementation – for now the items to give/take and the intended target are bound to the target actor as a side effect of selecting target actors/locations. I’ll try to put together something more adequate later, but for now, let’s see if that works.

Minor changes?

There is an incidental difference between picking and other behaviors I worked with so far: the pick methods defined in Script may imply moving to a location defined by a cell on the board.
So far, all my tests only required actors to move towards/away from other actors. However, because I decided to rely on existing script statements to implement picking, the requirement that a target tag may refer either to a tagged tile or a tagged actor propagated.
I’ve stubbornly followed suit, for the simple reason that it was legitimate to want to move towards/away from a given tile rather than a given actor. Meanwhile…

  • I have a serious performance issue to take care of, because cells in the data model don’t define a location vector. I have a method that generates a location vector every time, but it is unthinkable to have this run for many tiles at every frame, as it would kill runtime memory in a very, very short time.
  • While it is legitimate to attempt reaching an item on a tagged tile, the algorithm for selecting a tagged tile containing an item is also a concern.

Next time I might look into this in some detail – probably we can improve all this a lot by defining a base class for tiles and actors; also, I surely need to run a fun script to test picking, giving and snatching.

In my the last article I solved a technical issue related to my action graphs. Now I want to make it easier to write powerful scripts for my actors. Let’s recall a fragment from the previous example:

Actor* dog=[[Actor alloc]initWithX:0 y:0 z:0 tag:@"dog"];
OnApproach* inner=[[OnApproach alloc]initWithSource:dog target:@"actor" range:30.0f];
XAction* chase=[[MoveToActor alloc]initMovingActor:dog to:inner.target];
ReflexMap* reflexes=[[ReflexMap alloc]init];
[reflexes add:chase on:inner];

This isn’t practical, for several reasons:

  • The script requires defining an actual actor. Often, we’d like to specify ‘class behavior’ instead – maybe we want to describe general behaviors associated with dogs.
  • All this [[Actor alloc]init… stuff is about OK for framework level stuff. For behavioral scripts, it is too heavy.

What we’d really want to write is something like (check the previous article for reference)

class Dog{
  - bark at actors within 60 metres
  - chase actors within 30 metres
  - bite actors within 1 metre
}

I don’t want to get into the writing/binding of a scripting language and interpreter, but we can surely clean things up and get it closer to the above.

A Script class

I’ve specified a Script class with convenience methods. With these methods added, the ‘guarding dog’ script now looks like:

Script* s=[[Script alloc]init];
//
[s type:DOG];
	[s let:BITE when:HUMAN within:10];
	[s approach: HUMAN whenWithin:30];
	[s let:BARK when:HUMAN within:60];
[s xType];

type: and xType: tell the script to start/end a class declaration. The other functions are meant to be translated into an action graph. The next step is to decide how this is done. In the meantime, this is worth a couple of comments:

  • We no longer need defining a dog actor. The DOG tag allows us to define class behavior. This doesn’t prevent us from defining ad-hoc behaviors for a given actor (use the tag only once). I hope that tags will prove very useful helpers in writing concise, yet powerful scripts.
  • Script methods are somewhat ad-hoc. However, this is probably OK. I’m trying to simplify 90% of scripting. Having said that, the current script spec still leaves out a lot of the (structural/modal) complexity of the action graph.

Implementing the script class

So far my script class is just semantics. We want to do something with our semantics:

  • We want to store the script in some form.
  • We want to be able to make a script current on a given ‘stage’. In other words, when we attach the script to a scene or virtual worlds, we want our actors to behave according to that script.

The classes provided by my framework so far are not meant to describe a script. They are normally instantiated as runtime nodes in an action graph. At best, I can use them as prototypes, and this is exactly what I tried first. Here is a sample function implementation:

-(void)observe:(tag)kind{
	NearestActor* condition=[[NearestActor alloc]initWithAgent:proto target:kind];
	XAction* response=[[LookAt alloc]initWithAgent:proto lookingAt:cond.target];
	[map add:response on:condition];
}

This can potentially get very untidy. Say we had an actor with a given tag. we’d have to go back and check for all rules including an instance of the same-tag prototype and duplicate the rule so it becomes applicable to that actor. The reason why this process can become messy is that neither conditions nor actions enforce the object paradigm. The Script class, on the other hand, ‘starts with typing’. it assumes an actor as the context of any script statement.

As a result, it is probably wiser to define separate constructs used to store behavior definitions associated with a tagged actor. This is simply because doing ensures we track typing information at least until we actually bind a runtime actor to its behavior. Given an on-stage actor, we can then collect definitions for each of the actor’s tags and generate reflex maps accordingly. At this point, none of the reflex maps will be associated to the actors per se, which may cause other problems. This, however, goes down to a little of book-keeping.

Script structure – draft

I used the following classes to store script nodes:

  • Type - A type is associated with a tag name and (for now), a top level selector.
  • ScriptDef – ScriptDef is the base type for script elements, in this case ‘selector’ and ‘statement’
  • Selector – A selector specifies a ReflexMap (should be explained in my previous article)
  • Statement - For now, my statements are structured, conditional statements. Probably I need to break this down later, but for now this form should cover most of the interactions I wish to describe using the scripts.

Interpreter

I then defined an Interpreter class responsible for setting up a script given a Stage and Transition. This reads the script; for each class, I retrieve the actors bearing the matching tag name and build an action graph based on the class definition. I muddled a little more with my existing Condition and Action subclasses, but somehow managed to tie everything together.

Next time I’ll do some testing to check how everything works, and try to summarize things a little.

Recently, I started designing a game engine with a few simple goals in mind:

  1. My game engine is concerned with managing a virtual world model. It is not an animation engine or a sequence/transition manager.
  2. Although I developed a rough and ready animation API, the model must be separate from that API. This is so that I can later rewrite view using a 3D engine or whatever else.

I’ve been muddling a little bit with behavior programming. After ‘going dark’ for a few days I’ve decided to share my experience as I believe this could illuminate some design points.

Behavior programming – a draft API

A few important classes from the draft API:

  • Condition – a condition is an object that returns a boolean value, so it has a (BOOL)check method.
  • Action – an action is an object with a (void)apply method.
  • ReflexMap – an action mapping a trigger (a Condition) to a response (an Action). When apply is invoked, the reflex map iterates the current action, if any. If no action is currently selected, ReflexMap iterates its list of triggers. The first satisfied trigger condition causes it’s response to become current.

As you can see, the API is based on objectified functions. This is a choice, maybe I’ll get a chance to explain why another time.

An example

Here is sample code used to program simple behavior for a guarding dog:

Actor* dog=[[Actor alloc]initWithX:0 y:0 z:0 tag:@"dog"];
//
Condition* outer=[[OnApproach alloc]initWithSource:dog target:@"human" range:60.0f];
Condition* inner=[[OnApproach alloc]initWithSource:dog target:@"human" range:30.0f];
Condition* close=[[OnApproach alloc]initWithSource:dog target:@"human" range:10.0f];
//
XAction* bark=[[ActorGesture alloc]initWithActor:dog action:BARK];
XAction* bite=[[ActorGesture alloc]initWithActor:dog action:BITE];
XAction* chase=[[MoveTo alloc]initMovingActor:dog to:nil];
//
ReflexMap* reflexes=[[ReflexMap alloc]init];
[reflexes add:bite on:close];
[reflexes add:chase on:inner];
[reflexes add:bark on:outer];

The @”foo” bits just represent strings (in case you’re not too familiar with Objective C). I use those strings as tags, so the @”human” tag allows OnApproach to only target human intruders (not rabbits, leprechauns and so forth…)

As illustrated by this code, although the idea of defining rules using conditions and actions seems OK at first, the design isn’t. The problem is that a Condition (in this case OnApproach) can be fulfilled in various ways. When the condition is fulfilled, we need to pass data to the action to effect it correctly. So in this case onApproach is fulfilled with a given target, but MoveTo cannot bind the target detected by OnApproach. Let’s try to fix this.

Binding precondition output to postcondition input – 1: using arbitrary parameters

My first impression is that the OnApproach condition should be replaced by an event call processed by a listener, so we’d have something like:

on:(Actor*)actor approaches:(Actor*) agent{...}

The downside is that doing this will require that we re-implement the event handling function for every trigger/response pair. We don’t want to write a new class for that every time. We do need to bind the output of the trigger to the input of the matching action. We might then change change the Action and Condition classes:

@interface Condition
-(BOOL)check; // unchanged. we need to return a boolean value anyway.
-(NSArray*)result; // OnApproach will place a reference to the approaching actor in this array.
@end

@interface Action
-(void)apply:(NSArray*)param // allows injecting data into the triggered action.
@end

We still need to tell ReflexMap which parameters to inject into MoveTo. So we change a function in ReflexMap:

add:(Action*)action on:(Condition*)trigger;

Now becomes:

add:(Action*)action with:(int[])params on:(Condition*)trigger;

And our reflexes are then setup as follows:

int[] args={0}; // addresses the only output from OnApproach
[reflexes add:bite with:args on:close];
[reflexes add:chase with:args on:inner];
[reflexes add:bark with:args on:outer];

This solves the problem, but lacks clarity because conditions and actions now return/accept arrays of arbitrary length and content.

Binding precondition output to postcondition input – 2: sharing placeholders

The next idea is as follows: what if we could arrange that whatever target defined by OnApproach is addressable using MoveTo?
To do this requires modifying both OnApproach and MoveTo. On the bright side, we needn’t change the Action and Condition signatures:

  1. I defined an ActorRef class. ActorRef owns an Actor property (I could use a pointer to pointer, but that would be a little confusing).
  2. OnApproach defines targetRef as an ActorRef instance. When a target is detected, targetRef.actor is assigned.
  3. MoveTo also defines a targetRef property. When MoveTo is initialized, we pass the ActorRef instance owned by our OnApproach condition.

We can now change the original example as follows (skipping the bits that didn’t change):

OnApproach* inner=[[OnApproach alloc]initWithSource:dog target:@"actor" range:30.0f];
XAction* chase=[[MoveToActor alloc]initMovingActor:dog to:inner.target];

This seems to solve our problem nicely:

  • Type safety isn’t compromised.
  • The core interfaces remain simple
  • The binding process doesn’t involve ReflexMap
  • The code used to define our test script is simple and readable, compared to solution (1).

OK, enough for today then. Next time I’ll look into a way to further simplify behavioral scripts, as they are still a little heavy.

At this point, I have defined several classes that contribute to generating action graphs. An action graph is invoked at every frame. Roughly speaking, the action graph checks preconditions in the game world and applies post-conditions. Action graphs, however, are a little more structured and powerful than this given special constructs.

  • At the root of the action graph, the main Transition defines several actions to be applied at every frame.
  • A ReflexMap is an action that selects between competing responses in the presence of several stimuli.
  • A GearSelector is an action that maintains and effects a priority driven agenda. The GearSelector can enable/disable an action on the agenda, independently of whether the action is current or not. GearSelector allows mixing long and short term goals as it can pause a lower priority action until a higher priority action is complete.
  • Finally, XAction allows sequencing actions and using alternatives if an action fails.

All this stuff is fine, however, there are significant features of the action graph that can become problems:

  1. The action graph must provide nodes on a per instance basis. For example, if a type of actor is associated with a reflex map, we need to provide a separate reflex map for each actor of this type. This is because different actors are in a different context, so they do different things.
  2. Conditions often provide the basis for event driven behavior; however, conditions in the current implementation just return a boolean value. Often, even if a condition targets a specific actor, it can be fulfilled in various ways. We then typically would like to bind the matching event parameters in an associate postcondition.

Overall, it would be worth looking at this stuff from a more object oriented point of view, however we probably also want to keep objectified conditions and actions, because this provides a lot of flexibility at runtime.