direct: big formatting changes for the benefit of API reference
Part of the effort to move the API reference to Sphinx, see panda3d/panda3d-docs#21
This commit is contained in:
parent
ffeb8937bf
commit
f149fb4ab0
|
|
@ -104,45 +104,43 @@ class Actor(DirectObject, NodePath):
|
|||
lodNode = None, flattenable = True, setFinal = False,
|
||||
mergeLODBundles = None, allowAsyncBind = None,
|
||||
okMissing = None):
|
||||
"""__init__(self, string | string:string{}, string:string{} |
|
||||
string:(string:string{}){}, Actor=None)
|
||||
Actor constructor: can be used to create single or multipart
|
||||
"""Actor constructor: can be used to create single or multipart
|
||||
actors. If another Actor is supplied as an argument this
|
||||
method acts like a copy constructor. Single part actors are
|
||||
created by calling with a model and animation dictionary
|
||||
(animName:animPath{}) as follows:
|
||||
``(animName:animPath{})`` as follows::
|
||||
|
||||
a = Actor("panda-3k.egg", {"walk":"panda-walk.egg" \
|
||||
a = Actor("panda-3k.egg", {"walk":"panda-walk.egg",
|
||||
"run":"panda-run.egg"})
|
||||
|
||||
This could be displayed and animated as such:
|
||||
This could be displayed and animated as such::
|
||||
|
||||
a.reparentTo(render)
|
||||
a.loop("walk")
|
||||
a.stop()
|
||||
|
||||
Multipart actors expect a dictionary of parts and a dictionary
|
||||
of animation dictionaries (partName:(animName:animPath{}){}) as
|
||||
below:
|
||||
of animation dictionaries ``(partName:(animName:animPath{}){})``
|
||||
as below::
|
||||
|
||||
a = Actor(
|
||||
|
||||
# part dictionary
|
||||
{"head":"char/dogMM/dogMM_Shorts-head-mod", \
|
||||
"torso":"char/dogMM/dogMM_Shorts-torso-mod", \
|
||||
"legs":"char/dogMM/dogMM_Shorts-legs-mod"}, \
|
||||
{"head": "char/dogMM/dogMM_Shorts-head-mod",
|
||||
"torso": "char/dogMM/dogMM_Shorts-torso-mod",
|
||||
"legs": "char/dogMM/dogMM_Shorts-legs-mod"},
|
||||
|
||||
# dictionary of anim dictionaries
|
||||
{"head":{"walk":"char/dogMM/dogMM_Shorts-head-walk", \
|
||||
"run":"char/dogMM/dogMM_Shorts-head-run"}, \
|
||||
"torso":{"walk":"char/dogMM/dogMM_Shorts-torso-walk", \
|
||||
"run":"char/dogMM/dogMM_Shorts-torso-run"}, \
|
||||
"legs":{"walk":"char/dogMM/dogMM_Shorts-legs-walk", \
|
||||
"run":"char/dogMM/dogMM_Shorts-legs-run"} \
|
||||
{"head":{"walk": "char/dogMM/dogMM_Shorts-head-walk",
|
||||
"run": "char/dogMM/dogMM_Shorts-head-run"},
|
||||
"torso":{"walk": "char/dogMM/dogMM_Shorts-torso-walk",
|
||||
"run": "char/dogMM/dogMM_Shorts-torso-run"},
|
||||
"legs":{"walk": "char/dogMM/dogMM_Shorts-legs-walk",
|
||||
"run": "char/dogMM/dogMM_Shorts-legs-run"}
|
||||
})
|
||||
|
||||
In addition multipart actor parts need to be connected together
|
||||
in a meaningful fashion:
|
||||
in a meaningful fashion::
|
||||
|
||||
a.attach("head", "torso", "joint-head")
|
||||
a.attach("torso", "legs", "joint-hips")
|
||||
|
|
@ -151,7 +149,7 @@ class Actor(DirectObject, NodePath):
|
|||
# ADD LOD COMMENT HERE!
|
||||
#
|
||||
|
||||
Other useful Actor class functions:
|
||||
Other useful Actor class functions::
|
||||
|
||||
#fix actor eye rendering
|
||||
a.drawInFront("joint-pupil?", "eyes*")
|
||||
|
|
@ -1135,7 +1133,7 @@ class Actor(DirectObject, NodePath):
|
|||
def getJoints(self, partName = None, jointName = '*', lodName = None):
|
||||
""" Returns the list of all joints, from the named part or
|
||||
from all parts, that match the indicated jointName. The
|
||||
jointName may include pattern characters like *. """
|
||||
jointName may include pattern characters like \\*. """
|
||||
|
||||
joints=[]
|
||||
pattern = GlobPattern(jointName)
|
||||
|
|
@ -2439,15 +2437,15 @@ class Actor(DirectObject, NodePath):
|
|||
return ActorInterval.ActorInterval(self, *args, **kw)
|
||||
|
||||
def getAnimBlends(self, animName=None, partName=None, lodName=None):
|
||||
""" Returns a list of the form:
|
||||
"""Returns a list of the form::
|
||||
|
||||
[ (lodName, [(animName, [(partName, effect), (partName, effect), ...]),
|
||||
(animName, [(partName, effect), (partName, effect), ...]),
|
||||
...]),
|
||||
(lodName, [(animName, [(partName, effect), (partName, effect), ...]),
|
||||
(animName, [(partName, effect), (partName, effect), ...]),
|
||||
...]),
|
||||
... ]
|
||||
[ (lodName, [(animName, [(partName, effect), (partName, effect), ...]),
|
||||
(animName, [(partName, effect), (partName, effect), ...]),
|
||||
...]),
|
||||
(lodName, [(animName, [(partName, effect), (partName, effect), ...]),
|
||||
(animName, [(partName, effect), (partName, effect), ...]),
|
||||
...]),
|
||||
... ]
|
||||
|
||||
This list reports the non-zero control effects for each
|
||||
partName within a particular animation and LOD. """
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""ClusterClient: Master for mutli-piping or PC clusters. """
|
||||
"""ClusterClient: Master for multi-piping or PC clusters."""
|
||||
|
||||
from panda3d.core import *
|
||||
from .ClusterMsgs import *
|
||||
|
|
@ -8,6 +8,7 @@ from direct.showbase import DirectObject
|
|||
from direct.task import Task
|
||||
import os
|
||||
|
||||
|
||||
class ClusterClient(DirectObject.DirectObject):
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("ClusterClient")
|
||||
MGR_NUM = 1000000
|
||||
|
|
|
|||
|
|
@ -1,23 +1,26 @@
|
|||
|
||||
from .ClusterClient import *
|
||||
|
||||
# A dictionary of information for various cluster configurations.
|
||||
# Dictionary is keyed on cluster-config string
|
||||
# Each dictionary contains a list of display configurations, one for
|
||||
# each display in the cluster
|
||||
# Information that can be specified for each display:
|
||||
# display name: Name of display (used in Configrc to specify server)
|
||||
# display type: Used to flag client vs. server
|
||||
# pos: positional offset of display's camera from main cluster group
|
||||
# hpr: orientation offset of display's camera from main cluster group
|
||||
# focal length: display's focal length (in mm)
|
||||
# film size: display's film size (in inches)
|
||||
# film offset: offset of film back (in inches)
|
||||
# Note: Note, this overrides offsets specified in DirectCamConfig.py
|
||||
# For now we only specify frustum for first display region of configuration
|
||||
# TODO: Need to handle multiple display regions per cluster node and to
|
||||
# generalize to non cluster situations
|
||||
|
||||
#: A dictionary of information for various cluster configurations.
|
||||
#: Dictionary is keyed on cluster-config string
|
||||
#: Each dictionary contains a list of display configurations, one for
|
||||
#: each display in the cluster
|
||||
#:
|
||||
#: Information that can be specified for each display:
|
||||
#:
|
||||
#: - display name: Name of display (used in Configrc to specify server)
|
||||
#: - display type: Used to flag client vs. server
|
||||
#: - pos: positional offset of display's camera from main cluster group
|
||||
#: - hpr: orientation offset of display's camera from main cluster group
|
||||
#: - focal length: display's focal length (in mm)
|
||||
#: - film size: display's film size (in inches)
|
||||
#: - film offset: offset of film back (in inches)
|
||||
#:
|
||||
#: Note: this overrides offsets specified in DirectCamConfig.py
|
||||
#: For now we only specify frustum for first display region of configuration
|
||||
#:
|
||||
#: TODO: Need to handle multiple display regions per cluster node and to
|
||||
#: generalize to non cluster situations
|
||||
ClientConfigs = {
|
||||
'single-server': [{'display name': 'display0',
|
||||
'display mode': 'client',
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@ from direct.directnotify import DirectNotifyGlobal
|
|||
from direct.task import Task
|
||||
from panda3d.core import ConfigVariableBool
|
||||
|
||||
CollisionHandlerRayStart = 4000.0 # This is a hack, it may be better to use a line instead of a ray.
|
||||
# This is a hack, it may be better to use a line instead of a ray.
|
||||
CollisionHandlerRayStart = 4000.0
|
||||
|
||||
|
||||
class ControlManager:
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("ControlManager")
|
||||
|
|
@ -52,14 +54,14 @@ class ControlManager:
|
|||
return 'ControlManager: using \'%s\'' % self.currentControlsName
|
||||
|
||||
def add(self, controls, name="basic"):
|
||||
"""
|
||||
controls is an avatar control system.
|
||||
name is any key that you want to use to refer to the
|
||||
the controls later (e.g. using the use(<name>) call).
|
||||
"""Add a control instance to the list of available control systems.
|
||||
|
||||
Add a control instance to the list of available control systems.
|
||||
Args:
|
||||
controls: an avatar control system.
|
||||
name (str): any key that you want to use to refer to the controls
|
||||
later (e.g. using the use(<name>) call).
|
||||
|
||||
See also: use().
|
||||
See also: :meth:`use()`.
|
||||
"""
|
||||
assert self.notify.debugCall(id(self))
|
||||
assert controls is not None
|
||||
|
|
@ -77,15 +79,14 @@ class ControlManager:
|
|||
return self.controls.get(name)
|
||||
|
||||
def remove(self, name):
|
||||
"""
|
||||
name is any key that was used to refer to the
|
||||
the controls when they were added (e.g.
|
||||
using the add(<controls>, <name>) call).
|
||||
"""Remove a control instance from the list of available control
|
||||
systems.
|
||||
|
||||
Remove a control instance from the list of
|
||||
available control systems.
|
||||
Args:
|
||||
name: any key that was used to refer to the controls when they were
|
||||
added (e.g. using the add(<controls>, <name>) call).
|
||||
|
||||
See also: add().
|
||||
See also: :meth:`add()`.
|
||||
"""
|
||||
assert self.notify.debugCall(id(self))
|
||||
oldControls = self.controls.pop(name,None)
|
||||
|
|
@ -108,7 +109,7 @@ class ControlManager:
|
|||
|
||||
Use a previously added control system.
|
||||
|
||||
See also: add().
|
||||
See also: :meth:`add()`.
|
||||
"""
|
||||
assert self.notify.debugCall(id(self))
|
||||
if __debug__ and hasattr(self, "ignoreUse"):
|
||||
|
|
|
|||
|
|
@ -2,15 +2,17 @@
|
|||
DevWalker.py is for avatars.
|
||||
|
||||
A walker control such as this one provides:
|
||||
- creation of the collision nodes
|
||||
- handling the keyboard and mouse input for avatar movement
|
||||
- moving the avatar
|
||||
|
||||
- creation of the collision nodes
|
||||
- handling the keyboard and mouse input for avatar movement
|
||||
- moving the avatar
|
||||
|
||||
it does not:
|
||||
- play sounds
|
||||
- play animations
|
||||
|
||||
although it does send messeges that allow a listener to play sounds or
|
||||
- play sounds
|
||||
- play animations
|
||||
|
||||
although it does send messages that allow a listener to play sounds or
|
||||
animations based on walker events.
|
||||
"""
|
||||
|
||||
|
|
|
|||
|
|
@ -2,15 +2,17 @@
|
|||
GhostWalker.py is for avatars.
|
||||
|
||||
A walker control such as this one provides:
|
||||
- creation of the collision nodes
|
||||
- handling the keyboard and mouse input for avatar movement
|
||||
- moving the avatar
|
||||
|
||||
- creation of the collision nodes
|
||||
- handling the keyboard and mouse input for avatar movement
|
||||
- moving the avatar
|
||||
|
||||
it does not:
|
||||
- play sounds
|
||||
- play animations
|
||||
|
||||
although it does send messeges that allow a listener to play sounds or
|
||||
- play sounds
|
||||
- play animations
|
||||
|
||||
although it does send messages that allow a listener to play sounds or
|
||||
animations based on walker events.
|
||||
"""
|
||||
|
||||
|
|
|
|||
|
|
@ -2,15 +2,17 @@
|
|||
GravityWalker.py is for avatars.
|
||||
|
||||
A walker control such as this one provides:
|
||||
- creation of the collision nodes
|
||||
- handling the keyboard and mouse input for avatar movement
|
||||
- moving the avatar
|
||||
|
||||
- creation of the collision nodes
|
||||
- handling the keyboard and mouse input for avatar movement
|
||||
- moving the avatar
|
||||
|
||||
it does not:
|
||||
- play sounds
|
||||
- play animations
|
||||
|
||||
although it does send messeges that allow a listener to play sounds or
|
||||
- play sounds
|
||||
- play animations
|
||||
|
||||
although it does send messages that allow a listener to play sounds or
|
||||
animations based on walker events.
|
||||
"""
|
||||
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||||
|
|
|
|||
|
|
@ -135,14 +135,16 @@ class InputState(DirectObject.DirectObject):
|
|||
|
||||
def watch(self, name, eventOn, eventOff, startState=False, inputSource=None):
|
||||
"""
|
||||
This returns a token; hold onto the token and call token.release() when you
|
||||
no longer want to watch for these events.
|
||||
This returns a token; hold onto the token and call token.release() when
|
||||
you no longer want to watch for these events.
|
||||
|
||||
# set up
|
||||
token = inputState.watch('forward', 'w', 'w-up', inputSource=inputState.WASD)
|
||||
...
|
||||
# tear down
|
||||
token.release()
|
||||
Example::
|
||||
|
||||
# set up
|
||||
token = inputState.watch('forward', 'w', 'w-up', inputSource=inputState.WASD)
|
||||
...
|
||||
# tear down
|
||||
token.release()
|
||||
"""
|
||||
assert self.debugPrint(
|
||||
"watch(name=%s, eventOn=%s, eventOff=%s, startState=%s)"%(
|
||||
|
|
@ -191,15 +193,16 @@ class InputState(DirectObject.DirectObject):
|
|||
"""
|
||||
Force isSet(name) to return 'value'.
|
||||
|
||||
This returns a token; hold onto the token and call token.release() when you
|
||||
no longer want to force the state.
|
||||
This returns a token; hold onto the token and call token.release() when
|
||||
you no longer want to force the state.
|
||||
|
||||
example:
|
||||
# set up
|
||||
token=inputState.force('forward', True, inputSource='myForwardForcer')
|
||||
...
|
||||
# tear down
|
||||
token.release()
|
||||
Example::
|
||||
|
||||
# set up
|
||||
token = inputState.force('forward', True, inputSource='myForwardForcer')
|
||||
...
|
||||
# tear down
|
||||
token.release()
|
||||
"""
|
||||
token = InputStateForceToken(self)
|
||||
self._token2forceInfo[token] = (name, inputSource)
|
||||
|
|
|
|||
|
|
@ -2,15 +2,17 @@
|
|||
NonPhysicsWalker.py is for avatars.
|
||||
|
||||
A walker control such as this one provides:
|
||||
- creation of the collision nodes
|
||||
- handling the keyboard and mouse input for avatar movement
|
||||
- moving the avatar
|
||||
|
||||
- creation of the collision nodes
|
||||
- handling the keyboard and mouse input for avatar movement
|
||||
- moving the avatar
|
||||
|
||||
it does not:
|
||||
- play sounds
|
||||
- play animations
|
||||
|
||||
although it does send messeges that allow a listener to play sounds or
|
||||
- play sounds
|
||||
- play animations
|
||||
|
||||
although it does send messages that allow a listener to play sounds or
|
||||
animations based on walker events.
|
||||
"""
|
||||
|
||||
|
|
|
|||
|
|
@ -2,15 +2,17 @@
|
|||
ObserverWalker.py is for avatars.
|
||||
|
||||
A walker control such as this one provides:
|
||||
- creation of the collision nodes
|
||||
- handling the keyboard and mouse input for avatar movement
|
||||
- moving the avatar
|
||||
|
||||
- creation of the collision nodes
|
||||
- handling the keyboard and mouse input for avatar movement
|
||||
- moving the avatar
|
||||
|
||||
it does not:
|
||||
- play sounds
|
||||
- play animations
|
||||
|
||||
although it does send messeges that allow a listener to play sounds or
|
||||
- play sounds
|
||||
- play animations
|
||||
|
||||
although it does send messages that allow a listener to play sounds or
|
||||
animations based on walker events.
|
||||
"""
|
||||
|
||||
|
|
|
|||
|
|
@ -2,15 +2,17 @@
|
|||
PhysicsWalker.py is for avatars.
|
||||
|
||||
A walker control such as this one provides:
|
||||
- creation of the collision nodes
|
||||
- handling the keyboard and mouse input for avatar movement
|
||||
- moving the avatar
|
||||
|
||||
- creation of the collision nodes
|
||||
- handling the keyboard and mouse input for avatar movement
|
||||
- moving the avatar
|
||||
|
||||
it does not:
|
||||
- play sounds
|
||||
- play animations
|
||||
|
||||
although it does send messeges that allow a listener to play sounds or
|
||||
- play sounds
|
||||
- play animations
|
||||
|
||||
although it does send messages that allow a listener to play sounds or
|
||||
animations based on walker events.
|
||||
"""
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
TwoDWalker.py is for controling the avatars in a 2D Scroller game environment.
|
||||
TwoDWalker.py is for controlling the avatars in a 2D scroller game environment.
|
||||
"""
|
||||
|
||||
from .GravityWalker import *
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
""" Class used to create and control vrpn devices """
|
||||
"""Class used to create and control VRPN devices."""
|
||||
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
from panda3d.core import *
|
||||
|
|
|
|||
|
|
@ -1,8 +1,12 @@
|
|||
"""instantiate global DirectNotify used in Direct"""
|
||||
"""Instantiates global DirectNotify used in Direct."""
|
||||
|
||||
__all__ = ['directNotify', 'giveNotify']
|
||||
|
||||
from . import DirectNotify
|
||||
|
||||
#: The global :class:`~.DirectNotify.DirectNotify` object.
|
||||
directNotify = DirectNotify.DirectNotify()
|
||||
|
||||
#: Shorthand function for adding a DirectNotify category to a given class
|
||||
#: object. Alias of `.DirectNotify.DirectNotify.giveNotify`.
|
||||
giveNotify = directNotify.giveNotify
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
"""instantiate global Logger object"""
|
||||
"""Instantiates a global :class:`~.Logger.Logger` object."""
|
||||
|
||||
from . import Logger
|
||||
|
||||
#: Contains a global :class:`~.Logger.Logger` object.
|
||||
defaultLogger = Logger.Logger()
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ from panda3d.core import ConfigVariableBool, NotifyCategory, StreamWriter, Notif
|
|||
import time
|
||||
import sys
|
||||
|
||||
|
||||
class Notifier:
|
||||
serverDelta = 0
|
||||
|
||||
|
|
@ -23,12 +24,11 @@ class Notifier:
|
|||
|
||||
def __init__(self, name, logger=None):
|
||||
"""
|
||||
name is a string
|
||||
logger is a Logger
|
||||
|
||||
Create a new instance of the Notifier class with a given name
|
||||
and an optional Logger class for piping output to. If no logger
|
||||
specified, use the global default
|
||||
Parameters:
|
||||
name (str): a string name given to this Notifier instance.
|
||||
logger (Logger, optional): an optional Logger object for
|
||||
piping output to. If none is specified, the global
|
||||
:data:`~.LoggerGlobal.defaultLogger` is used.
|
||||
"""
|
||||
self.__name = name
|
||||
|
||||
|
|
|
|||
|
|
@ -1,8 +1,7 @@
|
|||
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
|
||||
class RotatingLog:
|
||||
"""
|
||||
A file() (or open()) replacement that will automatically open and write
|
||||
|
|
@ -11,22 +10,23 @@ class RotatingLog:
|
|||
|
||||
def __init__(self, path="./log_file", hourInterval=24, megabyteLimit=1024):
|
||||
"""
|
||||
path is a full or partial path with file name.
|
||||
hourInterval is the number of hours at which to rotate the file.
|
||||
megabyteLimit is the number of megabytes of file size the log
|
||||
may grow to, after which the log is rotated. Note: The log
|
||||
file may get a bit larger than limit do to writing out whole
|
||||
lines (last line may exceed megabyteLimit or "megabyteGuidline").
|
||||
Args:
|
||||
path: a full or partial path with file name.
|
||||
hourInterval: the number of hours at which to rotate the file.
|
||||
megabyteLimit: the number of megabytes of file size the log may
|
||||
grow to, after which the log is rotated. Note: The log file
|
||||
may get a bit larger than limit do to writing out whole lines
|
||||
(last line may exceed megabyteLimit or "megabyteGuidline").
|
||||
"""
|
||||
self.path=path
|
||||
self.timeInterval=None
|
||||
self.timeLimit=None
|
||||
self.sizeLimit=None
|
||||
self.path = path
|
||||
self.timeInterval = None
|
||||
self.timeLimit = None
|
||||
self.sizeLimit = None
|
||||
if hourInterval is not None:
|
||||
self.timeInterval=hourInterval*60*60
|
||||
self.timeLimit=time.time()+self.timeInterval
|
||||
self.timeInterval = hourInterval*60*60
|
||||
self.timeLimit = time.time()+self.timeInterval
|
||||
if megabyteLimit is not None:
|
||||
self.sizeLimit=megabyteLimit*1024*1024
|
||||
self.sizeLimit = megabyteLimit*1024*1024
|
||||
|
||||
def __del__(self):
|
||||
self.close()
|
||||
|
|
|
|||
|
|
@ -1,27 +1,31 @@
|
|||
"""
|
||||
You can use verify() just like assert, with these small differences:
|
||||
- you may need to "import Verify", if someone hasn't done it
|
||||
for you.
|
||||
- unlike assert where using parenthises are optional, verify()
|
||||
requires them.
|
||||
e.g.:
|
||||
assert foo # OK
|
||||
verify foo # Error
|
||||
assert foo # Not Recomended (may be interpreted as a tuple)
|
||||
verify(foo) # OK
|
||||
- verify() will print something like the following before raising
|
||||
an exception:
|
||||
verify failed:
|
||||
File "direct/src/showbase/ShowBase.py", line 60
|
||||
- verify() will optionally start pdb for you (this is currently
|
||||
false by default). You can either edit Verify.py to set
|
||||
wantVerifyPdb = 1 or if you are using ShowBase you can set
|
||||
want-verify-pdb 1 in your Configrc to start pdb automatically.
|
||||
- verify() will still function in the release build. It will
|
||||
not be removed by -O like assert will.
|
||||
You can use :func:`verify()` just like assert, with these small differences:
|
||||
|
||||
verify() will also throw an AssertionError, but you can ignore that if you
|
||||
like (I don't suggest trying to catch it, it's just doing it so that it can
|
||||
- you may need to ``import Verify``, if someone hasn't done it for you.
|
||||
|
||||
- unlike assert where using parentheses are optional, :func:`verify()`
|
||||
requires them, e.g.::
|
||||
|
||||
assert foo # OK
|
||||
verify foo # Error
|
||||
assert foo # Not Recomended (may be interpreted as a tuple)
|
||||
verify(foo) # OK
|
||||
|
||||
- :func:`verify()` will print something like this before raising an exception::
|
||||
|
||||
verify failed:
|
||||
File "direct/src/showbase/ShowBase.py", line 60
|
||||
|
||||
- :func:`verify()` will optionally start pdb for you (this is currently false
|
||||
by default). You can either edit Verify.py to set ``wantVerifyPdb = 1`` or
|
||||
if you are using ShowBase you can set ``want-verify-pdb 1`` in your
|
||||
Config.prc file to start pdb automatically.
|
||||
|
||||
- :func:`verify()` will still function in the release build. It will not be
|
||||
removed by -O like assert will.
|
||||
|
||||
:func:`verify()` will also throw an AssertionError, but you can ignore that if
|
||||
you like (I don't suggest trying to catch it, it's just doing it so that it can
|
||||
replace assert more fully).
|
||||
|
||||
Please do not use assert for things that you want run on release builds.
|
||||
|
|
@ -31,19 +35,20 @@ an exception can get it mistaken for an error handler. If your code
|
|||
needs to handle an error or throw an exception, you should do that
|
||||
(and not just assert for it).
|
||||
|
||||
If you want to be a super keen software engineer then avoid using verify().
|
||||
If you want to be, or already are, a super keen software engineer, but
|
||||
you don't always have the time to write proper error handling, go ahead
|
||||
and use verify() -- that's what it's for.
|
||||
If you want to be a super keen software engineer then avoid using
|
||||
:func:`verify()`. If you want to be, or already are, a super keen software
|
||||
engineer, but you don't always have the time to write proper error handling,
|
||||
go ahead and use :func:`verify()` -- that's what it's for.
|
||||
|
||||
Please use assert (properly) and do proper error handling; and use verify()
|
||||
only when debugging (i.e. when it won't be checked-in) or where it helps
|
||||
you resist using assert for error handling.
|
||||
Please use assert (properly) and do proper error handling; and use
|
||||
:func:`verify()` only when debugging (i.e. when it won't be checked-in) or
|
||||
where it helps you resist using assert for error handling.
|
||||
"""
|
||||
|
||||
from panda3d.core import ConfigVariableBool
|
||||
|
||||
wantVerifyPdb = ConfigVariableBool('want-verify-pdb', False) # Set to true to load pdb on failure.
|
||||
# Set to true to load pdb on failure.
|
||||
wantVerifyPdb = ConfigVariableBool('want-verify-pdb', False)
|
||||
|
||||
|
||||
def verify(assertion):
|
||||
|
|
@ -54,7 +59,7 @@ def verify(assertion):
|
|||
if not assertion:
|
||||
print("\n\nverify failed:")
|
||||
import sys
|
||||
print(" File \"%s\", line %d"%(
|
||||
print(" File \"%s\", line %d" % (
|
||||
sys._getframe(1).f_code.co_filename,
|
||||
sys._getframe(1).f_lineno))
|
||||
if wantVerifyPdb:
|
||||
|
|
@ -62,5 +67,6 @@ def verify(assertion):
|
|||
pdb.set_trace()
|
||||
raise AssertionError
|
||||
|
||||
|
||||
if not hasattr(__builtins__, "verify"):
|
||||
__builtins__["verify"] = verify
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
"""This package contains tools to help with distributing Panda3D
|
||||
applications. See the :ref:`distribution` section in the programming
|
||||
manual for further details.
|
||||
"""
|
||||
|
|
@ -1,3 +1,9 @@
|
|||
"""Extends setuptools with the ``build_apps`` and ``bdist_apps`` commands.
|
||||
|
||||
See the :ref:`distribution` section of the programming manual for information
|
||||
on how to use these commands.
|
||||
"""
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
import collections
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@ if __debug__:
|
|||
|
||||
class AsyncRequest(DirectObject):
|
||||
"""
|
||||
This class is used to make asynchronos reads and creates to a database.
|
||||
This class is used to make asynchronous reads and creates to a database.
|
||||
|
||||
You can create a list of self.neededObjects and then ask for each to be
|
||||
read or created, or if you only have one object that you need you can
|
||||
|
|
|
|||
|
|
@ -26,11 +26,12 @@ ESNum2Str = {
|
|||
ESGenerated: 'ESGenerated',
|
||||
}
|
||||
|
||||
|
||||
class DistributedObject(DistributedObjectBase):
|
||||
"""
|
||||
The Distributed Object class is the base class for all network based
|
||||
(i.e. distributed) objects. These will usually (always?) have a
|
||||
dclass entry in a *.dc file.
|
||||
dclass entry in a \\*.dc file.
|
||||
"""
|
||||
notify = directNotify.newCategory("DistributedObject")
|
||||
|
||||
|
|
|
|||
|
|
@ -1,11 +1,12 @@
|
|||
from direct.showbase.DirectObject import DirectObject
|
||||
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||||
|
||||
|
||||
class DistributedObjectBase(DirectObject):
|
||||
"""
|
||||
The Distributed Object class is the base class for all network based
|
||||
(i.e. distributed) objects. These will usually (always?) have a
|
||||
dclass entry in a *.dc file.
|
||||
dclass entry in a \\*.dc file.
|
||||
"""
|
||||
notify = directNotify.newCategory("DistributedObjectBase")
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import re
|
|||
BAD_DO_ID = BAD_ZONE_ID = 0 # 0xFFFFFFFF
|
||||
BAD_CHANNEL_ID = 0 # 0xFFFFFFFFFFFFFFFF
|
||||
|
||||
|
||||
class DoCollectionManager:
|
||||
def __init__(self):
|
||||
# Dict of {DistributedObject ids: DistributedObjects}
|
||||
|
|
@ -186,7 +187,6 @@ class DoCollectionManager:
|
|||
strToReturn = '%s%s' % (strToReturn, self._returnObjects(self.getDoTable(ownerView=False)))
|
||||
return strToReturn
|
||||
|
||||
|
||||
def printObjectCount(self):
|
||||
# print object counts by distributed object type
|
||||
print('==== OBJECT COUNT ====')
|
||||
|
|
@ -199,13 +199,14 @@ class DoCollectionManager:
|
|||
|
||||
def getDoList(self, parentId, zoneId=None, classType=None):
|
||||
"""
|
||||
parentId is any distributed object id.
|
||||
zoneId is a uint32, defaults to None (all zones). Try zone 2 if
|
||||
you're not sure which zone to use (0 is a bad/null zone and
|
||||
1 has had reserved use in the past as a no messages zone, while
|
||||
2 has traditionally been a global, uber, misc stuff zone).
|
||||
dclassType is a distributed class type filter, defaults
|
||||
to None (no filter).
|
||||
Args:
|
||||
parentId: any distributed object id.
|
||||
zoneId: a uint32, defaults to None (all zones). Try zone 2 if
|
||||
you're not sure which zone to use (0 is a bad/null zone and
|
||||
1 has had reserved use in the past as a no messages zone, while
|
||||
2 has traditionally been a global, uber, misc stuff zone).
|
||||
dclassType: a distributed class type filter, defaults to None
|
||||
(no filter).
|
||||
|
||||
If dclassName is None then all objects in the zone are returned;
|
||||
otherwise the list is filtered to only include objects of that type.
|
||||
|
|
|
|||
|
|
@ -26,15 +26,14 @@ class DoHierarchy:
|
|||
|
||||
def getDoIds(self, getDo, parentId, zoneId=None, classType=None):
|
||||
"""
|
||||
Moved from DoCollectionManager
|
||||
==============================
|
||||
parentId is any distributed object id.
|
||||
zoneId is a uint32, defaults to None (all zones). Try zone 2 if
|
||||
you're not sure which zone to use (0 is a bad/null zone and
|
||||
1 has had reserved use in the past as a no messages zone, while
|
||||
2 has traditionally been a global, uber, misc stuff zone).
|
||||
dclassType is a distributed class type filter, defaults
|
||||
to None (no filter).
|
||||
Args:
|
||||
parentId: any distributed object id.
|
||||
zoneId: a uint32, defaults to None (all zones). Try zone 2 if
|
||||
you're not sure which zone to use (0 is a bad/null zone and
|
||||
1 has had reserved use in the past as a no messages zone, while
|
||||
2 has traditionally been a global, uber, misc stuff zone).
|
||||
dclassType: a distributed class type filter, defaults to None
|
||||
(no filter).
|
||||
|
||||
If dclassName is None then all objects in the zone are returned;
|
||||
otherwise the list is filtered to only include objects of that type.
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ from panda3d.direct import *
|
|||
|
||||
from direct.distributed.MsgTypes import *
|
||||
|
||||
|
||||
class PyDatagram(Datagram):
|
||||
|
||||
# This is a little helper Dict to replace the huge <if> statement
|
||||
|
|
@ -29,8 +30,6 @@ class PyDatagram(Datagram):
|
|||
STBlob32: (Datagram.addBlob32, None),
|
||||
}
|
||||
|
||||
#def addChannel(self, channelId):
|
||||
# ...
|
||||
addChannel = Datagram.addUint64
|
||||
|
||||
def addServerHeader(self, channel, sender, code):
|
||||
|
|
@ -39,14 +38,12 @@ class PyDatagram(Datagram):
|
|||
self.addChannel(sender)
|
||||
self.addUint16(code)
|
||||
|
||||
|
||||
def addOldServerHeader(self, channel, sender, code):
|
||||
self.addChannel(channel)
|
||||
self.addChannel(sender)
|
||||
self.addChannel('A')
|
||||
self.addUint16(code)
|
||||
|
||||
|
||||
def addServerControlHeader(self, code):
|
||||
self.addInt8(1)
|
||||
self.addChannel(CONTROL_CHANNEL)
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ from panda3d.core import *
|
|||
from panda3d.direct import *
|
||||
# Import the type numbers
|
||||
|
||||
|
||||
class PyDatagramIterator(DatagramIterator):
|
||||
|
||||
# This is a little helper Dict to replace the huge <if> statement
|
||||
|
|
|
|||
|
|
@ -1,9 +1,8 @@
|
|||
"""Finite State Machine module: contains the ClassicFSM class.
|
||||
|
||||
.. note::
|
||||
|
||||
This module and class exist only for backward compatibility with
|
||||
existing code. New code should use the :mod:`.FSM` module instead.
|
||||
Note:
|
||||
This module and class exist only for backward compatibility with
|
||||
existing code. New code should use the :mod:`.FSM` module instead.
|
||||
"""
|
||||
|
||||
__all__ = ['ClassicFSM']
|
||||
|
|
@ -14,12 +13,14 @@ import weakref
|
|||
|
||||
if __debug__:
|
||||
_debugFsms = {}
|
||||
|
||||
def printDebugFsmList():
|
||||
global _debugFsms
|
||||
for k in sorted(_debugFsms.keys()):
|
||||
print("%s %s" % (k, _debugFsms[k]()))
|
||||
__builtins__['debugFsmList'] = printDebugFsmList
|
||||
|
||||
|
||||
class ClassicFSM(DirectObject):
|
||||
"""
|
||||
Finite State Machine class.
|
||||
|
|
@ -45,14 +46,14 @@ class ClassicFSM(DirectObject):
|
|||
"""__init__(self, string, State[], string, string, int)
|
||||
|
||||
ClassicFSM constructor: takes name, list of states, initial state and
|
||||
final state as:
|
||||
final state as::
|
||||
|
||||
fsm = ClassicFSM.ClassicFSM('stopLight',
|
||||
[State.State('red', enterRed, exitRed, ['green']),
|
||||
State.State('yellow', enterYellow, exitYellow, ['red']),
|
||||
State.State('green', enterGreen, exitGreen, ['yellow'])],
|
||||
'red',
|
||||
'red')
|
||||
fsm = ClassicFSM.ClassicFSM('stopLight',
|
||||
[State.State('red', enterRed, exitRed, ['green']),
|
||||
State.State('yellow', enterYellow, exitYellow, ['red']),
|
||||
State.State('green', enterGreen, exitGreen, ['yellow'])],
|
||||
'red',
|
||||
'red')
|
||||
|
||||
each state's last argument, a list of allowed state transitions,
|
||||
is optional; if left out (or explicitly specified to be
|
||||
|
|
|
|||
|
|
@ -1,5 +1,8 @@
|
|||
"""The new Finite State Machine module. This replaces the module
|
||||
previously called FSM (now called :mod:`.ClassicFSM`).
|
||||
|
||||
For more information on FSMs, consult the :ref:`finite-state-machines` section
|
||||
of the programming manual.
|
||||
"""
|
||||
|
||||
__all__ = ['FSMException', 'FSM']
|
||||
|
|
@ -14,12 +17,15 @@ from direct.stdpy.threading import RLock
|
|||
class FSMException(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class AlreadyInTransition(FSMException):
|
||||
pass
|
||||
|
||||
|
||||
class RequestDenied(FSMException):
|
||||
pass
|
||||
|
||||
|
||||
class FSM(DirectObject):
|
||||
"""
|
||||
A Finite State Machine. This is intended to be the base class
|
||||
|
|
@ -34,25 +40,25 @@ class FSM(DirectObject):
|
|||
|
||||
To define specialized behavior when entering or exiting a
|
||||
particular state, define a method named enterState() and/or
|
||||
exitState(), where "State" is the name of the state, e.g.:
|
||||
exitState(), where "State" is the name of the state, e.g.::
|
||||
|
||||
def enterRed(self):
|
||||
... do stuff ...
|
||||
def enterRed(self):
|
||||
... do stuff ...
|
||||
|
||||
def exitRed(self):
|
||||
... cleanup stuff ...
|
||||
def exitRed(self):
|
||||
... cleanup stuff ...
|
||||
|
||||
def enterYellow(self):
|
||||
... do stuff ...
|
||||
def enterYellow(self):
|
||||
... do stuff ...
|
||||
|
||||
def exitYellow(self):
|
||||
... cleanup stuff ...
|
||||
def exitYellow(self):
|
||||
... cleanup stuff ...
|
||||
|
||||
def enterGreen(self):
|
||||
... do stuff ...
|
||||
def enterGreen(self):
|
||||
... do stuff ...
|
||||
|
||||
def exitGreen(self):
|
||||
... cleanup stuff ...
|
||||
def exitGreen(self):
|
||||
... cleanup stuff ...
|
||||
|
||||
Both functions can access the previous state name as
|
||||
self.oldState, and the new state name we are transitioning to as
|
||||
|
|
@ -70,22 +76,22 @@ class FSM(DirectObject):
|
|||
input is always a string and a tuple of optional parameters (which
|
||||
is often empty), and the return value should either be None to do
|
||||
nothing, or the name of the state to transition into. For
|
||||
example:
|
||||
example::
|
||||
|
||||
def filterRed(self, request, args):
|
||||
if request in ['Green']:
|
||||
return (request,) + args
|
||||
return None
|
||||
def filterRed(self, request, args):
|
||||
if request in ['Green']:
|
||||
return (request,) + args
|
||||
return None
|
||||
|
||||
def filterYellow(self, request, args):
|
||||
if request in ['Red']:
|
||||
return (request,) + args
|
||||
return None
|
||||
def filterYellow(self, request, args):
|
||||
if request in ['Red']:
|
||||
return (request,) + args
|
||||
return None
|
||||
|
||||
def filterGreen(self, request, args):
|
||||
if request in ['Yellow']:
|
||||
return (request,) + args
|
||||
return None
|
||||
def filterGreen(self, request, args):
|
||||
if request in ['Yellow']:
|
||||
return (request,) + args
|
||||
return None
|
||||
|
||||
As above, the filterState() functions are optional. If any is
|
||||
omitted, the defaultFilter() method is called instead. A standard
|
||||
|
|
|
|||
|
|
@ -44,25 +44,22 @@ class FourState:
|
|||
|
||||
def __init__(self, names, durations = [0, 1, None, 1, 1]):
|
||||
"""
|
||||
names is a list of state names
|
||||
Names is a list of state names. Some examples are::
|
||||
|
||||
E.g.
|
||||
['off', 'opening', 'open', 'closing', 'closed',]
|
||||
|
||||
e.g. 2:
|
||||
['off', 'locking', 'locked', 'unlocking', 'unlocked',]
|
||||
|
||||
e.g. 3:
|
||||
['off', 'deactivating', 'deactive', 'activating', 'activated',]
|
||||
|
||||
durations is a list of time values (floats) or None values.
|
||||
|
||||
Each list must have five entries.
|
||||
|
||||
More Details
|
||||
.. rubric:: More Details
|
||||
|
||||
Here is a diagram showing the where the names from the list
|
||||
are used:
|
||||
are used::
|
||||
|
||||
+---------+
|
||||
| 0 (off) |----> (any other state and vice versa).
|
||||
|
|
|
|||
|
|
@ -45,27 +45,25 @@ class FourStateAI:
|
|||
|
||||
def __init__(self, names, durations = [0, 1, None, 1, 1]):
|
||||
"""
|
||||
names is a list of state names
|
||||
E.g.
|
||||
['off', 'opening', 'open', 'closing', 'closed',]
|
||||
Names is a list of state names. Some examples are::
|
||||
|
||||
e.g. 2:
|
||||
['off', 'locking', 'locked', 'unlocking', 'unlocked',]
|
||||
['off', 'opening', 'open', 'closing', 'closed',]
|
||||
|
||||
e.g. 3:
|
||||
['off', 'deactivating', 'deactive', 'activating', 'activated',]
|
||||
['off', 'locking', 'locked', 'unlocking', 'unlocked',]
|
||||
|
||||
['off', 'deactivating', 'deactive', 'activating', 'activated',]
|
||||
|
||||
durations is a list of durations in seconds or None values.
|
||||
The list of duration values should be the same length
|
||||
as the list of state names and the lists correspond.
|
||||
For each state, after n seconds, the ClassicFSM will move to
|
||||
the next state. That does not happen for any duration
|
||||
values of None.
|
||||
The list of duration values should be the same length
|
||||
as the list of state names and the lists correspond.
|
||||
For each state, after n seconds, the ClassicFSM will move to
|
||||
the next state. That does not happen for any duration
|
||||
values of None.
|
||||
|
||||
More Details
|
||||
.. rubric:: More Details
|
||||
|
||||
Here is a diagram showing the where the names from the list
|
||||
are used:
|
||||
are used::
|
||||
|
||||
+---------+
|
||||
| 0 (off) |----> (any other state and vice versa).
|
||||
|
|
|
|||
|
|
@ -3,4 +3,7 @@ This package contains implementations of a Finite State Machine, an
|
|||
abstract construct that holds a particular state and can transition
|
||||
between several defined states. These are useful for a range of logic
|
||||
programming tasks.
|
||||
|
||||
For more information on FSMs, consult the :ref:`finite-state-machines` section
|
||||
of the programming manual.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
"""This module defines various dialog windows for the DirectGUI system."""
|
||||
|
||||
__all__ = ['findDialog', 'cleanupDialog', 'DirectDialog', 'OkDialog', 'OkCancelDialog', 'YesNoDialog', 'YesNoCancelDialog', 'RetryCancelDialog']
|
||||
__all__ = [
|
||||
'findDialog', 'cleanupDialog', 'DirectDialog', 'OkDialog',
|
||||
'OkCancelDialog', 'YesNoDialog', 'YesNoCancelDialog', 'RetryCancelDialog',
|
||||
]
|
||||
|
||||
from panda3d.core import *
|
||||
from direct.showbase import ShowBaseGlobal
|
||||
|
|
@ -9,9 +12,9 @@ from .DirectFrame import *
|
|||
from .DirectButton import *
|
||||
import types
|
||||
|
||||
def findDialog(uniqueName):
|
||||
"""findPanel(string uniqueName)
|
||||
|
||||
def findDialog(uniqueName):
|
||||
"""
|
||||
Returns the panel whose uniqueName is given. This is mainly
|
||||
useful for debugging, to get a pointer to the current onscreen
|
||||
panel of a particular type.
|
||||
|
|
@ -20,6 +23,7 @@ def findDialog(uniqueName):
|
|||
return DirectDialog.AllDialogs[uniqueName]
|
||||
return None
|
||||
|
||||
|
||||
def cleanupDialog(uniqueName):
|
||||
"""cleanupPanel(string uniqueName)
|
||||
|
||||
|
|
@ -35,52 +39,48 @@ def cleanupDialog(uniqueName):
|
|||
# self.cleanup() directly
|
||||
DirectDialog.AllDialogs[uniqueName].cleanup()
|
||||
|
||||
|
||||
class DirectDialog(DirectFrame):
|
||||
|
||||
AllDialogs = {}
|
||||
PanelIndex = 0
|
||||
|
||||
def __init__(self, parent = None, **kw):
|
||||
"""
|
||||
DirectDialog(kw)
|
||||
|
||||
Creates a popup dialog to alert and/or interact with user.
|
||||
def __init__(self, parent=None, **kw):
|
||||
"""Creates a popup dialog to alert and/or interact with user.
|
||||
Some of the main keywords that can be used to customize the dialog:
|
||||
Keyword Definition
|
||||
------- ----------
|
||||
text Text message/query displayed to user
|
||||
geom Geometry to be displayed in dialog
|
||||
buttonTextList List of text to show on each button
|
||||
buttonGeomList List of geometry to show on each button
|
||||
buttonImageList List of images to show on each button
|
||||
buttonValueList List of values sent to dialog command for
|
||||
each button. If value is [] then the
|
||||
ordinal rank of the button is used as
|
||||
its value
|
||||
buttonHotKeyList List of hotkeys to bind to each button.
|
||||
Typing hotkey is equivalent to pressing
|
||||
the corresponding button.
|
||||
suppressKeys Set to true if you wish to suppress keys
|
||||
(i.e. Dialog eats key event), false if
|
||||
you wish Dialog to pass along key event
|
||||
buttonSize 4-tuple used to specify custom size for
|
||||
each button (to make bigger then geom/text
|
||||
for example)
|
||||
pad Space between border and interior graphics
|
||||
topPad Extra space added above text/geom/image
|
||||
midPad Extra space added between text/buttons
|
||||
sidePad Extra space added to either side of
|
||||
text/buttons
|
||||
buttonPadSF Scale factor used to expand/contract
|
||||
button horizontal spacing
|
||||
command Callback command used when a button is
|
||||
pressed. Value supplied to command
|
||||
depends on values in buttonValueList
|
||||
|
||||
Note: Number of buttons on the dialog depends upon the maximum
|
||||
length of any button[Text|Geom|Image|Value]List specified.
|
||||
Values of None are substituted for lists that are shorter
|
||||
than the max length
|
||||
Parameters:
|
||||
text (str): Text message/query displayed to user
|
||||
geom: Geometry to be displayed in dialog
|
||||
buttonTextList: List of text to show on each button
|
||||
buttonGeomList: List of geometry to show on each button
|
||||
buttonImageList: List of images to show on each button
|
||||
buttonValueList: List of values sent to dialog command for
|
||||
each button. If value is [] then the ordinal rank of
|
||||
the button is used as its value.
|
||||
buttonHotKeyList: List of hotkeys to bind to each button.
|
||||
Typing the hotkey is equivalent to pressing the
|
||||
corresponding button.
|
||||
suppressKeys: Set to true if you wish to suppress keys
|
||||
(i.e. Dialog eats key event), false if you wish Dialog
|
||||
to pass along key event.
|
||||
buttonSize: 4-tuple used to specify custom size for each
|
||||
button (to make bigger then geom/text for example)
|
||||
pad: Space between border and interior graphics
|
||||
topPad: Extra space added above text/geom/image
|
||||
midPad: Extra space added between text/buttons
|
||||
sidePad: Extra space added to either side of text/buttons
|
||||
buttonPadSF: Scale factor used to expand/contract button
|
||||
horizontal spacing
|
||||
command: Callback command used when a button is pressed.
|
||||
Value supplied to command depends on values in
|
||||
buttonValueList.
|
||||
|
||||
Note:
|
||||
The number of buttons on the dialog depends on the maximum
|
||||
length of any button[Text|Geom|Image|Value]List specified.
|
||||
Values of None are substituted for lists that are shorter
|
||||
than the max length
|
||||
"""
|
||||
|
||||
# Inherits from DirectFrame
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
""" Imports all of the DirectGUI classes. """
|
||||
"""Imports all of the :ref:`directgui` classes."""
|
||||
|
||||
from . import DirectGuiGlobals as DGG
|
||||
from .OnscreenText import *
|
||||
|
|
|
|||
|
|
@ -1,49 +1,57 @@
|
|||
"""
|
||||
Base class for all Direct Gui items. Handles composite widgets and
|
||||
Base class for all DirectGui items. Handles composite widgets and
|
||||
command line argument parsing.
|
||||
|
||||
Code Overview:
|
||||
Code overview:
|
||||
|
||||
1 Each widget defines a set of options (optiondefs) as a list of tuples
|
||||
of the form ('name', defaultValue, handler).
|
||||
1) Each widget defines a set of options (optiondefs) as a list of tuples
|
||||
of the form ``('name', defaultValue, handler)``.
|
||||
'name' is the name of the option (used during construction of configure)
|
||||
handler can be: None, method, or INITOPT. If a method is specified,
|
||||
it will be called during widget construction (via initialiseoptions),
|
||||
if the Handler is specified as an INITOPT, this is an option that can
|
||||
only be set during widget construction.
|
||||
handler can be: None, method, or INITOPT. If a method is specified, it
|
||||
will be called during widget construction (via initialiseoptions), if the
|
||||
Handler is specified as an INITOPT, this is an option that can only be set
|
||||
during widget construction.
|
||||
|
||||
2) DirectGuiBase.defineoptions is called. defineoption creates:
|
||||
2) :func:`~DirectGuiBase.defineoptions` is called. defineoption creates:
|
||||
|
||||
self._constructorKeywords = { keyword: [value, useFlag] }
|
||||
a dictionary of the keyword options specified as part of the constructor
|
||||
keywords can be of the form 'component_option', where component is
|
||||
the name of a widget's component, a component group or a component alias
|
||||
A dictionary of the keyword options specified as part of the
|
||||
constructor keywords can be of the form 'component_option', where
|
||||
component is the name of a widget's component, a component group or a
|
||||
component alias.
|
||||
|
||||
self._dynamicGroups, a list of group names for which it is permissible
|
||||
to specify options before components of that group are created.
|
||||
If a widget is a derived class the order of execution would be:
|
||||
foo.optiondefs = {}
|
||||
foo.defineoptions()
|
||||
fooParent()
|
||||
fooParent.optiondefs = {}
|
||||
fooParent.defineoptions()
|
||||
self._dynamicGroups
|
||||
A list of group names for which it is permissible to specify options
|
||||
before components of that group are created.
|
||||
If a widget is a derived class the order of execution would be::
|
||||
|
||||
3) addoptions is called. This combines options specified as keywords to
|
||||
the widget constructor (stored in self._constuctorKeywords)
|
||||
with the default options (stored in optiondefs). Results are stored in
|
||||
self._optionInfo = { keyword: [default, current, handler] }
|
||||
foo.optiondefs = {}
|
||||
foo.defineoptions()
|
||||
fooParent()
|
||||
fooParent.optiondefs = {}
|
||||
fooParent.defineoptions()
|
||||
|
||||
3) :func:`~DirectGuiBase.addoptions` is called. This combines options
|
||||
specified as keywords to the widget constructor (stored in
|
||||
self._constructorKeywords) with the default options (stored in optiondefs).
|
||||
Results are stored in
|
||||
``self._optionInfo = { keyword: [default, current, handler] }``.
|
||||
If a keyword is of the form 'component_option' it is left in the
|
||||
self._constructorKeywords dictionary (for use by component constructors),
|
||||
otherwise it is 'used', and deleted from self._constructorKeywords.
|
||||
Notes: - constructor keywords override the defaults.
|
||||
- derived class default values override parent class defaults
|
||||
- derived class handler functions override parent class functions
|
||||
|
||||
Notes:
|
||||
|
||||
- constructor keywords override the defaults.
|
||||
- derived class default values override parent class defaults
|
||||
- derived class handler functions override parent class functions
|
||||
|
||||
4) Superclass initialization methods are called (resulting in nested calls
|
||||
to define options (see 2 above)
|
||||
|
||||
5) Widget components are created via calls to self.createcomponent.
|
||||
User can specify aliases and groups for each component created.
|
||||
5) Widget components are created via calls to
|
||||
:func:`~DirectGuiBase.createcomponent`. User can specify aliases and groups
|
||||
for each component created.
|
||||
|
||||
Aliases are alternate names for components, e.g. a widget may have a
|
||||
component with a name 'entryField', which itself may have a component
|
||||
|
|
@ -55,8 +63,8 @@ Code Overview:
|
|||
Groups allow option specifications that apply to all members of the group.
|
||||
If a widget has components: 'text1', 'text2', and 'text3' which all belong
|
||||
to the 'text' group, they can be all configured with keywords of the form:
|
||||
'text_keyword' (e.g. text_font = 'comic.rgb'). A component's group
|
||||
is stored as the fourth element of its entry in self.__componentInfo
|
||||
'text_keyword' (e.g. ``text_font='comic.rgb'``). A component's group
|
||||
is stored as the fourth element of its entry in self.__componentInfo.
|
||||
|
||||
Note: the widget constructors have access to all remaining keywords in
|
||||
_constructorKeywords (those not transferred to _optionInfo by
|
||||
|
|
@ -71,9 +79,9 @@ Code Overview:
|
|||
component. If any constructor keywords remain at the end of component
|
||||
construction (and initialisation), an error is raised.
|
||||
|
||||
5) initialiseoptions is called. This method calls any option handlers to
|
||||
respond to any keyword/default values, then checks to see if any keywords
|
||||
are left unused. If so, an error is raised.
|
||||
5) :func:`~DirectGuiBase.initialiseoptions` is called. This method calls any
|
||||
option handlers to respond to any keyword/default values, then checks to
|
||||
see if any keywords are left unused. If so, an error is raised.
|
||||
"""
|
||||
|
||||
__all__ = ['DirectGuiBase', 'DirectGuiWidget']
|
||||
|
|
|
|||
|
|
@ -17,8 +17,9 @@ drawOrder = 100
|
|||
panel = None
|
||||
|
||||
# USEFUL GUI CONSTANTS
|
||||
# Constant used to indicate that an option can only be set by a call
|
||||
# to the constructor.
|
||||
|
||||
#: Constant used to indicate that an option can only be set by a call
|
||||
#: to the constructor.
|
||||
INITOPT = ['initopt']
|
||||
|
||||
# Mouse buttons
|
||||
|
|
@ -158,7 +159,3 @@ def getDefaultPanel():
|
|||
def setDefaultPanel(newPanel):
|
||||
global panel
|
||||
panel = newPanel
|
||||
|
||||
#from OnscreenText import *
|
||||
#from OnscreenGeom import *
|
||||
#from OnscreenImage import *
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
"""OnscreenImage module: contains the OnscreenImage class"""
|
||||
"""OnscreenImage module: contains the OnscreenImage class.
|
||||
|
||||
See the :ref:`onscreenimage` page in the programming manual for explanation of
|
||||
this class.
|
||||
"""
|
||||
|
||||
__all__ = ['OnscreenImage']
|
||||
|
||||
|
|
@ -21,14 +25,15 @@ class OnscreenImage(DirectObject, NodePath):
|
|||
parent = None,
|
||||
sort = 0):
|
||||
"""
|
||||
Make a image node from string or a node path,
|
||||
put it into the 2d sg and set it up with all the indicated parameters.
|
||||
Make a image node from string or a `~panda3d.core.NodePath`, put
|
||||
it into the 2-D scene graph and set it up with all the indicated
|
||||
parameters.
|
||||
|
||||
The parameters are as follows:
|
||||
Parameters:
|
||||
|
||||
image: the actual geometry to display or a file name.
|
||||
This may be omitted and specified later via setImage()
|
||||
if you don't have it available.
|
||||
This may be omitted and specified later via setImage()
|
||||
if you don't have it available.
|
||||
|
||||
pos: the x, y, z position of the geometry on the screen.
|
||||
This maybe a 3-tuple of floats or a vector.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
"""OnscreenText module: contains the OnscreenText class"""
|
||||
"""OnscreenText module: contains the OnscreenText class.
|
||||
|
||||
See the :ref:`onscreentext` page in the programming manual for explanation of
|
||||
this class.
|
||||
"""
|
||||
|
||||
__all__ = ['OnscreenText', 'Plain', 'ScreenTitle', 'ScreenPrompt', 'NameConfirm', 'BlackOnWhite']
|
||||
|
||||
|
|
@ -41,7 +45,7 @@ class OnscreenText(NodePath):
|
|||
Make a text node from string, put it into the 2d sg and set it
|
||||
up with all the indicated parameters.
|
||||
|
||||
The parameters are as follows:
|
||||
Parameters:
|
||||
|
||||
text: the actual text to display. This may be omitted and
|
||||
specified later via setText() if you don't have it
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
This package contains the DirectGui system, a set of classes
|
||||
This package contains the :ref:`directgui` system, a set of classes
|
||||
responsible for drawing graphical widgets to the 2-D scene graph.
|
||||
|
||||
It is based on the lower-level PGui system, which is implemented in
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
"""ActorInterval module: contains the ActorInterval class"""
|
||||
"""ActorInterval module: contains the ActorInterval class.
|
||||
|
||||
See the :ref:`actor-intervals` page in the programming manual for explanation
|
||||
of this class.
|
||||
"""
|
||||
|
||||
__all__ = ['ActorInterval', 'LerpAnimInterval']
|
||||
|
||||
|
|
|
|||
|
|
@ -34,26 +34,22 @@ class ParticleInterval(Interval):
|
|||
cleanup = False,
|
||||
name = None):
|
||||
"""
|
||||
particleEffect is a ParticleEffect
|
||||
parent is a NodePath: this is where the effect will be
|
||||
parented in the scenegraph
|
||||
worldRelative is a boolean: this will override 'renderParent'
|
||||
with render
|
||||
renderParent is a NodePath: this is where the particles will
|
||||
be rendered in the scenegraph
|
||||
duration is a float: for the time
|
||||
softStopT is a float: no effect if 0.0,
|
||||
a positive value will count from the
|
||||
start of the interval,
|
||||
a negative value will count from the
|
||||
end of the interval
|
||||
cleanup is a boolean: if True the effect will be destroyed
|
||||
and removed from the scenegraph upon
|
||||
interval completion
|
||||
set to False if planning on reusing
|
||||
the interval
|
||||
name is a string: use this for unique intervals so that
|
||||
they can be easily found in the taskMgr
|
||||
Args:
|
||||
particleEffect (ParticleEffect): a particle effect
|
||||
parent (NodePath): this is where the effect will be parented in the
|
||||
scene graph
|
||||
worldRelative (bool): this will override 'renderParent' with render
|
||||
renderParent (NodePath): this is where the particles will be
|
||||
rendered in the scenegraph
|
||||
duration (float): for the time
|
||||
softStopT (float): no effect if 0.0, a positive value will count
|
||||
from the start of the interval, a negative value will count
|
||||
from the end of the interval
|
||||
cleanup (boolean): if True the effect will be destroyed and removed
|
||||
from the scenegraph upon interval completion. Set to False if
|
||||
planning on reusing the interval.
|
||||
name (string): use this for unique intervals so that they can be
|
||||
easily found in the taskMgr.
|
||||
"""
|
||||
|
||||
# Generate unique name
|
||||
|
|
|
|||
|
|
@ -9,4 +9,6 @@ All interval types can be conveniently imported from the
|
|||
:mod:`.IntervalGlobal` module::
|
||||
|
||||
from direct.interval.IntervalGlobal import *
|
||||
|
||||
For more information about intervals, see the :ref:`intervals` manual page.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -10,6 +10,10 @@ The global AppRunner instance may be imported as follows::
|
|||
from direct.showbase.AppRunnerGlobal import appRunner
|
||||
|
||||
This will be None if Panda was not run from the runtime environment.
|
||||
|
||||
.. deprecated:: 1.10.0
|
||||
The p3d packaging system has been replaced with the new setuptools-based
|
||||
system. See the :ref:`distribution` manual section.
|
||||
"""
|
||||
|
||||
__all__ = ["AppRunner", "dummyAppRunner", "ArgumentError"]
|
||||
|
|
|
|||
|
|
@ -1,6 +1,11 @@
|
|||
""" This module is used to build a graphical installer
|
||||
or a standalone executable from a p3d file. It will try
|
||||
to build for as many platforms as possible. """
|
||||
to build for as many platforms as possible.
|
||||
|
||||
.. deprecated:: 1.10.0
|
||||
The p3d packaging system has been replaced with the new setuptools-based
|
||||
system. See the :ref:`distribution` manual section.
|
||||
"""
|
||||
|
||||
__all__ = ["Standalone", "Installer"]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
""" This module defines some simple classes and instances which are
|
||||
useful when writing code that integrates with JavaScript, especially
|
||||
code that runs in a browser via the web plugin. """
|
||||
code that runs in a browser via the web plugin.
|
||||
|
||||
.. deprecated:: 1.10.0
|
||||
The browser plug-in is no longer supported.
|
||||
"""
|
||||
|
||||
__all__ = ["UndefinedObject", "Undefined", "ConcreteStruct", "BrowserObject", "MethodWrapper"]
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,12 @@
|
|||
""" This module is used to build a "Package", a collection of files
|
||||
within a Panda3D Multifile, which can be easily be downloaded and/or
|
||||
patched onto a client machine, for the purpose of running a large
|
||||
application. """
|
||||
application.
|
||||
|
||||
.. deprecated:: 1.10.0
|
||||
The p3d packaging system has been replaced with the new setuptools-based
|
||||
system. See the :ref:`distribution` manual section.
|
||||
"""
|
||||
|
||||
__all__ = ["Packager", "PackagerError", "OutsideOfPackageError", "ArgumentError"]
|
||||
|
||||
|
|
@ -3926,21 +3931,22 @@ class metaclass_def(type):
|
|||
|
||||
return type.__new__(self, name, bases, dict)
|
||||
|
||||
|
||||
# Define these dynamically to stay compatible with Python 2 and 3.
|
||||
class_p3d = metaclass_def(str('class_p3d'), (), {})
|
||||
class_package = metaclass_def(str('class_package'), (), {})
|
||||
class_solo = metaclass_def(str('class_solo'), (), {})
|
||||
|
||||
class func_closure:
|
||||
|
||||
class func_closure:
|
||||
""" This class is used to create a closure on the function name,
|
||||
and also allows the *args, **kw syntax. In Python, the lambda
|
||||
and also allows the ``*args, **kw`` syntax. In Python, the lambda
|
||||
syntax, used with default parameters, is used more often to create
|
||||
a closure (that is, a binding of one or more variables into a
|
||||
callable object), but that syntax doesn't work with **kw.
|
||||
callable object), but that syntax doesn't work with ``**kw``.
|
||||
Fortunately, a class method is also a form of a closure, because
|
||||
it binds self; and this doesn't have any syntax problems with
|
||||
**kw. """
|
||||
``**kw``. """
|
||||
|
||||
def __init__(self, name):
|
||||
self.name = name
|
||||
|
|
|
|||
|
|
@ -1,4 +1,8 @@
|
|||
"""
|
||||
This package provides the Python interface to functionality relating to
|
||||
the Panda3D Runtime environment.
|
||||
|
||||
.. deprecated:: 1.10.0
|
||||
The p3d packaging system has been replaced with the new setuptools-based
|
||||
system. See the :ref:`distribution` manual section.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,3 +1,9 @@
|
|||
"""The Python specialization of the particle system.
|
||||
|
||||
See the :ref:`particle-effects` section in the manual for an explanation
|
||||
of the particle system.
|
||||
"""
|
||||
|
||||
from panda3d.core import *
|
||||
|
||||
from panda3d.physics import PhysicalNode
|
||||
|
|
@ -29,6 +35,7 @@ from . import SpriteParticleRendererExt
|
|||
from direct.directnotify.DirectNotifyGlobal import directNotify
|
||||
import sys
|
||||
|
||||
|
||||
class Particles(ParticleSystem):
|
||||
notify = directNotify.newCategory('Particles')
|
||||
id = 1
|
||||
|
|
@ -575,7 +582,6 @@ class Particles(ParticleSystem):
|
|||
|
||||
return dict(zip(('min','median','max'),[l*s/b for l,s,b in zip(litterRange,lifespanRange,birthRateRange)]))
|
||||
|
||||
|
||||
def accelerate(self,time,stepCount = 1,stepTime=0.0):
|
||||
if time > 0.0:
|
||||
if stepTime == 0.0:
|
||||
|
|
|
|||
|
|
@ -4,4 +4,7 @@ system.
|
|||
|
||||
Also see the :mod:`panda3d.physics` module, which contains the C++
|
||||
implementation of the particle system.
|
||||
|
||||
For more information about the particle system, see the :ref:`particle-effects`
|
||||
page in the manual.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -4,8 +4,13 @@ runp3d.py or via the Panda3D plugin or standalone executable.
|
|||
|
||||
This is needed for apps that start themselves by importing
|
||||
DirectStart; it provides a place for these apps to look for
|
||||
the AppRunner at startup. """
|
||||
the AppRunner at startup.
|
||||
|
||||
#: Contains the global AppRunner instance, or None if this application
|
||||
#: was not run from the runtime environment.
|
||||
.. deprecated:: 1.10.0
|
||||
The p3d packaging system has been replaced with the new setuptools-based
|
||||
system. See the :ref:`distribution` manual section.
|
||||
"""
|
||||
|
||||
#: Contains the global :class:`~.AppRunner.AppRunner` instance, or None
|
||||
#: if this application was not run from the runtime environment.
|
||||
appRunner = None
|
||||
|
|
|
|||
|
|
@ -1,6 +1,16 @@
|
|||
"""Contains the BufferViewer class, which is used as a debugging aid
|
||||
when debugging render-to-texture effects. It shows different views at
|
||||
the bottom of the screen showing the various render targets."""
|
||||
the bottom of the screen showing the various render targets.
|
||||
|
||||
When using ShowBase, the normal way to enable the BufferViewer is using the
|
||||
following code::
|
||||
|
||||
base.bufferViewer.toggleEnable()
|
||||
|
||||
Or, you can enable the following variable in your Config.prc::
|
||||
|
||||
show-buffers true
|
||||
"""
|
||||
|
||||
__all__ = ['BufferViewer']
|
||||
|
||||
|
|
@ -11,6 +21,7 @@ from direct.directnotify.DirectNotifyGlobal import *
|
|||
from direct.showbase.DirectObject import DirectObject
|
||||
import math
|
||||
|
||||
|
||||
class BufferViewer(DirectObject):
|
||||
notify = directNotify.newCategory('BufferViewer')
|
||||
|
||||
|
|
@ -100,11 +111,13 @@ class BufferViewer(DirectObject):
|
|||
|
||||
def setPosition(self, pos):
|
||||
"""Set the position of the cards. The valid values are:
|
||||
* llcorner - put them in the lower-left corner of the window
|
||||
* lrcorner - put them in the lower-right corner of the window
|
||||
* ulcorner - put them in the upper-left corner of the window
|
||||
* urcorner - put them in the upper-right corner of the window
|
||||
* window - put them in a separate window
|
||||
|
||||
- *llcorner* - put them in the lower-left corner of the window
|
||||
- *lrcorner* - put them in the lower-right corner of the window
|
||||
- *ulcorner* - put them in the upper-left corner of the window
|
||||
- *urcorner* - put them in the upper-right corner of the window
|
||||
- *window* - put them in a separate window
|
||||
|
||||
The initial value is 'lrcorner'."""
|
||||
valid=["llcorner","lrcorner","ulcorner","urcorner","window"]
|
||||
if (valid.count(pos)==0):
|
||||
|
|
@ -119,11 +132,13 @@ class BufferViewer(DirectObject):
|
|||
|
||||
def setLayout(self, lay):
|
||||
"""Set the layout of the cards. The valid values are:
|
||||
* vline - display them in a vertical line
|
||||
* hline - display them in a horizontal line
|
||||
* vgrid - display them in a vertical grid
|
||||
* hgrid - display them in a horizontal grid
|
||||
* cycle - display one card at a time, using selectCard/advanceCard
|
||||
|
||||
- *vline* - display them in a vertical line
|
||||
- *hline* - display them in a horizontal line
|
||||
- *vgrid* - display them in a vertical grid
|
||||
- *hgrid* - display them in a horizontal grid
|
||||
- *cycle* - display one card at a time, using selectCard/advanceCard
|
||||
|
||||
The default value is 'hline'."""
|
||||
valid=["vline","hline","vgrid","hgrid","cycle"]
|
||||
if (valid.count(lay)==0):
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
"""instantiate global BulletinBoard object"""
|
||||
"""Instantiates the global :class:`~.BulletinBoard.BulletinBoard` object."""
|
||||
|
||||
__all__ = ['bulletinBoard']
|
||||
|
||||
from . import BulletinBoard
|
||||
|
||||
#: The global :class:`~.BulletinBoard.BulletinBoard` object.
|
||||
bulletinBoard = BulletinBoard.BulletinBoard()
|
||||
|
|
|
|||
|
|
@ -3,16 +3,18 @@ from direct.directnotify.DirectNotifyGlobal import directNotify
|
|||
from panda3d.core import *
|
||||
from .PhasedObject import PhasedObject
|
||||
|
||||
|
||||
class DistancePhasedNode(PhasedObject, DirectObject, NodePath):
|
||||
"""
|
||||
This class defines a PhasedObject,NodePath object that will handle the phasing
|
||||
of an object in the scene graph according to its distance from some
|
||||
other collider object(such as an avatar).
|
||||
This class defines a PhasedObject,NodePath object that will handle
|
||||
the phasing of an object in the scene graph according to its
|
||||
distance from some other collider object(such as an avatar).
|
||||
|
||||
Since it's a NodePath, you can parent it to another object in the
|
||||
scene graph, or even inherit from this class to get its functionality.
|
||||
|
||||
What you will need to define to use this class:
|
||||
|
||||
- The distances at which you want the phases to load/unload
|
||||
- Whether you want the object to clean itself up or not when
|
||||
exitting the largest distance sphere
|
||||
|
|
@ -22,14 +24,14 @@ class DistancePhasedNode(PhasedObject, DirectObject, NodePath):
|
|||
- (Optional) A 'from' collision node to collide into our 'into' spheres
|
||||
|
||||
You specify the distances and function names by the phaseParamMap
|
||||
parameter to __init__(). For example:
|
||||
parameter to `__init__()`. For example::
|
||||
|
||||
phaseParamMap = {'Alias': distance, ...}
|
||||
...
|
||||
def loadPhaseAlias(self):
|
||||
pass
|
||||
def unloadPhaseAlias(self):
|
||||
pass
|
||||
phaseParamMap = {'Alias': distance, ...}
|
||||
...
|
||||
def loadPhaseAlias(self):
|
||||
pass
|
||||
def unloadPhaseAlias(self):
|
||||
pass
|
||||
|
||||
If the 'fromCollideNode' is supplied, we will set up our own
|
||||
traverser and only traverse below this node. It will send out
|
||||
|
|
@ -40,14 +42,15 @@ class DistancePhasedNode(PhasedObject, DirectObject, NodePath):
|
|||
Most of the time, it will be reacting to events from the main
|
||||
collision traverser.
|
||||
|
||||
IMPORTANT!: The following only applies when autoCleanup == True:
|
||||
If you unload the last phase, by either calling
|
||||
cleanup() or by exitting the last phase's distance,
|
||||
you will need to explicitly call reset() to get the
|
||||
distance phasing to work again. This was done so if
|
||||
either this node or the collider is removed from the
|
||||
scene graph(eg. avatar teleport), the phased object
|
||||
will clean itself up automatically.
|
||||
IMPORTANT:
|
||||
|
||||
The following only applies when ``autoCleanup is True``:
|
||||
If you unload the last phase, by either calling `cleanup()` or
|
||||
by exiting the last phase's distance, you will need to
|
||||
explicitly call `reset()` to get the distance phasing to work
|
||||
again. This was done so if either this node or the collider is
|
||||
removed from the scene graph (e.g. avatar teleport), the phased
|
||||
object will clean itself up automatically.
|
||||
"""
|
||||
|
||||
notify = directNotify.newCategory("DistancePhasedObject")
|
||||
|
|
@ -118,7 +121,6 @@ class DistancePhasedNode(PhasedObject, DirectObject, NodePath):
|
|||
def __str__(self):
|
||||
return '%s in phase \'%s\'' % (NodePath.__str__(self), self.getPhase())
|
||||
|
||||
|
||||
def cleanup(self):
|
||||
"""
|
||||
Disables all collisions.
|
||||
|
|
@ -262,9 +264,9 @@ class BufferedDistancePhasedNode(DistancePhasedNode):
|
|||
border.
|
||||
|
||||
You specify the buffer amount in the bufferParamMap parameter
|
||||
to __init__(). It has this format:
|
||||
to :meth:`__init__()`. It has this format::
|
||||
|
||||
bufferParamMap = {'alias':(distance, bufferAmount), ...}
|
||||
bufferParamMap = {'alias':(distance, bufferAmount), ...}
|
||||
"""
|
||||
notify = directNotify.newCategory("BufferedDistancePhasedObject")
|
||||
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@ def _excepthookDumpVars(eType, eValue, tb):
|
|||
oldExcepthook(eType, eValue, origTb)
|
||||
|
||||
def install(log, upload):
|
||||
"""Installs the exception hook."""
|
||||
global oldExcepthook
|
||||
global wantStackDumpLog
|
||||
global wantStackDumpUpload
|
||||
|
|
|
|||
|
|
@ -1,7 +1,9 @@
|
|||
from direct.showbase.GarbageReport import GarbageReport
|
||||
|
||||
|
||||
class GarbageReportScheduler:
|
||||
# runs a garbage report every once in a while and logs the results
|
||||
"""Runs a garbage report every once in a while and logs the results."""
|
||||
|
||||
def __init__(self, waitBetween=None, waitScale=None):
|
||||
# waitBetween is in seconds
|
||||
# waitScale is a multiplier for the waitBetween every time around
|
||||
|
|
@ -30,6 +32,7 @@ class GarbageReportScheduler:
|
|||
self._taskName)
|
||||
# and increase the delay every time around
|
||||
self._waitBetween = self._waitBetween * self._waitScale
|
||||
|
||||
def _runGarbageReport(self, task):
|
||||
# run a garbage report and schedule the next one after this one finishes
|
||||
# give this job 3 times as many timeslices as normal-priority jobs
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""instantiate global InputState object"""
|
||||
"""Instantiates the global :class:`~.InputState.InputState` object."""
|
||||
|
||||
__all__ = ['inputState']
|
||||
|
||||
|
|
@ -7,4 +7,5 @@ __all__ = ['inputState']
|
|||
|
||||
from direct.controls import InputState
|
||||
|
||||
#: The global :class:`~.InputState.InputState` object.
|
||||
inputState = InputState.InputState()
|
||||
|
|
|
|||
|
|
@ -3,14 +3,22 @@ from direct.showbase.DirectObject import DirectObject
|
|||
if __debug__:
|
||||
from panda3d.core import PStatCollector
|
||||
|
||||
class Job(DirectObject):
|
||||
# Base class for cpu-intensive or non-time-critical operations that
|
||||
# are run through the JobManager.
|
||||
|
||||
# values to yield from your run() generator method
|
||||
class Job(DirectObject):
|
||||
"""Base class for cpu-intensive or non-time-critical operations that
|
||||
are run through the :class:`.JobManager`.
|
||||
|
||||
To use, subclass and override the `run()` method.
|
||||
"""
|
||||
|
||||
#: Yielded from the `run()` generator method when the job is done.
|
||||
Done = object()
|
||||
Continue = None # 'yield None' is acceptable in place of 'yield Job.Continue'
|
||||
Sleep = object() # yield any remaining time for this job until next frame
|
||||
|
||||
#: ``yield None`` is acceptable in place of ``yield Job.Continue``
|
||||
Continue = None
|
||||
|
||||
#: Yield any remaining time for this job until next frame.
|
||||
Sleep = object()
|
||||
|
||||
# These priorities determine how many timeslices a job gets relative to other
|
||||
# jobs. A job with priority of 1000 will run 10 times more often than a job
|
||||
|
|
@ -37,13 +45,14 @@ class Job(DirectObject):
|
|||
return 'job-finished-%s' % self._id
|
||||
|
||||
def run(self):
|
||||
# this is a generator
|
||||
# override and do your processing
|
||||
# yield Job.Continue when possible/reasonable
|
||||
# try not to run longer than the JobManager's timeslice between yields
|
||||
#
|
||||
# when done, yield Job.Done
|
||||
#
|
||||
"""This should be overridden with a generator that does the
|
||||
needful processing.
|
||||
|
||||
yield `Job.Continue` when possible/reasonable, and try not to run
|
||||
longer than the JobManager's timeslice between yields.
|
||||
|
||||
When done, yield `Job.Done`.
|
||||
"""
|
||||
raise NotImplementedError("don't call down")
|
||||
|
||||
def getPriority(self):
|
||||
|
|
@ -57,23 +66,22 @@ class Job(DirectObject):
|
|||
self._printing = False
|
||||
|
||||
def resume(self):
|
||||
# called every time JobManager is going to start running this job
|
||||
"""
|
||||
if self._printing:
|
||||
# we may be suspended/resumed multiple times per frame, that gets spammy
|
||||
# if we need to pick out the output of a job, put a prefix onto each line
|
||||
# of the output
|
||||
print 'JOB:%s:RESUME' % self._name
|
||||
"""
|
||||
pass
|
||||
"""Called every time JobManager is going to start running this job."""
|
||||
#if self._printing:
|
||||
# # we may be suspended/resumed multiple times per frame, that gets spammy
|
||||
# # if we need to pick out the output of a job, put a prefix onto each line
|
||||
# # of the output
|
||||
# print('JOB:%s:RESUME' % self._name)
|
||||
|
||||
def suspend(self):
|
||||
# called when JobManager is going to stop running this job for a while
|
||||
"""Called when JobManager is going to stop running this job for a
|
||||
while.
|
||||
"""
|
||||
if self._printing:
|
||||
#print 'JOB:%s:SUSPEND' % self._name
|
||||
pass
|
||||
"""
|
||||
pass
|
||||
|
||||
#if self._printing:
|
||||
# #print('JOB:%s:SUSPEND' % self._name)
|
||||
# pass
|
||||
# """
|
||||
|
||||
def _setFinished(self):
|
||||
self._finished = True
|
||||
|
|
|
|||
|
|
@ -2,4 +2,5 @@ __all__ = ['jobMgr']
|
|||
|
||||
from . import JobManager
|
||||
|
||||
#: Contains the global :class:`~.JobManager.JobManager` object.
|
||||
jobMgr = JobManager.JobManager()
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
# objects that report different types of leaks to the ContainerLeakDetector
|
||||
"""Contains objects that report different types of leaks to the
|
||||
ContainerLeakDetector.
|
||||
"""
|
||||
|
||||
from panda3d.core import *
|
||||
from direct.showbase.DirectObject import DirectObject
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
"""Loader module: contains the Loader class"""
|
||||
"""This module contains a high-level interface for loading models, textures,
|
||||
sound, music, shaders and fonts from disk.
|
||||
"""
|
||||
|
||||
__all__ = ['Loader']
|
||||
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
"""This defines the Messenger class, which is responsible for most of the
|
||||
event handling that happens on the Python side."""
|
||||
event handling that happens on the Python side.
|
||||
"""
|
||||
|
||||
__all__ = ['Messenger']
|
||||
|
||||
|
|
@ -10,26 +11,28 @@ import types
|
|||
|
||||
from direct.stdpy.threading import Lock
|
||||
|
||||
|
||||
class Messenger:
|
||||
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("Messenger")
|
||||
|
||||
def __init__(self):
|
||||
"""
|
||||
One is keyed off the event name. It has the following structure:
|
||||
One is keyed off the event name. It has the following structure::
|
||||
|
||||
{event1: {object1: [method, extraArgs, persistent],
|
||||
object2: [method, extraArgs, persistent]},
|
||||
event2: {object1: [method, extraArgs, persistent],
|
||||
object2: [method, extraArgs, persistent]}}
|
||||
|
||||
This dictionary allow for efficient callbacks when the messenger
|
||||
hears an event.
|
||||
This dictionary allows for efficient callbacks when the
|
||||
messenger hears an event.
|
||||
|
||||
A second dictionary remembers which objects are accepting which
|
||||
events. This allows for efficient ignoreAll commands.
|
||||
|
||||
Or, for an example with more real data::
|
||||
|
||||
Or, for an example with more real data:
|
||||
{'mouseDown': {avatar: [avatar.jump, [2.0], 1]}}
|
||||
"""
|
||||
# eventName->objMsgrId->callbackInfo
|
||||
|
|
@ -281,20 +284,20 @@ class Messenger:
|
|||
"""
|
||||
return (not self.isAccepting(event, object))
|
||||
|
||||
def send(self, event, sentArgs=[], taskChain = None):
|
||||
def send(self, event, sentArgs=[], taskChain=None):
|
||||
"""
|
||||
Send this event, optionally passing in arguments
|
||||
Send this event, optionally passing in arguments.
|
||||
|
||||
event is usually a string.
|
||||
sentArgs is a list of any data that you want passed along to the
|
||||
handlers listening to this event.
|
||||
|
||||
If taskChain is not None, it is the name of the task chain
|
||||
which should receive the event. If taskChain is None, the
|
||||
event is handled immediately. Setting a non-None taskChain
|
||||
will defer the event (possibly till next frame or even later)
|
||||
and create a new, temporary task within the named taskChain,
|
||||
but this is the only way to send an event across threads.
|
||||
Args:
|
||||
event (str): The name of the event.
|
||||
sentArgs (list): A list of arguments to be passed along to the
|
||||
handlers listening to this event.
|
||||
taskChain (str, optional): If not None, the name of the task chain
|
||||
which should receive the event. If None, then the event is
|
||||
handled immediately. Setting a non-None taskChain will defer
|
||||
the event (possibly till next frame or even later) and create a
|
||||
new, temporary task within the named taskChain, but this is the
|
||||
only way to send an event across threads.
|
||||
"""
|
||||
if Messenger.notify.getDebug() and not self.quieting.get(event):
|
||||
assert Messenger.notify.debug(
|
||||
|
|
@ -485,7 +488,7 @@ class Messenger:
|
|||
This is intended for debugging use only.
|
||||
This function is not defined if python is ran with -O (optimize).
|
||||
|
||||
See Also: unwatch
|
||||
See Also: `unwatch`
|
||||
"""
|
||||
if not self.__watching.get(needle):
|
||||
self.__isWatching += 1
|
||||
|
|
@ -499,7 +502,7 @@ class Messenger:
|
|||
This is intended for debugging use only.
|
||||
This function is not defined if python is ran with -O (optimize).
|
||||
|
||||
See Also: watch
|
||||
See Also: `watch`
|
||||
"""
|
||||
if self.__watching.get(needle):
|
||||
self.__isWatching -= 1
|
||||
|
|
@ -514,7 +517,7 @@ class Messenger:
|
|||
This is intended for debugging use only.
|
||||
This function is not defined if python is ran with -O (optimize).
|
||||
|
||||
See Also: unquiet
|
||||
See Also: `unquiet`
|
||||
"""
|
||||
if not self.quieting.get(message):
|
||||
self.quieting[message]=1
|
||||
|
|
@ -528,7 +531,7 @@ class Messenger:
|
|||
This is intended for debugging use only.
|
||||
This function is not defined if python is ran with -O (optimize).
|
||||
|
||||
See Also: quiet
|
||||
See Also: `quiet`
|
||||
"""
|
||||
if self.quieting.get(message):
|
||||
del self.quieting[message]
|
||||
|
|
@ -658,4 +661,3 @@ class Messenger:
|
|||
detailed_repr = detailedRepr
|
||||
get_all_accepting = getAllAccepting
|
||||
toggle_verbose = toggleVerbose
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
"""instantiate global Messenger object"""
|
||||
"""Instantiates the global :class:`~.Messenger.Messenger` object."""
|
||||
|
||||
__all__ = ['messenger']
|
||||
|
||||
from . import Messenger
|
||||
|
||||
#: Contains the global :class:`~.Messenger.Messenger` instance.
|
||||
messenger = Messenger.Messenger()
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
"""This file demonstrates one way to create a mirror effect in Panda.
|
||||
Call setupMirror() to create a mirror in the world that reflects
|
||||
Call :func:`setupMirror()` to create a mirror in the world that reflects
|
||||
everything in front of it.
|
||||
|
||||
The approach taken here is to create an offscreen buffer with its own
|
||||
|
|
|
|||
|
|
@ -1,7 +1,8 @@
|
|||
"""PhysicsManagerGlobal module: contains the global physics manager"""
|
||||
"""Instantiates the global :class:`~panda3d.physics.PhysicsManager` object."""
|
||||
|
||||
__all__ = ['physicsMgr']
|
||||
|
||||
from panda3d.physics import PhysicsManager
|
||||
|
||||
#: Contains the global :class:`~panda3d.physics.PhysicsManager` instance.
|
||||
physicsMgr = PhysicsManager()
|
||||
|
|
|
|||
|
|
@ -7,11 +7,13 @@ or be the same type.
|
|||
|
||||
Internally the pool is implemented with 2 lists, free items and used items.
|
||||
|
||||
Example::
|
||||
Example:
|
||||
|
||||
p = Pool([1, 2, 3, 4, 5])
|
||||
x = p.checkout()
|
||||
p.checkin(x)
|
||||
.. code-block:: python
|
||||
|
||||
p = Pool([1, 2, 3, 4, 5])
|
||||
x = p.checkout()
|
||||
p.checkin(x)
|
||||
|
||||
"""
|
||||
|
||||
|
|
@ -20,6 +22,7 @@ __all__ = ['Pool']
|
|||
|
||||
from direct.directnotify import DirectNotifyGlobal
|
||||
|
||||
|
||||
class Pool:
|
||||
|
||||
notify = DirectNotifyGlobal.directNotify.newCategory("Pool")
|
||||
|
|
|
|||
|
|
@ -1,36 +1,35 @@
|
|||
"""Contains miscellaneous utility functions and classes."""
|
||||
|
||||
__all__ = ['indent',
|
||||
'doc', 'adjust', 'difference', 'intersection', 'union',
|
||||
'sameElements', 'makeList', 'makeTuple', 'list2dict', 'invertDict',
|
||||
'invertDictLossless', 'uniqueElements', 'disjoint', 'contains',
|
||||
'replace', 'reduceAngle', 'fitSrcAngle2Dest', 'fitDestAngle2Src',
|
||||
'closestDestAngle2', 'closestDestAngle', 'getSetterName',
|
||||
'getSetter', 'Functor', 'Stack', 'Queue',
|
||||
'bound', 'clamp', 'lerp', 'average', 'addListsByValue',
|
||||
'boolEqual', 'lineupPos', 'formatElapsedSeconds', 'solveQuadratic',
|
||||
'findPythonModule', 'mostDerivedLast',
|
||||
'clampScalar', 'weightedChoice', 'randFloat', 'normalDistrib',
|
||||
'weightedRand', 'randUint31', 'randInt32',
|
||||
'SerialNumGen', 'serialNum', 'uniqueName', 'Enum', 'Singleton',
|
||||
'SingletonError', 'printListEnum', 'safeRepr',
|
||||
'fastRepr', 'isDefaultValue',
|
||||
'ScratchPad', 'Sync', 'itype', 'getNumberedTypedString',
|
||||
'getNumberedTypedSortedString',
|
||||
'printNumberedTyped', 'DelayedCall', 'DelayedFunctor',
|
||||
'FrameDelayedCall', 'SubframeCall', 'getBase', 'GoldenRatio',
|
||||
'GoldenRectangle', 'rad90', 'rad180', 'rad270', 'rad360',
|
||||
'nullGen', 'loopGen', 'makeFlywheelGen', 'flywheel',
|
||||
'listToIndex2item', 'listToItem2index',
|
||||
'formatTimeCompact','deeptype','StdoutCapture','StdoutPassthrough',
|
||||
'Averager', 'getRepository', 'formatTimeExact', 'startSuperLog', 'endSuperLog',
|
||||
'typeName', 'safeTypeName', 'histogramDict', 'unescapeHtmlString']
|
||||
__all__ = [
|
||||
|
||||
'indent', 'doc', 'adjust', 'difference', 'intersection', 'union',
|
||||
'sameElements', 'makeList', 'makeTuple', 'list2dict', 'invertDict',
|
||||
'invertDictLossless', 'uniqueElements', 'disjoint', 'contains', 'replace',
|
||||
'reduceAngle', 'fitSrcAngle2Dest', 'fitDestAngle2Src', 'closestDestAngle2',
|
||||
'closestDestAngle', 'getSetterName', 'getSetter', 'Functor', 'Stack',
|
||||
'Queue', 'bound', 'clamp', 'lerp', 'average', 'addListsByValue',
|
||||
'boolEqual', 'lineupPos', 'formatElapsedSeconds', 'solveQuadratic',
|
||||
'findPythonModule', 'mostDerivedLast', 'clampScalar', 'weightedChoice',
|
||||
'randFloat', 'normalDistrib', 'weightedRand', 'randUint31', 'randInt32',
|
||||
'SerialNumGen', 'serialNum', 'uniqueName', 'Enum', 'Singleton',
|
||||
'SingletonError', 'printListEnum', 'safeRepr', 'fastRepr',
|
||||
'isDefaultValue', 'ScratchPad', 'Sync', 'itype', 'getNumberedTypedString',
|
||||
'getNumberedTypedSortedString', 'printNumberedTyped', 'DelayedCall',
|
||||
'DelayedFunctor', 'FrameDelayedCall', 'SubframeCall', 'getBase',
|
||||
'GoldenRatio', 'GoldenRectangle', 'rad90', 'rad180', 'rad270', 'rad360',
|
||||
'nullGen', 'loopGen', 'makeFlywheelGen', 'flywheel', 'listToIndex2item',
|
||||
'listToItem2index', 'formatTimeCompact', 'deeptype', 'StdoutCapture',
|
||||
'StdoutPassthrough', 'Averager', 'getRepository', 'formatTimeExact',
|
||||
'startSuperLog', 'endSuperLog', 'typeName', 'safeTypeName',
|
||||
'histogramDict', 'unescapeHtmlString',
|
||||
]
|
||||
|
||||
if __debug__:
|
||||
__all__ += ['StackTrace', 'traceFunctionCall', 'traceParentCall', 'printThisCall',
|
||||
'stackEntryInfo', 'lineInfo', 'callerInfo', 'lineTag',
|
||||
'profileFunc', 'profiled', 'startProfile', 'printProfile',
|
||||
'getProfileResultString', 'printStack', 'printReverseStack']
|
||||
__all__ += ['StackTrace', 'traceFunctionCall', 'traceParentCall',
|
||||
'printThisCall', 'stackEntryInfo', 'lineInfo', 'callerInfo',
|
||||
'lineTag', 'profileFunc', 'profiled', 'startProfile',
|
||||
'printProfile', 'getProfileResultString', 'printStack',
|
||||
'printReverseStack']
|
||||
|
||||
import types
|
||||
import math
|
||||
|
|
@ -652,13 +651,15 @@ if __debug__:
|
|||
""" decorator for profiling functions
|
||||
turn categories on and off via "want-profile-categoryName 1"
|
||||
|
||||
e.g.
|
||||
e.g.::
|
||||
|
||||
@profiled('particles')
|
||||
def loadParticles():
|
||||
...
|
||||
@profiled('particles')
|
||||
def loadParticles():
|
||||
...
|
||||
|
||||
want-profile-particles 1
|
||||
::
|
||||
|
||||
want-profile-particles 1
|
||||
"""
|
||||
assert type(category) in (str, type(None)), "must provide a category name for @profiled"
|
||||
|
||||
|
|
@ -1195,13 +1196,14 @@ def normalDistrib(a, b, gauss=random.gauss):
|
|||
|
||||
def weightedRand(valDict, rng=random.random):
|
||||
"""
|
||||
pass in a dictionary with a selection -> weight mapping. Eg.
|
||||
{"Choice 1": 10,
|
||||
"Choice 2": 30,
|
||||
"bear": 100}
|
||||
pass in a dictionary with a selection -> weight mapping. E.g.::
|
||||
|
||||
-Weights need not add up to any particular value.
|
||||
-The actual selection will be returned.
|
||||
{"Choice 1": 10,
|
||||
"Choice 2": 30,
|
||||
"bear": 100}
|
||||
|
||||
- Weights need not add up to any particular value.
|
||||
- The actual selection will be returned.
|
||||
"""
|
||||
selections = list(valDict.keys())
|
||||
weights = list(valDict.values())
|
||||
|
|
@ -1997,42 +1999,42 @@ def report(types = [], prefix = '', xform = None, notifyFunc = None, dConfigPara
|
|||
has no effect and no wrapping/transform occurs. So in production,
|
||||
it's as if the report has been asserted out.
|
||||
|
||||
Parameters::
|
||||
types : A subset list of ['timeStamp', 'frameCount', 'avLocation']
|
||||
This allows you to specify certain useful bits of info.
|
||||
Parameters:
|
||||
types: A subset list of ['timeStamp', 'frameCount', 'avLocation']
|
||||
This allows you to specify certain useful bits of info:
|
||||
|
||||
module: Prints the module that this report statement
|
||||
can be found in.
|
||||
args: Prints the arguments as they were passed to
|
||||
this function.
|
||||
timeStamp: Adds the current frame time to the output.
|
||||
deltaStamp: Adds the current AI synched frame time to
|
||||
the output
|
||||
frameCount: Adds the current frame count to the output.
|
||||
Usually cleaner than the timeStamp output.
|
||||
avLocation: Adds the localAvatar's network location
|
||||
to the output. Useful for interest debugging.
|
||||
interests: Prints the current interest state after the
|
||||
report.
|
||||
stackTrace: Prints a stack trace after the report.
|
||||
- *module*: Prints the module that this report statement
|
||||
can be found in.
|
||||
- *args*: Prints the arguments as they were passed to this
|
||||
function.
|
||||
- *timeStamp*: Adds the current frame time to the output.
|
||||
- *deltaStamp*: Adds the current AI synched frame time to
|
||||
the output
|
||||
- *frameCount*: Adds the current frame count to the output.
|
||||
Usually cleaner than the timeStamp output.
|
||||
- *avLocation*: Adds the localAvatar's network location to
|
||||
the output. Useful for interest debugging.
|
||||
- *interests*: Prints the current interest state after the
|
||||
report.
|
||||
- *stackTrace*: Prints a stack trace after the report.
|
||||
|
||||
prefix: Optional string to prepend to output, just before the function.
|
||||
Allows for easy grepping and is useful when merging AI/Client
|
||||
reports into a single file.
|
||||
prefix: Optional string to prepend to output, just before the
|
||||
function. Allows for easy grepping and is useful when
|
||||
merging AI/Client reports into a single file.
|
||||
|
||||
xform: Optional callback that accepts a single parameter: argument 0 to
|
||||
the decorated function. (assumed to be 'self')
|
||||
It should return a value to be inserted into the report output string.
|
||||
xform: Optional callback that accepts a single parameter:
|
||||
argument 0 to the decorated function. (assumed to be 'self')
|
||||
It should return a value to be inserted into the report
|
||||
output string.
|
||||
|
||||
notifyFunc: A notify function such as info, debug, warning, etc.
|
||||
By default the report will be printed to stdout. This
|
||||
will allow you send the report to a designated 'notify'
|
||||
output.
|
||||
notifyFunc: A notify function such as info, debug, warning, etc.
|
||||
By default the report will be printed to stdout. This will
|
||||
allow you send the report to a designated 'notify' output.
|
||||
|
||||
dConfigParam: A list of Config.prc string variables.
|
||||
By default the report will always print. If you
|
||||
specify this param, it will only print if one of the
|
||||
specified config strings resolve to True.
|
||||
dConfigParam: A list of Config.prc string variables.
|
||||
By default the report will always print. If you specify
|
||||
this param, it will only print if one of the specified
|
||||
config strings resolve to True.
|
||||
"""
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,19 @@ class ShowBase(DirectObject.DirectObject):
|
|||
config = DConfig
|
||||
notify = directNotify.newCategory("ShowBase")
|
||||
|
||||
def __init__(self, fStartDirect = True, windowType = None):
|
||||
def __init__(self, fStartDirect=True, windowType=None):
|
||||
"""Opens a window, sets up a 3-D and several 2-D scene graphs, and
|
||||
everything else needed to render the scene graph to the window.
|
||||
|
||||
To prevent a window from being opened, set windowType to the string
|
||||
'none' (or 'offscreen' to create an offscreen buffer). If this is not
|
||||
specified, the default value is taken from the 'window-type'
|
||||
configuration variable.
|
||||
|
||||
This constructor will add various things to the Python builtins scope,
|
||||
including this instance itself (under the name ``base``).
|
||||
"""
|
||||
|
||||
self.__dev__ = self.config.GetBool('want-dev', __debug__)
|
||||
builtins.__dev__ = self.__dev__
|
||||
|
||||
|
|
@ -1854,6 +1866,7 @@ class ShowBase(DirectObject.DirectObject):
|
|||
self.notify.debug("Disabling music")
|
||||
|
||||
def SetAllSfxEnables(self, bEnabled):
|
||||
"""Calls ``setActive(bEnabled)`` on all valid SFX managers."""
|
||||
for i in range(len(self.sfxManagerList)):
|
||||
if (self.sfxManagerIsValidList[i]):
|
||||
self.sfxManagerList[i].setActive(bEnabled)
|
||||
|
|
@ -2587,9 +2600,9 @@ class ShowBase(DirectObject.DirectObject):
|
|||
sourceLens = None):
|
||||
|
||||
"""
|
||||
Similar to screenshot(), this sets up a temporary cube map
|
||||
Texture which it uses to take a series of six snapshots of the
|
||||
current scene, one in each of the six cube map directions.
|
||||
Similar to :meth:`screenshot()`, this sets up a temporary cube
|
||||
map Texture which it uses to take a series of six snapshots of
|
||||
the current scene, one in each of the six cube map directions.
|
||||
This requires rendering a new frame.
|
||||
|
||||
Unlike screenshot(), source may only be a GraphicsWindow,
|
||||
|
|
@ -2651,19 +2664,19 @@ class ShowBase(DirectObject.DirectObject):
|
|||
cameraMask = PandaNode.getAllCameraMask(),
|
||||
numVertices = 1000, sourceLens = None):
|
||||
"""
|
||||
This works much like saveCubeMap(), and uses the graphics
|
||||
API's hardware cube-mapping ability to get a 360-degree view
|
||||
of the world. But then it converts the six cube map faces
|
||||
into a single fisheye texture, suitable for applying as a
|
||||
static environment map (sphere map).
|
||||
This works much like :meth:`saveCubeMap()`, and uses the
|
||||
graphics API's hardware cube-mapping ability to get a 360-degree
|
||||
view of the world. But then it converts the six cube map faces
|
||||
into a single fisheye texture, suitable for applying as a static
|
||||
environment map (sphere map).
|
||||
|
||||
For eye-relative static environment maps, sphere maps are
|
||||
often preferable to cube maps because they require only a
|
||||
single texture and because they are supported on a broader
|
||||
range of hardware.
|
||||
For eye-relative static environment maps, sphere maps are often
|
||||
preferable to cube maps because they require only a single
|
||||
texture and because they are supported on a broader range of
|
||||
hardware.
|
||||
|
||||
The return value is the filename if successful, or None if
|
||||
there is a problem.
|
||||
The return value is the filename if successful, or None if there
|
||||
is a problem.
|
||||
"""
|
||||
if source == None:
|
||||
source = self.win
|
||||
|
|
@ -2740,17 +2753,22 @@ class ShowBase(DirectObject.DirectObject):
|
|||
format = 'png', sd = 4, source = None):
|
||||
"""
|
||||
Spawn a task to capture a movie using the screenshot function.
|
||||
- namePrefix will be used to form output file names (can include
|
||||
path information (e.g. '/i/beta/frames/myMovie')
|
||||
- duration is the length of the movie in seconds
|
||||
- fps is the frame rate of the resulting movie
|
||||
- format specifies output file format (e.g. png, bmp)
|
||||
- sd specifies number of significant digits for frame count in the
|
||||
output file name (e.g. if sd = 4, movie_0001.png)
|
||||
- source is the Window, Buffer, DisplayRegion, or Texture from which
|
||||
to save the resulting images. The default is the main window.
|
||||
|
||||
The task is returned, so that it can be awaited.
|
||||
Args:
|
||||
namePrefix (str): used to form output file names (can
|
||||
include path information (e.g. '/i/beta/frames/myMovie')
|
||||
duration (float): the length of the movie in seconds
|
||||
fps (float): the frame rate of the resulting movie
|
||||
format (str): specifies output file format (e.g. png, bmp)
|
||||
sd (int): specifies number of significant digits for frame
|
||||
count in the output file name (e.g. if sd = 4, the name
|
||||
will be something like movie_0001.png)
|
||||
source: the Window, Buffer, DisplayRegion, or Texture from
|
||||
which to save the resulting images. The default is the
|
||||
main window.
|
||||
|
||||
Returns:
|
||||
A `~direct.task.Task` that can be awaited.
|
||||
"""
|
||||
globalClock.setMode(ClockObject.MNonRealTime)
|
||||
globalClock.setDt(1.0/float(fps))
|
||||
|
|
@ -3113,11 +3131,12 @@ class ShowBase(DirectObject.DirectObject):
|
|||
self.startDirect(fWantDirect = fDirect, fWantTk = fTk, fWantWx = fWx)
|
||||
|
||||
def run(self):
|
||||
""" This method runs the TaskManager when self.appRunner is
|
||||
None, which is to say, when we are not running from within a
|
||||
p3d file. When we *are* within a p3d file, the Panda
|
||||
runtime has to be responsible for running the main loop, so
|
||||
we can't allow the application to do it. """
|
||||
"""This method runs the :class:`~direct.task.Task.TaskManager`
|
||||
when ``self.appRunner is None``, which is to say, when we are
|
||||
not running from within a p3d file. When we *are* within a p3d
|
||||
file, the Panda3D runtime has to be responsible for running the
|
||||
main loop, so we can't allow the application to do it.
|
||||
"""
|
||||
|
||||
if self.appRunner is None or self.appRunner.dummy or \
|
||||
(self.appRunner.interactiveConsole and not self.appRunner.initialAppImport):
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
"""This module serves as a container to hold the global ShowBase instance, as
|
||||
an alternative to using the builtin scope.
|
||||
"""This module serves as a container to hold the global
|
||||
:class:`~.ShowBase.ShowBase` instance, as an alternative to using the builtin
|
||||
scope.
|
||||
|
||||
Note that you cannot directly import `base` from this module since ShowBase
|
||||
may not have been created yet; instead, ShowBase dynamically adds itself to
|
||||
|
|
@ -16,6 +17,7 @@ from . import DConfig as config
|
|||
|
||||
__dev__ = config.GetBool('want-dev', __debug__)
|
||||
|
||||
#: The global instance of the :class:`panda3d.core.VirtualFileSystem`.
|
||||
vfs = VirtualFileSystem.getGlobalPtr()
|
||||
ostream = Notify.out()
|
||||
globalClock = ClockObject.getGlobalClock()
|
||||
|
|
@ -30,17 +32,23 @@ hidden = NodePath("hidden")
|
|||
# Set direct notify categories now that we have config
|
||||
directNotify.setDconfigLevels()
|
||||
|
||||
|
||||
def run():
|
||||
"""Deprecated alias for :meth:`base.run() <.ShowBase.run>`."""
|
||||
assert ShowBase.notify.warning("run() is deprecated, use base.run() instead")
|
||||
base.run()
|
||||
|
||||
|
||||
def inspect(anObject):
|
||||
"""Opens up a :mod:`direct.tkpanels.Inspector` GUI panel for inspecting an
|
||||
object."""
|
||||
# Don't use a regular import, to prevent ModuleFinder from picking
|
||||
# it up as a dependency when building a .p3d package.
|
||||
import importlib
|
||||
Inspector = importlib.import_module('direct.tkpanels.Inspector')
|
||||
return Inspector.inspect(anObject)
|
||||
|
||||
|
||||
import sys
|
||||
if sys.version_info >= (3, 0):
|
||||
import builtins
|
||||
|
|
|
|||
|
|
@ -36,4 +36,5 @@ del bordercolors
|
|||
|
||||
|
||||
def spawnTkLoop():
|
||||
"""Alias for :meth:`base.spawnTkLoop() <.ShowBase.spawnTkLoop>`."""
|
||||
base.spawnTkLoop()
|
||||
|
|
|
|||
|
|
@ -1,3 +1,10 @@
|
|||
"""The VFS importer allows importing Python modules from Panda3D's virtual
|
||||
file system, through Python's standard import mechanism.
|
||||
|
||||
Calling the :func:`register()` function to register the import hooks should be
|
||||
sufficient to enable this functionality.
|
||||
"""
|
||||
|
||||
__all__ = ['register', 'sharedPackages',
|
||||
'reloadSharedPackage', 'reloadSharedPackages']
|
||||
|
||||
|
|
@ -8,19 +15,18 @@ import marshal
|
|||
import imp
|
||||
import types
|
||||
|
||||
# The sharedPackages dictionary lists all of the "shared packages",
|
||||
# special Python packages that automatically span multiple directories
|
||||
# via magic in the VFSImporter. You can make a package "shared"
|
||||
# simply by adding its name into this dictionary (and then calling
|
||||
# reloadSharedPackages() if it's already been imported).
|
||||
|
||||
# When a package name is in this dictionary at import time, *all*
|
||||
# instances of the package are located along sys.path, and merged into
|
||||
# a single Python module with a __path__ setting that represents the
|
||||
# union. Thus, you can have a direct.showbase.foo in your own
|
||||
# application, and loading it won't shadow the system
|
||||
# direct.showbase.ShowBase which is in a different directory on disk.
|
||||
|
||||
#: The sharedPackages dictionary lists all of the "shared packages",
|
||||
#: special Python packages that automatically span multiple directories
|
||||
#: via magic in the VFSImporter. You can make a package "shared"
|
||||
#: simply by adding its name into this dictionary (and then calling
|
||||
#: reloadSharedPackages() if it's already been imported).
|
||||
#:
|
||||
#: When a package name is in this dictionary at import time, *all*
|
||||
#: instances of the package are located along sys.path, and merged into
|
||||
#: a single Python module with a __path__ setting that represents the
|
||||
#: union. Thus, you can have a direct.showbase.foo in your own
|
||||
#: application, and loading it won't shadow the system
|
||||
#: direct.showbase.ShowBase which is in a different directory on disk.
|
||||
sharedPackages = {}
|
||||
|
||||
vfs = VirtualFileSystem.getGlobalPtr()
|
||||
|
|
@ -31,6 +37,7 @@ if not __debug__:
|
|||
# We implement that by reversing the extension names.
|
||||
compiledExtensions = [ 'pyo', 'pyc' ]
|
||||
|
||||
|
||||
class VFSImporter:
|
||||
""" This class serves as a Python importer to support loading
|
||||
Python .py and .pyc/.pyo files from Panda's Virtual File System,
|
||||
|
|
@ -326,6 +333,7 @@ class VFSLoader:
|
|||
|
||||
return code
|
||||
|
||||
|
||||
class VFSSharedImporter:
|
||||
""" This is a special importer that is added onto the meta_path
|
||||
list, so that it is called before sys.path is traversed. It uses
|
||||
|
|
@ -418,6 +426,7 @@ class VFSSharedImporter:
|
|||
# Couldn't figure it out.
|
||||
return None
|
||||
|
||||
|
||||
class VFSSharedLoader:
|
||||
""" The second part of VFSSharedImporter, this imports a list of
|
||||
packages and combines them. """
|
||||
|
|
@ -470,6 +479,7 @@ class VFSSharedLoader:
|
|||
|
||||
return mod
|
||||
|
||||
|
||||
_registered = False
|
||||
def register():
|
||||
""" Register the VFSImporter on the path_hooks, if it has not
|
||||
|
|
@ -488,6 +498,7 @@ def register():
|
|||
# folders that previously were loaded directly.
|
||||
sys.path_importer_cache = {}
|
||||
|
||||
|
||||
def reloadSharedPackage(mod):
|
||||
""" Reloads the specific module as a shared package, adding any
|
||||
new directories that might have appeared on the search path. """
|
||||
|
|
@ -515,6 +526,7 @@ def reloadSharedPackage(mod):
|
|||
sharedPackages[childname] = True
|
||||
reloadSharedPackage(child)
|
||||
|
||||
|
||||
def reloadSharedPackages():
|
||||
""" Walks through the sharedPackages list, and forces a reload of
|
||||
any modules on that list that have already been loaded. This
|
||||
|
|
@ -530,4 +542,3 @@ def reloadSharedPackages():
|
|||
continue
|
||||
|
||||
reloadSharedPackage(mod)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
""" This module is now vestigial. """
|
||||
|
||||
|
||||
def spawnWxLoop():
|
||||
"""Alias for :meth:`base.spawnWxLoop() <.ShowBase.spawnWxLoop>`."""
|
||||
base.spawnWxLoop()
|
||||
|
|
|
|||
|
|
@ -34,6 +34,11 @@ else:
|
|||
|
||||
|
||||
def open(file, mode='r', buffering=-1, encoding=None, errors=None, newline=None, closefd=True):
|
||||
"""This function emulates the built-in Python open() function, additionally
|
||||
providing support for Panda's virtual file system. It takes the same
|
||||
arguments as Python's built-in open() function.
|
||||
"""
|
||||
|
||||
if sys.version_info >= (3, 0):
|
||||
# Python 3 is much stricter than Python 2, which lets
|
||||
# unknown flags fall through.
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ mechanism for sharing context between different objects written to the
|
|||
same pickle stream, so each NodePath has to write itself without
|
||||
knowing about the other NodePaths that will also be writing to the
|
||||
same stream. This replacement module solves this problem by defining
|
||||
a __reduce_persist__() replacement method for __reduce__(), which
|
||||
accepts a pointer to the Pickler object itself, allowing for shared
|
||||
context between all objects written by that Pickler.
|
||||
a ``__reduce_persist__()`` replacement method for ``__reduce__()``,
|
||||
which accepts a pointer to the Pickler object itself, allowing for
|
||||
shared context between all objects written by that Pickler.
|
||||
|
||||
Unfortunately, cPickle cannot be supported, because it does not
|
||||
support extensions of this nature. """
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
""" This module defines a Python-level wrapper around the C++
|
||||
AsyncTaskManager interface. It replaces the old full-Python
|
||||
implementation of the Task system. """
|
||||
:class:`~panda3d.core.AsyncTaskManager` interface. It replaces the old
|
||||
full-Python implementation of the Task system.
|
||||
|
||||
For more information about the task system, consult the
|
||||
:ref:`tasks-and-event-handling` page in the programming manual.
|
||||
"""
|
||||
|
||||
__all__ = ['Task', 'TaskManager',
|
||||
'cont', 'done', 'again', 'pickup', 'exit',
|
||||
|
|
@ -68,7 +72,7 @@ again = AsyncTask.DSAgain
|
|||
pickup = AsyncTask.DSPickup
|
||||
exit = AsyncTask.DSExit
|
||||
|
||||
# Alias PythonTask to Task for historical purposes.
|
||||
#: Task aliases to :class:`panda3d.core.PythonTask` for historical purposes.
|
||||
Task = PythonTask
|
||||
|
||||
# Copy the module-level enums above into the class level. This funny
|
||||
|
|
@ -274,7 +278,7 @@ class TaskManager:
|
|||
def getTasksMatching(self, taskPattern):
|
||||
"""Returns a list of all tasks, active or sleeping, with a
|
||||
name that matches the pattern, which can include standard
|
||||
shell globbing characters like *, ?, and []. """
|
||||
shell globbing characters like \\*, ?, and []. """
|
||||
|
||||
return self.__makeTaskList(self.mgr.findTasksMatching(GlobPattern(taskPattern)))
|
||||
|
||||
|
|
@ -302,7 +306,7 @@ class TaskManager:
|
|||
uponDeath = None, appendTask = False, owner = None):
|
||||
|
||||
"""Adds a task to be performed at some time in the future.
|
||||
This is identical to add(), except that the specified
|
||||
This is identical to `add()`, except that the specified
|
||||
delayTime is applied to the Task object first, which means
|
||||
that the task will not begin executing until at least the
|
||||
indicated delayTime (in seconds) has elapsed.
|
||||
|
|
@ -326,59 +330,61 @@ class TaskManager:
|
|||
def add(self, funcOrTask, name = None, sort = None, extraArgs = None,
|
||||
priority = None, uponDeath = None, appendTask = False,
|
||||
taskChain = None, owner = None):
|
||||
|
||||
"""
|
||||
Add a new task to the taskMgr. The task will begin executing
|
||||
immediately, or next frame if its sort value has already
|
||||
passed this frame.
|
||||
|
||||
The parameters are:
|
||||
Parameters:
|
||||
funcOrTask: either an existing Task object (not already
|
||||
added to the task manager), or a callable function
|
||||
object. If this is a function, a new Task object will be
|
||||
created and returned. You may also pass in a coroutine
|
||||
object.
|
||||
|
||||
funcOrTask - either an existing Task object (not already added
|
||||
to the task manager), or a callable function object. If this
|
||||
is a function, a new Task object will be created and returned.
|
||||
You may also pass in a coroutine object.
|
||||
name (str): the name to assign to the Task. Required,
|
||||
unless you are passing in a Task object that already has
|
||||
a name.
|
||||
|
||||
name - the name to assign to the Task. Required, unless you
|
||||
are passing in a Task object that already has a name.
|
||||
extraArgs (list): the list of arguments to pass to the task
|
||||
function. If this is omitted, the list is just the task
|
||||
object itself.
|
||||
|
||||
extraArgs - the list of arguments to pass to the task
|
||||
function. If this is omitted, the list is just the task
|
||||
object itself.
|
||||
appendTask (bool): If this is true, then the task object
|
||||
itself will be appended to the end of the extraArgs list
|
||||
before calling the function.
|
||||
|
||||
appendTask - a boolean flag. If this is true, then the task
|
||||
object itself will be appended to the end of the extraArgs
|
||||
list before calling the function.
|
||||
sort (int): the sort value to assign the task. The default
|
||||
sort is 0. Within a particular task chain, it is
|
||||
guaranteed that the tasks with a lower sort value will
|
||||
all run before tasks with a higher sort value run.
|
||||
|
||||
sort - the sort value to assign the task. The default sort is
|
||||
0. Within a particular task chain, it is guaranteed that the
|
||||
tasks with a lower sort value will all run before tasks with a
|
||||
higher sort value run.
|
||||
priority (int): the priority at which to run the task. The
|
||||
default priority is 0. Higher priority tasks are run
|
||||
sooner, and/or more often. For historical purposes, if
|
||||
you specify a priority without also specifying a sort,
|
||||
the priority value is understood to actually be a sort
|
||||
value. (Previously, there was no priority value, only a
|
||||
sort value, and it was called "priority".)
|
||||
|
||||
priority - the priority at which to run the task. The default
|
||||
priority is 0. Higher priority tasks are run sooner, and/or
|
||||
more often. For historical purposes, if you specify a
|
||||
priority without also specifying a sort, the priority value is
|
||||
understood to actually be a sort value. (Previously, there
|
||||
was no priority value, only a sort value, and it was called
|
||||
"priority".)
|
||||
uponDeath (bool): a function to call when the task
|
||||
terminates, either because it has run to completion, or
|
||||
because it has been explicitly removed.
|
||||
|
||||
uponDeath - a function to call when the task terminates,
|
||||
either because it has run to completion, or because it has
|
||||
been explicitly removed.
|
||||
taskChain (str): the name of the task chain to assign the
|
||||
task to.
|
||||
|
||||
taskChain - the name of the task chain to assign the task to.
|
||||
|
||||
owner - an optional Python object that is declared as the
|
||||
"owner" of this task for maintenance purposes. The owner must
|
||||
have two methods: owner._addTask(self, task), which is called
|
||||
when the task begins, and owner._clearTask(self, task), which
|
||||
is called when the task terminates. This is all the owner
|
||||
means.
|
||||
|
||||
The return value of add() is the new Task object that has been
|
||||
added, or the original Task object that was passed in.
|
||||
owner: an optional Python object that is declared as the
|
||||
"owner" of this task for maintenance purposes. The
|
||||
owner must have two methods:
|
||||
``owner._addTask(self, task)``, which is called when the
|
||||
task begins, and ``owner._clearTask(self, task)``, which
|
||||
is called when the task terminates. This is all the
|
||||
ownermeans.
|
||||
|
||||
Returns:
|
||||
The new Task object that has been added, or the original
|
||||
Task object that was passed in.
|
||||
"""
|
||||
|
||||
task = self.__setupTask(funcOrTask, name, priority, sort, extraArgs, taskChain, appendTask, owner, uponDeath)
|
||||
|
|
@ -458,8 +464,8 @@ class TaskManager:
|
|||
|
||||
def removeTasksMatching(self, taskPattern):
|
||||
"""Removes all tasks whose names match the pattern, which can
|
||||
include standard shell globbing characters like *, ?, and [].
|
||||
See also remove().
|
||||
include standard shell globbing characters like \\*, ?, and [].
|
||||
See also :meth:`remove()`.
|
||||
|
||||
Returns the number of tasks removed.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
"""TaskManagerGlobal module: contains the global task manager"""
|
||||
"""Contains the global :class:`~.Task.TaskManager` object."""
|
||||
|
||||
__all__ = ['taskMgr']
|
||||
|
||||
|
|
|
|||
|
|
@ -5,4 +5,7 @@ manages scheduled functions that are executed at designated intervals.
|
|||
The global task manager object can be imported as a singleton::
|
||||
|
||||
from direct.task.TaskManagerGlobal import taskMgr
|
||||
|
||||
For more information about the task system, consult the
|
||||
:ref:`tasks-and-event-handling` page in the programming manual.
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,4 +1,106 @@
|
|||
""" Finite State Machine Inspector module """
|
||||
"""Defines the `FSMInspector` class, which opens a Tkinter window for
|
||||
inspecting :ref:`finite-state-machines`.
|
||||
|
||||
Using the Finite State Inspector
|
||||
--------------------------------
|
||||
|
||||
1) In your Config.prc add::
|
||||
|
||||
want-tk #t
|
||||
|
||||
2) Start up the show and create a Finite State Machine::
|
||||
|
||||
from direct.showbase.ShowBaseGlobal import *
|
||||
|
||||
from direct.fsm import ClassicFSM
|
||||
from direct.fsm import State
|
||||
|
||||
def enterState():
|
||||
print('enterState')
|
||||
|
||||
def exitState():
|
||||
print 'exitState'
|
||||
|
||||
fsm = ClassicFSM.ClassicFSM('stopLight',
|
||||
[State.State('red', enterState, exitState, ['green']),
|
||||
State.State('yellow', enterState, exitState, ['red']),
|
||||
State.State('green', enterState, exitState, ['yellow'])],
|
||||
'red',
|
||||
'red')
|
||||
|
||||
import FSMInspector
|
||||
|
||||
inspector = FSMInspector.FSMInspector(fsm, title = fsm.getName())
|
||||
|
||||
# Note, the inspectorPos argument is optional, the inspector will
|
||||
# automagically position states on startup
|
||||
fsm = ClassicFSM.ClassicFSM('stopLight', [
|
||||
State.State('yellow',
|
||||
enterState,
|
||||
exitState,
|
||||
['red'],
|
||||
inspectorPos = [95.9, 48.0]),
|
||||
State.State('red',
|
||||
enterState,
|
||||
exitState,
|
||||
['green'],
|
||||
inspectorPos = [0.0, 0.0]),
|
||||
State.State('green',
|
||||
enterState,
|
||||
exitState,
|
||||
['yellow'],
|
||||
inspectorPos = [0.0, 95.9])],
|
||||
'red',
|
||||
'red')
|
||||
|
||||
3) Pop open a viewer::
|
||||
|
||||
import FSMInspector
|
||||
insp = FSMInspector.FSMInspector(fsm)
|
||||
|
||||
or if you wish to be fancy::
|
||||
|
||||
insp = FSMInspector.FSMInspector(fsm, title = fsm.getName())
|
||||
|
||||
Features:
|
||||
|
||||
- Right mouse button over a state pops up a menu allowing you to
|
||||
request a transition to that state
|
||||
- Middle mouse button will grab the canvas and slide things around if
|
||||
your state machine is bigger than the viewing area
|
||||
- There are some self explanatory menu options up at the top, the most
|
||||
useful being: "print ClassicFSM layout" which will print out Python
|
||||
code which will create an ClassicFSM augmented with layout
|
||||
information for the viewer so everything shows up in the same place
|
||||
the next time you inspect the state machine
|
||||
|
||||
Caveat
|
||||
------
|
||||
|
||||
There is an unexplained problem with using Tk and emacs right now which
|
||||
occasionally results in everything locking up. This procedure seems to
|
||||
avoid the problem for me::
|
||||
|
||||
# Start up the show
|
||||
from direct.showbase.ShowBaseGlobal import *
|
||||
|
||||
# You will see the window and a Tk panel pop open
|
||||
|
||||
# Type a number at the emacs prompt
|
||||
>>> 123
|
||||
|
||||
# At this point everything will lock up and you won't get your prompt back
|
||||
|
||||
# Hit a bunch of Control-C's in rapid succession, in most cases
|
||||
# this will break you out of whatever badness you were in and
|
||||
# from that point on everything will behave normally
|
||||
|
||||
|
||||
# This is how you pop up an inspector
|
||||
import FSMInspector
|
||||
inspector = FSMInspector.FSMInspector(fsm, title = fsm.getName())
|
||||
|
||||
"""
|
||||
|
||||
__all__ = ['FSMInspector', 'StateInspector']
|
||||
|
||||
|
|
@ -14,6 +116,7 @@ else:
|
|||
|
||||
DELTA = (5.0 / 360.) * 2.0 * math.pi
|
||||
|
||||
|
||||
class FSMInspector(AppShell):
|
||||
# Override class variables
|
||||
appname = 'ClassicFSM Inspector'
|
||||
|
|
@ -445,104 +548,3 @@ class StateInspector(Pmw.MegaArchetype):
|
|||
|
||||
def exitedState(self):
|
||||
self._canvas.itemconfigure(self.marker, fill = 'CornflowerBlue')
|
||||
|
||||
|
||||
"""
|
||||
# USING FINITE STATE INSPECTOR
|
||||
|
||||
1) in your Configrc add:
|
||||
|
||||
want-tk #t
|
||||
|
||||
2) start up the show and create a Finite State Machine
|
||||
|
||||
from direct.showbase.ShowBaseGlobal import *
|
||||
|
||||
from direct.fsm import ClassicFSM
|
||||
from direct.fsm import State
|
||||
|
||||
def enterState():
|
||||
print 'enterState'
|
||||
|
||||
def exitState():
|
||||
print 'exitState'
|
||||
|
||||
fsm = ClassicFSM.ClassicFSM('stopLight',
|
||||
[State.State('red', enterState, exitState, ['green']),
|
||||
State.State('yellow', enterState, exitState, ['red']),
|
||||
State.State('green', enterState, exitState, ['yellow'])],
|
||||
'red',
|
||||
'red')
|
||||
|
||||
import FSMInspector
|
||||
|
||||
inspector = FSMInspector.FSMInspector(fsm, title = fsm.getName())
|
||||
|
||||
# Note, the inspectorPos argument is optional, the inspector will
|
||||
# automagically position states on startup
|
||||
fsm = ClassicFSM.ClassicFSM('stopLight', [
|
||||
State.State('yellow',
|
||||
enterState,
|
||||
exitState,
|
||||
['red'],
|
||||
inspectorPos = [95.9, 48.0]),
|
||||
State.State('red',
|
||||
enterState,
|
||||
exitState,
|
||||
['green'],
|
||||
inspectorPos = [0.0, 0.0]),
|
||||
State.State('green',
|
||||
enterState,
|
||||
exitState,
|
||||
['yellow'],
|
||||
inspectorPos = [0.0, 95.9])],
|
||||
'red',
|
||||
'red')
|
||||
|
||||
3) Pop open a viewer
|
||||
|
||||
import FSMInspector
|
||||
insp = FSMInspector.FSMInspector(fsm)
|
||||
|
||||
or if you wish to be fancy:
|
||||
|
||||
insp = FSMInspector.FSMInspector(fsm, title = fsm.getName())
|
||||
|
||||
Features:
|
||||
- Right mouse button over a state pops up a menu allowing you to
|
||||
request a transition to that state
|
||||
- Middle mouse button will grab the canvas and slide things around
|
||||
if your state machine is bigger than the viewing area
|
||||
- There are some self explanatory menu options up at the top, the most
|
||||
useful being: "print ClassicFSM layout" which will print out python code
|
||||
which will create an ClassicFSM augmented with layout information for the
|
||||
viewer so everything shows up in the same place the next time you
|
||||
inspect the state machine
|
||||
|
||||
CAVEAT:
|
||||
|
||||
There is some unexplained problems with using TK and emacs right now which
|
||||
occasionally results in everything locking up. This procedure seems to
|
||||
avoid the problem for me:
|
||||
|
||||
# Start up the show
|
||||
from direct.showbase.ShowBaseGlobal import *
|
||||
|
||||
# You will see the window and a Tk panel pop open
|
||||
|
||||
# Type a number at the emacs prompt
|
||||
>>> 123
|
||||
|
||||
# At this point everything will lock up and you won't get your prompt back
|
||||
|
||||
# Hit a bunch of Control-C's in rapid succession, in most cases
|
||||
# this will break you out of whatever badness you were in and
|
||||
# from that point on everything will behave normally
|
||||
|
||||
|
||||
# This is how you pop up an inspector
|
||||
import FSMInspector
|
||||
inspector = FSMInspector.FSMInspector(fsm, title = fsm.getName())
|
||||
|
||||
"""
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
"""This package provides various GUI panels useful during Panda3D development
|
||||
written using the Tkinter framework.
|
||||
"""
|
||||
|
|
@ -0,0 +1 @@
|
|||
"""This package provides various Tkinter widgets."""
|
||||
Loading…
Reference in New Issue