image image


Physics for Game Developers: It’s no Rocket Science

Irgendwie hatte ich das Bedürfnis, meine Erkenntnisse aus den Beiträgen der letzten Tage, in denen ich ausgewählte Skripte aus dem ersten Kapitel von »The Nature of Code« von Processing (Java) nach Pygame Zero portierte, auch mal in spielerischer Weise auszuprobieren. Also ersetzte ich den Ball durch eine Rakete. Eigentlich wollte ich nur wissen, ob man die eingebaute Winkel-Funktion von Pygame Zero zusammen mit meinem PVector.heading() nutzen kann.

image

Ich habe wild herumexperimentiert und es geht. Aber ehrlich gesagt, habe ich (noch) nicht alles verstanden. Ist die 0°-Position eines Bildes bei Pygame Zeros angle-Methoden nach Osten ausgerichtet? Ich glaube, ich muß erst einmal ein gutes Physikbuch konsultieren.

Dennoch, was habe ich getan? Zuerst einmal habe ich es mit Pygame Zeros Methode angle_to() versucht (siehe die auskommentierte Zeile im Quellcode). Das funktioniert, aber die Rakete dreht sich für meinen Geschmack zu abrupt nach dem Mauszeiger. Das wirkt nicht sehr realistisch. Also habe ich es mit

self.angle = -self.velocity.heading()*(180/math.pi)

versucht und das wirkt schon sehr viel organischer. Die Multiplikation mit 180/math.pi ist notwendig, weil PVectors heading()-Methode Radianten zurückliefert, Pygame Zeros angle aber Grad erwartet.

Das sieht schon sehr korrekt aus, aber ich verstehe es noch nicht völlig. Aber ich erinnere mich, daß ich irgendwo in Daniel Shiffmans Videos, aber auch in »The Nature of Code« (Kapitel 6, Autonome Agenten) etwas über Steering, Velocity und Desired Velocity gelesen habe. Daher werde ich bei Gelegenheit darauf zurückkommen.

Ansonsten ist die Klasse Rocket eigentlich eine Kopie der Klasse Mover aus den letzten Beiträgen. Lediglich die Animation der Rakete (der Feuerschweif flackert im Weltraum1) habe ich mit der neu hinzugefügten Methode make_animation() realisiert:

    def make_animation(self):
        if self.frame <= 5:
            self.image = "ship1"
        elif self.frame <= 10:
            self.image = "ship2"
        elif self.frame <= 15:
            self.image = "ship3"
        elif self.frame <= 20:
            self.image = "ship4"
        if self.frame >= 20:
            self.frame = 0
        self.frame += 1

Hier wird einfach alle fünf Frames das Bild der Rakete ausgetauscht. Die Raketenbildchen stammen übrigens von Jacob Zinman-Jeanes, der sie unter einer Creative-Commons-Lizenz (CC-BY-3.0) auf Gamedevtuts+ veröffentlicht hat. Der Anstand und die Lizenz verlangt die Nennung des Urhebers und das habe ich hiermit mit Freude erledigt.

So, wie gewohnt nun auch noch der vollständige Quellcode:

import pygame
import pgzrun
from pvector import PVector
import math

WIDTH = 600
HEIGHT = 450
TITLE = "Rocket 1"
RADIUS = 32

class Rocket(Actor):
    
    def __init__(self, x, y, im):
        super().__init__(im, (x, y))
        self.pos = (x, y)
        self.im = im
        self.location = PVector(x, y)
        self.velocity = PVector(0, 0)
        self.frame = 0
        self.angle = 90
        self.topspeed = 10

    def update(self):
        mouse_x, mouse_y = pygame.mouse.get_pos()
        mouse = PVector(mouse_x, mouse_y)
        dir = mouse - self.location
        dir.normalize()
        dir.mult(0.5)
        self.acceleration = dir
        self.velocity.add(self.acceleration)
        self.velocity.limit(self.topspeed)
        self.location.add(self.velocity)
        self.pos = (self.location.x, self.location.y)
        # self.angle = self.angle_to((mouse_x, mouse_y))
        self.angle = -self.velocity.heading()*(180/math.pi)
        
    def make_animation(self):
        if self.frame <= 5:
            self.image = "ship1"
        elif self.frame <= 10:
            self.image = "ship2"
        elif self.frame <= 15:
            self.image = "ship3"
        elif self.frame <= 20:
            self.image = "ship4"
        if self.frame >= 20:
            self.frame = 0
        self.frame += 1

    def check_edges(self):
        if (self.location.x > WIDTH - RADIUS):
            self.location.x = RADIUS
        elif (self.location.x < RADIUS):
            self.location.x = WIDTH - RADIUS
        if (self.location.y > HEIGHT - RADIUS):
            self.location.y = RADIUS
        elif (self.location.y < RADIUS):
            self.location.y = HEIGHT - RADIUS

rocket = Rocket(100, 200, "ship1")

def draw():
    screen.blit("background", (0, 0))
    rocket.draw()

def update():
    rocket.make_animation()
    rocket.update()
    rocket.check_edges()

pgzrun.go()

Dieser ist auch wieder mit sämtlichen Assets in meinem GitHub-Repositorium zu finden. Wenn Ihr die Ordnerstruktur in rocket unverändert laßt und Ihr Pygame Zero ( Version 1.2) installiert habt, sollte der Code out of the Box lauffähig sein.

  1. Komme mir jetzt keiner mit der Tatsache, daß in der Leere des Weltalls kein Feuer flackern kann. Das hier ist ein Spiel, und da gilt: Keine Logik auf die Bühne. 


(Kommentieren) 

image image



Ü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!


Werbung


image  image  image
image  image  image


image