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:
rdb 2019-10-29 20:43:15 +01:00
parent ffeb8937bf
commit f149fb4ab0
79 changed files with 939 additions and 736 deletions

View File

@ -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. """

View File

@ -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

View File

@ -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',

View File

@ -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"):

View File

@ -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.
"""

View File

@ -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.
"""

View File

@ -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

View File

@ -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)

View File

@ -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.
"""

View File

@ -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.
"""

View File

@ -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.
"""

View File

@ -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 *

View File

@ -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 *

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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.
"""

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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")

View File

@ -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.

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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).

View File

@ -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).

View File

@ -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.
"""

View File

@ -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

View File

@ -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 *

View File

@ -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']

View File

@ -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 *

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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']

View File

@ -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

View File

@ -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.
"""

View File

@ -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"]

View File

@ -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"]

View File

@ -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"]

View File

@ -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

View File

@ -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.
"""

View File

@ -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:

View File

@ -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.
"""

View File

@ -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

View File

@ -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):

View File

@ -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()

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -2,4 +2,5 @@ __all__ = ['jobMgr']
from . import JobManager
#: Contains the global :class:`~.JobManager.JobManager` object.
jobMgr = JobManager.JobManager()

View File

@ -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

View File

@ -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']

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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()

View File

@ -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")

View File

@ -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.
"""

View File

@ -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):

View File

@ -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

View File

@ -36,4 +36,5 @@ del bordercolors
def spawnTkLoop():
"""Alias for :meth:`base.spawnTkLoop() <.ShowBase.spawnTkLoop>`."""
base.spawnTkLoop()

View File

@ -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)

View File

@ -1,4 +1,6 @@
""" This module is now vestigial. """
def spawnWxLoop():
"""Alias for :meth:`base.spawnWxLoop() <.ShowBase.spawnWxLoop>`."""
base.spawnWxLoop()

View File

@ -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.

View File

@ -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. """

View File

@ -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.
"""

View File

@ -1,4 +1,4 @@
"""TaskManagerGlobal module: contains the global task manager"""
"""Contains the global :class:`~.Task.TaskManager` object."""
__all__ = ['taskMgr']

View File

@ -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.
"""

View File

@ -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())
"""

View File

@ -0,0 +1,3 @@
"""This package provides various GUI panels useful during Panda3D development
written using the Tkinter framework.
"""

View File

@ -0,0 +1 @@
"""This package provides various Tkinter widgets."""