Ein Sonntag ohne ein wenig mit Processing.py zu spielen, ist in Zeiten der Pandemie kein Sonntag für mich. Also habe ich mir das erste der gestern vorgestellten Videos vorgenommen und mir überlegt, was man daraus schickes entwickeln kann. Herausgekommen ist ein kleines Experiment, das zeigt, wie man »Flucht und Verfolgung« (Chasing and Evading) für Spiele in Python implementieren kann.
Ich habe zuerst einen kleinen Spieler implementiert, der mit der Tastatur im Bildschirmfenster bewegt werden, aber dieses nicht verlassen kann. Natürlich bekam er eine eigene Klasse Player
spendiert:
class Player():
def __init__(self):
self.pos = PVector(width/2, height/2)
self.w = self.h = 32
self.max_speed = 6
self.speed = PVector(0, 0)
self.img = loadImage("knt1_fr1.gif")
self.debug = True # False
def update(self):
if self.speed.x >= self.max_speed:
self.speed.x = self.max_speed
if self.speed.y >= self.max_speed:
self.speed.y = self.max_speed
self.pos.x += self.speed.x
self.pos.y += self.speed.y
self.check_boundaries()
def display(self):
image(self.img, self.pos.x, self.pos.y)
if self.debug:
fill(255, 255, 0, 100)
circle(self.pos.x + self.w/2, self.pos.y + self.h/2, 400)
def check_boundaries(self):
if self.pos.x >= width - self.w:
self.pos.x = width - self.w
elif self.pos.x <= 0:
self.pos.x = 0
if self.pos.y >= height - self.h:
self.pos.y = height - self.h
elif self.pos.y <= 0:
self.pos.y = 0
Bis auf die Tastaturabfrage ist die gesamte Logik für das Spiel hier implementiert. Die Tastaturabfrage im Hauptprogramm lenkt und beschleunigt den Spieler:
def keyPressed():
global player
if key == CODED:
if keyCode == UP:
player.speed.y -= vel
elif keyCode == DOWN:
player.speed.y += vel
elif keyCode == LEFT:
player.speed.x -= vel
elif keyCode == RIGHT:
player.speed.x += vel
def keyReleased():
global player
if key == CODED:
if keyCode == UP or keyCode == DOWN:
player.speed.y = 0
elif keyCode == LEFT or keyCode == RIGHT:
player.speed.x = 0
Der Spieler wird natürlich nicht unbegrenzt beschleunigt, sondern seine Maximalgeschwindigkeit wird durch die Variable max_speed
nach oben begrenzt. Eine Besonderheit in der Player-Klasse ist auch noch der Debug Mode. Wird nämlich debug = True
gesetzt, wird um die Spielerfigur ein (halb-) transparenter Kreis gezeichnet, der zeigt, ab wann er vom Gegner gesehen und verfolgt werden kann.
Ansonsten ist die Klasse straight forward: Die Methode update()
holt sich die Beschleunigung von der Tastaturabfrage ab und display()
zeigt das Bild des Spielers an der aktuellen Position an. Außerdem ruft update()
auch noch die Methode check_boundaries()
auf, die dafür sorgt, daß die Spielerfigur nicht über die Ränder des Spielefensters verschwinden kann.
Die Klasse Enemy
ist der Klasse Player
sehr ähnlich, der Konstruktor ist nahezu identisch, außer daß die Startposition des Gegeners per Zufall festgelegt wird:
class Enemy():
def __init__(self):
self.pos = PVector(random(width - 200) + 100, random(height - 200) + 100)
self.w = self.h = 32
self.vel = PVector(0, 0)
self.img = loadImage("npc3_fr1.gif")
def update(self):
self.pos.x += self.vel.x
self.pos.y += self.vel.y
def display(self):
image(self.img, self.pos.x, self.pos.y)
def chase(self, p):
if dist(self.pos.x, self.pos.y, p.x, p.y) > 200:
self.vel.x = self.vel.y = 0
return
if abs(self.pos.x - p.x) < abs(self.pos.y - p.y):
# Vertical separation is bigger
if self.pos.y < p.y:
self.vel.y = 2
self.vel.x = 0
else:
self.vel.y = -2
self.vel.x = 0
else:
# Horizontal separation is bigger
if self.pos.x < p.x:
self.vel.x = 2
self.vel.y = 0
else:
self.vel.x = -2
self.vel.y = 0
Der Gegner soll natürlich ein halbwegs intelligentes Verhalten zeigen, das in der Methode chase()
implementiert ist. Dort wird zuerst überprüft, ob der Spieler überhaupt im Sichtradius des Gegners ist. Wenn nicht, wird die Methode chase()
vom Gegner wieder verlassen (mit return
). Ist der Spieler aber in Sichtweite, überprüft die Methode, ob der x- oder der y-Abstand zwischen den beiden der größere ist und versucht, den größeren Abstand zwischen den beiden Protagonisten zu verkürzen (dabei wird am Vorzeichen des Abstandes festgestellt, ob sich der Spieler rechts oder links respektive oberhalb oder unterhalb des Gegners befindet.)
In der draw()
-Funktion des Hauptprogramms werden erst die update()-
und draw()
-Methoden für den Spieler und dann die chase()-
, update()
- und draw()
-Methoden des Gegners aufgerufen. Das komplette Hauptprogramm sieht so aus:
from player import Player
from enemy import Enemy
WIDTH = 800
HEIGHT = 600
vel = 2
def setup():
global enemy, player
size(WIDTH, HEIGHT)
this.surface.setTitle("Flucht & Verfolgung")
player = Player()
enemy = Enemy()
def draw():
global enemy, player
background(107, 142, 35)
player.update()
player.display()
enemy.chase(player.pos)
enemy.update()
enemy.display()
def keyPressed():
global player
if key == CODED:
if keyCode == UP:
player.speed.y -= vel
elif keyCode == DOWN:
player.speed.y += vel
elif keyCode == LEFT:
player.speed.x -= vel
elif keyCode == RIGHT:
player.speed.x += vel
def keyReleased():
global player
if key == CODED:
if keyCode == UP or keyCode == DOWN:
player.speed.y = 0
elif keyCode == LEFT or keyCode == RIGHT:
player.speed.x = 0
Die beiden Sprites sind aus der »Last Guardian Sprite Collection« von Philipp Lenssen, die dieser unter der CC-BY 3.0-Lizenz auf OpenGameArt.org veröffentlicht hat. Die Lizenz verlangt einen Link auf die Seite des Schöpfers und die Namensnennung. Das ist hiermit geschehen.
Den Quellcode und die Assets habe ich auch auf GitHub hochgeladen. Habt mindestens ebensoviel Spaß damit, wie ich beim Programmieren hatte.
Über …
Der Schockwellenreiter ist seit dem 24. April 2000 das Weblog digitale Kritzelheft von Jörg Kantel (Neuköllner, EDV-Leiter Rentner, Autor, Netzaktivist und Hundesportler — Reihenfolge rein zufällig). Hier steht, was mir gefällt. Wem es nicht gefällt, der braucht ja nicht mitzulesen. Wer aber mitliest, ist herzlich willkommen und eingeladen, mitzudiskutieren!
Alle eigenen Inhalte des Schockwellenreiters stehen unter einer Creative-Commons-Lizenz, jedoch können fremde Inhalte (speziell Videos, Photos und sonstige Bilder) unter einer anderen Lizenz stehen.
Der Besuch dieser Webseite wird aktuell von der Piwik Webanalyse erfaßt. Hier können Sie der Erfassung widersprechen.
Diese Seite verwendet keine Cookies. Warum auch? Was allerdings die iframes
von Amazon, YouTube und Co. machen, entzieht sich meiner Kenntnis.
Werbung
Diese Spalte wurde absichtlich leergelassen!