image image


image

Happy Halloween Stage 3: Die Jagd auf die Kürbisse (nun mit HUD)

Die Programmierung meines kleinen Halloween-Gimmicks in TigerJython, in dem der Spieler mit einer kleinen Rakete eine Menge herumstreunender Kürbisse jagen und abschießen muß, geht weiter. Wie gestern angekündigt, habe ich dem Spiel nun einen HUD (HUD – nicht Hut!) spendiert, einen »Head-Up-Display«, der den erreichten Punktestand anzeigt.

Dafür mußte ich tief in die Dokumentation eintauchen, denn die (»semi«-) offiziellen Tutorien tun sich schwer mit Erklärungen, wie man denn Texte in ein GameGrid-Fester zaubert. Aber ich wurde fündig: GameGrid besitzt eine Klasse TextActor(), die genau dafür da ist. Als ersten Parameter bekommt sie den darzustellenden Text, der zweite Parameter ist die Farbe des Textes und der dritte Parameter die Farbe des Hintergrundes. Und schließlich muß noch der Font übergeben werden (der eine Subklasse von jawa.awt.font ist). In meinem Fall sah der Aufruf daher so aus:

        displayScore = TextActor("Score: " + str(self.score), c, BGCOLOR,
                       Font("ComicHelvetic_Medium", Font.BOLD, 20))
        win.addActor(displayScore, Location(40, 20))

Als Font wollte ich die freie Comic Helvetic nutzen, mit der ich hier ja schon einmal herumgespielt hatte. Die Frage war nur: Findet TigerJython sie auch? Ja, einfach die .otf-Datei in den Data-Folder verfrachten und dann den Font mit vollem Namen (aber ohne Dateiendung) aufrufen.

Ansonsten habe ich gegenüber der letzten Version nur noch eine kleine Änderung vorgenommen. Im Gegensatz zu den chaotischen Kürbissen sollte die Rakete, wenn sie auf den Spielfeldrand trifft, den Gesetzen der Physik gehorchen: Einfallswinkel = Ausfallswinkel. Das ist bei den senkrechten Rändern 180 Grad - Einfallswinkel und bei den waagrechten 360 Grad - Einfallswinkel. Das habe ich in diesen Zeilen berücksichtigt:

            if self.getX() >= RIGHTMARGIN - 10:
                self.setX(RIGHTMARGIN -10)
                newDir = 180 - self.dir
                self.setDirection(newDir)
                self.dir = newDir
            elif self.getX() <= LEFTMARGIN + 10:
                self.setX(LEFTMARGIN + 10)
                newDir = 180 - self.dir
                self.setDirection(newDir)
                self.dir = newDir
            if self.getY() >= BOTTOMMARGIN - 10:
                self.setY(BOTTOMMARGIN - 10)
                newDir = 360 - self.dir
                self.setDirection(newDir)
                self.dir = newDir
            elif self.getY() <= TOPMARGIN + 10:
                self.setY(TOPMARGIN + 10)
                newDir = 360 - self.dir
                self.setDirection(newDir)
                self.dir = newDir

Einmal in Bewegung wuselt nun die Rakete ganz schön flott über den Bildschirm und das jeweilige self.dir = newDir sorgt dafür, daß auch die Geschosse in die Richtung feuern, die die Rakete eingeschlagen hat.

So, und hier ist der vollständige Quellcode dieses Zwischenstandes, damit Ihr das Programm bis hierher nachvollziehen und nachprogrammieren könnt:

# title: Pumpkin Attack Stage 3
# Author: Jörg Kantel

from gamegrid import *
from random import randint
import os

WIDTH = 680
HEIGHT = 680
LEFTMARGIN = 40 + 14
RIGHTMARGIN = 640 - 14
TOPMARGIN = 40 + 14
BOTTOMMARGIN = 640 - 14

NOPUMP = 30

DATAPATH = os.path.join(os.getcwd(), "data")
BGCOLOR = Color(color("#2b3e50"))

class Background(Actor):
    
    def __init__(self):
        Actor.__init__(self, False, os.path.join(DATAPATH, "moonnight2.jpg"))
        
class Player(Actor):
    
    def __init__(self):
        Actor.__init__(self, True, os.path.join(DATAPATH, "rocket1.png"))
        self.dir = 0
        self.speed = 5
        self.firecount = 0
        self.score = 0
        c = Color.white
        displayScore = TextActor("Score: " + str(self.score), c, BGCOLOR, Font("ComicHelvetic_Medium", Font.BOLD, 20))
        win.addActor(displayScore, Location(40, 20))
        
    def fire(self):
        if self.firecount < 0:
            missile = Missile()
            enemyList = win.getActors(Enemy)
            for enemy in enemyList:
                missile.addCollisionActor(enemy)
            win.addActor(missile, Location(self.getX(), self.getY()))
            missile.direction = self.dir
            self.firecount = 15
             
    def act(self):
        if isKeyPressed(37):       # LEFT
            self.dir -= 5 % 360
            self.direction = self.dir
        elif isKeyPressed(39):     # RIGHT
            self.dir += 5 % 360
            self.direction = self.dir
        elif isKeyPressed(38):     # UP
            self.move(self.speed)
            if self.getX() >= RIGHTMARGIN - 10:
                self.setX(RIGHTMARGIN -10)
                newDir = 180 - self.dir
                self.setDirection(newDir)
                self.dir = newDir
            elif self.getX() <= LEFTMARGIN + 10:
                self.setX(LEFTMARGIN + 10)
                newDir = 180 - self.dir
                self.setDirection(newDir)
                self.dir = newDir
            if self.getY() >= BOTTOMMARGIN - 10:
                self.setY(BOTTOMMARGIN - 10)
                newDir = 360 - self.dir
                self.setDirection(newDir)
                self.dir = newDir
            elif self.getY() <= TOPMARGIN + 10:
                self.setY(TOPMARGIN + 10)
                newDir = 360 - self.dir
                self.setDirection(newDir)
                self.dir = newDir
        if isKeyPressed(32):   # SPACE
            self.fire()
        self.firecount -= 1        

class Missile(Actor):
    
    def __init__(self):
        Actor.__init__(self, True, os.path.join(DATAPATH, "missile.png"))
        self.speed = 15
        self.direction = player.dir
    
    def act(self):
        self.move(self.speed)
        if self.getX() >= RIGHTMARGIN:
            win.removeActor(self)
        elif self.getX() <= LEFTMARGIN:
            win.removeActor(self)
        if self.getY() >= BOTTOMMARGIN:
            win.removeActor(self)
        elif self.getY() <= TOPMARGIN:
            win.removeActor(self)

    def collide(self, actor1, actor2):
        xpos = actor2.getX()
        ypos = actor2.getY()
        win.removeActor(self)
        win.removeActor(actor2)
        hit = Explosion()
        win.addActor(hit, Location(xpos, ypos))
#        if player.score == 10:
#            win.doPause()         # Für Screenshot
        player.score += 1
        c = Color.white
        displayScore = TextActor("Score: " + str(player.score), c, BGCOLOR, Font("ComicHelvetic_Medium", Font.BOLD, 20))
        win.addActor(displayScore, Location(40, 20))
        return 0

class Explosion(Actor):
    
    def __init__(self):
        Actor.__init__(self, True, os.path.join(DATAPATH, "explosion.png"))
        self.timer = 5
    
    def act(self):
        self.timer -= 1
        if self.timer <= 0:
            win.removeActor(self)    
 
class Enemy(Actor):
    
    def __init__(self):
        Actor.__init__(self, False, os.path.join(DATAPATH, "pumpkin.png"))
        self.speed = randint(1, 5)
        
    def act(self):
        self.move(self.speed)
        if self.getX() >= RIGHTMARGIN:
            self.setX(RIGHTMARGIN)
            self.direction -= randint(90, 270)
        elif self.getX() <= LEFTMARGIN:
            self.setX(LEFTMARGIN)
            self.direction -= randint(90, 270)
        if self.getY() >= BOTTOMMARGIN:
            self.setY(BOTTOMMARGIN)
            self.direction -= randint(90, 270)
        elif self.getY() <= TOPMARGIN:
            self.setY(TOPMARGIN)
            self.direction -= randint(90, 270)

 
win = makeGameGrid(WIDTH, HEIGHT, 1, BGCOLOR, True)
win.setPosition(1300, 40)
win.setTitle("Pumpkin Attack, Stage 3 🎃")   # Titelzeile mit Pumpkin-Emoji (im Editor nicht sichtbar)
win.setSimulationPeriod(20)

bg = Background()
win.addActor(bg, Location(WIDTH//2, HEIGHT//2))

for _ in range(NOPUMP):
    p = Enemy()
    win.addActor(p, Location(randint(54, 640 - 14), (randint(54, 640 - 14))))
    p.setDirection(randint(20, 340))

player = Player()
win.addActor(player, Location(320, 320))

win.show()
win.doRun()

Und hier die Übersicht über die bisher veröffentlichten Folgen:

Ich denke, ich werde dem Spiel noch ein oder zwei Beiträge spendieren. Dann dürfte Halloween auch schon vorbei sein und die Kürbisse ihre Schuldigkeit getan haben. Still digging!


(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 ehemaliger 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