mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 09:52:27 -04:00
initial revision, includes StateVar, FunctionCall and EnterExit
This commit is contained in:
parent
31824702f5
commit
ce3927480c
200
direct/src/fsm/StatePush.py
Executable file
200
direct/src/fsm/StatePush.py
Executable file
@ -0,0 +1,200 @@
|
|||||||
|
class PushesStateChanges:
|
||||||
|
# base class for objects that broadcast state changes to a set of subscriber objects
|
||||||
|
def __init__(self, value):
|
||||||
|
self._value = value
|
||||||
|
# push state changes to these objects
|
||||||
|
self._subscribers = set()
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
if len(self._subscribers) != 0:
|
||||||
|
raise '%s object still has subscribers in destroy(): %s' % (
|
||||||
|
self.__class__.__name__, self._subscribers)
|
||||||
|
del self._subscribers
|
||||||
|
del self._value
|
||||||
|
|
||||||
|
def getState(self):
|
||||||
|
return self._value
|
||||||
|
|
||||||
|
def _addSubscription(self, subscriber):
|
||||||
|
self._subscribers.add(subscriber)
|
||||||
|
|
||||||
|
def _removeSubscription(self, subscriber):
|
||||||
|
self._subscribers.remove(subscriber)
|
||||||
|
|
||||||
|
def _handlePotentialStateChange(self, value):
|
||||||
|
oldValue = self._value
|
||||||
|
self._value = value
|
||||||
|
if oldValue != value:
|
||||||
|
self._handleStateChange()
|
||||||
|
|
||||||
|
def _handleStateChange(self):
|
||||||
|
# push this object's state to the subscribing objects
|
||||||
|
for subscriber in self._subscribers:
|
||||||
|
subscriber._recvStatePush(self)
|
||||||
|
|
||||||
|
if __debug__:
|
||||||
|
psc = PushesStateChanges(0)
|
||||||
|
assert psc.getState() == 0
|
||||||
|
psc.destroy()
|
||||||
|
del psc
|
||||||
|
|
||||||
|
class ReceivesStateChanges:
|
||||||
|
# base class for objects that subscribe to state changes from PushesStateChanges objects
|
||||||
|
def __init__(self, other):
|
||||||
|
self._other = None
|
||||||
|
self._subscribeTo(other)
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
self._unsubscribe()
|
||||||
|
del self._other
|
||||||
|
|
||||||
|
def _subscribeTo(self, other):
|
||||||
|
self._unsubscribe()
|
||||||
|
self._other = other
|
||||||
|
if self._other:
|
||||||
|
self._other._addSubscription(self)
|
||||||
|
|
||||||
|
def _unsubscribe(self):
|
||||||
|
if self._other:
|
||||||
|
self._other._removeSubscription(self)
|
||||||
|
self._other = None
|
||||||
|
|
||||||
|
def _recvStatePush(self, other):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if __debug__:
|
||||||
|
rsc = ReceivesStateChanges(None)
|
||||||
|
rsc.destroy()
|
||||||
|
del rsc
|
||||||
|
|
||||||
|
class StateVar(PushesStateChanges):
|
||||||
|
# coder-friendly object that allows values to be set on it and pushes those values
|
||||||
|
# as state changes
|
||||||
|
def set(self, value):
|
||||||
|
PushesStateChanges._handlePotentialStateChange(self, value)
|
||||||
|
|
||||||
|
def get(self):
|
||||||
|
return PushesStateChanges.getState(self)
|
||||||
|
|
||||||
|
if __debug__:
|
||||||
|
sv = StateVar(0)
|
||||||
|
assert sv.get() == 0
|
||||||
|
sv.set(1)
|
||||||
|
assert sv.get() == 1
|
||||||
|
sv.destroy()
|
||||||
|
del sv
|
||||||
|
|
||||||
|
class StateChangeNode(PushesStateChanges, ReceivesStateChanges):
|
||||||
|
# base class that can be used to create a state-change notification chain
|
||||||
|
def __init__(self, other):
|
||||||
|
ReceivesStateChanges.__init__(self, other)
|
||||||
|
PushesStateChanges.__init__(self, other.getState())
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
PushesStateChanges.destroy(self)
|
||||||
|
ReceivesStateChanges.destroy(self)
|
||||||
|
|
||||||
|
def _recvStatePush(self, other):
|
||||||
|
# got a state push, apply new state to self
|
||||||
|
self._handlePotentialStateChange(other._value)
|
||||||
|
|
||||||
|
if __debug__:
|
||||||
|
sv = StateVar(0)
|
||||||
|
assert sv.get() == 0
|
||||||
|
scn = StateChangeNode(sv)
|
||||||
|
assert scn.getState() == 0
|
||||||
|
sv.set(1)
|
||||||
|
assert sv.get() == 1
|
||||||
|
assert scn.getState() == 1
|
||||||
|
scn2 = StateChangeNode(scn)
|
||||||
|
assert scn2.getState() == 1
|
||||||
|
sv.set(2)
|
||||||
|
assert scn2.getState() == 2
|
||||||
|
scn3 = StateChangeNode(scn)
|
||||||
|
assert scn3.getState() == 2
|
||||||
|
sv.set(3)
|
||||||
|
assert scn2.getState() == 3
|
||||||
|
assert scn3.getState() == 3
|
||||||
|
scn3.destroy()
|
||||||
|
scn2.destroy()
|
||||||
|
scn.destroy()
|
||||||
|
sv.destroy()
|
||||||
|
del scn3
|
||||||
|
del scn2
|
||||||
|
del scn
|
||||||
|
del sv
|
||||||
|
|
||||||
|
class FunctionCall(StateChangeNode):
|
||||||
|
# calls func with new state whenever state changes
|
||||||
|
def __init__(self, other, func):
|
||||||
|
self._func = func
|
||||||
|
StateChangeNode.__init__(self, other)
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
StateChangeNode.destroy(self)
|
||||||
|
del self._func
|
||||||
|
|
||||||
|
def _handleStateChange(self):
|
||||||
|
self._func(self._value)
|
||||||
|
StateChangeNode._handleStateChange(self)
|
||||||
|
|
||||||
|
if __debug__:
|
||||||
|
l = []
|
||||||
|
def handler(value, l=l):
|
||||||
|
l.append(value)
|
||||||
|
assert l == []
|
||||||
|
sv = StateVar(0)
|
||||||
|
fc = FunctionCall(sv, handler)
|
||||||
|
assert l == []
|
||||||
|
sv.set(1)
|
||||||
|
assert l == [1,]
|
||||||
|
sv.set(2)
|
||||||
|
assert l == [1,2,]
|
||||||
|
fc.destroy()
|
||||||
|
sv.destroy()
|
||||||
|
del fc
|
||||||
|
del sv
|
||||||
|
|
||||||
|
class EnterExit(StateChangeNode):
|
||||||
|
# call enterFunc when our state becomes true, exitFunc when it becomes false
|
||||||
|
def __init__(self, other, enterFunc, exitFunc):
|
||||||
|
self._enterFunc = enterFunc
|
||||||
|
self._exitFunc = exitFunc
|
||||||
|
StateChangeNode.__init__(self, other)
|
||||||
|
|
||||||
|
def destroy(self):
|
||||||
|
StateChangeNode.destroy(self)
|
||||||
|
del self._exitFunc
|
||||||
|
del self._enterFunc
|
||||||
|
|
||||||
|
def _handlePotentialStateChange(self, value):
|
||||||
|
# convert the incoming state as a bool
|
||||||
|
StateChangeNode._handlePotentialStateChange(self, bool(value))
|
||||||
|
|
||||||
|
def _handleStateChange(self):
|
||||||
|
if self._value:
|
||||||
|
self._enterFunc()
|
||||||
|
else:
|
||||||
|
self._exitFunc()
|
||||||
|
StateChangeNode._handleStateChange(self)
|
||||||
|
|
||||||
|
if __debug__:
|
||||||
|
l = []
|
||||||
|
def enter(l=l):
|
||||||
|
l.append(1)
|
||||||
|
def exit(l=l):
|
||||||
|
l.append(0)
|
||||||
|
sv = StateVar(0)
|
||||||
|
ee = EnterExit(sv, enter, exit)
|
||||||
|
sv.set(0)
|
||||||
|
assert l == []
|
||||||
|
sv.set(1)
|
||||||
|
assert l == [1,]
|
||||||
|
sv.set(2)
|
||||||
|
assert l == [1,]
|
||||||
|
sv.set(0)
|
||||||
|
assert l == [1,0,]
|
||||||
|
sv.set(True)
|
||||||
|
assert l == [1,0,1,]
|
||||||
|
sv.set(False)
|
||||||
|
assert l == [1,0,1,0,]
|
Loading…
x
Reference in New Issue
Block a user