Title: miniworlds: Rand erkennen und abprallen

# Rand erkennen und abprallen

Objekte in einer miniworlds-Welt können an den Rand stoßen – und dann entweder
stoppen, umkehren oder verschwinden. Dieses Tutorial zeigt, wie du den Rand
erkennst und einen Actor davon abprallen lässt: zuerst mit eigenen Berechnungen,
dann mit der miniworlds-API.

### Das Ziel

Ein Ball bewegt sich diagonal durch die Welt und prallt an allen vier Rändern ab.

import miniworlds

world = miniworlds.World(460, 300)

ball = miniworlds.Circle((100, 80), 20)
ball.direction = 45
ball.speed = 3

@ball.register
def act(self):
self.move()
borders = self.detect_borders()
if borders:
self.bounce_from_border(borders)

world.run()

Der Ball prallt endlos ab. Im Folgenden wird erklärt, wie das funktioniert.

## Rand erkennen

### Ohne API: Position prüfen

Die einfachste Art, den Rand zu erkennen: die x- und y-Position des Actors mit
den Weltgrenzen vergleichen. Die Position bezieht sich auf den **Mittelpunkt**
des Actors.

import miniworlds world = miniworlds.World(460, 300) world.add_background((230, 238, 248)) ball = miniworlds.Circle((230, 150), 20) ball.color = (60, 120, 220) ball.vx = 3 ball.vy = 2 @ball.register def act(self): self.x = self.x + self.vx self.y = self.y + self.vy if self.x - 20 <= 0: print("linker Rand") if self.x + 20 >= world.width: print("rechter Rand") if self.y - 20 <= 0: print("oberer Rand") if self.y + 20 >= world.height: print("unterer Rand") world.run()

Der Radius des Kreises (20) muss mitgerechnet werden, damit der Rand erst dann
als erreicht gilt, wenn der Ball wirklich die Kante berührt – nicht erst wenn
sein Mittelpunkt dort ankommt.

### Mit API: detect_borders()

`detect_borders()` macht diese Prüfung für dich. Es berücksichtigt
automatisch die Größe des Actors und gibt eine Liste der berührten Ränder zurück.

import miniworlds

world = miniworlds.World(460, 300)

ball = miniworlds.Circle((230, 150), 20)
ball.direction = 45
ball.speed = 3

@ball.register
def act(self):
self.move()
borders = self.detect_borders()
if borders:
print("Ränder berührt:", borders)

world.run()

`borders` ist eine Liste mit Strings wie `["left"]` oder `["top", "right"]`.
Du kannst einzelne Ränder gezielt abfragen:

if "left" in borders:
print("linker Rand")
if "right" in borders:
print("rechter Rand")
if "top" in borders:
print("oberer Rand")
if "bottom" in borders:
print("unterer Rand")

## Abprallen

### Ohne API: Geschwindigkeit umkehren

Beim Abprallen gilt: Der Einfallswinkel ist gleich dem Ausfallswinkel. Mit
Geschwindigkeitskomponenten `vx` und `vy` bedeutet das: Das Vorzeichen der
jeweiligen Komponente wird umgekehrt.

import miniworlds world = miniworlds.World(460, 300) world.add_background((230, 238, 248)) ball = miniworlds.Circle((100, 80), 20) ball.color = (60, 120, 220) ball.vx = 3 ball.vy = 2 @ball.register def act(self): self.x = self.x + self.vx self.y = self.y + self.vy if self.x - 20 <= 0 or self.x + 20 >= world.width: self.vx = -self.vx if self.y - 20 <= 0 or self.y + 20 >= world.height: self.vy = -self.vy world.run()

Links- und Rechtsrand kehren `vx` um, oben und unten kehren `vy` um. Der Ball
prallt dadurch korrekt ab.

### Mit API: bounce_from_border()

`bounce_from_border(borders)` berechnet die neue Richtung automatisch aus den
berührten Rändern. Voraussetzung ist, dass der Actor mit `direction` und
`move()` bewegt wird.

!!! note Wichtige Reihenfolge
`bounce_from_border()` erwartet die Liste aus `detect_borders()`. Der Aufruf
ohne vorherige Randerkennung hat keinen Effekt. Zuerst `detect_borders()`,
dann `bounce_from_border(borders)`.

## Der Ereignis-Ansatz: on_detecting_borders

Statt in jedem Frame aktiv zu prüfen, kannst du den Rand auch als Ereignis
behandeln. miniworlds ruft `on_detecting_borders` automatisch auf, sobald
der Actor einen Rand berührt.

import miniworlds

world = miniworlds.World(460, 300)

ball = miniworlds.Circle((100, 80), 20)
ball.direction = 45
ball.speed = 3

@ball.register
def act(self):
self.move()

@ball.register
def on_detecting_borders(self, borders):
self.bounce_from_border(borders)

world.run()

Der `act`-Handler bewegt den Ball, `on_detecting_borders` reagiert automatisch
auf den Kontakt. Die Logik ist so auf zwei klare Aufgaben aufgeteilt.

## Zusammenfassung

# Rand erkennen
borders = ball.detect_borders() # gibt Liste zurück: ["left"], ["top", "right"], ...

# Einzelne Ränder prüfen
ball.detect_left_border() # True/False
ball.detect_right_border() # True/False

# Abprallen
ball.bounce_from_border(borders) # Richtung automatisch spiegeln

# Ereignis-basiert
@ball.register
def on_detecting_borders(self, borders):
self.bounce_from_border(borders)

| Ansatz | Vorteil | Nachteil |
| Manuell (vx/vy) | Vollständige Kontrolle | Mehr Code, Radius manuell beachten |
| detect_borders() | Kein manuelles Rechnen | Erfordert direction/move-Bewegungsmodell |
| on_detecting_borders | Saubere Trennung | Weniger direkter Einblick in den Ablauf |