mirror of
https://github.com/RYDE-WORK/ballistica.git
synced 2026-01-25 00:13:27 +08:00
update examples
This commit is contained in:
parent
7673e01b9b
commit
7ecd804c1b
@ -1 +1 @@
|
||||
175217515325031448193730963697929841246
|
||||
225891607870108897605481763130834194451
|
||||
@ -102,7 +102,7 @@ class Context:
|
||||
|
||||
Category: General Utility Classes
|
||||
|
||||
Many operations such as ba.newnode() or ba.gettexture() operate
|
||||
Many operations such as ba.newnode or ba.gettexture operate
|
||||
implicitly on the current context. Each ba.Activity has its own
|
||||
Context and objects within that activity (nodes, media, etc) can only
|
||||
interact with other objects from that context.
|
||||
@ -114,17 +114,17 @@ class Context:
|
||||
the UI (there is a special 'ui' context for all user-interface-related
|
||||
functionality)
|
||||
|
||||
When instantiating a ba.Context instance, a single 'source' argument
|
||||
When instantiating a ba.Context instance, a single ``'source'`` argument
|
||||
is passed, which can be one of the following strings/objects:
|
||||
|
||||
'empty':
|
||||
``'empty'``:
|
||||
Gives an empty context; it can be handy to run code here to ensure
|
||||
it does no loading of media, creation of nodes, etc.
|
||||
|
||||
'current':
|
||||
``'current'``:
|
||||
Sets the context object to the current context.
|
||||
|
||||
'ui':
|
||||
``'ui'``:
|
||||
Sets to the UI context. UI functions as well as loading of media to
|
||||
be used in said functions must happen in the UI context.
|
||||
|
||||
@ -138,16 +138,18 @@ class Context:
|
||||
|
||||
|
||||
Usage:
|
||||
Contexts are generally used with the python 'with' statement, which
|
||||
sets the context as current on entry and resets it to the previous
|
||||
value on exit.
|
||||
|
||||
Contexts are generally used with the python 'with' statement, which
|
||||
sets the context as current on entry and resets it to the previous
|
||||
value on exit.
|
||||
|
||||
# Example: load a few textures into the UI context
|
||||
# (for use in widgets, etc):
|
||||
with ba.Context('ui'):
|
||||
tex1 = ba.gettexture('foo_tex_1')
|
||||
tex2 = ba.gettexture('foo_tex_2')
|
||||
Example:
|
||||
Load a few textures into the UI context
|
||||
(for use in widgets, etc):
|
||||
```python
|
||||
>>> with ba.Context('ui'):
|
||||
... tex1 = ba.gettexture('foo_tex_1')
|
||||
... tex2 = ba.gettexture('foo_tex_2')
|
||||
```
|
||||
"""
|
||||
|
||||
def __init__(self, source: Any):
|
||||
@ -189,17 +191,21 @@ class ContextCall:
|
||||
shutdown, whereas ba.WeakCall simply looks at whether the target
|
||||
object still exists.
|
||||
|
||||
# Example A: code like this can inadvertently prevent our activity
|
||||
# (self) from ending until the operation completes, since the bound
|
||||
# method we're passing (self.dosomething) contains a strong-reference
|
||||
# to self).
|
||||
start_some_long_action(callback_when_done=self.dosomething)
|
||||
Examples:
|
||||
Example A: code like this can inadvertently prevent our activity
|
||||
(self) from ending until the operation completes, since the bound
|
||||
method we're passing (self.dosomething) contains a strong-reference
|
||||
to self).
|
||||
>>> start_some_long_action(callback_when_done=self.dosomething)
|
||||
|
||||
# Example B: in this case our activity (self) can still die
|
||||
# properly; the callback will clear itself when the activity starts
|
||||
# shutting down, becoming a harmless no-op and releasing the reference
|
||||
# to our activity.
|
||||
start_long_action(callback_when_done=ba.ContextCall(self.mycallback))
|
||||
Example B: in this case our activity (self) can still die
|
||||
properly; the callback will clear itself when the activity starts
|
||||
shutting down, becoming a harmless no-op and releasing the reference
|
||||
to our activity.
|
||||
```python
|
||||
>>> start_long_action(
|
||||
... callback_when_done=ba.ContextCall(self.mycallback))
|
||||
```
|
||||
"""
|
||||
|
||||
def __init__(self, call: Callable):
|
||||
@ -235,41 +241,41 @@ class InputDevice:
|
||||
|
||||
Attributes:
|
||||
|
||||
allows_configuring
|
||||
allows_configuring (bool):
|
||||
Whether the input-device can be configured.
|
||||
|
||||
has_meaningful_button_names
|
||||
has_meaningful_button_names (bool):
|
||||
Whether button names returned by this instance match labels
|
||||
on the actual device. (Can be used to determine whether to show
|
||||
them in controls-overlays, etc.).
|
||||
|
||||
player
|
||||
player (Optional[ba.SessionPlayer]):
|
||||
The player associated with this input device.
|
||||
|
||||
client_id
|
||||
client_id (int):
|
||||
The numeric client-id this device is associated with.
|
||||
This is only meaningful for remote client inputs; for
|
||||
all local devices this will be -1.
|
||||
|
||||
name
|
||||
name (str):
|
||||
The name of the device.
|
||||
|
||||
unique_identifier
|
||||
unique_identifier (str):
|
||||
A string that can be used to persistently identify the device,
|
||||
even among other devices of the same type. Used for saving
|
||||
prefs, etc.
|
||||
|
||||
id
|
||||
id (int):
|
||||
The unique numeric id of this device.
|
||||
|
||||
instance_number
|
||||
instance_number (int):
|
||||
The number of this device among devices of the same type.
|
||||
|
||||
is_controller_app
|
||||
is_controller_app (bool):
|
||||
Whether this input-device represents a locally-connected
|
||||
controller-app.
|
||||
|
||||
is_remote_client
|
||||
is_remote_client (bool):
|
||||
Whether this input-device represents a remotely-connected
|
||||
client.
|
||||
|
||||
@ -362,20 +368,20 @@ class Material:
|
||||
A material can affect physical characteristics, generate sounds,
|
||||
or trigger callback functions when collisions occur.
|
||||
|
||||
Materials are applied to 'parts', which are groups of one or more
|
||||
rigid bodies created as part of a ba.Node. Nodes can have any number
|
||||
Materials are applied to ``'parts'``, which are groups of one or more
|
||||
rigid bodies created as part of a ba.Node. Nodes can have any number
|
||||
of parts, each with its own set of materials. Generally materials are
|
||||
specified as array attributes on the Node. The 'spaz' node, for
|
||||
example, has various attributes such as 'materials',
|
||||
'roller_materials', and 'punch_materials', which correspond to the
|
||||
specified as array attributes on the Node. The ``'spaz'`` node, for
|
||||
example, has various attributes such as ``'materials'``,
|
||||
``'roller_materials'``, and ``'punch_materials'``, which correspond to the
|
||||
various parts it creates.
|
||||
|
||||
Use ba.Material() to instantiate a blank material, and then use its
|
||||
add_actions() method to define what the material does.
|
||||
Use ba.Material to instantiate a blank material, and then use its
|
||||
ba.Material.add_actions method to define what the material does.
|
||||
|
||||
Attributes:
|
||||
|
||||
label
|
||||
label (str):
|
||||
A label for the material; only used for debugging.
|
||||
"""
|
||||
|
||||
@ -393,133 +399,139 @@ class Material:
|
||||
Add one or more actions to the material, optionally with conditions.
|
||||
|
||||
Conditions:
|
||||
Conditions are provided as tuples which can be combined to form boolean
|
||||
logic. A single condition might look like ``('condition_name', cond_arg)``,
|
||||
or a more complex nested one might look like ``(('some_condition',
|
||||
cond_arg), 'or', ('another_condition', cond2_arg))``.
|
||||
|
||||
Conditions are provided as tuples which can be combined to form boolean
|
||||
logic. A single condition might look like ('condition_name', cond_arg),
|
||||
or a more complex nested one might look like (('some_condition',
|
||||
cond_arg), 'or', ('another_condition', cond2_arg)).
|
||||
|
||||
'and', 'or', and 'xor' are available to chain together 2 conditions, as
|
||||
seen above.
|
||||
``'and'``, ``'or'``, and ``'xor'`` are available to chain together 2 conditions, as
|
||||
seen above.
|
||||
|
||||
Available Conditions:
|
||||
``('they_have_material', material)`` - does the part we're hitting have a
|
||||
given ba.Material?
|
||||
|
||||
('they_have_material', material) - does the part we're hitting have a
|
||||
given ba.Material?
|
||||
``('they_dont_have_material', material)`` - does the part we're hitting
|
||||
not have a given ba.Material?
|
||||
|
||||
('they_dont_have_material', material) - does the part we're hitting
|
||||
not have a given ba.Material?
|
||||
``('eval_colliding')`` - is ``'collide'`` true at this point in material
|
||||
evaluation? (see the modify_part_collision action)
|
||||
|
||||
('eval_colliding') - is 'collide' true at this point in material
|
||||
evaluation? (see the modify_part_collision action)
|
||||
``('eval_not_colliding')`` - is 'collide' false at this point in material
|
||||
evaluation? (see the modify_part_collision action)
|
||||
|
||||
('eval_not_colliding') - is 'collide' false at this point in material
|
||||
evaluation? (see the modify_part_collision action)
|
||||
``('we_are_younger_than', age)`` - is our part younger than ``'age'``
|
||||
(in milliseconds)?
|
||||
|
||||
('we_are_younger_than', age) - is our part younger than 'age'
|
||||
(in milliseconds)?
|
||||
``('we_are_older_than', age)`` - is our part older than ``'age'``
|
||||
(in milliseconds)?
|
||||
|
||||
('we_are_older_than', age) - is our part older than 'age'
|
||||
(in milliseconds)?
|
||||
``('they_are_younger_than', age)`` - is the part we're hitting younger than
|
||||
``'age'`` (in milliseconds)?
|
||||
|
||||
('they_are_younger_than', age) - is the part we're hitting younger than
|
||||
'age' (in milliseconds)?
|
||||
``('they_are_older_than', age)`` - is the part we're hitting older than
|
||||
``'age'`` (in milliseconds)?
|
||||
|
||||
('they_are_older_than', age) - is the part we're hitting older than
|
||||
'age' (in milliseconds)?
|
||||
``('they_are_same_node_as_us')`` - does the part we're hitting belong to
|
||||
the same ba.Node as us?
|
||||
|
||||
('they_are_same_node_as_us') - does the part we're hitting belong to
|
||||
the same ba.Node as us?
|
||||
|
||||
('they_are_different_node_than_us') - does the part we're hitting
|
||||
belong to a different ba.Node than us?
|
||||
``('they_are_different_node_than_us')`` - does the part we're hitting
|
||||
belong to a different ba.Node than us?
|
||||
|
||||
Actions:
|
||||
|
||||
In a similar manner, actions are specified as tuples. Multiple actions
|
||||
can be specified by providing a tuple of tuples.
|
||||
In a similar manner, actions are specified as tuples. Multiple actions
|
||||
can be specified by providing a tuple of tuples.
|
||||
|
||||
Available Actions:
|
||||
``('call', when, callable)`` - calls the provided callable; ``'when'`` can be
|
||||
either ``'at_connect'`` or ``'at_disconnect'``. ``'at_connect'`` means to fire
|
||||
when the two parts first come in contact; ``'at_disconnect'`` means to
|
||||
fire once they cease being in contact.
|
||||
|
||||
('call', when, callable) - calls the provided callable; 'when' can be
|
||||
either 'at_connect' or 'at_disconnect'. 'at_connect' means to fire
|
||||
when the two parts first come in contact; 'at_disconnect' means to
|
||||
fire once they cease being in contact.
|
||||
``('message', who, when, message_obj)`` - sends a message object; ``'who'`` can
|
||||
be either ``'our_node'`` or ``'their_node'``, ``'when'`` can be ``'at_connect'`` or
|
||||
``'at_disconnect'``, and message_obj is the message object to send.
|
||||
This has the same effect as calling the node's ba.Node.handlemessage
|
||||
method.
|
||||
|
||||
('message', who, when, message_obj) - sends a message object; 'who' can
|
||||
be either 'our_node' or 'their_node', 'when' can be 'at_connect' or
|
||||
'at_disconnect', and message_obj is the message object to send.
|
||||
This has the same effect as calling the node's handlemessage()
|
||||
method.
|
||||
``('modify_part_collision', attr, value)`` - changes some characteristic
|
||||
of the physical collision that will occur between our part and their
|
||||
part. This change will remain in effect as long as the two parts
|
||||
remain overlapping. This means if you have a part with a material
|
||||
that turns ``'collide'`` off against parts younger than 100ms, and it
|
||||
touches another part that is 50ms old, it will continue to not
|
||||
collide with that part until they separate, even if the 100ms
|
||||
threshold is passed. Options for attr/value are: ``'physical'`` (boolean
|
||||
value; whether a *physical* response will occur at all), ``'friction'``
|
||||
(float value; how friction-y the physical response will be),
|
||||
``'collide'`` (boolean value; whether *any* collision will occur at all,
|
||||
including non-physical stuff like callbacks), ``'use_node_collide'``
|
||||
(boolean value; whether to honor modify_node_collision overrides for
|
||||
this collision), ``'stiffness'`` (float value, how springy the physical
|
||||
response is), ``'damping'`` (float value, how damped the physical
|
||||
response is), ``'bounce'`` (float value; how bouncy the physical response
|
||||
is).
|
||||
|
||||
('modify_part_collision', attr, value) - changes some characteristic
|
||||
of the physical collision that will occur between our part and their
|
||||
part. This change will remain in effect as long as the two parts
|
||||
remain overlapping. This means if you have a part with a material
|
||||
that turns 'collide' off against parts younger than 100ms, and it
|
||||
touches another part that is 50ms old, it will continue to not
|
||||
collide with that part until they separate, even if the 100ms
|
||||
threshold is passed. Options for attr/value are: 'physical' (boolean
|
||||
value; whether a *physical* response will occur at all), 'friction'
|
||||
(float value; how friction-y the physical response will be),
|
||||
'collide' (boolean value; whether *any* collision will occur at all,
|
||||
including non-physical stuff like callbacks), 'use_node_collide'
|
||||
(boolean value; whether to honor modify_node_collision overrides for
|
||||
this collision), 'stiffness' (float value, how springy the physical
|
||||
response is), 'damping' (float value, how damped the physical
|
||||
response is), 'bounce' (float value; how bouncy the physical response
|
||||
is).
|
||||
``('modify_node_collision', attr, value)`` - similar to
|
||||
``modify_part_collision``, but operates at a node-level.
|
||||
collision attributes set here will remain in effect as long as
|
||||
*anything* from our part's node and their part's node overlap.
|
||||
A key use of this functionality is to prevent new nodes from
|
||||
colliding with each other if they appear overlapped;
|
||||
if ``modify_part_collision`` is used, only the individual parts that
|
||||
were overlapping would avoid contact, but other parts could still
|
||||
contact leaving the two nodes 'tangled up'. Using
|
||||
``modify_node_collision ensures`` that the nodes must completely
|
||||
separate before they can start colliding. Currently the only attr
|
||||
available here is ``'collide'`` (a boolean value).
|
||||
|
||||
('modify_node_collision', attr, value) - similar to
|
||||
modify_part_collision, but operates at a node-level.
|
||||
collision attributes set here will remain in effect as long as
|
||||
*anything* from our part's node and their part's node overlap.
|
||||
A key use of this functionality is to prevent new nodes from
|
||||
colliding with each other if they appear overlapped;
|
||||
if modify_part_collision is used, only the individual parts that
|
||||
were overlapping would avoid contact, but other parts could still
|
||||
contact leaving the two nodes 'tangled up'. Using
|
||||
modify_node_collision ensures that the nodes must completely
|
||||
separate before they can start colliding. Currently the only attr
|
||||
available here is 'collide' (a boolean value).
|
||||
``('sound', sound, volume)`` - plays a ba.Sound when a collision occurs, at
|
||||
a given volume, regardless of the collision speed/etc.
|
||||
|
||||
('sound', sound, volume) - plays a ba.Sound when a collision occurs, at
|
||||
a given volume, regardless of the collision speed/etc.
|
||||
``('impact_sound', sound, targetImpulse, volume)`` - plays a sound when a
|
||||
collision occurs, based on the speed of impact. Provide a ba.Sound, a
|
||||
target-impulse, and a volume.
|
||||
|
||||
('impact_sound', sound, targetImpulse, volume) - plays a sound when a
|
||||
collision occurs, based on the speed of impact. Provide a ba.Sound, a
|
||||
target-impulse, and a volume.
|
||||
``('skid_sound', sound, targetImpulse, volume)`` - plays a sound during a
|
||||
collision when parts are 'scraping' against each other. Provide a
|
||||
ba.Sound, a target-impulse, and a volume.
|
||||
|
||||
('skid_sound', sound, targetImpulse, volume) - plays a sound during a
|
||||
collision when parts are 'scraping' against each other. Provide a
|
||||
ba.Sound, a target-impulse, and a volume.
|
||||
``('roll_sound', sound, targetImpulse, volume)`` - plays a sound during a
|
||||
collision when parts are 'rolling' against each other. Provide a
|
||||
ba.Sound, a target-impulse, and a volume.
|
||||
|
||||
('roll_sound', sound, targetImpulse, volume) - plays a sound during a
|
||||
collision when parts are 'rolling' against each other. Provide a
|
||||
ba.Sound, a target-impulse, and a volume.
|
||||
Examples:
|
||||
example 1: create a material that lets us ignore
|
||||
collisions against any nodes we touch in the first
|
||||
100 ms of our existence; handy for preventing us from
|
||||
exploding outward if we spawn on top of another object:
|
||||
```python
|
||||
>>> m = ba.Material()
|
||||
... m.add_actions(
|
||||
... conditions=(('we_are_younger_than', 100),
|
||||
... 'or', ('they_are_younger_than', 100)),
|
||||
... actions=('modify_node_collision', 'collide', False))
|
||||
```
|
||||
|
||||
# example 1: create a material that lets us ignore
|
||||
# collisions against any nodes we touch in the first
|
||||
# 100 ms of our existence; handy for preventing us from
|
||||
# exploding outward if we spawn on top of another object:
|
||||
m = ba.Material()
|
||||
m.add_actions(conditions=(('we_are_younger_than', 100),
|
||||
'or',('they_are_younger_than', 100)),
|
||||
actions=('modify_node_collision', 'collide', False))
|
||||
example 2: send a ba.DieMessage to anything we touch, but cause
|
||||
no physical response. This should cause any ba.Actor to drop dead:
|
||||
```python
|
||||
>>> m = ba.Material()
|
||||
... m.add_actions(
|
||||
... actions=(('modify_part_collision', 'physical', False),
|
||||
... ('message', 'their_node', 'at_connect',
|
||||
... ba.DieMessage())))
|
||||
```
|
||||
|
||||
# example 2: send a DieMessage to anything we touch, but cause
|
||||
# no physical response. This should cause any ba.Actor to drop dead:
|
||||
m = ba.Material()
|
||||
m.add_actions(actions=(('modify_part_collision', 'physical', False),
|
||||
('message', 'their_node', 'at_connect',
|
||||
ba.DieMessage())))
|
||||
|
||||
# example 3: play some sounds when we're contacting the ground:
|
||||
m = ba.Material()
|
||||
m.add_actions(conditions=('they_have_material',
|
||||
shared.footing_material),
|
||||
actions=(('impact_sound', ba.getsound('metalHit'), 2, 5),
|
||||
('skid_sound', ba.getsound('metalSkid'), 2, 5)))
|
||||
example 3: play some sounds when we're contacting the ground:
|
||||
```python
|
||||
>>> m = ba.Material()
|
||||
... m.add_actions(
|
||||
... conditions=('they_have_material',
|
||||
shared.footing_material),
|
||||
... actions=(('impact_sound', ba.getsound('metalHit'), 2, 5),
|
||||
... ('skid_sound', ba.getsound('metalSkid'), 2, 5)))
|
||||
```
|
||||
|
||||
"""
|
||||
return None
|
||||
@ -688,14 +700,17 @@ class Node:
|
||||
Connect one of this node's attributes to an attribute on another node.
|
||||
This will immediately set the target attribute's value to that of the
|
||||
source attribute, and will continue to do so once per step as long as
|
||||
the two nodes exist. The connection can be severed by setting the
|
||||
the two nodes exist. The connection can be severed by setting the
|
||||
target attribute to any value or connecting another node attribute
|
||||
to it.
|
||||
|
||||
# Example: create a locator and attach a light to it:
|
||||
light = ba.newnode('light')
|
||||
loc = ba.newnode('locator', attrs={'position': (0,10,0)})
|
||||
loc.connectattr('position', light, 'position')
|
||||
Example:
|
||||
Create a locator and attach a light to it:
|
||||
```python
|
||||
>>> light = ba.newnode('light')
|
||||
... loc = ba.newnode('locator', attrs={'position': (0, 10, 0)})
|
||||
... loc.connectattr('position', light, 'position')
|
||||
```
|
||||
"""
|
||||
return None
|
||||
|
||||
@ -1005,16 +1020,19 @@ class Timer:
|
||||
timeformat: A ba.TimeFormat value determining how the passed time is
|
||||
interpreted.
|
||||
|
||||
# Example: use a Timer object to print repeatedly for a few seconds:
|
||||
def say_it():
|
||||
ba.screenmessage('BADGER!')
|
||||
def stop_saying_it():
|
||||
self.t = None
|
||||
ba.screenmessage('MUSHROOM MUSHROOM!')
|
||||
# Create our timer; it will run as long as we have the self.t ref.
|
||||
self.t = ba.Timer(0.3, say_it, repeat=True)
|
||||
# Now fire off a one-shot timer to kill it.
|
||||
ba.timer(3.89, stop_saying_it)
|
||||
Example:
|
||||
Use a Timer object to print repeatedly for a few seconds:
|
||||
```python
|
||||
>>> def say_it():
|
||||
... ba.screenmessage('BADGER!')
|
||||
... def stop_saying_it():
|
||||
... self.t = None
|
||||
... ba.screenmessage('MUSHROOM MUSHROOM!')
|
||||
... # Create our timer; it will run as long as we have the self.t ref.
|
||||
... self.t = ba.Timer(0.3, say_it, repeat=True)
|
||||
... # Now fire off a one-shot timer to kill it.
|
||||
... ba.timer(3.89, stop_saying_it)
|
||||
```
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
@ -1797,10 +1815,13 @@ def do_once() -> bool:
|
||||
The call is made from. Returns True if this location has not been
|
||||
registered already, and False if it has.
|
||||
|
||||
# Example: this print will only fire for the first loop iteration:
|
||||
for i in range(10):
|
||||
if ba.do_once():
|
||||
print('Hello once from loop!')
|
||||
Example:
|
||||
This print will only fire for the first loop iteration:
|
||||
```python
|
||||
>>> for i in range(10):
|
||||
... if ba.do_once():
|
||||
... print('Hello once from loop!')
|
||||
```
|
||||
"""
|
||||
return bool()
|
||||
|
||||
@ -3572,8 +3593,8 @@ def set_have_mods(have_mods: bool) -> None:
|
||||
|
||||
|
||||
def set_internal_language_keys(
|
||||
listobj: list[tuple[str, str]],
|
||||
random_names_list: list[tuple[str, str]]) -> None:
|
||||
listobj: list[tuple[str, str]],
|
||||
random_names_list: list[tuple[str, str]]) -> None:
|
||||
"""set_internal_language_keys(listobj: list[tuple[str, str]],
|
||||
random_names_list: list[tuple[str, str]]) -> None
|
||||
|
||||
@ -3591,7 +3612,7 @@ def set_low_level_config_value(key: str, value: int) -> None:
|
||||
|
||||
|
||||
def set_map_bounds(
|
||||
bounds: tuple[float, float, float, float, float, float]) -> None:
|
||||
bounds: tuple[float, float, float, float, float, float]) -> None:
|
||||
"""set_map_bounds(bounds: tuple[float, float, float, float, float, float])
|
||||
-> None
|
||||
|
||||
@ -3943,8 +3964,8 @@ def textwidget(edit: ba.Widget = None,
|
||||
|
||||
@overload
|
||||
def time(
|
||||
timetype: ba.TimeType = TimeType.SIM,
|
||||
timeformat: Literal[TimeFormat.SECONDS] = TimeFormat.SECONDS) -> float:
|
||||
timetype: ba.TimeType = TimeType.SIM,
|
||||
timeformat: Literal[TimeFormat.SECONDS] = TimeFormat.SECONDS) -> float:
|
||||
...
|
||||
|
||||
|
||||
@ -4037,45 +4058,53 @@ def timer(time: float,
|
||||
This timer cannot be canceled or modified once created. If you
|
||||
require the ability to do so, use the ba.Timer class instead.
|
||||
|
||||
time: length of time (in seconds by default) that the timer will wait
|
||||
before firing. Note that the actual delay experienced may vary
|
||||
depending on the timetype. (see below)
|
||||
Arguments:
|
||||
time (float):
|
||||
Length of time (in seconds by default) that the timer will wait
|
||||
before firing. Note that the actual delay experienced may vary
|
||||
depending on the timetype. (see below)
|
||||
|
||||
call: A callable Python object. Note that the timer will retain a
|
||||
strong reference to the callable for as long as it exists, so you
|
||||
may want to look into concepts such as ba.WeakCall if that is not
|
||||
desired.
|
||||
call (Callable[[], Any]):
|
||||
A callable Python object. Note that the timer will retain a
|
||||
strong reference to the callable for as long as it exists, so you
|
||||
may want to look into concepts such as ba.WeakCall if that is not
|
||||
desired.
|
||||
|
||||
repeat: if True, the timer will fire repeatedly, with each successive
|
||||
firing having the same delay as the first.
|
||||
repeat (bool):
|
||||
If True, the timer will fire repeatedly, with each successive
|
||||
firing having the same delay as the first.
|
||||
|
||||
timetype can be either 'sim', 'base', or 'real'. It defaults to
|
||||
'sim'. Types are explained below:
|
||||
|
||||
'sim' time maps to local simulation time in ba.Activity or ba.Session
|
||||
timetype (ba.TimeType):
|
||||
Can be either ``SIM``, ``BASE``, or ``REAL``. It defaults to
|
||||
``SIM``.
|
||||
|
||||
timeformat (ba.TimeFormat):
|
||||
Defaults to seconds but can also be milliseconds.
|
||||
|
||||
- SIM time maps to local simulation time in ba.Activity or ba.Session
|
||||
Contexts. This means that it may progress slower in slow-motion play
|
||||
modes, stop when the game is paused, etc. This time type is not
|
||||
available in UI contexts.
|
||||
|
||||
'base' time is also linked to gameplay in ba.Activity or ba.Session
|
||||
- BASE time is also linked to gameplay in ba.Activity or ba.Session
|
||||
Contexts, but it progresses at a constant rate regardless of
|
||||
slow-motion states or pausing. It can, however, slow down or stop
|
||||
in certain cases such as network outages or game slowdowns due to
|
||||
cpu load. Like 'sim' time, this is unavailable in UI contexts.
|
||||
|
||||
'real' time always maps to actual clock time with a bit of filtering
|
||||
added, regardless of Context. (the filtering prevents it from going
|
||||
- REAL time always maps to actual clock time with a bit of filtering
|
||||
added, regardless of Context. (The filtering prevents it from going
|
||||
backwards or jumping forward by large amounts due to the app being
|
||||
backgrounded, system time changing, etc.)
|
||||
Real time timers are currently only available in the UI context.
|
||||
|
||||
the 'timeformat' arg defaults to seconds but can also be milliseconds.
|
||||
|
||||
# timer example: print some stuff through time:
|
||||
ba.screenmessage('hello from now!')
|
||||
ba.timer(1.0, ba.Call(ba.screenmessage, 'hello from the future!'))
|
||||
ba.timer(2.0, ba.Call(ba.screenmessage, 'hello from the future 2!'))
|
||||
"""
|
||||
Examples:
|
||||
Print some stuff through time:
|
||||
```python
|
||||
>>> ba.screenmessage('hello from now!')
|
||||
>>> ba.timer(1.0, ba.Call(ba.screenmessage, 'hello from the future!'))
|
||||
>>> ba.timer(2.0, ba.Call(ba.screenmessage,
|
||||
... 'hello from the future 2!'))
|
||||
```"""
|
||||
return None
|
||||
|
||||
|
||||
|
||||
@ -33,15 +33,18 @@ class Actor:
|
||||
(killing off or transitioning out their nodes) when the last Python
|
||||
reference to them disappears, so you can use logic such as:
|
||||
|
||||
# Create a flag Actor in our game activity:
|
||||
from bastd.actor.flag import Flag
|
||||
self.flag = Flag(position=(0, 10, 0))
|
||||
|
||||
# Later, destroy the flag.
|
||||
# (provided nothing else is holding a reference to it)
|
||||
# We could also just assign a new flag to this value.
|
||||
# Either way, the old flag disappears.
|
||||
self.flag = None
|
||||
Example:
|
||||
```python
|
||||
>>> # Create a flag Actor in our game activity:
|
||||
>>> from bastd.actor.flag import Flag
|
||||
>>> self.flag = Flag(position=(0, 10, 0))
|
||||
>>>
|
||||
>>> # Later, destroy the flag.
|
||||
>>> # (provided nothing else is holding a reference to it)
|
||||
>>> # We could also just assign a new flag to this value.
|
||||
>>> # Either way, the old flag disappears.
|
||||
>>> self.flag = None
|
||||
```
|
||||
|
||||
This is in contrast to the behavior of the more low level ba.Nodes,
|
||||
which are always explicitly created and destroyed and don't care
|
||||
@ -51,18 +54,18 @@ class Actor:
|
||||
if you want an Actor to stick around until explicitly killed
|
||||
regardless of references.
|
||||
|
||||
Another key feature of ba.Actor is its handlemessage() method, which
|
||||
Another key feature of ba.Actor is its ba.Actor.handlemessage method, which
|
||||
takes a single arbitrary object as an argument. This provides a safe way
|
||||
to communicate between ba.Actor, ba.Activity, ba.Session, and any other
|
||||
class providing a handlemessage() method. The most universally handled
|
||||
message type for Actors is the ba.DieMessage.
|
||||
|
||||
# Another way to kill the flag from the example above:
|
||||
# We can safely call this on any type with a 'handlemessage' method
|
||||
# (though its not guaranteed to always have a meaningful effect).
|
||||
# In this case the Actor instance will still be around, but its exists()
|
||||
# and is_alive() methods will both return False.
|
||||
self.flag.handlemessage(ba.DieMessage())
|
||||
Another way to kill the flag from the example above:
|
||||
We can safely call this on any type with a 'handlemessage' method
|
||||
(though its not guaranteed to always have a meaningful effect).
|
||||
In this case the Actor instance will still be around, but its exists()
|
||||
and is_alive() methods will both return False.
|
||||
>>> self.flag.handlemessage(ba.DieMessage())
|
||||
"""
|
||||
|
||||
def __init__(self) -> None:
|
||||
|
||||
@ -166,6 +166,15 @@ class _WeakCall:
|
||||
... ba.timer(5.0, ba.WeakCall(foo.bar))
|
||||
... foo = None
|
||||
|
||||
EXAMPLE C: Wrap a method call with some positional and keyword args:
|
||||
>>> myweakcall = ba.WeakCall(self.dostuff, argval1,
|
||||
... namedarg=argval2)
|
||||
... # Now we have a single callable to run that whole mess.
|
||||
... # The same as calling myobj.dostuff(argval1, namedarg=argval2)
|
||||
... # (provided my_obj still exists; this will do nothing
|
||||
... # otherwise).
|
||||
... myweakcall()
|
||||
|
||||
Note: additional args and keywords you provide to the WeakCall()
|
||||
constructor are stored as regular strong-references; you'll need
|
||||
to wrap them in weakrefs manually if desired.
|
||||
@ -176,17 +185,6 @@ class _WeakCall:
|
||||
|
||||
Pass a callable as the first arg, followed by any number of
|
||||
arguments or keywords.
|
||||
|
||||
Examples:
|
||||
Example: wrap a method call with some positional and
|
||||
keyword args:
|
||||
>>> myweakcall = ba.WeakCall(myobj.dostuff, argval1,
|
||||
... namedarg=argval2)
|
||||
... # Now we have a single callable to run that whole mess.
|
||||
... # The same as calling myobj.dostuff(argval1, namedarg=argval2)
|
||||
... # (provided my_obj still exists; this will do nothing
|
||||
... # otherwise).
|
||||
... myweakcall()
|
||||
"""
|
||||
if hasattr(args[0], '__func__'):
|
||||
self._call = WeakMethod(args[0])
|
||||
@ -232,12 +230,12 @@ class _Call:
|
||||
Pass a callable as the first arg, followed by any number of
|
||||
arguments or keywords.
|
||||
|
||||
# Example: wrap a method call with 1 positional and 1 keyword arg:
|
||||
mycall = ba.Call(myobj.dostuff, argval1, namedarg=argval2)
|
||||
|
||||
# Now we have a single callable to run that whole mess.
|
||||
# ..the same as calling myobj.dostuff(argval1, namedarg=argval2)
|
||||
mycall()
|
||||
Example:
|
||||
Wrap a method call with 1 positional and 1 keyword arg:
|
||||
>>> mycall = ba.Call(myobj.dostuff, argval, namedarg=argval2)
|
||||
... # Now we have a single callable to run that whole mess.
|
||||
... # ..the same as calling myobj.dostuff(argval, namedarg=argval2)
|
||||
... mycall()
|
||||
"""
|
||||
self._call = args[0]
|
||||
self._args = args[1:]
|
||||
@ -251,7 +249,6 @@ class _Call:
|
||||
str(self._args) + ' _keywds=' + str(self._keywds) + '>')
|
||||
|
||||
|
||||
# Hack: pdoc won't run this
|
||||
if TYPE_CHECKING:
|
||||
WeakCall = Call
|
||||
Call = Call
|
||||
@ -375,15 +372,18 @@ def storagename(suffix: str = None) -> str:
|
||||
|
||||
Note that this will function even if called in the class definition.
|
||||
|
||||
# Example: generate a unique name for storage purposes:
|
||||
class MyThingie:
|
||||
|
||||
# This will give something like '_mymodule_submodule_mythingie_data'.
|
||||
_STORENAME = ba.storagename('data')
|
||||
|
||||
# Use that name to store some data in the Activity we were passed.
|
||||
def __init__(self, activity):
|
||||
activity.customdata[self._STORENAME] = {}
|
||||
Examples:
|
||||
Generate a unique name for storage purposes:
|
||||
```python
|
||||
>>> class MyThingie:
|
||||
... # This will give something like
|
||||
... # '_mymodule_submodule_mythingie_data'.
|
||||
... _STORENAME = ba.storagename('data')
|
||||
...
|
||||
... # Use that name to store some data in the Activity we were passed.
|
||||
... def __init__(self, activity):
|
||||
... activity.customdata[self._STORENAME] = {}
|
||||
```
|
||||
"""
|
||||
frame = inspect.currentframe()
|
||||
if frame is None:
|
||||
|
||||
@ -376,24 +376,29 @@ class Lstr:
|
||||
To see available resource keys, look at any of the bs_language_*.py files
|
||||
in the game or the translations pages at bombsquadgame.com/translate.
|
||||
|
||||
# EXAMPLE 1: specify a string from a resource path
|
||||
mynode.text = ba.Lstr(resource='audioSettingsWindow.titleText')
|
||||
Examples:
|
||||
EXAMPLE 1: specify a string from a resource path
|
||||
>>> mynode.text = ba.Lstr(resource='audioSettingsWindow.titleText')
|
||||
|
||||
# EXAMPLE 2: specify a translated string via a category and english value;
|
||||
# if a translated value is available, it will be used; otherwise the
|
||||
# english value will be. To see available translation categories, look
|
||||
# under the 'translations' resource section.
|
||||
mynode.text = ba.Lstr(translate=('gameDescriptions', 'Defeat all enemies'))
|
||||
EXAMPLE 2: specify a translated string via a category and english
|
||||
value; if a translated value is available, it will be used; otherwise
|
||||
the english value will be. To see available translation categories,
|
||||
look under the 'translations' resource section.
|
||||
>>> mynode.text = ba.Lstr(translate=('gameDescriptions', 'Defeat all enemies'))
|
||||
|
||||
# EXAMPLE 3: specify a raw value and some substitutions. Substitutions can
|
||||
# be used with resource and translate modes as well.
|
||||
mynode.text = ba.Lstr(value='${A} / ${B}',
|
||||
subs=[('${A}', str(score)), ('${B}', str(total))])
|
||||
EXAMPLE 3: specify a raw value and some substitutions. Substitutions
|
||||
can be used with resource and translate modes as well.
|
||||
>>> mynode.text = ba.Lstr(value='${A} / ${B}',
|
||||
... subs=[('${A}', str(score)), ('${B}', str(total))])
|
||||
|
||||
# EXAMPLE 4: Lstrs can be nested. This example would display the resource
|
||||
# at res_a but replace ${NAME} with the value of the resource at res_b
|
||||
mytextnode.text = ba.Lstr(resource='res_a',
|
||||
subs=[('${NAME}', ba.Lstr(resource='res_b'))])
|
||||
EXAMPLE 4: ba.Lstr's can be nested. This example would display the
|
||||
resource at res_a but replace ${NAME} with the value of the
|
||||
resource at res_b
|
||||
```python
|
||||
>>> mytextnode.text = ba.Lstr(
|
||||
... resource='res_a',
|
||||
... subs=[('${NAME}', ba.Lstr(resource='res_b'))])
|
||||
```
|
||||
"""
|
||||
|
||||
# pylint: disable=dangerous-default-value
|
||||
|
||||
@ -21,7 +21,7 @@ void PythonClassContext::SetupType(PyTypeObject* obj) {
|
||||
"\n"
|
||||
"Category: General Utility Classes\n"
|
||||
"\n"
|
||||
"Many operations such as ba.newnode() or ba.gettexture() operate\n"
|
||||
"Many operations such as ba.newnode or ba.gettexture operate\n"
|
||||
"implicitly on the current context. Each ba.Activity has its own\n"
|
||||
"Context and objects within that activity (nodes, media, etc) can only\n"
|
||||
"interact with other objects from that context.\n"
|
||||
@ -33,16 +33,16 @@ void PythonClassContext::SetupType(PyTypeObject* obj) {
|
||||
"the UI (there is a special 'ui' context for all user-interface-related\n"
|
||||
"functionality)\n"
|
||||
"\n"
|
||||
"When instantiating a ba.Context instance, a single 'source' argument\n"
|
||||
"When instantiating a ba.Context instance, a single ``'source'`` argument\n"
|
||||
"is passed, which can be one of the following strings/objects:\n\n"
|
||||
"'empty':\n"
|
||||
"``'empty'``:\n"
|
||||
" Gives an empty context; it can be handy to run code here to ensure\n"
|
||||
" it does no loading of media, creation of nodes, etc.\n"
|
||||
"\n"
|
||||
"'current':\n"
|
||||
"``'current'``:\n"
|
||||
" Sets the context object to the current context.\n"
|
||||
"\n"
|
||||
"'ui':\n"
|
||||
"``'ui'``:\n"
|
||||
" Sets to the UI context. UI functions as well as loading of media to\n"
|
||||
" be used in said functions must happen in the UI context.\n"
|
||||
"\n"
|
||||
@ -56,16 +56,18 @@ void PythonClassContext::SetupType(PyTypeObject* obj) {
|
||||
"\n"
|
||||
"\n"
|
||||
"Usage:\n"
|
||||
" Contexts are generally used with the python 'with' statement, which\n"
|
||||
" sets the context as current on entry and resets it to the previous\n"
|
||||
" value on exit.\n"
|
||||
"\n"
|
||||
"Contexts are generally used with the python 'with' statement, which\n"
|
||||
"sets the context as current on entry and resets it to the previous\n"
|
||||
"value on exit.\n"
|
||||
"\n"
|
||||
"# Example: load a few textures into the UI context\n"
|
||||
"# (for use in widgets, etc):\n"
|
||||
"with ba.Context('ui'):\n"
|
||||
" tex1 = ba.gettexture('foo_tex_1')\n"
|
||||
" tex2 = ba.gettexture('foo_tex_2')\n";
|
||||
"Example:\n"
|
||||
" Load a few textures into the UI context\n"
|
||||
" (for use in widgets, etc):\n"
|
||||
" ```python\n"
|
||||
" >>> with ba.Context('ui'):\n"
|
||||
" ... tex1 = ba.gettexture('foo_tex_1')\n"
|
||||
" ... tex2 = ba.gettexture('foo_tex_2')\n"
|
||||
" ```\n";
|
||||
|
||||
obj->tp_new = tp_new;
|
||||
obj->tp_dealloc = (destructor)tp_dealloc;
|
||||
|
||||
@ -38,17 +38,21 @@ void PythonClassContextCall::SetupType(PyTypeObject* obj) {
|
||||
"shutdown, whereas ba.WeakCall simply looks at whether the target\n"
|
||||
"object still exists.\n"
|
||||
"\n"
|
||||
"# Example A: code like this can inadvertently prevent our activity\n"
|
||||
"# (self) from ending until the operation completes, since the bound\n"
|
||||
"# method we're passing (self.dosomething) contains a strong-reference\n"
|
||||
"# to self).\n"
|
||||
"start_some_long_action(callback_when_done=self.dosomething)\n"
|
||||
"Examples:\n"
|
||||
" Example A: code like this can inadvertently prevent our activity\n"
|
||||
" (self) from ending until the operation completes, since the bound\n"
|
||||
" method we're passing (self.dosomething) contains a strong-reference\n"
|
||||
" to self).\n"
|
||||
" >>> start_some_long_action(callback_when_done=self.dosomething)\n"
|
||||
"\n"
|
||||
"# Example B: in this case our activity (self) can still die\n"
|
||||
"# properly; the callback will clear itself when the activity starts\n"
|
||||
"# shutting down, becoming a harmless no-op and releasing the reference\n"
|
||||
"# to our activity.\n"
|
||||
"start_long_action(callback_when_done=ba.ContextCall(self.mycallback))\n";
|
||||
" Example B: in this case our activity (self) can still die\n"
|
||||
" properly; the callback will clear itself when the activity starts\n"
|
||||
" shutting down, becoming a harmless no-op and releasing the reference\n"
|
||||
" to our activity.\n"
|
||||
" ```python\n"
|
||||
" >>> start_long_action(\n"
|
||||
" ... callback_when_done=ba.ContextCall(self.mycallback))\n"
|
||||
" ```\n";
|
||||
|
||||
obj->tp_new = tp_new;
|
||||
obj->tp_dealloc = (destructor)tp_dealloc;
|
||||
|
||||
@ -56,16 +56,16 @@ void PythonClassMaterial::SetupType(PyTypeObject* obj) {
|
||||
"A material can affect physical characteristics, generate sounds,\n"
|
||||
"or trigger callback functions when collisions occur.\n"
|
||||
"\n"
|
||||
"Materials are applied to 'parts', which are groups of one or more\n"
|
||||
"rigid bodies created as part of a ba.Node. Nodes can have any number\n"
|
||||
"Materials are applied to ``'parts'``, which are groups of one or more\n"
|
||||
"rigid bodies created as part of a ba.Node. Nodes can have any number\n"
|
||||
"of parts, each with its own set of materials. Generally materials are\n"
|
||||
"specified as array attributes on the Node. The 'spaz' node, for\n"
|
||||
"example, has various attributes such as 'materials',\n"
|
||||
"'roller_materials', and 'punch_materials', which correspond to the\n"
|
||||
"specified as array attributes on the Node. The ``'spaz'`` node, for\n"
|
||||
"example, has various attributes such as ``'materials'``,\n"
|
||||
"``'roller_materials'``, and ``'punch_materials'``, which correspond to the\n"
|
||||
"various parts it creates.\n"
|
||||
"\n"
|
||||
"Use ba.Material() to instantiate a blank material, and then use its\n"
|
||||
"add_actions() method to define what the material does.\n"
|
||||
"Use ba.Material to instantiate a blank material, and then use its\n"
|
||||
"ba.Material.add_actions method to define what the material does.\n"
|
||||
"\n"
|
||||
"Attributes:\n"
|
||||
"\n"
|
||||
@ -281,133 +281,139 @@ PyMethodDef PythonClassMaterial::tp_methods[] = {
|
||||
"Add one or more actions to the material, optionally with conditions.\n"
|
||||
"\n"
|
||||
"Conditions:\n"
|
||||
" Conditions are provided as tuples which can be combined to form boolean\n"
|
||||
" logic. A single condition might look like ``('condition_name', cond_arg)``,\n"
|
||||
" or a more complex nested one might look like ``(('some_condition',\n"
|
||||
" cond_arg), 'or', ('another_condition', cond2_arg))``.\n"
|
||||
"\n"
|
||||
"Conditions are provided as tuples which can be combined to form boolean\n"
|
||||
"logic. A single condition might look like ('condition_name', cond_arg),\n"
|
||||
"or a more complex nested one might look like (('some_condition',\n"
|
||||
"cond_arg), 'or', ('another_condition', cond2_arg)).\n"
|
||||
"\n"
|
||||
"'and', 'or', and 'xor' are available to chain together 2 conditions, as\n"
|
||||
" seen above.\n"
|
||||
" ``'and'``, ``'or'``, and ``'xor'`` are available to chain together 2 conditions, as\n"
|
||||
" seen above.\n"
|
||||
"\n"
|
||||
"Available Conditions:\n"
|
||||
" ``('they_have_material', material)`` - does the part we\'re hitting have a\n"
|
||||
" given ba.Material?\n"
|
||||
"\n"
|
||||
"('they_have_material', material) - does the part we\'re hitting have a\n"
|
||||
" given ba.Material?\n"
|
||||
" ``('they_dont_have_material', material)`` - does the part we\'re hitting\n"
|
||||
" not have a given ba.Material?\n"
|
||||
"\n"
|
||||
"('they_dont_have_material', material) - does the part we\'re hitting\n"
|
||||
" not have a given ba.Material?\n"
|
||||
" ``('eval_colliding')`` - is ``'collide'`` true at this point in material\n"
|
||||
" evaluation? (see the modify_part_collision action)\n"
|
||||
"\n"
|
||||
"('eval_colliding') - is 'collide' true at this point in material\n"
|
||||
" evaluation? (see the modify_part_collision action)\n"
|
||||
" ``('eval_not_colliding')`` - is 'collide' false at this point in material\n"
|
||||
" evaluation? (see the modify_part_collision action)\n"
|
||||
"\n"
|
||||
"('eval_not_colliding') - is 'collide' false at this point in material\n"
|
||||
" evaluation? (see the modify_part_collision action)\n"
|
||||
" ``('we_are_younger_than', age)`` - is our part younger than ``'age'``\n"
|
||||
" (in milliseconds)?\n"
|
||||
"\n"
|
||||
"('we_are_younger_than', age) - is our part younger than 'age'\n"
|
||||
" (in milliseconds)?\n"
|
||||
" ``('we_are_older_than', age)`` - is our part older than ``'age'``\n"
|
||||
" (in milliseconds)?\n"
|
||||
"\n"
|
||||
"('we_are_older_than', age) - is our part older than 'age'\n"
|
||||
" (in milliseconds)?\n"
|
||||
" ``('they_are_younger_than', age)`` - is the part we're hitting younger than\n"
|
||||
" ``'age'`` (in milliseconds)?\n"
|
||||
"\n"
|
||||
"('they_are_younger_than', age) - is the part we're hitting younger than\n"
|
||||
" 'age' (in milliseconds)?\n"
|
||||
" ``('they_are_older_than', age)`` - is the part we're hitting older than\n"
|
||||
" ``'age'`` (in milliseconds)?\n"
|
||||
"\n"
|
||||
"('they_are_older_than', age) - is the part we're hitting older than\n"
|
||||
" 'age' (in milliseconds)?\n"
|
||||
" ``('they_are_same_node_as_us')`` - does the part we're hitting belong to\n"
|
||||
" the same ba.Node as us?\n"
|
||||
"\n"
|
||||
"('they_are_same_node_as_us') - does the part we're hitting belong to\n"
|
||||
" the same ba.Node as us?\n"
|
||||
"\n"
|
||||
"('they_are_different_node_than_us') - does the part we're hitting\n"
|
||||
" belong to a different ba.Node than us?\n"
|
||||
" ``('they_are_different_node_than_us')`` - does the part we're hitting\n"
|
||||
" belong to a different ba.Node than us?\n"
|
||||
"\n"
|
||||
"Actions:\n"
|
||||
"\n"
|
||||
"In a similar manner, actions are specified as tuples. Multiple actions\n"
|
||||
"can be specified by providing a tuple of tuples.\n"
|
||||
" In a similar manner, actions are specified as tuples. Multiple actions\n"
|
||||
" can be specified by providing a tuple of tuples.\n"
|
||||
"\n"
|
||||
"Available Actions:\n"
|
||||
" ``('call', when, callable)`` - calls the provided callable; ``'when'`` can be\n"
|
||||
" either ``'at_connect'`` or ``'at_disconnect'``. ``'at_connect'`` means to fire\n"
|
||||
" when the two parts first come in contact; ``'at_disconnect'`` means to\n"
|
||||
" fire once they cease being in contact.\n"
|
||||
"\n"
|
||||
"('call', when, callable) - calls the provided callable; 'when' can be\n"
|
||||
" either 'at_connect' or 'at_disconnect'. 'at_connect' means to fire\n"
|
||||
" when the two parts first come in contact; 'at_disconnect' means to\n"
|
||||
" fire once they cease being in contact.\n"
|
||||
" ``('message', who, when, message_obj)`` - sends a message object; ``'who'`` can\n"
|
||||
" be either ``'our_node'`` or ``'their_node'``, ``'when'`` can be ``'at_connect'`` or\n"
|
||||
" ``'at_disconnect'``, and message_obj is the message object to send.\n"
|
||||
" This has the same effect as calling the node's ba.Node.handlemessage\n"
|
||||
" method.\n"
|
||||
"\n"
|
||||
"('message', who, when, message_obj) - sends a message object; 'who' can\n"
|
||||
" be either 'our_node' or 'their_node', 'when' can be 'at_connect' or\n"
|
||||
" 'at_disconnect', and message_obj is the message object to send.\n"
|
||||
" This has the same effect as calling the node's handlemessage()\n"
|
||||
" method.\n"
|
||||
" ``('modify_part_collision', attr, value)`` - changes some characteristic\n"
|
||||
" of the physical collision that will occur between our part and their\n"
|
||||
" part. This change will remain in effect as long as the two parts\n"
|
||||
" remain overlapping. This means if you have a part with a material\n"
|
||||
" that turns ``'collide'`` off against parts younger than 100ms, and it\n"
|
||||
" touches another part that is 50ms old, it will continue to not\n"
|
||||
" collide with that part until they separate, even if the 100ms\n"
|
||||
" threshold is passed. Options for attr/value are: ``'physical'`` (boolean\n"
|
||||
" value; whether a *physical* response will occur at all), ``'friction'``\n"
|
||||
" (float value; how friction-y the physical response will be),\n"
|
||||
" ``'collide'`` (boolean value; whether *any* collision will occur at all,\n"
|
||||
" including non-physical stuff like callbacks), ``'use_node_collide'``\n"
|
||||
" (boolean value; whether to honor modify_node_collision overrides for\n"
|
||||
" this collision), ``'stiffness'`` (float value, how springy the physical\n"
|
||||
" response is), ``'damping'`` (float value, how damped the physical\n"
|
||||
" response is), ``'bounce'`` (float value; how bouncy the physical response\n"
|
||||
" is).\n"
|
||||
"\n"
|
||||
"('modify_part_collision', attr, value) - changes some characteristic\n"
|
||||
" of the physical collision that will occur between our part and their\n"
|
||||
" part. This change will remain in effect as long as the two parts\n"
|
||||
" remain overlapping. This means if you have a part with a material\n"
|
||||
" that turns 'collide' off against parts younger than 100ms, and it\n"
|
||||
" touches another part that is 50ms old, it will continue to not\n"
|
||||
" collide with that part until they separate, even if the 100ms\n"
|
||||
" threshold is passed. Options for attr/value are: 'physical' (boolean\n"
|
||||
" value; whether a *physical* response will occur at all), 'friction'\n"
|
||||
" (float value; how friction-y the physical response will be),\n"
|
||||
" 'collide' (boolean value; whether *any* collision will occur at all,\n"
|
||||
" including non-physical stuff like callbacks), 'use_node_collide'\n"
|
||||
" (boolean value; whether to honor modify_node_collision overrides for\n"
|
||||
" this collision), 'stiffness' (float value, how springy the physical\n"
|
||||
" response is), 'damping' (float value, how damped the physical\n"
|
||||
" response is), 'bounce' (float value; how bouncy the physical response\n"
|
||||
" is).\n"
|
||||
" ``('modify_node_collision', attr, value)`` - similar to\n"
|
||||
" ``modify_part_collision``, but operates at a node-level.\n"
|
||||
" collision attributes set here will remain in effect as long as\n"
|
||||
" *anything* from our part's node and their part's node overlap.\n"
|
||||
" A key use of this functionality is to prevent new nodes from\n"
|
||||
" colliding with each other if they appear overlapped;\n"
|
||||
" if ``modify_part_collision`` is used, only the individual parts that\n"
|
||||
" were overlapping would avoid contact, but other parts could still\n"
|
||||
" contact leaving the two nodes 'tangled up'. Using\n"
|
||||
" ``modify_node_collision ensures`` that the nodes must completely\n"
|
||||
" separate before they can start colliding. Currently the only attr\n"
|
||||
" available here is ``'collide'`` (a boolean value).\n"
|
||||
"\n"
|
||||
"('modify_node_collision', attr, value) - similar to\n"
|
||||
" modify_part_collision, but operates at a node-level.\n"
|
||||
" collision attributes set here will remain in effect as long as\n"
|
||||
" *anything* from our part's node and their part's node overlap.\n"
|
||||
" A key use of this functionality is to prevent new nodes from\n"
|
||||
" colliding with each other if they appear overlapped;\n"
|
||||
" if modify_part_collision is used, only the individual parts that\n"
|
||||
" were overlapping would avoid contact, but other parts could still\n"
|
||||
" contact leaving the two nodes 'tangled up'. Using\n"
|
||||
" modify_node_collision ensures that the nodes must completely\n"
|
||||
" separate before they can start colliding. Currently the only attr\n"
|
||||
" available here is 'collide' (a boolean value).\n"
|
||||
" ``('sound', sound, volume)`` - plays a ba.Sound when a collision occurs, at\n"
|
||||
" a given volume, regardless of the collision speed/etc.\n"
|
||||
"\n"
|
||||
"('sound', sound, volume) - plays a ba.Sound when a collision occurs, at\n"
|
||||
" a given volume, regardless of the collision speed/etc.\n"
|
||||
" ``('impact_sound', sound, targetImpulse, volume)`` - plays a sound when a\n"
|
||||
" collision occurs, based on the speed of impact. Provide a ba.Sound, a\n"
|
||||
" target-impulse, and a volume.\n"
|
||||
"\n"
|
||||
"('impact_sound', sound, targetImpulse, volume) - plays a sound when a\n"
|
||||
" collision occurs, based on the speed of impact. Provide a ba.Sound, a\n"
|
||||
" target-impulse, and a volume.\n"
|
||||
" ``('skid_sound', sound, targetImpulse, volume)`` - plays a sound during a\n"
|
||||
" collision when parts are 'scraping' against each other. Provide a\n"
|
||||
" ba.Sound, a target-impulse, and a volume.\n"
|
||||
"\n"
|
||||
"('skid_sound', sound, targetImpulse, volume) - plays a sound during a\n"
|
||||
" collision when parts are 'scraping' against each other. Provide a\n"
|
||||
" ba.Sound, a target-impulse, and a volume.\n"
|
||||
" ``('roll_sound', sound, targetImpulse, volume)`` - plays a sound during a\n"
|
||||
" collision when parts are 'rolling' against each other. Provide a\n"
|
||||
" ba.Sound, a target-impulse, and a volume.\n"
|
||||
"\n"
|
||||
"('roll_sound', sound, targetImpulse, volume) - plays a sound during a\n"
|
||||
" collision when parts are 'rolling' against each other. Provide a\n"
|
||||
" ba.Sound, a target-impulse, and a volume.\n"
|
||||
"Examples:\n"
|
||||
" example 1: create a material that lets us ignore\n"
|
||||
" collisions against any nodes we touch in the first\n"
|
||||
" 100 ms of our existence; handy for preventing us from\n"
|
||||
" exploding outward if we spawn on top of another object:\n"
|
||||
" ```python\n"
|
||||
" >>> m = ba.Material()\n"
|
||||
" ... m.add_actions(\n"
|
||||
" ... conditions=(('we_are_younger_than', 100),\n"
|
||||
" ... 'or', ('they_are_younger_than', 100)),\n"
|
||||
" ... actions=('modify_node_collision', 'collide', False))\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
"# example 1: create a material that lets us ignore\n"
|
||||
"# collisions against any nodes we touch in the first\n"
|
||||
"# 100 ms of our existence; handy for preventing us from\n"
|
||||
"# exploding outward if we spawn on top of another object:\n"
|
||||
"m = ba.Material()\n"
|
||||
"m.add_actions(conditions=(('we_are_younger_than', 100),\n"
|
||||
" 'or',('they_are_younger_than', 100)),\n"
|
||||
" actions=('modify_node_collision', 'collide', False))\n"
|
||||
" example 2: send a ba.DieMessage to anything we touch, but cause\n"
|
||||
" no physical response. This should cause any ba.Actor to drop dead:\n"
|
||||
" ```python\n"
|
||||
" >>> m = ba.Material()\n"
|
||||
" ... m.add_actions(\n"
|
||||
" ... actions=(('modify_part_collision', 'physical', False),\n"
|
||||
" ... ('message', 'their_node', 'at_connect',\n"
|
||||
" ... ba.DieMessage())))\n"
|
||||
" ```\n"
|
||||
"\n"
|
||||
"# example 2: send a DieMessage to anything we touch, but cause\n"
|
||||
"# no physical response. This should cause any ba.Actor to drop dead:\n"
|
||||
"m = ba.Material()\n"
|
||||
"m.add_actions(actions=(('modify_part_collision', 'physical', False),\n"
|
||||
" ('message', 'their_node', 'at_connect',\n"
|
||||
" ba.DieMessage())))\n"
|
||||
"\n"
|
||||
"# example 3: play some sounds when we're contacting the ground:\n"
|
||||
"m = ba.Material()\n"
|
||||
"m.add_actions(conditions=('they_have_material',\n"
|
||||
" shared.footing_material),\n"
|
||||
" actions=(('impact_sound', ba.getsound('metalHit'), 2, 5),\n"
|
||||
" ('skid_sound', ba.getsound('metalSkid'), 2, 5)))\n"
|
||||
" example 3: play some sounds when we're contacting the ground:\n"
|
||||
" ```python\n"
|
||||
" >>> m = ba.Material()\n"
|
||||
" ... m.add_actions(\n"
|
||||
" ... conditions=('they_have_material',\n"
|
||||
" shared.footing_material),\n"
|
||||
" ... actions=(('impact_sound', ba.getsound('metalHit'), 2, 5),\n"
|
||||
" ... ('skid_sound', ba.getsound('metalSkid'), 2, 5)))\n"
|
||||
" ```\n"
|
||||
"\n"},
|
||||
{"__dir__", (PyCFunction)Dir, METH_NOARGS,
|
||||
"allows inclusion of our custom attrs in standard python dir()"},
|
||||
|
||||
@ -440,14 +440,17 @@ PyMethodDef PythonClassNode::tp_methods[] = {
|
||||
"Connect one of this node's attributes to an attribute on another node.\n"
|
||||
"This will immediately set the target attribute's value to that of the\n"
|
||||
"source attribute, and will continue to do so once per step as long as\n"
|
||||
"the two nodes exist. The connection can be severed by setting the\n"
|
||||
"the two nodes exist. The connection can be severed by setting the\n"
|
||||
"target attribute to any value or connecting another node attribute\n"
|
||||
"to it.\n"
|
||||
"\n"
|
||||
"# Example: create a locator and attach a light to it:\n"
|
||||
"light = ba.newnode('light')\n"
|
||||
"loc = ba.newnode('locator', attrs={'position': (0,10,0)})\n"
|
||||
"loc.connectattr('position', light, 'position')"},
|
||||
"Example:\n"
|
||||
" Create a locator and attach a light to it:\n"
|
||||
" ```python\n"
|
||||
" >>> light = ba.newnode('light')\n"
|
||||
" ... loc = ba.newnode('locator', attrs={'position': (0, 10, 0)})\n"
|
||||
" ... loc.connectattr('position', light, 'position')\n"
|
||||
" ```\n"},
|
||||
{"__dir__", (PyCFunction)Dir, METH_NOARGS,
|
||||
"allows inclusion of our custom attrs in standard python dir()"},
|
||||
{nullptr}};
|
||||
|
||||
@ -45,16 +45,19 @@ void PythonClassTimer::SetupType(PyTypeObject* obj) {
|
||||
"timeformat: A ba.TimeFormat value determining how the passed time is\n"
|
||||
"interpreted.\n"
|
||||
"\n"
|
||||
"# Example: use a Timer object to print repeatedly for a few seconds:\n"
|
||||
"def say_it():\n"
|
||||
" ba.screenmessage('BADGER!')\n"
|
||||
"def stop_saying_it():\n"
|
||||
" self.t = None\n"
|
||||
" ba.screenmessage('MUSHROOM MUSHROOM!')\n"
|
||||
"# Create our timer; it will run as long as we have the self.t ref.\n"
|
||||
"self.t = ba.Timer(0.3, say_it, repeat=True)\n"
|
||||
"# Now fire off a one-shot timer to kill it.\n"
|
||||
"ba.timer(3.89, stop_saying_it)";
|
||||
"Example:\n"
|
||||
" Use a Timer object to print repeatedly for a few seconds:\n"
|
||||
" ```python\n"
|
||||
" >>> def say_it():\n"
|
||||
" ... ba.screenmessage('BADGER!')\n"
|
||||
" ... def stop_saying_it():\n"
|
||||
" ... self.t = None\n"
|
||||
" ... ba.screenmessage('MUSHROOM MUSHROOM!')\n"
|
||||
" ... # Create our timer; it will run as long as we have the self.t ref.\n"
|
||||
" ... self.t = ba.Timer(0.3, say_it, repeat=True)\n"
|
||||
" ... # Now fire off a one-shot timer to kill it.\n"
|
||||
" ... ba.timer(3.89, stop_saying_it)\n"
|
||||
" ```\n";
|
||||
obj->tp_new = tp_new;
|
||||
obj->tp_dealloc = (destructor)tp_dealloc;
|
||||
}
|
||||
|
||||
@ -1033,52 +1033,53 @@ auto PythonMethodsApp::GetMethods() -> std::vector<PyMethodDef> {
|
||||
"This timer cannot be canceled or modified once created. If you\n"
|
||||
" require the ability to do so, use the ba.Timer class instead.\n"
|
||||
"\n"
|
||||
"time: length of time (in seconds by default) that the timer will "
|
||||
"wait\n"
|
||||
"before firing. Note that the actual delay experienced may vary\n "
|
||||
"depending on the timetype. (see below)\n"
|
||||
"Arguments:\n"
|
||||
" time (float):\n"
|
||||
" Length of time (in seconds by default) that the timer will wait\n"
|
||||
" before firing. Note that the actual delay experienced may vary\n "
|
||||
" depending on the timetype. (see below)\n"
|
||||
"\n"
|
||||
"call: A callable Python object. Note that the timer will retain a\n"
|
||||
"strong reference to the callable for as long as it exists, so you\n"
|
||||
"may want to look into concepts such as ba.WeakCall if that is not\n"
|
||||
"desired.\n"
|
||||
" call (Callable[[], Any]):\n"
|
||||
" A callable Python object. Note that the timer will retain a\n"
|
||||
" strong reference to the callable for as long as it exists, so you\n"
|
||||
" may want to look into concepts such as ba.WeakCall if that is not\n"
|
||||
" desired.\n"
|
||||
"\n"
|
||||
"repeat: if True, the timer will fire repeatedly, with each "
|
||||
"successive\n"
|
||||
"firing having the same delay as the first.\n"
|
||||
" repeat (bool):\n"
|
||||
" If True, the timer will fire repeatedly, with each successive\n"
|
||||
" firing having the same delay as the first.\n"
|
||||
"\n"
|
||||
"timetype can be either 'sim', 'base', or 'real'. It defaults to\n"
|
||||
"'sim'. Types are explained below:\n"
|
||||
"\n"
|
||||
" timetype (ba.TimeType):\n"
|
||||
" Can be either ``SIM``, ``BASE``, or ``REAL``. It defaults to\n"
|
||||
" ``SIM``. \n"
|
||||
"\n"
|
||||
" timeformat (ba.TimeFormat):\n"
|
||||
" Defaults to seconds but can also be milliseconds.\n"
|
||||
"\n"
|
||||
"'sim' time maps to local simulation time in ba.Activity or "
|
||||
"ba.Session\n"
|
||||
"Contexts. This means that it may progress slower in slow-motion "
|
||||
"play\n"
|
||||
"- SIM time maps to local simulation time in ba.Activity or ba.Session\n"
|
||||
"Contexts. This means that it may progress slower in slow-motion play\n"
|
||||
"modes, stop when the game is paused, etc. This time type is not\n"
|
||||
"available in UI contexts.\n"
|
||||
"\n"
|
||||
"'base' time is also linked to gameplay in ba.Activity or ba.Session\n"
|
||||
"- BASE time is also linked to gameplay in ba.Activity or ba.Session\n"
|
||||
"Contexts, but it progresses at a constant rate regardless of\n "
|
||||
"slow-motion states or pausing. It can, however, slow down or stop\n"
|
||||
"in certain cases such as network outages or game slowdowns due to\n"
|
||||
"cpu load. Like 'sim' time, this is unavailable in UI contexts.\n"
|
||||
"\n"
|
||||
"'real' time always maps to actual clock time with a bit of "
|
||||
"filtering\n"
|
||||
"added, regardless of Context. (the filtering prevents it from "
|
||||
"going\n"
|
||||
"- REAL time always maps to actual clock time with a bit of filtering\n"
|
||||
"added, regardless of Context. (The filtering prevents it from going\n"
|
||||
"backwards or jumping forward by large amounts due to the app being\n"
|
||||
"backgrounded, system time changing, etc.)\n"
|
||||
"Real time timers are currently only available in the UI context.\n"
|
||||
"\n"
|
||||
"the 'timeformat' arg defaults to seconds but can also be "
|
||||
"milliseconds.\n"
|
||||
"\n"
|
||||
"# timer example: print some stuff through time:\n"
|
||||
"ba.screenmessage('hello from now!')\n"
|
||||
"ba.timer(1.0, ba.Call(ba.screenmessage, 'hello from the future!'))\n"
|
||||
"ba.timer(2.0, ba.Call(ba.screenmessage, 'hello from the future "
|
||||
"2!'))\n"},
|
||||
"Examples:\n"
|
||||
" Print some stuff through time:\n"
|
||||
" ```python\n"
|
||||
" >>> ba.screenmessage('hello from now!')\n"
|
||||
" >>> ba.timer(1.0, ba.Call(ba.screenmessage, 'hello from the future!'))\n"
|
||||
" >>> ba.timer(2.0, ba.Call(ba.screenmessage,\n"
|
||||
" ... 'hello from the future 2!'))\n"
|
||||
" ```\n"},
|
||||
|
||||
{"time", (PyCFunction)PyTime, METH_VARARGS | METH_KEYWORDS,
|
||||
"time(timetype: ba.TimeType = TimeType.SIM,\n"
|
||||
|
||||
@ -846,10 +846,13 @@ auto PythonMethodsSystem::GetMethods() -> std::vector<PyMethodDef> {
|
||||
"The call is made from. Returns True if this location has not been\n"
|
||||
"registered already, and False if it has.\n"
|
||||
"\n"
|
||||
"# Example: this print will only fire for the first loop iteration:\n"
|
||||
"for i in range(10):\n"
|
||||
" if ba.do_once():\n"
|
||||
" print('Hello once from loop!')"},
|
||||
"Example:\n"
|
||||
" This print will only fire for the first loop iteration:\n"
|
||||
" ```python\n"
|
||||
" >>> for i in range(10):\n"
|
||||
" ... if ba.do_once():\n"
|
||||
" ... print('Hello once from loop!')\n"
|
||||
" ```\n"},
|
||||
|
||||
{"_app", (PyCFunction)PyApp, METH_VARARGS | METH_KEYWORDS,
|
||||
"_app() -> ba.App\n"
|
||||
|
||||
@ -89,7 +89,7 @@ def generate(projroot: str) -> None:
|
||||
pdoc.render.configure(docformat='google',
|
||||
search=True,
|
||||
show_source=True)
|
||||
pdoc.pdoc('ba', 'bastd', output_directory=outdirname)
|
||||
pdoc.pdoc('ba', output_directory=outdirname)
|
||||
except Exception as exc:
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user