Home - Forums - Documentation - Gallery - Bugs
Current revision (15:21, 4 August 2008) (edit) (undo)
 
(3 intermediate revisions not shown.)
Line 25: Line 25:
Usually you will use the call to SetEntity to register with its message channel, or create further property classes on it.
Usually you will use the call to SetEntity to register with its message channel, or create further property classes on it.
 +
 +
'''Important:''' SetEntity can be called with 0 as a parameter, in case your pc is being detached or the entity destroyed, so you have to test for this when overriding SetEntity.
<source lang="python">
<source lang="python">
Line 36: Line 38:
# dont forget to call common behaviour or you'll get in trouble.
# dont forget to call common behaviour or you'll get in trouble.
pyPcCommon.SetEntity(self,entity)
pyPcCommon.SetEntity(self,entity)
 +
if not entity:
 +
return
print "assigned to entity:",entity.Name
print "assigned to entity:",entity.Name
Line 84: Line 88:
def SetEntity(self,entity):
def SetEntity(self,entity):
pyPcCommon.SetEntity(self,entity)
pyPcCommon.SetEntity(self,entity)
 +
if not entity:
 +
return
# now register with the entity message channel
# now register with the entity message channel
channel = entity.MessageChannel
channel = entity.MessageChannel
Line 110: Line 116:
entity.MessageChannel.SendMessage("cel.foo.bar",self,pars)
entity.MessageChannel.SendMessage("cel.foo.bar",self,pars)
- 
-
the first form is more efficient when we will send the same message many times, while the second is good for casual sending of messages.
 
</source>
</source>
 +
 +
 +
the first form is more efficient when we will send the same message many times, while the second is good for casual sending of messages.
= Properties =
= Properties =
Line 119: Line 126:
Python property classes support a mechanism to transparently treat python class attributes as cel properties, this means any property you set on the map or elsewhere (like quests) will directly translate to a python attribute change in your instance.
Python property classes support a mechanism to transparently treat python class attributes as cel properties, this means any property you set on the map or elsewhere (like quests) will directly translate to a python attribute change in your instance.
-
You can override SetProperty to intercept property setting from the outside and react appropriately on your code. Otherwise you have to assume your property can be changed anytime from the outside (which may work good for many uses).
+
You can define a python getter and setter for your property as usual. Otherwise you have to assume your property can be changed anytime from the outside (which may work good for many uses).
<source lang="python">
<source lang="python">
class AnotherPropClass(pyPcCommon):
class AnotherPropClass(pyPcCommon):
def __init__(self,oreg):
def __init__(self,oreg):
-
pyPcCommon.__init__(self,oreg)
+
pyPcCommon.__init__(self,oreg)
-
def SetProperty(self,id,val):
+
self._life = 10
-
print "property set from outside world!",fromid(id),val
+
def GetLife(self):
-
return pyPcCommon.SetProperty(self,id,val)
+
return self._life
 +
def SetLife(self,val):
 +
self._life = val
 +
if self._life <= 0:
 +
print "Dead" # and possibly do something
 +
life = property(GetLife,SetLife)
</source>
</source>
Line 142: Line 154:
print "InitTalk"
print "InitTalk"
# do stuff
# do stuff
- 
</source>
</source>

Current revision

Contents

Introduction

This is documentation for the future python property class system. Note all documented here works in current cel svn, but is experimental and still subject to change.

A Simple Python Property Class

from pycel import *
 
class HelloWorldPropClass(pyPcCommon):
        def __init__(self,oreg):
                pyPcCommon.__init__(self,oreg)
                print "Hello World!!"
 
CEL_IMPLEMENT_FACTORY(HelloWorldPropClass,"pchelloworld")

Where "pchelloworld" would be the actual name to use when creating such a property class.

Knowing when the entity has been set

You thought property classes live inside entities? False! Initially they are created on component nirvana, and (usually) after that they get assigned to an entity, and you get a SetEntity call in your property class. Note this can happen more times, but you don't need to support it (but you might).

Usually you will use the call to SetEntity to register with its message channel, or create further property classes on it.

Important: SetEntity can be called with 0 as a parameter, in case your pc is being detached or the entity destroyed, so you have to test for this when overriding SetEntity.

from pycel import *
 
class HelloWorldExtended(pyPcCommon):
        def __init__(self,oreg):
                pyPcCommon.__init__(self,oreg)
        def SetEntity(self,entity):
                # dont forget to call common behaviour or you'll get in trouble.
                pyPcCommon.SetEntity(self,entity)
                if not entity:
                     return
                print "assigned to entity:",entity.Name
 
CEL_IMPLEMENT_FACTORY(HelloWorldExtended,"pchelloworld2")

Registering time events with the physical layer

All python property classes implement a cel timer listener, this means they can register with the physical layer to get time ticks. The following example should illustrate sufficiently:

from pycel import *
 
class RotatePropClass(pyPcCommon):
        def __init__(self,oreg):
                pyPcCommon.__init__(self,oreg)
                # register for tick events
                PhysicalLayer.CallbackEveryFrame(self,CEL_EVENT_PRE)
                # register to be called back when 1 second has passed
                PhysicalLayer.CallbackOnce(self,1000,CEL_EVENT_PRE)
        def TickEveryFrame(self):
                # this gets called before every frame gets drawn in response
                # to CallbackEveryFrame registering.
                mov = celMesh(self.GetEntity()).Mesh.GetMovable()
                rot = csYRotMatrix3(0.1)
                mov.Transform(rot)
                mov.UpdateMove()
        def TickOnce(self):
                # this gets called after the requested time has passed in
                # response to CallbackOnce.
                print "One second has passed!"
 
CEL_IMPLEMENT_FACTORY(RotatePropClass,"pcrotate")


Receiving Messages

class RotatePropClass(pyPcCommon,pyMessageReceiver):
        def __init__(self,oreg):
                pyPcCommon.__init__(self,oreg)
                pyMessageReceiver.__init__(self,oreg)
        def SetEntity(self,entity):
                pyPcCommon.SetEntity(self,entity)
                if not entity:
                     return
                # now register with the entity message channel
                channel = entity.MessageChannel
                # we register to messages based on masks, so here we register
                # to cel.foo. to receive any messages starting with that pattern.
                channel.Subscribe(self,"cel.foo.")
        def ReceiveMessage(self,msg, sender, ret, params):
            # here the messages are received
            if msg == getid("cel.foo.bar"):
                 print "do something"
            elif msg == getid("cel.foo.anotherbar"):
                 print "do something else"
            return 0


Sending Messages

dispatcher = entity.MessageChannel.CreateMessageDispatcher(self,"cel.foo.bar")
dispatcher.SendMessage(pars)
 
or
 
entity.MessageChannel.SendMessage("cel.foo.bar",self,pars)


the first form is more efficient when we will send the same message many times, while the second is good for casual sending of messages.

Properties

Python property classes support a mechanism to transparently treat python class attributes as cel properties, this means any property you set on the map or elsewhere (like quests) will directly translate to a python attribute change in your instance.

You can define a python getter and setter for your property as usual. Otherwise you have to assume your property can be changed anytime from the outside (which may work good for many uses).

class AnotherPropClass(pyPcCommon):
        def __init__(self,oreg):
             pyPcCommon.__init__(self,oreg)
             self._life = 10
        def GetLife(self):
             return self._life
        def SetLife(self,val):
             self._life = val
             if self._life <= 0:
                print "Dead" # and possibly do something
        life = property(GetLife,SetLife)

Actions

Actions are also transparently translated to instance method calls. This methods need to have args as first parameter, which will be a celParameterBlock.

class TalkingPropClass(pyPcCommon):
        def __init__(self,oreg):
                pyPcCommon.__init__(self,oreg)
        def InitTalk(self,args):
                print "InitTalk"
                # do stuff


Loading your property classes

Usually you will place the .py file somewhere in pythonpath, and add some config options to celstart.cfg (or your own app).

CsPython.Module.1 = mypcclasses

(where the file would be mypcclasses.py in this case).

You can add as many files as you want using this mechanism.

For this to work you need cspython loaded, either manually in some programming language or by placing the following in config file (like celstart.cfg for celstart):

System.Plugins.iScript = crystalspace.script.python

| Article | Discussion | View source | History |