Game of Life in pygame: как можно вручную нажимать на ячейки, чтобы активировать / деактивировать их? - PullRequest
0 голосов
/ 22 мая 2019

Работа над этой версией Game of Life в Pygame.В конце я хочу иметь два варианта запуска игры: один, где вы можете запустить игру, и он запускается автоматически со случайной сеткой, и игра, где пользователь начинает игру с пустой сетки и может активировать / деактивировать ячейки.В настоящее время у меня есть только режим случайной сетки, и я борюсь с активацией / деактивацией клеток.В handle_events () есть функция, которая позволяет пользователю нажимать на ячейки, чтобы активировать их в произвольной сетке, если игра приостановлена, но по какой-то причине не позволяет пользователю снова деактивировать эти ячейки.Кроме того, он перезаписывается в следующей итерации.

Кто-нибудь знает, как я могу это исправить?И что было бы лучшим способом создать два разных режима игры («случайная игра» и «пользователь выбирает режим ячейки»).

Заранее спасибо

Я разместил код ниже.

import pygame
import random
import sys

grid_size = width, height = 400, 400
cell_size = 10
color_dead = 0, 0, 0  # Background
color_alive = 255, 255, 255  # alive cell, can be any color.  #orange = 255, 100, 0 #yellow = 255,255,0, # red=255,0,0 #Green 0,200,0
fps_max = 10


class GameOfLife:
    def __init__(self):
      #The screen
        pygame.init()
        pygame.display.set_caption("Game of Life - Created by ") 
        self.FPSCLOCK = pygame.time.Clock()
        self.screen = pygame.display.set_mode(grid_size)
        self.clear_screen()  # you clear the screen before it starts running
        pygame.display.flip() #Update the full display Surface to the screen
        self.last_update_completed = 0
        #self.desired_milliseconds_between_updates = (1.0 / fps_max) * 1000
        self.active_grid = 0
        self.num_cols = int(width / cell_size)
        self.num_rows = int(height / cell_size)
        self.grids = []
        self.init_grids()
        self.set_grid()
        self.paused = False
        self.game_over = False

    def is_in_range(self, x, y):
        if x in range(self.x, self.x + self.size + 1) and y in range(self.y, self.y + self.size + 1):
            return True
        else:
            return False

    def init_grids(self):

        def create_grid():
            rows = []
            for row_num in range(self.num_rows):
                list_of_columns = [0] * self.num_cols
                rows.append(list_of_columns)
            return rows

        self.grids.append(create_grid())
        self.grids.append(create_grid())
        self.active_grid = 0


        #print(self.grids[0])
        #print(rows)
        #print(type(rows))


    #set_grid(0)  = all dead
    #set_grid(1) = all alive
    #set_grid() = random
    #set_grid(None) = random
    def set_grid(self, value=None, grid =0):
       for r in range(self.num_rows):
           for c in range(self.num_cols):
                if value is None:
                    cell_value = random.choice([0,1])
                else:
                    cell_value = value
                self.grids[grid][r][c] = cell_value

    def draw_grid(self):
        self.clear_screen()  # you clear the screen before it starts running
        for c in range(self.num_cols):
            for r in range(self.num_rows):
                if self.grids[self.active_grid][r][c] == 1:
                    color = color_alive
                else:
                    color = color_dead

                #pygame.draw.rect(self.screen, color, ((c * cell_size + (cell_size / 2)),(r * cell_size + (cell_size / 2)), cell_size, cell_size) )
                posn = (int(c * cell_size + cell_size / 2),
                        int(r * cell_size + cell_size / 2))
                pygame.draw.circle(self.screen, color, posn, int(cell_size / 2), 0)
        pygame.display.flip()

    def clear_screen(self):
        self.screen.fill(color_dead)

    def get_cell(self, r, c):
        try:
            cell_value = self.grids[self.active_grid][r][c]
        except:
            #print("Couldn't get cell value: row: %d, col %d" % (r, c))
            cell_value = 0
        return cell_value

    def check_cell_neighbors(self, row_index, col_index):
        # Get the number of alive cells surrounding the current cell
        # self.grids[self.active_grid][r][c]   #is the current cell
        num_alive_neighbors = 0
        num_alive_neighbors += self.get_cell(row_index - 1, col_index - 1)
        num_alive_neighbors += self.get_cell(row_index - 1, col_index)
        num_alive_neighbors += self.get_cell(row_index - 1, col_index + 1)
        num_alive_neighbors += self.get_cell(row_index, col_index - 1)
        num_alive_neighbors += self.get_cell(row_index, col_index + 1)
        num_alive_neighbors += self.get_cell(row_index + 1, col_index - 1)
        num_alive_neighbors += self.get_cell(row_index + 1, col_index)
        num_alive_neighbors += self.get_cell(row_index + 1, col_index + 1)

        #print(num_alive_neighbors)
        #print("alive neighbors: %d")

# Rules
#1 Any live cell with fewer than two live neighbours dies, as if by underpopulation.
#2 Any live cell with two or three live neighbours lives on to the next generation.
#3 Any live cell with more than three live neighbours dies, as if by overpopulation.
#4 Any dead cell with exactly three live neighbours becomes a live cell, as if by reproduction.


        if self.grids[self.active_grid][row_index][col_index] == 1: #Alive
            if num_alive_neighbors > 3:
                return 0  # it dies of overpopulation # More than three live neighbors, rule number 3.
            if num_alive_neighbors < 2:
                return 0  # it dies of underpopulation = Rule number 1 = fewer than two live neighbors
            if num_alive_neighbors == 2 or num_alive_neighbors == 3:  # If there are 3 or 4 neighbors, and the cell is alive, it stays alive.
                return 1  # Rule number 2. Two or three live neighbours, it continuous to live.
        elif self.grids[self.active_grid][row_index][col_index] == 0: #Dead
            if num_alive_neighbors ==3:
                return 1 #It comes to life.
        return self.grids[self.active_grid][row_index][col_index]

    def update_generation(self):
        """
        Inspect current generation state, prepare next generation
        :return:
        """
        self.set_grid(0, self.inactive_grid())
        for r in range(self.num_rows - 1):
            for c in range(self.num_cols - 1):
                next_gen_state = self.check_cell_neighbors(r, c)
                # Set inactive grid future cell state
                self.grids[self.inactive_grid()][r][c] = next_gen_state  # if it is zero, than is is 1. if it is 1, it is gonna be 0. Picks the offgrid.
        self.active_grid = self.inactive_grid()


        #inspect the current active generation
        # update the inactive grid to store next generation
        #swap out the active grid
        #self.set_grid(None) #This means that you randomize the grid

    def inactive_grid(self):
        return (self.active_grid + 1) % 2

    def handle_events(self):
        for event in pygame.event.get():
            if self.paused:
                if event.type == pygame.MOUSEBUTTONDOWN:
                    if(event.button==1):
                        mousepos_x, mousepos_y = event.pos
                        r, c = ((mousepos_x - cell_size / 2) // cell_size,
                                (mousepos_y - cell_size / 2) // cell_size)
                        print(event.pos, '->', (r, c))  # Show result.
                        mousepos_x, mousepos_y = event.pos# Index Y rows down, X columns to the right
                        for col in range(self.num_cols):
                            for row in range(self.num_rows):
                                if self.grids[self.active_grid][col][row] == 1:
                                    color = color_dead
                                elif self.grids[self.active_grid][col][row] == 0:
                                    color = 255,0,255#color_alive


                        posn = (int(r * cell_size + cell_size / 2),
                                int(c * cell_size + cell_size / 2))
                        print(posn) 
                        pygame.draw.circle(self.screen, color, posn, int(cell_size / 2), 0)
                pygame.display.flip()

            if event.type == pygame.KEYDOWN:
                if event.unicode == 's':
                    if self.paused:
                        self.paused = False
                        print("unpaused")
                    else:
                        self.paused = True
                        print("paused")
                #Randomizin the grid
                elif event.unicode == 'r':
                    print("randomizing the grid")
                    self.active_grid = 0
                    self.set_grid(None, self.active_grid) #randomizing
                    self.set_grid(0,self.inactive_grid()) #set to 0.
                    self.draw_grid() #Even if it is paused.
                # Quitfunction
                elif event.unicode == 'q':  #If I press q, game_over becomes TRUE, which returns/ends in the def run().
                    print("Quitting the grid")
                    self.game_over = True


                # print(event.unicode)
                # print("Key pressed")
                # print(event.unicode)

            # if event is keypress of "s" then pause the loop/game.
            #if event is keypress "r" then randomize grid
            # if event is keypress of "q"then quit
            if event.type == pygame.QUIT:
                sys.exit()

    def run(self):
        while True:
            if self.game_over:
                return #So if it is game_over by pressing Q, you leave the loop.
            self.handle_events()  # when you run, you want to handle the events
            if self.paused:
                continue
            self.update_generation()  # Upgrade the generation
            self.draw_grid()  # and draw the grid
            self.FPSCLOCK.tick(fps_max)

if __name__ == "__main__":
    game = GameOfLife()
    game.run()

Ответы [ 2 ]

0 голосов
/ 23 мая 2019

Я не уверен, что вы пытаетесь сделать в функции handle_events() для обработки нажатий кнопок мыши.Вот версия, которая позволяет активировать и деактивировать ячейки при щелчке, а изменения будут перезаписаны в следующем поколении (если только они все не умерли из-за применения правил обновления поколения).

Я не знаюНе думаю, что вам нужны разные режимы (например, «случайный» или «пользователь выбирает»), потому что это может быть достигнуто с помощью различных одноклавишных команд, которые вы уже реализовали, хотя вам необходимо добавить еще один, который позволял бы очищать вручнуюсетки.

def handle_events(self):
    for event in pygame.event.get():
        if self.paused:
            if event.type == pygame.MOUSEBUTTONDOWN:
                if(event.button==1):
                    mousepos_x, mousepos_y = event.pos
                    c, r = (int((mousepos_x - cell_size / 2) // cell_size),
                            int((mousepos_y - cell_size / 2) // cell_size))
                    #print(event.pos, '->', (r, c))  # Show result.
                    if r in range(self.num_rows) and c in range(self.num_cols):
                        # Toggle state of cell: active <--> inactive
                        if self.grids[self.active_grid][r][c] == 1:
                            self.grids[self.active_grid][r][c] = 0
                            color = color_dead
                        else:
                            self.grids[self.active_grid][r][c] = 1
                            color = color_alive
                        # Redraw cell in its new color.
                        posn = (int(c * cell_size + cell_size / 2),
                                int(r * cell_size + cell_size / 2))
                        #print('  posn:', posn)
                        pygame.draw.circle(self.screen, color, posn, int(cell_size / 2), 0)

                        pygame.display.flip()

        if event.type == pygame.KEYDOWN:
            if event.unicode == 's':
                .
                .
                .

0 голосов
/ 22 мая 2019

Похоже, вы просто меняете цвет ячеек вместо напрямую , изменяя сами значения.Поэтому добавьте конкретное индексирование и установите значение, противоположное ему, и это должно решить обе проблемы.

mousepos_x, mousepos_y = event.pos# Index Y rows down, X columns to the right
if self.grids[self.active_grid][int(mousepos_x / 10)][int(mousepos_y / 10)] == 1:
    color = color_dead
    self.grids[self.active_grid][int(mousepos_x / 10)][int(mousepos_y / 10)] = 0

elif self.grids[self.active_grid][int(mousepos_x / 10)][int(mousepos_y / 10)] == 0:
    color = 255,0,255#color_alive
    self.grids[self.active_grid][int(mousepos_x / 10)][int(mousepos_y / 10)] = 1

Это должно решить обе проблемы.

...