Thursday, November 5, 2009

TickHandler and its Kids!



As mentioned previously, the TickHandler can receive tick events from the GameObjectCollector. We previously discussed Tickhandler, but now we will cover its two direct subclasses: GameObject and PyTickHandler.


GameObject

GameObject (GameObjectCollector *c)
GameObject (GameObjectCollector *c, const string &grid)
GameObject (GameObjectCollector *c, const char *rGrid)
GOComponent * GetGOC (const char *rFamilyID)
GOComponent * GetGOC (const string &familyID)
void SetGOC (GOComponent *newGOC)
void DelGOC (const char *rFamilyID)
void DelGOC (const string &familyID)
void ClearGOCs ()
void SetLocation (GameMapLocation *gloc)
GameMapLocation * GetLocation ()
Point GetLocationPoint ()
GamePoint * GWGetLocation ()
bool Tick (TickPhase phase)
bool TestProposition (char *name, bool truth, float value)
void UpdateProposition (GameProposition &g)
void AddProposition (GameProposition *prop)
GameProposition * GetProposition (string &name, bool truth)
GameProposition * GetProposition (char *name, bool truth)
float Distance (GameObject *obj)
GameReferenceType GetReferenceType ()


GameObject is intended to be the first concrete class to be registered with the GameObjectCollector. It could be thought as an object in the game environment. It could represent both and actor or a tree. The GameObject uses a game object component system that is very similar to what is described in Game Programming Gems: 6. The components make up the specialized behavior of varios GameObjects, and will be covered in much more detail in my next post. It is the ability to set and get these components that allow some objects, an avatar for example, to have an Artificial Intelligence, and some objects, such as a trap, to have minimal intelligence.

PyTickHandler

PyTickHandler (PyObject *o, GameObjectCollector *c, const char *tid)
bool Tick (TickPhase phase)


This handler is very generic, and dellegates the handling of the Tick call to whatever python object is attached to this object. This allows a great deal of extensibility, as you can allow any python object to participate in the tick events of the GameObjectCollector. An example might be a timing component, a state renderer, or simply an object that resurrects fallen avatars as their deaths are detected in the tick event cycle.

Tuesday, November 3, 2009

GameReference, GameObjectCollector, and TickHandler

GameReference

GameReference (GameObjectCollector *c)
GameReference (GameObjectCollector *c, const string &grid)
GameReference (GameObjectCollector *c, const char *rGrid)
virtual ~GameReference ()
const string & GetID ()
char * GetIDRaw ()
bool IncRef ()
bool DecRef ()
int RefCount ()
bool Collectable ()
bool Attach (PyObject *p)
bool Collect (bool force=false)
PyObject *GetPyObject ()
GameObjectCollector *GetCollector ()
virtual GameReferenceType GetReferenceType ()

In GankWar, the GameReference is the basic class of entities in the game. GameReference provices a reference counting scheme, which allows for memory management of items in the "zone". You might ask why I bothered implementing my own refcounting mechanism? It just seemed right. I was spending a lot of time know when something was crossing the reference boundaries between c++ and python; so, I used this system to work it out. To increment the reference count, you would call IncRef(), and to decrement DecRef(). If the reference count reaches zero, the item will be marked for collection in the next cycle of the GameObjectCollector.

GameObjectCollector

GameObjectCollector (const string &tid)
GameObjectCollector (const char *tid)
~GameObjectCollector ()
void Put (GameReference *ref)
GameReference * Get (const string &id)
GameReference * Get (const char *rid)
void Collect (GameReference *ref)
void CollectAll ()
void PutAll ()
string NextID ()
void Register (TickHandler *handler, TickPhase phase)
void UnRegister (TickHandler *handler, TickPhase phase)
void Tick ()
void ForEach (GameReferenceType grt, foreachgameobject_cb fn, void *user_data)

The GameObjectCollector is the heart of a zone, as it manages GameReferences. It also handles "Tick" events within the scenario. As mentioned previously, it will insert and collect GameReferences at the beginning of each Tick cycle. A Tick has three specific phases to it, pretick, tick, and posttick. These various tick events are handled by TickHandlers.

TickHandler

TickHandler (GameObjectCollector *c)
TickHandler (GameObjectCollector *c, const string &grid)
TickHandler (GameObjectCollector *c, const char *rGrid)
virtual bool Tick (TickPhase phase)
void StopTicking (TickPhase phase)
void StartTicking (TickPhase phase)
bool IsTicking (TickPhase phase)


TickHandler is a subclass of GameReference that can be registered with the GameObjectCollector to recieve Tick events for a given phase in the Tick. They server various roles and are very flexible to support behavior that needs to occur at a given Tick. And example might be a reporting component that reports on the state of the simulation at the end of every tick.

Thursday, October 29, 2009

GankWar and Virtualization

I have been working on making GankWar more Linux friendly, which will allow folks to work on it without requiring they have Visual Studio. With that in mind, I installed various components on Virtual Box with Ubuntu desktop version, and I got everything running.

I am still having some issues, as I can hit orbited locally on the VM and everything behaves like it should, and the Zone Runner messages are received. I can hit Orbited from outside the VM, and it appears to connect, registers for the same channel as the local STOMP client does, but does not receive the messages that the local client is receiving. I am guessing it is either in how I am sending the messages or some domain thing to channel registration... okay I don't believe that either /grin. I am chalking it up to me being an Orbited Noob, and I am rolling up my sleeves to dig deeper.

Tuesday, October 27, 2009

High Level GankWar System View

GankWar is a simulation type game, where players will be either able to play their avatars, or allow artificial intelligence instructions, through behavior trees, to guide the actions of their players. The AI will be able to be switched on and off, but the avatar will always be present in the gaming world.

The interface will use HTML and Canvas, which makes compatibility with Internet Explorer unlikely, though not impossible. The web interface will provide something slightly more graphical than the typical roguelike, but will play much the same as one.

In order to stream events to and from the browser, a Comet server will be used, to handle the persistent connection and data pushed from the server. Data and presentation pulled from the server by the client will be handled by a standard web framework. In the prototype, my chosen Comet server, Orbited, will handle both Comet and presentation layer, but shortly into full development I see something like Django taking over the presentation layer surrounding the map.

The MapRunner is a Twisted Python STOMP client, that is running the Game Engine while communicating with the connected clients via the STOMP protocol.

More to come as I have time!

Wednesday, October 21, 2009

From Sleep I Rise!

Well, I have not exactly been sleeping, but I have been buried under work. My blogging has not been going... period. I am going to try to fix that by turning to a project that I am doing for fun: GankWar. There is nothing new about the idea, but I will be implementing a Roguelike Multiplayer Online (Just MO... No MMO) that will enable players to write artificial intelligence to drive their persona while they are not in game. I hope this will add more diversity to the mob AI. The engine is a C++ library that has python bindings. My objective for this game is not to rock the gaming world with my brilliance, as that would be a comedy and not a game, but to hopefully learn a few things about game making, while having fun along the way.

Anyhow, I will be updating this blog periodically with code samples and such as it progresses.

Saturday, March 28, 2009

I think I've Lost My Memory!

I know it has been forever since I have posted, but work has been busy. I do want to share something, not ground breaking, that we have started doing to track down memory issues in our javascript applications. In my example below, I create this alien registerEventHandler function that would take an object and register for an event on it by name, taking a function and a scope.



function getClosure(arg1,arg2){
var trkel = document.createElement("DIV");
trkel.setAttribute("id","TRACK_getClosure" );
registerEventHandler(arg1,"click",
function(){ .... },this);
}


As we can see, when this function is ran, we register a function as a handler. A function which involves a closure ( function within function holds containing scope). This is not a problem, so much, if it is cleaned up, after the arg1 has seen its day. When we have a stray memory issue we will use sIEve and code like above. While the closure is alive, sIEve will show the element whose ID is "TRACK_getClosure" as not freed and orphaned. When our code behaves, the element is dereferenced and gets freed. This same approach can be used to track the life of objects, and if they get destroyed, by assigning the tracker_el instance directly too the object; so, when all references to the object are cleaned up, the element will be reclaimed.

I hope this helps you all like it has helped us!

Thursday, December 18, 2008

Event Driven Construction Part 2

In my previous post,Event Driven Construction , I discussed the concept of using metaclasses to provide event driven construction of singleton services.  I wanted to introduce two more examples.  One is a class which combines the two metaclasses from the previous post together:

class CreateAndSignal(EventSingleton,
CreateOnSignal):
pass

class D(object):
__metaclass__ = CreateAndSignal
_i_signal = "C-Created"
_o_signal = "D-Created"

class E(object):
__metaclass__ = CreateAndSignal
_i_signal = "C-Created"
_o_signal = "E-Created"


In the code above, I have created two classes of type CreateAndSignal, which construct themselves on recieving _i_signal, and upon construction throw the event _o_signal. In the example both classes await the event "C-Created"; so, lets provide that class as well, which is of type EventSingleton from the previous post.

class C(object):
__metaclass__ = EventSingleton
_o_signal = "C-Created"

Now with a class that does the same by tracking a few signals we can wait on multiple events.

def getOnDependancy(sig,k):
x = lambda *args:k.onDependancy(sig)
return x
class CreateAfterDependancies(Singleton):
msg="[%s]CreateAfterDependancies(%s)%s"
def __init__(cls,name,bases,dic):
super(CreateAfterDependancies,cls).\
__init__(name,bases,dic)
cls._d_signal_lookup = {}
cls._d_signals = list(cls._d_signals)
for signal in cls._d_signals:
rec=getOnDependancy(signal,cls)
cls._d_signal_lookup[signal] = rec
connectEx(rec,signal)
def __call__(cls,*args,**kw):
if cls.isSatisfied():
return super(
CreateAfterDependancies,cls).\
__call__(*args,**kw)
else:
msg = "Dependencies not met"
raise Exception(msg)
def isSatisfied(cls):
return len(cls._d_signals) == 0
def onDependancy(cls,signal):
if signal in cls._d_signals:
rec=cls._d_signal_lookup[signal]
del cls._d_signal_lookup[signal]
cls._d_signals.remove(signal)
satisfied = (cls.isSatisfied() \
and 1) or 0
msg=["--%s"%repr(cls._d_signals),
"--Creating"]
print cls.msg%(signal,
cls.__name__,
msg[satisfied])
if satisfied:
cls()

By creating closures to functions that will remove the signal when fired and check to see if all dependencies have been met, this class allows us to create based off of more than one event, as previous classes worked.


class G(object):
__metaclass__ = CreateAfterDependancies
_d_signals = ["E-Created","F-Created"]

C()

The classes above create a build condition which can be visualized by:
C->D
->E -> F
And the output of:

[C]EventSingleton(C-Created)
[D]CreateOnSignal(C-Created)
[D]EventSingleton(D-Created)
[E]CreateOnSignal(C-Created)
[E]EventSingleton(E-Created)
[E-Created]CreateAfterDependancies(G)--['F-Created']