游戏机如何处理状态 [英] Pygame how to handle states

查看:22
本文介绍了游戏机如何处理状态的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我最近用pyGame完成了一款连接四个类型的游戏。在任一玩家获胜后,它会显示一个菜单,询问你是想再次玩还是退出,每个选项都有一个按钮。程序根据Game类中包含游戏状态的变量知道是运行游戏还是显示菜单。问题是,我必须在程序中的几个点上有一个if-elif子句来查看要做什么。例如,在Game.draw方法中,它要么绘制游戏棋盘和棋子,要么绘制菜单,Game.on_click方法将事件发送到游戏板或菜单中的按钮等。所以我的问题是,是否有一种方法可以跟踪游戏状态,而不需要分散在程序中的if-elif子句?

game.py:

import pygame

from board import Board
from player import Player
from button import Button
from constants import (
    BLACK,
    RED,
    YELLOW,
    GREEN,
    WHITE,
    SQUARE_SIZE,
    ROWS,
    WIDTH,
    HEIGHT
)


class Game:
    PLAYING = 0
    HAS_WON = 1

    def __init__(self, win):
        self.win = win
        # self.running = True
        self.state = self.PLAYING
        self.running = True
        self.board = Board()

        self.players = [Player(RED, self.board), Player(YELLOW, self.board)]
        self.player_turn_counter = 0

        pygame.font.init()
        self.font = pygame.font.SysFont("Arial", 36)
        self.text = ""

        play_again_xpos = WIDTH // 5
        play_again_ypos = (HEIGHT // 5) * 4
        play_again_button = Button("Play Again",
                                   GREEN,
                                   self.play_again,
                                   xpos=play_again_xpos,
                                   ypos=play_again_ypos,
                                   show_border=True,
                                   border_color=(255, 255, 255))

        quit_xpos = (WIDTH // 5) * 4
        quit_ypos = (HEIGHT // 5) * 4
        quit_button = Button("Quit",
                             RED,
                             self.quit,
                             xpos=quit_xpos,
                             ypos=quit_ypos,
                             show_border=True,
                             border_color=(255, 255, 255))

        self.buttons = [play_again_button, quit_button]

    def play_again(self):
        self.__init__(self.win)
        self.run()

    def quit(self):
        self.running = False

    def draw(self):
        self.win.fill(BLACK)
        self.board.draw(self.win)
        if self.state == self.HAS_WON:
            # self.win.fill(WHITE)
            text = self.font.render(self.text, True, WHITE)

            text_rect = text.get_rect()
            text_rect.centerx = WIDTH // 2
            text_rect.centery = ((SQUARE_SIZE * ROWS) // 3) - SQUARE_SIZE // 2

            self.win.blit(text, text_rect)

            for button in self.buttons:
                button.draw(self.win)
            # self.play_again_button.draw(self.win)
            # self.quit_button.draw(self.win)

        pygame.display.update()

    def is_full(self, column):
        board = self.board.get_board()
        # pieces = []

        # for row in board:
        #     pieces.append(row[column])

        # return all(pieces)
        return all([row[column] for row in board])

    def on_win(self, color):
        self.state = self.HAS_WON
        colors = {(255, 255, 0): "Yellow", (255, 0, 0): "Red"}
        self.text = f"{colors[color]} has won!"
        # print(f"{colors[color]} has won!")

    def on_click(self):
        if self.state == self.PLAYING:
            column = self.board.get_column()
            if not self.is_full(column):
                self.player_turn_counter += 1
                self.player_turn_counter = self.player_turn_counter % 2
            self.players[self.player_turn_counter].on_click()
            has_won, color = self.board.check_for_win()
            if has_won:
                self.on_win(color)
        elif self.state == self.HAS_WON:
            for button in self.buttons:
                button.on_click()

    def run(self):
        clock = pygame.time.Clock()

        while self.running:
            clock.tick(60)

            for event in pygame.event.get():
                if event.type == pygame.QUIT:
                    self.running = False

                if event.type == pygame.MOUSEBUTTONDOWN:
                    self.on_click()

            self.draw()

以下是整个计划的GitHub回购: https://github.com/pianocomposer321/ConnectFour.git

推荐答案

创建两个具有相同接口的类,每个州一个。这些类包含与游戏状态相关的实现:

class Playing:
    def __init__(self, game)
        self.game = game

    def draw(self):
        # [...]

    def on_click(self):
        # [...]
class HasWon:
    def __init__(self, game):
        self.game = game

    def draw(self):
        # [...]

    def on_click(self):
        # [...]

Game类使用实现游戏状态的类。另一个属性(self.current)引用当前状态类。另一种方法(set_state)切换状态变量并根据状态设置self.current。这是程序中唯一需要if-elif子句的地方。在其他方法中,您可以委托游戏状态实现的实现方法(如self.current.draw()self.current.on_click()):

class Game:
    PLAYING = 0
    HAS_WON = 1

    def __init__(self, win):
        # [...]

        self.playing = Playing(self)
        self.haswon = HasWon(self)
        self.set_state(self.PLAYING)
        
    def set_state(new_state):
        self.state = self.PLAYING
        if self.state == self.PLAYING:
            self.current = self.playing
        elif self.state == self.HAS_WON:
            self.current = self.haswon

    def draw(self):
        self.win.fill(BLACK)
        self.board.draw(self.win)
        
        self.current.draw()

        pygame.display.update()

    def on_win(self, color):
        self.set_state(self.HAS_WON)
        # [...]
        

    def on_click(self):
        self.current.on_click()

这篇关于游戏机如何处理状态的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆