Skip to content

WaypointPlugin

Manages named positions in the map used for NPC navigation, player spawning, and portal destinations.

Location

Overview

The WaypointPlugin is a simple but essential plugin that stores named positions (waypoints) from Tiled maps. Waypoints are used throughout the framework for:

  • Player spawning - Portal destinations when transitioning between maps
  • NPC movement - Target positions for pathfinding-based movement
  • Scripting - Named locations for positioning entities in cutscenes

Waypoints are defined as Point objects in Tiled's "Waypoints" object layer and automatically loaded when a map is loaded.

Configuration

The WaypointPlugin uses the following setting from pedre.conf.settings:

  • TILE_SIZE - Size of each tile in pixels, used to convert waypoint pixel coordinates to tile coordinates (default: 32)

This can be overridden in your project's settings.py:

# Custom tile size
TILE_SIZE = 16  # For smaller tiles

Public API

Waypoint Retrieval

get_waypoint

get_waypoint(name: str) -> tuple[float, float] | None

Get waypoint position by name.

Parameters:

  • name - Waypoint name as defined in Tiled

Returns:

  • Tuple of (tile_x, tile_y) in tile coordinates, or None if not found

Example:

# Get waypoint position
waypoint = waypoint_plugin.get_waypoint("town_center")
if waypoint:
    tile_x, tile_y = waypoint
    print(f"Town center is at tile ({tile_x}, {tile_y})")

Notes:

  • Returns tile coordinates, not pixel coordinates
  • Waypoint names are case-sensitive
  • Returns None for non-existent waypoints

get_waypoints

get_waypoints() -> dict[str, tuple[float, float]]

Get all waypoints in the current map.

Returns:

  • Dictionary mapping waypoint names to (tile_x, tile_y) tuples

Example:

# List all waypoints
for name, (x, y) in waypoint_plugin.get_waypoints().items():
    print(f"{name}: tile ({x}, {y})")

Notes:

  • Returns all waypoints loaded from the current map
  • Dictionary is empty if no waypoints are loaded
  • Waypoints are cleared when transitioning to a new map

Tiled Integration

load_from_tiled

load_from_tiled(tile_map: arcade.TileMap, arcade_scene: arcade.Scene) -> None

Load waypoints from Tiled map object layer.

Parameters:

  • tile_map - The loaded Tiled map
  • arcade_scene - The arcade Scene (not used for waypoints)

Notes:

  • Called automatically by PluginLoader during map loading
  • Looks for "Waypoints" object layer in the Tiled map
  • Converts pixel coordinates to tile coordinates using settings.TILE_SIZE
  • Only processes Point objects with valid name and shape properties
  • Logs waypoint loading for debugging

Plugin Lifecycle

setup

setup(context: GameContext) -> None

Initialize the waypoint plugin with game context.

Parameters:

  • context - Game context providing access to other plugins

Notes:

  • Called automatically by PluginLoader
  • Stores reference to game context

reset

reset() -> None

Reset waypoint plugin for new game.

Notes:

  • Clears all waypoints
  • Called when starting a new game

Usage Examples

Basic Waypoint Lookup

# Get a specific waypoint
spawn_point = waypoint_plugin.get_waypoint("player_spawn")
if spawn_point:
    tile_x, tile_y = spawn_point
    # Convert to pixel coordinates if needed
    pixel_x = tile_x * settings.TILE_SIZE
    pixel_y = tile_y * settings.TILE_SIZE

Using Waypoints in Scripts

Waypoints are commonly used in scripts for NPC movement:

{
    "merchant_goes_home": {
        "scene": "village",
        "trigger": {
            "event": "time_of_day",
            "hour": 18
        },
        "actions": [
            {"type": "move_npc", "npcs": ["merchant"], "waypoint": "merchant_home"},
            {"type": "wait_for_movement", "npc": "merchant"}
        ]
    }
}

Portal Destinations

Waypoints define where the player spawns after portal transitions:

In Tiled (forest.tmx):

Waypoints Layer:
  - Point named "from_village" at (100, 200)
  - Point named "from_cave" at (500, 300)

In Script:

{
    "village_to_forest": {
        "trigger": {"event": "portal_entered", "portal": "forest_entrance"},
        "actions": [
            {"type": "change_scene", "target_map": "forest.tmx", "spawn_waypoint": "from_village"}
        ]
    }
}

Checking Waypoint Existence

# Verify waypoint exists before using it
waypoint_name = "secret_cave"
if waypoint_plugin.get_waypoint(waypoint_name):
    print(f"Waypoint '{waypoint_name}' exists")
    # Proceed with movement or spawning
else:
    logger.warning(f"Waypoint '{waypoint_name}' not found in current map")

Listing All Waypoints

# Debug: List all available waypoints
waypoints = waypoint_plugin.get_waypoints()
if waypoints:
    print(f"Found {len(waypoints)} waypoints:")
    for name, (x, y) in waypoints.items():
        print(f"  {name}: ({x}, {y})")
else:
    print("No waypoints in this map")

Tiled Map Setup

Creating Waypoints in Tiled

  1. Create Waypoints Layer:
  2. Add an Object Layer named "Waypoints"
  3. This layer should be at the top of the layer stack

  4. Add Point Objects:

  5. Select the Waypoints layer
  6. Click "Insert Point" tool (or press I)
  7. Click on the map where you want the waypoint
  8. Set the name property for the point

  9. Naming Convention:

  10. Use descriptive names (e.g., "player_spawn", "merchant_home", "from_village")
  11. Names should be lowercase with underscores
  12. Names must be unique within the map

Example Waypoint Setup:

Layer: Waypoints (Object Layer)

Points:
  - name: "player_spawn" at (320, 240)
  - name: "merchant_home" at (640, 480)
  - name: "from_village" at (100, 100)
  - name: "from_forest" at (750, 50)
  - name: "town_square" at (400, 300)
  - name: "inn_entrance" at (200, 450)

Important Notes

  • Point Objects Only: Waypoints must be Point objects, not rectangles or polygons
  • Name Required: Each waypoint must have a name property set
  • No Duplicates: Waypoint names must be unique within a map
  • Case Sensitive: Waypoint names are case-sensitive in lookups
  • Automatic Conversion: Pixel coordinates are automatically converted to tile coordinates

Technical Details

Coordinate System

Waypoints are stored in tile coordinates internally:

# Tiled stores waypoints in pixel coordinates (e.g., x=320, y=240)
# WaypointPlugin converts to tile coordinates during loading:
tile_x = int(pixel_x // settings.TILE_SIZE)  # e.g., 320 // 32 = 10
tile_y = int(pixel_y // settings.TILE_SIZE)  # e.g., 240 // 32 = 7

This makes waypoints independent of tile size and easier to use with grid-based pathfinding.

Loading Process

When a map is loaded:

  1. PluginLoader calls waypoint_plugin.load_from_tiled(tile_map, scene)
  2. WaypointPlugin looks for "Waypoints" object layer
  3. For each Point object in the layer:
  4. Validates it has a name and shape property
  5. Extracts pixel coordinates from shape[0] and shape[1]
  6. Converts to tile coordinates using settings.TILE_SIZE
  7. Stores in waypoints dictionary: {name: (tile_x, tile_y)}
  8. Logs the number of waypoints loaded

Storage

Waypoints are stored in a simple dictionary:

self.waypoints: dict[str, tuple[float, float]] = {
    "player_spawn": (10.0, 7.0),
    "merchant_home": (20.0, 15.0),
    "from_village": (3.0, 3.0),
}

Reset Behavior

Waypoints are automatically cleared when:

  • A new map is loaded (via reset())
  • A new game is started (via reset())

This ensures waypoints from one map don't carry over to another.

Custom Waypoint Implementation

If you need to replace the waypoint plugin with a custom implementation, you can extend the WaypointBasePlugin abstract base class.

WaypointBasePlugin

Location: src/pedre/plugins/waypoint/base.py

The WaypointBasePlugin class defines the minimum interface that any waypoint plugin must implement.

Required Methods

Your custom waypoint plugin must implement this abstract method:

from pedre.plugins.waypoint.base import WaypointBasePlugin

class CustomWaypointPlugin(WaypointBasePlugin):
    """Custom waypoint implementation."""

    name = "waypoint"
    dependencies = []

    def get_waypoints(self) -> dict[str, tuple[float, float]]:
        """Get all waypoints."""
        ...

Registration

Register your custom waypoint plugin using the @PluginRegistry.register decorator:

from pedre.plugins.registry import PluginRegistry
from pedre.plugins.waypoint.base import WaypointBasePlugin

@PluginRegistry.register
class CustomWaypointPlugin(WaypointBasePlugin):
    name = "waypoint"
    dependencies = []

    def get_waypoints(self) -> dict[str, tuple[float, float]]:
        # Return waypoints from custom storage
        return self.custom_waypoint_storage

Notes on Custom Implementation

  • Your custom plugin inherits from BasePlugin (via WaypointBasePlugin), so you must implement the standard plugin lifecycle methods: setup(), cleanup(), and reset()
  • The role attribute is set to "waypoint_plugin" in the base class
  • Your implementation can use any storage system (database, JSON, CSV, etc.)
  • Register your custom waypoint plugin in your project's INSTALLED_PLUGINS setting before the default "pedre.plugins.waypoint" to replace it

Example Custom Implementation:

# In myproject/plugins/custom_waypoint.py
from pedre.plugins.registry import PluginRegistry
from pedre.plugins.waypoint.base import WaypointBasePlugin

@PluginRegistry.register
class DatabaseWaypointPlugin(WaypointBasePlugin):
    """Waypoint plugin that stores waypoints in a database."""

    name = "waypoint"
    dependencies = []

    def __init__(self):
        self.db = Database()
        # ... rest of initialization ...

    def get_waypoints(self) -> dict[str, tuple[float, float]]:
        # Query database for waypoints
        return self.db.query("SELECT name, x, y FROM waypoints")

    # ... implement other methods ...
# In myproject/settings.py
INSTALLED_PLUGINS = [
    "myproject.plugins.custom_waypoint",  # Load custom waypoint first
    "pedre.plugins.camera",
    "pedre.plugins.audio",
    # ... rest of plugins (omit "pedre.plugins.waypoint") ...
]

See Also