Новичок в python (и программировании), но я пытаюсь создать игру жизни. Теперь я играю в жизнь, которая начинается со случайного количества активных ячеек, но я хочу иметь возможность активировать или деактивировать ячейки, нажимая на них.
Я пробовал несколько вещей, я знаю, что должен использовать pygame.MOUSEBUTTONDOWN. Я получаю от него координаты, но тогда я не знаю, как использовать эти координаты, чтобы изменить значение ячейки с 1 на 0 или с 0 на 1.
Цель состоит в том, чтобы создать переключатель для «случайного режима» (как сейчас) и «активного режима», где пользователь может выбирать ячейки.
Ниже кода, который у меня есть до сих пор:
import pygame
import random
import sys
grid_size = width, height = 400, 400
cell_size = 10
color_dead = 0, 0, 0
color_alive = 255, 0, 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.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 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
#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) )
pygame.draw.circle(self.screen,
color,
(int(c * cell_size + (cell_size / 2)),
int(r * cell_size + (cell_size / 2))),
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 event.type == pygame.MOUSEBUTTONDOWN:
mousepos_x, mousepos_y = event.pos
print(event.pos[0])
print(cell_size)
#Get the position of the mouseclick
#print(mousepos_x, mousepos_y)
click = pygame.mouse.get_pos()
#print(click)
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':
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()
Когда вы получаете позиции мыши x и y, вы можете проиндексировать список ячеек и изменить указанное значение на 1, поэтому в вашем коде обработки событий:
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
mousepos_x, mousepos_y = event.pos
self.grids[mousepos_y][mousepos_x] = 1 # Index Y rows down, X columns to the right
Пока каждая ячейка составляет 1 пиксель, это должно изменить это значение, и поэтому оно будет отображаться на экране/также работать с логикой.
Pygasm: Каждая ячейка — это не 1 пиксель, это круги.
Относительно быстрый способ сделать это — просто выполнить обратный расчет, который используется для вычисления центральной точки каждой окружности ячеек в методе draw_grid()
.
Вот его версия, которую я немного изменил, чтобы подчеркнуть математику, связанную с вычислением координат x и y этой точки (которая хранится в кортеже posn
):
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
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 handle_events(self):
for event in pygame.event.get():
if event.type == pygame.MOUSEBUTTONDOWN:
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.
if event.type == pygame.KEYDOWN:
if event.unicode == 's':
...
Спасибо, сэр! Я разместил свой новый код ниже. Теперь он активирует ряд ячеек в нижней части экрана. Любые советы о том, как я могу исправить код?
@Fabio: Извините, я не совсем понимаю дополнительный вопрос, который вы опубликовали в качестве ответа. Ячейки можно изменить (активировать или деактивировать) в функции handle_events()
. Код в последней части моего ответа показывает, как вычислить строку и столбец (r
и c
) ячейки, которая была нажата из положения события мыши, чтобы эти значения можно было использовать для изменения цвета соответствующей ячейки в сетка.
да, я хочу иметь возможность изменять (активировать/деактивировать) ячейки в функции handle_events. Теперь я использую значения r и c для изменения ячеек, но я борюсь с несколькими проблемами: 1) теперь я могу только активировать ячейки, деактивация по какой-то причине не работает. 2) похоже, что я активирую только ячейки в текущей сетке, если я сниму паузу, активированные ячейки снова станут игрой жизни, активированные ячейки снова станут неактивными (они перезаписываются?). Вы знаете, что я делаю неправильно здесь?
@Fabio: Это много проблем, плюс похоже, что вы внесли ряд изменений в свой код, что затрудняет дальнейшую помощь, поэтому я предлагаю вам опубликовать новый вопрос с вашим текущим кодом вместе с описанием. проблем.
@Фабио: P.S. Проблемы с ячейками, которые снова становятся неактивными и / или перезаписываются, вероятно, имеют какое-то отношение к тому факту, что на самом деле используются отдельные сетки два, поэтому вам нужно убедиться, что обновляется правильная сетка при внесении изменений в функцию handle_events()
.
Но это так не работает, к сожалению. Одна из многих вещей, которые я пробовал