Step 1#
step_01.py#
1import random
2from pathlib import Path
3
4import arcade
5from arcade.experimental import Shadertoy
6
7# Do the math to figure out our screen dimensions
8SCREEN_WIDTH = 800
9SCREEN_HEIGHT = 600
10SCREEN_TITLE = "Ray-casting Demo"
11
12SPRITE_SCALING = 0.25
13
14# How fast the camera pans to the player. 1.0 is instant.
15CAMERA_SPEED = 0.1
16
17PLAYER_MOVEMENT_SPEED = 7
18BOMB_COUNT = 70
19PLAYING_FIELD_WIDTH = 1600
20PLAYING_FIELD_HEIGHT = 1600
21
22
23class MyGame(arcade.Window):
24
25 def __init__(self, width, height, title):
26 super().__init__(width, height, title)
27
28 # The shader toy and 'channels' we'll be using
29 self.shadertoy = None
30 self.channel0 = None
31 self.channel1 = None
32 self.load_shader()
33
34 # Sprites and sprite lists
35 self.player_sprite = None
36 self.wall_list = arcade.SpriteList()
37 self.player_list = arcade.SpriteList()
38 self.bomb_list = arcade.SpriteList()
39 self.physics_engine = None
40
41 self.generate_sprites()
42 arcade.set_background_color(arcade.color.ARMY_GREEN)
43
44 def load_shader(self):
45 # Where is the shader file? Must be specified as a path.
46 shader_file_path = Path("step_01.glsl")
47
48 # Size of the window
49 window_size = self.get_size()
50
51 # Create the shader toy
52 self.shadertoy = Shadertoy.create_from_file(window_size, shader_file_path)
53
54 # Create the channels 0 and 1 frame buffers.
55 # Make the buffer the size of the window, with 4 channels (RGBA)
56 self.channel0 = self.shadertoy.ctx.framebuffer(
57 color_attachments=[self.shadertoy.ctx.texture(window_size, components=4)]
58 )
59 self.channel1 = self.shadertoy.ctx.framebuffer(
60 color_attachments=[self.shadertoy.ctx.texture(window_size, components=4)]
61 )
62
63 # Assign the frame buffers to the channels
64 self.shadertoy.channel_0 = self.channel0.color_attachments[0]
65 self.shadertoy.channel_1 = self.channel1.color_attachments[0]
66
67 def generate_sprites(self):
68 # -- Set up several columns of walls
69 for x in range(0, PLAYING_FIELD_WIDTH, 128):
70 for y in range(0, PLAYING_FIELD_HEIGHT, int(128 * SPRITE_SCALING)):
71 # Randomly skip a box so the player can find a way through
72 if random.randrange(2) > 0:
73 wall = arcade.Sprite(":resources:images/tiles/boxCrate_double.png", SPRITE_SCALING)
74 wall.center_x = x
75 wall.center_y = y
76 self.wall_list.append(wall)
77
78 # -- Set some hidden bombs in the area
79 for i in range(BOMB_COUNT):
80 bomb = arcade.Sprite(":resources:images/tiles/bomb.png", 0.25)
81 placed = False
82 while not placed:
83 bomb.center_x = random.randrange(PLAYING_FIELD_WIDTH)
84 bomb.center_y = random.randrange(PLAYING_FIELD_HEIGHT)
85 if not arcade.check_for_collision_with_list(bomb, self.wall_list):
86 placed = True
87 self.bomb_list.append(bomb)
88
89 # Create the player
90 self.player_sprite = arcade.Sprite(":resources:images/animated_characters/female_person/femalePerson_idle.png",
91 scale=SPRITE_SCALING)
92 self.player_sprite.center_x = 256
93 self.player_sprite.center_y = 512
94 self.player_list.append(self.player_sprite)
95
96 # Physics engine, so we don't run into walls
97 self.physics_engine = arcade.PhysicsEngineSimple(self.player_sprite, self.wall_list)
98
99 def on_draw(self):
100 # Select the channel 0 frame buffer to draw on
101 self.channel0.use()
102 self.channel0.clear()
103 # Draw the walls
104 self.wall_list.draw()
105
106 # Select this window to draw on
107 self.use()
108 # Clear to background color
109 self.clear()
110 # Run the shader and render to the window
111 self.shadertoy.render()
112
113 def on_key_press(self, key, modifiers):
114 """Called whenever a key is pressed. """
115
116 if key == arcade.key.UP:
117 self.player_sprite.change_y = PLAYER_MOVEMENT_SPEED
118 elif key == arcade.key.DOWN:
119 self.player_sprite.change_y = -PLAYER_MOVEMENT_SPEED
120 elif key == arcade.key.LEFT:
121 self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
122 elif key == arcade.key.RIGHT:
123 self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
124
125 def on_key_release(self, key, modifiers):
126 """Called when the user releases a key. """
127
128 if key == arcade.key.UP or key == arcade.key.DOWN:
129 self.player_sprite.change_y = 0
130 elif key == arcade.key.LEFT or key == arcade.key.RIGHT:
131 self.player_sprite.change_x = 0
132
133 def on_update(self, delta_time):
134 """ Movement and game logic """
135
136 # Call update on all sprites (The sprites don't do much in this
137 # example though.)
138 self.physics_engine.update()
139
140
141if __name__ == "__main__":
142 MyGame(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
143 arcade.run()