Dies ist der vierte Teil einer fünfteiligen Tutorial-Reihe zum Erstellen von Spielen mit Python 3 und Pygame. Im dritten Teil haben wir uns mit dem Kern von Breakout befasst, gelernt, wie man mit Ereignissen umgeht, einen Blick auf die wichtigsten Breakout-Klassen geworfen und gesehen, wie man verschiedene Spielobjekte bewegt.
In diesem Teil lernen wir, wie man Kollisionen erkennt und was passiert, wenn der Ball auf verschiedene Objekte wie Paddel, Ziegel, Wände, Decken und Böden trifft. Abschließend besprechen wir wichtige Themen der Spiel-Benutzeroberfläche, insbesondere die Erstellung von Menüs mit unseren eigenen benutzerdefinierten Schaltflächen.
Im Spiel kollidieren Dinge miteinander. Der Durchbruch ist keine Ausnahme. Meistens ist es so, dass der Ball etwas trifft. handle_ball_collisions()
方法有一个嵌套函数,名为 intersect()
, wird verwendet, um zu testen, ob der Ball ein Objekt trifft und wo er das Objekt trifft. Wenn der Ball das Objekt verfehlt, wird „Links“, „Rechts“, „Oben“, „Unten“ oder „Keine“ zurückgegeben.
def handle_ball_collisions(self): def intersect(obj, ball): edges = dict( left=Rect(obj.left, obj.top, 1, obj.height), right=Rect(obj.right, obj.top, 1, obj.height), top=Rect(obj.left, obj.top, obj.width, 1), bottom=Rect(obj.left, obj.bottom, obj.width, 1)) collisions = set(edge for edge, rect in edges.items() if ball.bounds.colliderect(rect)) if not collisions: return None if len(collisions) == 1: return list(collisions)[0] if 'top' in collisions: if ball.centery >= obj.top: return 'top' if ball.centerx < obj.left: return 'left' else: return 'right' if 'bottom' in collisions: if ball.centery >= obj.bottom: return 'bottom' if ball.centerx < obj.left: return 'left' else: return 'right'
Wenn der Ball den Schläger trifft, springt er weg. Wenn es auf die Oberseite des Paddels trifft, prallt es zurück, behält aber die gleiche horizontale Geschwindigkeitskomponente bei.
Wenn es jedoch auf eine Seite des Paddels trifft, springt es auf die andere Seite (nach links oder rechts) und setzt seine Abwärtsbewegung fort, bis es den Boden berührt. Dieser Code verwendet die Intersect-Funktion().
# Hit paddle s = self.ball.speed edge = intersect(self.paddle, self.ball) if edge is not None: self.sound_effects['paddle_hit'].play() if edge == 'top': speed_x = s[0] speed_y = -s[1] if self.paddle.moving_left: speed_x -= 1 elif self.paddle.moving_left: speed_x += 1 self.ball.speed = speed_x, speed_y elif edge in ('left', 'right'): self.ball.speed = (-s[0], s[1])
Wenn der Schläger den Ball auf dem Weg nach unten verfehlt (oder der Ball die Seite des Schlägers trifft), fällt der Ball weiter und landet schließlich auf dem Boden. An diesem Punkt verliert der Spieler ein Leben und der Ball wird wiederhergestellt, sodass das Spiel fortgesetzt werden kann. Das Spiel endet, wenn der Spieler keine Leben mehr hat.
# Hit floor if self.ball.top > c.screen_height: self.lives -= 1 if self.lives == 0: self.game_over = True else: self.create_ball()
Wenn der Ball eine Wand oder Decke trifft, springt er einfach zurück.
# Hit ceiling if self.ball.top < 0: self.ball.speed = (s[0], -s[1]) # Hit wall if self.ball.left < 0 or self.ball.right > c.screen_width: self.ball.speed = (-s[0], s[1])
Wenn der Ball einen Stein trifft, ist das ein großes Ereignis in Breakout – der Stein verschwindet, der Spieler erhält einen Punkt, der Ball springt zurück und ein paar andere Dinge passieren (Soundeffekte und möglicherweise Spezialeffekte), die ich besprechen werde das später.
Um festzustellen, ob ein Stein getroffen wurde, prüft der Code, ob irgendwelche Steine den Ball kreuzen:
# Hit brick for brick in self.bricks: edge = intersect(brick, self.ball) if not edge: continue self.bricks.remove(brick) self.objects.remove(brick) self.score += self.points_per_brick if edge in ('top', 'bottom'): self.ball.speed = (s[0], -s[1]) else: self.ball.speed = (-s[0], s[1])
Die meisten Spiele haben eine Art Benutzeroberfläche. Breakout verfügt über ein einfaches Menü mit zwei Schaltflächen: „PLAY“ und „QUIT“. Dieses Menü erscheint, wenn das Spiel beginnt, und verschwindet, wenn der Spieler auf „Start“ klickt. Sehen wir uns an, wie Schaltflächen und Menüs implementiert sind und wie sie sich in das Spiel integrieren.
Pygame verfügt nicht über eine integrierte UI-Bibliothek. Es gibt Erweiterungen von Drittanbietern, aber ich habe beschlossen, meine eigene Schaltfläche für das Menü zu erstellen. Schaltflächen sind Spielobjekte mit drei Zuständen: normal, schwebend und gedrückt. Der Normalzustand liegt vor, wenn sich die Maus nicht über der Schaltfläche befindet, und der Hover-Zustand liegt vor, wenn sich die Maus über der Schaltfläche befindet, die linke Maustaste jedoch nicht gedrückt wird. Der gedrückte Zustand liegt vor, wenn sich die Maus über der Schaltfläche befindet und der Spieler die linke Maustaste drückt.
Die Schaltfläche ist als Rechteck mit einer Hintergrundfarbe und darauf angezeigtem Text implementiert. Die Schaltfläche erhält außerdem eine on_click-Funktion (standardmäßig eine Noop-Lambda-Funktion), die aufgerufen wird, wenn auf die Schaltfläche geklickt wird.
import pygame from game_object import GameObject from text_object import TextObject import config as c class Button(GameObject): def __init__(self, x, y, w, h, text, on_click=lambda x: None, padding=0): super().__init__(x, y, w, h) self.state = 'normal' self.on_click = on_click self.text = TextObject(x + padding, y + padding, lambda: text, c.button_text_color, c.font_name, c.font_size) def draw(self, surface): pygame.draw.rect(surface, self.back_color, self.bounds) self.text.draw(surface)
Schaltflächen verarbeiten ihre eigenen Mausereignisse und ändern ihren internen Status basierend auf diesen Ereignissen. Beim Drücken der Taste wird die MOUSEBUTTONUP
事件,表示玩家点击了按钮,并调用 on_click()
-Funktion empfangen.
def handle_mouse_event(self, type, pos): if type == pygame.MOUSEMOTION: self.handle_mouse_move(pos) elif type == pygame.MOUSEBUTTONDOWN: self.handle_mouse_down(pos) elif type == pygame.MOUSEBUTTONUP: self.handle_mouse_up(pos) def handle_mouse_move(self, pos): if self.bounds.collidepoint(pos): if self.state != 'pressed': self.state = 'hover' else: self.state = 'normal' def handle_mouse_down(self, pos): if self.bounds.collidepoint(pos): self.state = 'pressed' def handle_mouse_up(self, pos): if self.state == 'pressed': self.on_click(self) self.state = 'hover'
Die back_color
-Eigenschaft, die zum Zeichnen des Hintergrundrechtecks verwendet wird, gibt immer eine Farbe zurück, die dem aktuellen Status der Schaltfläche entspricht, sodass der Spieler deutlich erkennen kann, dass die Schaltfläche aktiv ist:
@property def back_color(self): return dict(normal=c.button_normal_back_color, hover=c.button_hover_back_color, pressed=c.button_pressed_back_color)[self.state]
create_menu()
函数创建一个带有两个按钮的菜单,其中包含文本“PLAY”和“QUIT”。它有两个嵌套函数,名为 on_play()
和 on_quit()
,它提供给相应的按钮。每个按钮都添加到 objects
列表(待绘制)以及 menu_buttons
Felder.
def create_menu(self): for i, (text, handler) in enumerate((('PLAY', on_play), ('QUIT', on_quit))): b = Button(c.menu_offset_x, c.menu_offset_y + (c.menu_button_h + 5) * i, c.menu_button_w, c.menu_button_h, text, handler, padding=5) self.objects.append(b) self.menu_buttons.append(b) self.mouse_handlers.append(b.handle_mouse_event)
Wenn auf die PLAY-Schaltfläche geklickt wird, wird on_play() aufgerufen, das von objects
列表中删除按钮,这样就不再绘制它们了。此外,触发游戏开始的布尔字段 is_game_running
和 start_level
auf True gesetzt wird.
Auf „True“ setzen, wenn auf die Schaltfläche „Beenden“ geklickt wird, wodurch die letzte Spielsequenz ausgelöst wird. is_game_running
设置为 False
(有效暂停游戏)并且 game_over
def on_play(button): for b in self.menu_buttons: self.objects.remove(b) self.is_game_running = True self.start_level = True def on_quit(button): self.game_over = True self.is_game_running = False
Das Ein- und Ausblenden von Menüs ist implizit. Wenn sich die Schaltflächen in der
-Liste befinden, ist das Menü sichtbar; wenn sie entfernt werden, wird es ausgeblendet. So einfach ist das. objects
Es ist möglich, ein verschachteltes Menü mit einer eigenen Oberfläche zu erstellen, die Unterkomponenten wie Schaltflächen darstellt, und diese Menükomponente dann einfach hinzuzufügen/zu entfernen, aber dieses einfache Menü benötigt das nicht.
In diesem Abschnitt behandeln wir die Kollisionserkennung und was passiert, wenn der Ball auf verschiedene Objekte wie Paddel, Ziegel, Wände, Decken und Böden trifft. Darüber hinaus haben wir ein eigenes Menü mit benutzerdefinierten Schaltflächen erstellt, die je nach Befehl ein- und ausgeblendet werden.
In diesem letzten Teil der Serie werfen wir einen Blick auf das letzte Spiel und legen dabei großen Wert auf Spielstände und Leben, Soundeffekte und Musik.
Dann werden wir ein komplexes Spezialeffektsystem entwickeln, um das Spiel interessanter zu machen. Abschließend besprechen wir zukünftige Richtungen und mögliche Verbesserungen.
Das obige ist der detaillierte Inhalt vonErstellen interaktiver Spiele mit Python 3 und Pygame: Teil 4. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!