Home › Kategorie 08

🔬 Advanced Topics

ADVANCED ⏱ ~50 Min

Tilemaps mit Tiled Map Editor

Arcade unterstützt das TMX-Format des Tiled Map Editors. Level können grafisch erstellt und direkt in Arcade geladen werden.

🗺️ Tiled Map Editor ist ein kostenloser, vielseitiger Map-Editor. Kostenlos unter mapeditor.org verfügbar. Exportiere als .tmx und lade es mit arcade.load_tilemap().
PYTHON – Tilemap laden
def setup(self):
    # Tilemap laden
    layer_options = {
        "Platforms": {"use_spatial_hash": True},
        "Moving Platforms": {"use_spatial_hash": False},
        "Coins": {"use_spatial_hash": True},
        "Enemies": {"use_spatial_hash": False},
    }

    self.tile_map = arcade.load_tilemap(
        map_file="assets/maps/level_01.tmx",
        scaling=0.5,
        layer_options=layer_options
    )

    # Scene aus der Tilemap erstellen
    self.scene = arcade.Scene.from_tilemap(self.tile_map)

    # Hintergrundfarbe aus Tiled übernehmen
    if self.tile_map.background_color:
        arcade.set_background_color(self.tile_map.background_color)

    # Weltgrenzen berechnen
    self.level_width = (
        self.tile_map.width * self.tile_map.tile_width * 0.5
    )

    # Physik-Engine mit Tilemap-Layers
    self.physics_engine = arcade.PhysicsEnginePlatformer(
        player_sprite=self.player,
        platforms=self.scene["Platforms"],
        gravity_constant=1.0,
        ladders=self.scene["Ladders"]
    )

def on_draw(self):
    self.clear()
    with self.camera.activate():
        self.scene.draw()  # Alle Layer zeichnen
💡 Layer-Typen in Tiled: Tile Layer (Kacheln), Object Layer (Spawn-Punkte, Trigger-Zonen), Image Layer (Hintergrundbilder). Alle werden von Arcade korrekt interpretiert.

Pathfinding mit A*

Arcade hat eingebautes A*-Pathfinding. Gegner können damit den kürzesten Weg zum Spieler finden, Hindernisse umgehen inklusive.

PYTHON – A* Pathfinding
def setup(self):
    # Hindernis-Liste für Pathfinding
    self.barrier_list = arcade.AStarBarrierList(
        moving_sprite=self.enemy,
        blocking_sprites=self.wall_list,
        grid_size=32,           # Gittergröße
        left=0, right=1600,    # Weltgrenzen
        bottom=0, top=1600
    )

def on_update(self, delta_time):
    # Pfad zum Spieler berechnen
    path = arcade.astar_calculate_path(
        start_point=self.enemy.position,
        end_point=self.player.position,
        astar_barrier_list=self.barrier_list,
        diagonal_movement=False  # Keine Diagonalen
    )

    if path and len(path) > 1:
        # Nächsten Schritt im Pfad ansteuern
        next_x, next_y = path[1]
        dx = next_x - self.enemy.center_x
        dy = next_y - self.enemy.center_y
        speed = 2
        distance = ((dx**2) + (dy**2))**0.5
        if distance > 0:
            self.enemy.change_x = dx / distance * speed
            self.enemy.change_y = dy / distance * speed

# Sichtlinie prüfen (für KI)
can_see = arcade.has_line_of_sight(
    point_1=self.enemy.position,
    point_2=self.player.position,
    walls=self.wall_list
)

Performance-Optimierung

⚡ Spatial Hashing

use_spatial_hash=True für statische Wände/Plattformen. Macht Kollisionsabfragen O(1) statt O(n).

📦 ShapeElementList

Für statische Hintergrundelemente – alles in einem GPU Draw Call statt einzelner draw_*()-Aufrufe.

🎯 Texture Atlas

Alle Sprites in einer Textur zusammenführen. Arcade macht das automatisch, aber Customisierung möglich.

📊 FPS Monitoring

arcade.get_fps() und arcade.PerfGraph für Echtzeit-Performance-Analyse.

PYTHON – Performance-Tipps
# FPS anzeigen
def on_draw(self):
    self.clear()
    self.scene.draw()

    # FPS Counter
    fps = arcade.get_fps()
    arcade.draw_text(f"FPS: {fps:.0f}", 10, 10, arcade.color.WHITE, 14)

# Performance-Timing aktivieren
arcade.enable_timings()

def on_update(self, delta_time):
    # Timings ausgeben
    if self.frame_count % 60 == 0:  # Jede Sekunde
        arcade.print_timings()

# Sprites außerhalb des Bildschirms nicht updaten
def on_update(self, delta_time):
    for enemy in self.enemy_list:
        # Nur nahe Gegner updaten
        dist = arcade.get_distance_between_sprites(enemy, self.player)
        if dist < 1000:
            enemy.update()

# Lazy SpriteLists (nur wenn benötigt geladen)
lazy_list = arcade.SpriteList(lazy=True)  # Initialisierung verzögern

Shader-Grundlagen

Arcade bietet direkten OpenGL-Zugriff für Post-Processing-Effekte wie Glow, CRT-Filter, Lichteffekte und mehr.

PYTHON – Licht-System
from arcade.experimental import LightLayer, Light

def setup(self):
    # Licht-Layer erstellen
    self.light_layer = LightLayer(800, 600)
    self.light_layer.set_background_color(arcade.color.BLACK)

    # Licht beim Spieler
    self.player_light = Light(
        400, 300,       # Position
        radius=200,     # Leuchtradius
        color=arcade.csscolor.WHITE,
        mode="soft"    # "hard" oder "soft"
    )
    self.light_layer.add(self.player_light)

    # Fackel-Licht
    torch_light = Light(200, 100, radius=100,
                         color=(255, 100, 0), mode="soft")
    self.light_layer.add(torch_light)

def on_update(self, delta_time):
    # Licht folgt dem Spieler
    self.player_light.position = self.player.position

def on_draw(self):
    self.clear()
    with self.light_layer:
        # Alles in diesem Block wird beleuchtet
        self.scene.draw()
    # Licht-Layer rendern
    self.light_layer.draw()

Spiel verteilen: PyInstaller

Mit PyInstaller kann ein Arcade-Spiel in eine eigenständige .exe (Windows) oder App (Mac/Linux) verpackt werden.

TERMINAL – PyInstaller
# PyInstaller installieren
pip install pyinstaller

# Einfaches Bundling (eine .exe)
pyinstaller --onefile --windowed main.py

# Mit Asset-Dateien
pyinstaller --onefile --windowed \
    --add-data "assets;assets" \
    --add-data "maps;maps" \
    main.py

# Windows: Eigenes Icon
pyinstaller --onefile --windowed --icon=icon.ico main.py
PYTHON – Asset-Pfade für PyInstaller
import sys
import os

def resource_path(relative_path):
    """Korrekte Pfade für PyInstaller-Bundle und Entwicklung."""
    if hasattr(sys, '_MEIPASS'):
        # Im Bundle: Temp-Verzeichnis
        base_path = sys._MEIPASS
    else:
        # In Entwicklung: Projektverzeichnis
        base_path = os.path.dirname(os.path.abspath(__file__))

    return os.path.join(base_path, relative_path)

# Verwendung:
sprite = arcade.Sprite(resource_path("assets/player.png"))

Scenes

arcade.Scene ist ein organisiertes Container-Objekt für mehrere SpriteLists – ideal für Level mit Tilemaps.

PYTHON – Scene
def setup(self):
    # Manuelle Scene erstellen
    self.scene = arcade.Scene()

    # Layer hinzufügen (Reihenfolge = Zeichenreihenfolge)
    self.scene.add_sprite_list("Background")
    self.scene.add_sprite_list("Platforms", use_spatial_hash=True)
    self.scene.add_sprite_list("Coins")
    self.scene.add_sprite_list("Enemies")
    self.scene.add_sprite_list("Player")

    # Sprites zu Layer hinzufügen
    self.scene.add_sprite("Player", self.player)
    self.scene.add_sprite("Coins", coin)

    # Layer abrufen
    coin_layer = self.scene["Coins"]
    platform_layer = self.scene.get_sprite_list("Platforms")

def on_draw(self):
    self.clear()
    # Alle Layer in richtiger Reihenfolge zeichnen
    self.scene.draw()

    # Oder einzelne Layer:
    self.scene.draw("Background")
    self.scene.draw("Platforms")
A* Pathfinding Simulator – Klicke Start/Ziel oder Hindernisse
Setze Start (grün) und Ziel (rot), dann klicke "Pfad berechnen"