From f165c37886cf65a7201f2134284507ffb114311c Mon Sep 17 00:00:00 2001 From: Paul <36696816+pushfoo@users.noreply.github.com> Date: Sat, 24 Feb 2024 08:48:11 -0500 Subject: [PATCH] Fix game of life scaling the window instead of the texture (#1986) * Fix window sizing in game of life example (#1985) * Clean up import order and spacing * Use more style-compliant main check for running the shader game of life * Fix grammar in comment * Update comments and docstrings on implementation * Rephrase top-level example docstring for clarity * phrasing tweak --- arcade/examples/gl/game_of_life_colors.py | 59 +++++++++++++---------- 1 file changed, 33 insertions(+), 26 deletions(-) diff --git a/arcade/examples/gl/game_of_life_colors.py b/arcade/examples/gl/game_of_life_colors.py index 44a124759..8b6475fce 100644 --- a/arcade/examples/gl/game_of_life_colors.py +++ b/arcade/examples/gl/game_of_life_colors.py @@ -1,17 +1,17 @@ """ Game of Life - Shader Version -We're doing this in in a simple way drawing to textures. -We need two textures. One to keep the old state and -another to draw the new state into. These textures are -flipped around every frame. +This version uses shaders which draws to textures to +run Conway's Game of Life with an added twist: colors. -This version of Game of Life also use colors. Dominant -colonies will keep spreading their color. +Press SPACE to reset the simulation with random data. -Press SPACE to generate new initial data +It uses two textures: One to keep the old state and +a second to draw the new state into. These textures are +flipped around after every update. -The cell and window size can be tweaked in the parameters below. +You can configure the cell and window size by changing +the constants at the top of the file after the imports. If Python and Arcade are installed, this example can be run from the command line with: python -m arcade.examples.gl.game_of_life_colors @@ -19,14 +19,15 @@ import random from array import array -from arcade import key import arcade +from arcade import key from arcade.gl import geometry + CELL_SIZE = 2 # Cell size in pixels WINDOW_WIDTH = 512 # Width of the window WINDOW_HEIGHT = 512 # Height of the window -FRAME_DELAY = 2 # The game will only update every 2th frame +FRAME_DELAY = 2 # The game will only update every 2nd frame class GameOfLife(arcade.Window): @@ -35,17 +36,17 @@ def __init__(self, width, height): super().__init__(width, height, "Game of Life - Shader Version") self.frame = 0 - # Configure the size of the playfield (cells) - self.size = width // CELL_SIZE, height // CELL_SIZE + # Calculate how many cells we need to simulate at this pixel size + self.texture_size = width // CELL_SIZE, height // CELL_SIZE # Create two textures for the next and previous state (RGB textures) self.texture_1 = self.ctx.texture( - self.size, + self.texture_size, components=3, filter=(self.ctx.NEAREST, self.ctx.NEAREST), ) self.texture_2 = self.ctx.texture( - self.size, + self.texture_size, components=3, filter=(self.ctx.NEAREST, self.ctx.NEAREST) ) @@ -85,9 +86,9 @@ def __init__(self, width, height): """, ) - # Shader for creating the next game state. - # It takes the previous state as input (texture0) - # and renders the next state directly into the second texture. + # Shader which calculates the next game state. + # It uses the previous state as input (texture0) and + # renders the next state into the second texture. self.life_program = self.ctx.program( vertex_shader=""" #version 330 @@ -164,21 +165,25 @@ def __init__(self, width, height): ) def gen_initial_data(self, num_values: int): - """ - Generate initial data. We need to be careful about the initial state. - Just throwing in lots of random numbers will make the entire system - die in a few frames. We need to give enough room for life to exist. + """Generate initial data. + + We need to be careful about the initial game state. Carelessly + random numbers will make the simulation die in only a few frames. + Instead, we need to generate values which leave room for life + to exist. - This might be the slowest possible way we would generate the initial - data, but it works for this example :) + The implementtation below is one of the slowest possible ways to + would generate the initial data, but it keeps things simple for + this example. """ choices = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 64, 128, 192, 255] for i in range(num_values): yield random.choice(choices) def write_initial_state(self): - """Write initial data to the source texture""" - self.texture_1.write(array('B', self.gen_initial_data(self.size[0] * self.size[1] * 3))) + """Write initial data to the source texture.""" + size = self.texture_size + self.texture_1.write(array('B', self.gen_initial_data(size[0] * size[1] * 3))) def on_draw(self): self.clear() @@ -214,4 +219,6 @@ def on_key_press(self, symbol: int, modifiers: int): self.write_initial_state() -GameOfLife(WINDOW_WIDTH, WINDOW_HEIGHT).run() +if __name__ == "__main__": + game = GameOfLife(WINDOW_WIDTH, WINDOW_HEIGHT) + game.run()