InteractionPlugin¶
Manages interactive objects that players can activate in the game world.
Location¶
- Implementation: src/pedre/plugins/interaction/plugin.py
- Base class: src/pedre/plugins/interaction/base.py
- Events: src/pedre/plugins/interaction/events.py
- Conditions: src/pedre/plugins/interaction/conditions.py
Configuration¶
The InteractionPlugin uses the following settings from pedre.conf.settings:
Distance and Input Settings¶
INTERACTION_PLUGIN_DISTANCE- Maximum distance in pixels for player to interact with objects (default: 50)INTERACTION_KEY- Key for interacting with objects (default:"SPACE")
These can be overridden in your project's settings.py:
# Custom interaction settings
INTERACTION_PLUGIN_DISTANCE = 64 # Increase interaction range
INTERACTION_KEY = "E"
Public API¶
Object Registration¶
register_object¶
register_object(sprite: arcade.Sprite, name: str, properties: dict) -> None
Register an interactive object in the plugin.
Parameters:
sprite- The arcade Sprite representing this object visually. The sprite's position (center_x, center_y) is used for distance calculationsname- Unique identifier for this object. Should match the object's name in Tiled for consistencyproperties- Dictionary of custom properties from Tiled
Example:
# From map loading code
for obj in tiled_map.object_lists["Interactive"]:
interaction_mgr.register_object(
sprite=obj.sprite,
name=obj.name,
properties=obj.properties
)
Notes:
- Objects are stored by name, so each name must be unique within the plugin
- Registering an object with an existing name will overwrite the previous object
- Usually called automatically by
load_from_tiled()
Object Queries¶
get_nearby_object¶
get_nearby_object(player_sprite: arcade.Sprite) -> InteractiveObject | None
Get the nearest interactive object within interaction distance.
Parameters:
player_sprite- The player's arcade Sprite
Returns:
- The nearest
InteractiveObjectwithininteraction_distance, orNoneif no objects are in range
Example:
nearby_obj = interaction_mgr.get_nearby_object(self.player_sprite)
if nearby_obj:
interaction_mgr.handle_interaction(nearby_obj)
Notes:
- Uses Euclidean distance to determine proximity
- When multiple objects are within range, the nearest one is selected automatically
- Distance calculation uses center points of both the player sprite and object sprites
get_interactive_objects¶
get_interactive_objects() -> dict[str, InteractiveObject]
Get all registered interactive objects.
Returns:
- Dictionary mapping object names to
InteractiveObjectinstances
Example:
objects = interaction_mgr.get_interactive_objects()
for name, obj in objects.items():
print(f"Object: {name} at ({obj.sprite.center_x}, {obj.sprite.center_y})")
Interaction Handling¶
handle_interaction¶
handle_interaction(obj: InteractiveObject) -> bool
Handle interaction with an object by publishing an event.
Parameters:
obj- TheInteractiveObjectto interact with
Returns:
Truewhen the interaction is handled
Example:
obj = interaction_mgr.get_nearby_object(player_sprite)
if obj:
success = interaction_mgr.handle_interaction(obj)
if success:
audio_mgr.play_sfx("interact.wav")
Notes:
- Publishes an
ObjectInteractedEventon the event bus - Marks the object as interacted with using
mark_as_interacted() - Actual interaction behavior is typically handled by the script plugin listening to the event
Interaction State¶
mark_as_interacted¶
mark_as_interacted(object_name: str) -> None
Mark an object as interacted with.
Parameters:
object_name- Name of the object
Example:
Notes:
- Automatically called by
handle_interaction() - Used for tracking interaction state (e.g., one-time interactions)
has_interacted_with¶
has_interacted_with(object_name: str) -> bool
Check if an object has been interacted with.
Parameters:
object_name- Name of the object to check
Returns:
Trueif the object has been interacted with,Falseotherwise
Example:
if not interaction_mgr.has_interacted_with("treasure_chest"):
show_treasure_animation()
else:
show_empty_chest()
Notes:
- Interaction state is persisted in save files
- Useful for one-time interactions or quest progression
State Management¶
clear¶
clear() -> None
Clear all registered interactive objects from the plugin.
Example:
Notes:
- Removes all interactive objects from the registry
- Does not clear the
interacted_objectsset - After calling
clear(),get_nearby_object()will always returnNoneuntil new objects are registered
Save/Load Support¶
get_save_state¶
get_save_state() -> dict[str, Any]
Return serializable state for saving.
Returns:
- Dictionary containing the set of interacted object names
Example:
save_data = {
"player_position": (x, y),
"interaction": interaction_mgr.get_save_state(),
# ... other save data
}
Notes:
- Saves the
interacted_objectsset as a list - Object registrations are not saved (recreated from Tiled maps on load)
restore_save_state¶
restore_save_state(state: dict[str, Any]) -> None
Restore interacted objects set from save data.
Parameters:
state- Dictionary containing saved interaction state
Example:
Notes:
- Restores the
interacted_objectsset - Does not need sprites to exist (phase 1 restore)
InteractiveObject¶
The InteractiveObject dataclass represents an interactive element in the game world.
Location: src/pedre/plugins/interaction/base.py
Attributes:
sprite: arcade.Sprite- The arcade Sprite representing this object in the game worldname: str- Unique identifier for this objectproperties: dict- Dictionary of custom properties from Tiled or code
Example:
from pedre.plugins.interaction.base import InteractiveObject
obj = InteractiveObject(
sprite=my_sprite,
name="mysterious_lever",
properties={"message": "A rusty lever..."}
)
Events¶
ObjectInteractedEvent¶
Published when player interacts with an interactive object.
Attributes:
object_name: str- Name of the interacted object
Script Trigger Example:
{
"trigger": {
"event": "object_interacted",
"object_name": "treasure_chest"
},
"actions": [
{"type": "dialog", "speaker": "Plugin", "text": ["You found a health potion!"]}
]
}
Notes:
- Fires after the object is marked as interacted
- The
object_namefilter is optional (omit to trigger for any object)
Conditions¶
object_interacted¶
Check if an object has been interacted with.
Parameters:
check:"object_interacted"object: Name of the object to checkequals: Expected value (default: true)
Example:
{
"trigger": {
"event": "portal_entered",
"portal": "exit"
},
"conditions": [
{
"check": "object_interacted",
"object": "treasure_chest"
}
]
}
Check if NOT interacted:
Use Cases:
- Gating progression behind object interactions
- Quest prerequisites
- One-time interactions (e.g., treasure chests)
Tiled Map Integration¶
Interactive objects can be placed in Tiled maps using object layers:
- Create an "Interactive" object layer
- Add objects (rectangles, polygons, etc.) to represent interaction zones
- Set custom properties on each object:
Required Properties:
name(string) - Unique identifier for the object (e.g., "town_sign")
Example Tiled Setup:
Plugin Lifecycle¶
setup¶
setup(context: GameContext) -> None
Initialize the interaction plugin with game context.
Parameters:
context- Game context providing access to other plugins
Notes:
- Called automatically by PluginLoader
- Stores reference to game context
cleanup¶
cleanup() -> None
Clean up interaction resources when the scene unloads.
Notes:
- Clears all registered interactive objects
- Called automatically by PluginLoader
reset¶
reset() -> None
Reset interaction plugin for new game.
Notes:
- Clears interactive objects and interaction history
- Called when starting a new game
on_key_press¶
on_key_press(symbol: int, modifiers: int) -> bool
Handle key presses for object interaction.
Parameters:
symbol- Arcade key constantmodifiers- Modifier key bitfield
Returns:
Trueif interaction occurred
Notes:
- Called automatically by PluginLoader
- Checks for
INTERACTION_KEYpress (default: SPACE) - Finds nearby object and triggers interaction
load_from_tiled¶
load_from_tiled(tile_map: arcade.TileMap, arcade_scene: arcade.Scene) -> None
Load interactive objects from Tiled map object layer.
Parameters:
tile_map- The loaded Tiled maparcade_scene- The arcade Scene
Notes:
- Called automatically by PluginLoader
- Looks for "Interactive" object layer
- Creates sprites from object geometry
- Objects without names are skipped
Custom Interaction Implementation¶
If you need to replace the interaction plugin with a custom implementation (e.g., for different interaction mechanics, targeting plugins, or UI), you can extend the InteractionBasePlugin abstract base class.
InteractionBasePlugin¶
Location: src/pedre/plugins/interaction/base.py
The InteractionBasePlugin class defines the minimum interface that any interaction plugin must implement.
Required Methods¶
Your custom interaction plugin must implement these abstract methods:
from pedre.plugins.interaction.base import InteractionBasePlugin, InteractiveObject
class CustomInteractionPlugin(InteractionBasePlugin):
"""Custom interaction implementation."""
name = "interaction"
dependencies = []
def get_interactive_objects(self) -> dict[str, InteractiveObject]:
"""Get interactive objects."""
...
def has_interacted_with(self, object_name: str) -> bool:
"""Check if an object has been interacted with."""
...
Registration¶
Register your custom interaction plugin using the @PluginRegistry.register decorator:
from pedre.plugins.registry import PluginRegistry
from pedre.plugins.interaction.base import InteractionBasePlugin, InteractiveObject
@PluginRegistry.register
class TargetedInteractionPlugin(InteractionBasePlugin):
"""Custom interaction plugin with cursor targeting."""
name = "interaction"
dependencies = []
# ... implement all abstract methods ...
Notes on Custom Implementation¶
- Your custom plugin inherits from
BasePlugin(viaInteractionBasePlugin), so you must implement the standard plugin lifecycle methods:setup(),cleanup(),get_save_state(), andrestore_save_state() - The
roleattribute is set to"interaction_plugin"in the base class - Your implementation can use any interaction method (distance-based, targeting, UI menus, etc.)
- The two abstract methods (
get_interactive_objects()andhas_interacted_with()) are the minimum required interface - Register your custom interaction plugin in your project's
INSTALLED_PLUGINSsetting before the default"pedre.plugins.interaction"to replace it
Example Custom Implementation:
# In myproject/plugins/custom_interaction.py
from pedre.plugins.registry import PluginRegistry
from pedre.plugins.interaction.base import InteractionBasePlugin, InteractiveObject
from pedre.plugins.interaction.events import ObjectInteractedEvent
from pedre.conf import settings
import arcade
@PluginRegistry.register
class MenuInteractionPlugin(InteractionBasePlugin):
"""Interaction plugin with radial menu selection."""
name = "interaction"
dependencies = []
def __init__(self):
self.interaction_distance = settings.INTERACTION_PLUGIN_DISTANCE
self.interactive_objects = {}
self.interacted_objects = set()
self.nearby_objects = []
self.selected_index = 0
def setup(self, context):
self.context = context
def cleanup(self):
self.interactive_objects.clear()
def get_save_state(self):
return {"interacted_objects": list(self.interacted_objects)}
def restore_save_state(self, state):
self.interacted_objects = set(state.get("interacted_objects", []))
def get_interactive_objects(self) -> dict[str, InteractiveObject]:
return self.interactive_objects
def has_interacted_with(self, object_name: str) -> bool:
return object_name in self.interacted_objects
def on_key_press(self, symbol: int, modifiers: int) -> bool:
"""Handle menu navigation and selection."""
if symbol == arcade.key.TAB:
if self.nearby_objects:
self.selected_index = (self.selected_index + 1) % len(self.nearby_objects)
return True
elif symbol == arcade.key.E:
if self.nearby_objects and self.selected_index < len(self.nearby_objects):
obj = self.nearby_objects[self.selected_index]
self.handle_interaction(obj)
return True
return False
def handle_interaction(self, obj: InteractiveObject):
"""Handle interaction with object."""
self.interacted_objects.add(obj.name)
self.context.event_bus.publish(ObjectInteractedEvent(object_name=obj.name))
# In myproject/settings.py
INSTALLED_PLUGINS = [
"myproject.plugins.custom_interaction", # Load custom interaction first
"pedre.plugins.camera",
"pedre.plugins.input",
# ... rest of plugins (omit "pedre.plugins.interaction") ...
]
See Also¶
- ScriptPlugin - Event-driven scripting for handling interactions
- NPCPlugin - NPC interaction plugin
- DialogPlugin - Conversation plugin
- Configuration Guide
- Scripting Conditions
- Scripting Events