生命游戏 - 如何通过鼠标点击激活细胞?
Game of Life - How can I activate cells with mouseclicks?
python(和编程)的新手,但我正在尝试创建一个生活游戏。我现在是一个生命游戏,从随机数量的活动细胞开始,但我希望能够通过单击它们来激活或停用细胞。
我尝试了几种方法,我知道我必须使用 pygame.MOUSEBUTTONDOWN。我从中获取坐标,但后来我不知道如何使用这些坐标将单元格值从 1 更改为 0 或从 0 更改为 1。
目标是为“'random mode'”(现在)和“'active mode'”创建一个切换,用户可以在其中 select 个单元格。
下面是我目前的代码:
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 个像素,这应该会更改该值,因此它会显示在 screen/also 逻辑上。
一种相对快速的方法是简单地进行逆向计算,该计算用于计算 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':
...
python(和编程)的新手,但我正在尝试创建一个生活游戏。我现在是一个生命游戏,从随机数量的活动细胞开始,但我希望能够通过单击它们来激活或停用细胞。
我尝试了几种方法,我知道我必须使用 pygame.MOUSEBUTTONDOWN。我从中获取坐标,但后来我不知道如何使用这些坐标将单元格值从 1 更改为 0 或从 0 更改为 1。
目标是为“'random mode'”(现在)和“'active mode'”创建一个切换,用户可以在其中 select 个单元格。
下面是我目前的代码:
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 个像素,这应该会更改该值,因此它会显示在 screen/also 逻辑上。
一种相对快速的方法是简单地进行逆向计算,该计算用于计算 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':
...