PlayerPlugin¶
Manages player spawning, movement, animation, and state.
Location¶
- Implementation: src/pedre/plugins/player/plugin.py
- Base class: src/pedre/plugins/player/base.py
Configuration¶
The PlayerPlugin uses the following settings from pedre.conf.settings:
Movement Settings¶
PLAYER_MOVEMENT_SPEED- Movement speed in pixels per second (default: 180.0)TILE_SIZE- Size of tiles for grid-based calculations (default: 64)
These can be overridden in your project's settings.py:
Public API¶
Player Access¶
get_player_sprite¶
get_player_sprite() -> AnimatedSprite | None
Get the player sprite instance.
Returns:
- The
AnimatedSpriteinstance or None if not loaded
Example:
player_sprite = context.player_plugin.get_player_sprite()
if player_sprite:
print(f"Player at ({player_sprite.center_x}, {player_sprite.center_y})")
Notes:
- Returns None before scene is loaded
- Player sprite is created during
load_from_tiled() - Used by other plugins (camera, portals, interactions)
Plugin Lifecycle¶
setup¶
setup(context: GameContext) -> None
Initialize the player plugin with game context.
Parameters:
context- Game context providing access to other plugins
Notes:
- Called automatically by PluginLoader
- Stores reference to game context
- Must be called before loading player from Tiled
update¶
update(delta_time: float) -> None
Update player movement and animation.
Parameters:
delta_time- Time since last update in seconds
Example:
Notes:
- Called automatically by PluginLoader each frame
- Processes input from InputPlugin
- Blocks movement when dialog is showing
- Updates player position and animation state
- Handles direction changes based on movement
load_from_tiled¶
load_from_tiled(tile_map: arcade.TileMap, arcade_scene: arcade.Scene) -> None
Load player from Tiled map object layer.
Parameters:
tile_map- The loaded Tiled maparcade_scene- The arcade Scene to add player to
Notes:
- Called automatically by PluginLoader
- Looks for "Player" object layer
- Uses first player object in layer
- Resolves sprite via content registry (
spritessub-registry, usingsprite_idproperty or"player"as default) - Supports portal-based spawning via waypoints
reset¶
reset() -> None
Reset player plugin state for new game.
Notes:
- Clears player sprite and sprite list
- Called when starting a new game
Save/Load Support¶
get_save_state¶
get_save_state() -> dict[str, Any]
Return serializable state for saving.
Returns:
- Dictionary containing player position
Example:
Notes:
- Saves player_x and player_y coordinates
- Returns empty dict if no player sprite exists
restore_save_state¶
restore_save_state(state: dict[str, Any]) -> None
Phase 1: No metadata to restore for player (sprites don't exist yet).
Parameters:
state- Dictionary containing saved player state
Notes:
- Player sprite doesn't exist during this phase
- Actual restoration happens in
apply_entity_state()
apply_entity_state¶
apply_entity_state(state: dict[str, Any]) -> None
Phase 2: Apply saved player position after sprite exists.
Parameters:
state- Dictionary containing saved player state
Example:
Notes:
- Restores player_x and player_y coordinates
- Must be called after
load_from_tiled() - Logs restored position for debugging
State Serialization¶
to_dict¶
to_dict() -> dict[str, float]
Serialize player position to dictionary.
Returns:
- Dictionary with
player_xandplayer_ykeys
Example:
position_data = player_plugin.to_dict()
print(f"Player at ({position_data['player_x']}, {position_data['player_y']})")
from_dict¶
from_dict(data: dict[str, float]) -> None
Restore player position from dictionary.
Parameters:
data- Dictionary withplayer_xandplayer_ykeys
Example:
Notes:
- Only applies position if player sprite exists
- Requires both
player_xandplayer_ykeys
Player Sprite and Content Registry¶
The player sprite is defined entirely via the content registry — no properties are read from the Tiled Player object (only its spawn position). The plugin looks up the "player" key in the players sub-registry (players.json), then uses that entry's sprite_id field to find the sprite definition in sprites.json.
Tiled Map Integration¶
The player is placed in Tiled maps using the "Player" object layer:
- Create a "Player" object layer
- Add a point object where the player should spawn by default
No Tiled object properties are needed. All sprite and spawn configuration lives in players.json.
players.json fields:
| Field | Type | Required | Description |
|---|---|---|---|
sprite_id |
string | Yes | ID of the sprite definition in sprites.json |
spawn_at_position |
list of strings | No | Map names where the player spawns at the Tiled object position instead of a portal waypoint |
Example players.json:
Example sprite content registry entry (sprites.json):
{
"player": {
"sprite_sheet": "characters/player.png",
"frame_width": 32,
"states": {
"idle": {"row": 0, "frames": 4},
"walk": {"row": 1, "frames": 6}
}
}
}
See the Sprites Content Reference and Players Content Reference for full details on defining sprite and player entries.
Portal-Based Spawning¶
When loading a scene, the player can spawn at a waypoint instead of the default position:
How It Works:
- ScenePlugin stores a
next_spawn_waypointwhen transitioning scenes - PlayerPlugin checks
spawn_at_positioninplayers.jsonfor the current map name - If the map is not in
spawn_at_positionand a waypoint exists, player spawns at the waypoint's pixel coordinates - If the map is in
spawn_at_positionor no waypoint is set, uses the default position from the Tiled object
Example:
# Request scene transition with spawn waypoint
context.scene_plugin.request_transition(
map_file="castle.tmx",
spawn_waypoint="entrance"
)
# PlayerPlugin will spawn player at "entrance" waypoint
# instead of default position from Tiled map
Notes:
- Waypoint must exist in target scene's waypoint plugin
- Spawn waypoint is cleared after use (one-time)
- Default position from Tiled is used as fallback
Player State¶
The PlayerPlugin maintains the player sprite and its state throughout the game session.
Player Sprite Lifecycle¶
- Creation - Player sprite is created during
load_from_tiled() - Updates - Position and animation updated every frame in
update() - Persistence - Position saved/restored during save/load operations
- Reset - Cleared when starting a new game
State Tracking¶
The player state includes:
- Position -
center_xandcenter_ycoordinates in pixels - Direction - Current facing direction (up, down, left, right)
- Animation State - Walking or idle
- Velocity - Movement vector from input plugin
Movement Plugin¶
The PlayerPlugin handles movement processing each frame:
Movement Processing Flow¶
- Input Check - Get movement vector from InputPlugin
- Dialog Blocking - Block movement if dialog is showing
- Direction Update - Update player direction based on movement
- Animation Update - Update walk/idle animation state
Direction Logic¶
Direction changes are based on movement priority:
if dx > 0:
direction = "right"
elif dx < 0:
direction = "left"
elif dy > 0:
direction = "up"
elif dy < 0:
direction = "down"
Notes:
- Horizontal movement (dx) takes precedence over vertical (dy)
- Direction only updates when actually moving
- Last direction is preserved when stopped
Animation States¶
The player has two animation states:
- Idle - When stationary (dx = 0 and dy = 0)
- Walk - When moving (dx != 0 or dy != 0)
Each state has 4 directional variants (up, down, left, right).
Usage Examples¶
Accessing Player Position¶
# Get player sprite
player_sprite = context.player_plugin.get_player_sprite()
if player_sprite:
# Access position
x = player_sprite.center_x
y = player_sprite.center_y
print(f"Player at ({x}, {y})")
Checking Player Distance¶
# Check distance to NPC
player_sprite = context.player_plugin.get_player_sprite()
npc_sprite = context.npc_plugin.get_npc_by_name("merchant").sprite
distance = arcade.get_distance_between_sprites(player_sprite, npc_sprite)
if distance < 50:
print("Player near merchant")
Following Player with Camera¶
# Camera automatically follows player
context.camera_plugin.set_follow_player(smooth=True)
# Stop following
context.camera_plugin.stop_follow()
Spawning at Specific Location¶
The player spawns at waypoints during scene transitions. This is typically handled by scripts:
Integration with Other Plugins¶
InputPlugin Integration¶
The InputPlugin provides movement vectors:
# In update loop
dx, dy = context.input_plugin.get_movement_vector()
# PlayerPlugin processes this input
# Updates player sprite velocity and direction
Notes:
- Input is automatically processed during
update() - Movement is blocked when dialogs are showing
- Direction changes are based on movement vector
CameraPlugin Integration¶
The CameraPlugin can follow the player:
# Enable player following
context.camera_plugin.set_follow_player(smooth=True)
# Camera automatically tracks player position
Notes:
- Player sprite must exist before camera can follow
- Camera uses player position for centering
- Smooth following interpolates camera movement
DialogPlugin Integration¶
Dialog blocks player movement:
Notes:
- Player cannot move while dialog is visible
- Input is still processed but not applied
- Movement resumes when dialog closes
ScenePlugin Integration¶
Scene transitions handle player spawning:
# ScenePlugin provides spawn waypoint
spawn_waypoint = context.scene_plugin.get_next_spawn_waypoint()
# PlayerPlugin spawns at waypoint location (pixel coordinates)
if spawn_waypoint:
waypoint_pos = context.waypoint_plugin.get_waypoint(spawn_waypoint)
if waypoint_pos:
pixel_x, pixel_y = waypoint_pos
player.center_x = pixel_x
player.center_y = pixel_y
Notes:
- Waypoint-based spawning is optional (
spawn_at_portalproperty) - Falls back to Tiled map position if waypoint not found
- Spawn waypoint is cleared after use
PhysicsPlugin Integration¶
Physics engine prevents wall collisions:
# Physics engine uses player sprite
physics_engine = arcade.PhysicsEngineSimple(player_sprite, walls)
# Movement is constrained by physics
physics_engine.update()
Notes:
- Physics must be invalidated when player sprite changes
- Collision response is handled by physics plugin
- Player velocity is set by PlayerPlugin, constrained by PhysicsPlugin
Troubleshooting¶
Player Not Appearing¶
If the player doesn't appear on the map:
- Check Player layer - Ensure Tiled map has "Player" object layer
- Verify content registry - Ensure a
"player"entry (or the value ofsprite_id) exists in yourspritescontent registry - Check spawn position - Verify player object has valid x/y coordinates
- Review logs - Look for errors during
load_from_tiled()
Player Not Moving¶
If the player sprite exists but doesn't move:
- Check InputPlugin - Ensure input plugin is working (
get_movement_vector()) - Verify update loop - Confirm
player_plugin.update(delta_time)is called every frame - Check dialog state - Ensure dialog isn't blocking movement
- Test physics - Verify physics engine allows movement (not stuck in walls)
Animation Not Playing¶
If animations aren't working:
- Check sprite definition - Ensure animation states are defined in the content registry sprite entry
- Verify sprite sheet - Ensure the sprite sheet file exists at the configured path
- Test movement - Animations require actual movement to trigger walk states
- Review AnimatedSprite - Check base animation plugin is functioning
Spawn Waypoint Issues¶
If portal-based spawning doesn't work:
- Check waypoint exists - Verify target waypoint is in destination scene
- Verify spawn_at_portal - Ensure property is set to
true - Check scene transition - Confirm
spawn_waypointis passed to scene change - Review logs - Look for waypoint resolution warnings
Custom Player Implementation¶
If you need to replace the player plugin with a custom implementation, you can extend the PlayerBasePlugin abstract base class.
PlayerBasePlugin¶
Location: src/pedre/plugins/player/base.py
The PlayerBasePlugin class defines the minimum interface that any player plugin must implement.
Required Methods¶
Your custom player plugin must implement these abstract methods:
from pedre.plugins.player.base import PlayerBasePlugin
from pedre.sprites import AnimatedSprite
class CustomPlayerPlugin(PlayerBasePlugin):
"""Custom player implementation."""
name = "player"
dependencies = ["input", "waypoint"]
def get_player_sprite(self) -> AnimatedSprite | None:
"""Get the player sprite."""
...
Registration¶
Register your custom player plugin using the @PluginRegistry.register decorator:
from pedre.plugins.registry import PluginRegistry
from pedre.plugins.player.base import PlayerBasePlugin
@PluginRegistry.register
class CustomPlayerPlugin(PlayerBasePlugin):
name = "player"
dependencies = ["input", "waypoint"]
# ... implement all abstract methods ...
Notes on Custom Implementation¶
- Your custom plugin inherits from
BasePlugin(viaPlayerBasePlugin), so you must implement the standard plugin lifecycle methods:setup(),cleanup(), andreset() - The
roleattribute is set to"player_plugin"in the base class - Your implementation can use any sprite type or movement system
- Register your custom player plugin in your project's
INSTALLED_PLUGINSsetting before the default"pedre.plugins.player"to replace it
Example Custom Implementation:
# In myproject/plugins/custom_player.py
from pedre.plugins.registry import PluginRegistry
from pedre.plugins.player.base import PlayerBasePlugin
@PluginRegistry.register
class PhysicsPlayerPlugin(PlayerBasePlugin):
"""Player plugin with physics-based movement."""
name = "player"
dependencies = ["input", "waypoint", "physics"]
def __init__(self):
self.player_sprite = None
self.velocity = (0, 0)
# ... rest of initialization ...
def get_player_sprite(self) -> AnimatedSprite | None:
return self.player_sprite
def update(self, delta_time: float) -> None:
# Custom physics-based movement
# ... physics calculations ...
pass
# ... implement other abstract methods ...
# In myproject/settings.py
INSTALLED_PLUGINS = [
"myproject.plugins.custom_player", # Load custom player first
"pedre.plugins.camera",
"pedre.plugins.audio",
# ... rest of plugins (omit "pedre.plugins.player") ...
]
See Also¶
- InputPlugin - Keyboard input handling
- CameraPlugin - Camera following
- ScenePlugin - Scene transitions and spawning
- WaypointPlugin - Waypoint plugin
- Configuration Guide
- AnimatedSprite