PlayerPlugin¶
Manages player spawning, movement, animation, and state.
Location¶
- Implementation: src/pedre/plugins/player/plugin.py
- Base class: src/pedre/plugins/player/base.py
- Sprites: src/pedre/plugins/player/sprites.py
- Types: src/pedre/plugins/player/types.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() -> AnimatedPlayer | None
Get the player sprite instance.
Returns:
- The AnimatedPlayer sprite 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
- Creates AnimatedPlayer sprite from object data
- 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
AnimatedPlayer Sprites¶
AnimatedPlayer is a specialized sprite for the player character with 4-directional animations.
Creating AnimatedPlayer¶
from pedre.plugins.player.sprites import AnimatedPlayer
player = AnimatedPlayer(
sprite_sheet="characters/player.png",
center_x=320,
center_y=240,
scale=2.0,
tile_size=32,
# Idle animations (4 directions)
idle_up_frames=4,
idle_up_row=0,
idle_down_frames=4,
idle_down_row=1,
idle_left_frames=4,
idle_left_row=2,
idle_right_frames=4,
idle_right_row=3,
# Walk animations (4 directions)
walk_up_frames=6,
walk_up_row=4,
walk_down_frames=6,
walk_down_row=5,
walk_left_frames=6,
walk_left_row=6,
walk_right_frames=6,
walk_right_row=7
)
Animation Properties¶
Base Animation Properties (from sprite sheet):
idle_up_frames,idle_up_row- Idle facing upidle_down_frames,idle_down_row- Idle facing downidle_left_frames,idle_left_row- Idle facing leftidle_right_frames,idle_right_row- Idle facing rightwalk_up_frames,walk_up_row- Walk upward animationwalk_down_frames,walk_down_row- Walk downward animationwalk_left_frames,walk_left_row- Walk left animationwalk_right_frames,walk_right_row- Walk right animation
Key Differences from AnimatedNPC¶
AnimatedPlayer does not include special animations (appear, disappear, interact) to keep the player character implementation simple and focused on core movement functionality. This reflects the different use cases:
- Player: Always visible, user-controlled, focused on movement
- NPC: May appear/disappear, has interaction states, AI-controlled
Tiled Map Integration¶
The player can be placed in Tiled maps using the "Player" object layer:
- Create a "Player" object layer
- Add a point object where the player should spawn
- Set custom properties on the object:
Required Properties:
sprite_sheet(string) - Path to sprite sheet (relative to assets)
Optional Properties:
tile_size(int) - Size of each tile in sprite sheet (default: from sheet)scale(float) - Sprite scale multiplier (default: 1.0)spawn_at_portal(bool) - Whether to use portal spawn waypoint (default: true)- Animation properties (see above)
Example Tiled Properties:
sprite_sheet: characters/player.png
tile_size: 32
scale: 2.0
spawn_at_portal: true
walk_up_frames: 6
walk_up_row: 0
walk_down_frames: 6
walk_down_row: 1
idle_up_frames: 4
idle_up_row: 4
idle_down_frames: 4
idle_down_row: 5
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 for this waypoint during
load_from_tiled() - If
spawn_at_portal=trueand waypoint exists, player spawns there - If waypoint not found or
spawn_at_portal=false, uses default position from Tiled
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
if spawn_waypoint:
waypoint_pos = context.waypoint_plugin.get_waypoint(spawn_waypoint)
player.center_x = waypoint_pos.x
player.center_y = waypoint_pos.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 sprite sheet - Check
sprite_sheetproperty points to valid file - 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 sheet - Ensure animation frames exist in sprite sheet
- Verify properties - Check
idle_*andwalk_*frame/row properties - 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.plugins.player.sprites import AnimatedPlayer
class CustomPlayerPlugin(PlayerBasePlugin):
"""Custom player implementation."""
name = "player"
dependencies = ["input", "waypoint"]
def get_player_sprite(self) -> AnimatedPlayer | 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) -> AnimatedPlayer | 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