54 static asc_transform rotations[4]; |
54 static asc_transform rotations[4]; |
55 static asc_vec2f directions[4]; |
55 static asc_vec2f directions[4]; |
56 |
56 |
57 typedef struct { |
57 typedef struct { |
58 enum MoveDirection direction; |
58 enum MoveDirection direction; |
|
59 /** |
|
60 * The speed in tiles per second. |
|
61 */ |
|
62 float speed; |
59 } Spaceship; |
63 } Spaceship; |
|
64 |
|
65 static const unsigned game_field_size = 512; |
|
66 static const unsigned game_field_tile_size = 32; |
60 |
67 |
61 static void init_globals(void) { |
68 static void init_globals(void) { |
62 asc_transform_identity(rotations[MOVE_UP]); |
69 asc_transform_identity(rotations[MOVE_UP]); |
63 asc_transform_roll(rotations[MOVE_LEFT], asc_rad(-90)); |
70 asc_transform_roll(rotations[MOVE_LEFT], asc_rad(-90)); |
64 asc_transform_roll(rotations[MOVE_RIGHT], asc_rad(90)); |
71 asc_transform_roll(rotations[MOVE_RIGHT], asc_rad(90)); |
76 static void init_textures(void) { |
83 static void init_textures(void) { |
77 asc_texture_init_2d(tex2d, TEX2D_COUNT); |
84 asc_texture_init_2d(tex2d, TEX2D_COUNT); |
78 asc_texture_from_file(TEXTURE_SHIP, "ship.png"); |
85 asc_texture_from_file(TEXTURE_SHIP, "ship.png"); |
79 asc_texture_from_file(TEXTURE_BACKDROP, "backdrop.png"); |
86 asc_texture_from_file(TEXTURE_BACKDROP, "backdrop.png"); |
80 asc_gl_context_add_cleanup_func(asc_active_glctx, destroy_textures); |
87 asc_gl_context_add_cleanup_func(asc_active_glctx, destroy_textures); |
|
88 } |
|
89 |
|
90 static void scale_backdrop(AscBehavior *behavior) { |
|
91 // scale the backdrop to the size of the window |
|
92 if (asc_active_window->resized) { |
|
93 asc_ptr_cast(AscSprite, sprite, behavior->node); |
|
94 asc_vec2u window_size = asc_active_window->dimensions; |
|
95 asc_sprite_set_size(sprite, window_size); |
|
96 } |
|
97 } |
|
98 |
|
99 static void create_backdrop(void) { |
|
100 AscSceneNode *node = asc_sprite( |
|
101 .texture = TEXTURE_BACKDROP, |
|
102 .texture_scale_mode = ASC_TEXTURE_SCALE_REPEAT |
|
103 ); |
|
104 asc_behavior_add(node, .func = scale_backdrop); |
|
105 asc_scene_add_node(BACKDROP_SCENE, node); |
81 } |
106 } |
82 |
107 |
83 static void update_fps_counter(AscBehavior *behavior) { |
108 static void update_fps_counter(AscBehavior *behavior) { |
84 asc_ptr_cast(AscText, node, behavior->node); |
109 asc_ptr_cast(AscText, node, behavior->node); |
85 static float last_fps = 0.f; |
110 static float last_fps = 0.f; |
100 (int) bottom_right.y - (int) text_size.height - 10 |
125 (int) bottom_right.y - (int) text_size.height - 10 |
101 )); |
126 )); |
102 } |
127 } |
103 } |
128 } |
104 |
129 |
105 static void scale_backdrop(AscBehavior *behavior) { |
|
106 // scale the backdrop to the size of the window |
|
107 if (asc_active_window->resized) { |
|
108 asc_ptr_cast(AscSprite, sprite, behavior->node); |
|
109 asc_vec2u window_size = asc_active_window->dimensions; |
|
110 asc_sprite_set_size(sprite, window_size); |
|
111 } |
|
112 } |
|
113 |
|
114 static void create_backdrop(void) { |
|
115 AscSceneNode *node = asc_sprite( |
|
116 .texture = TEXTURE_BACKDROP, |
|
117 .texture_scale_mode = ASC_TEXTURE_SCALE_REPEAT |
|
118 ); |
|
119 asc_behavior_add(node, .func = scale_backdrop); |
|
120 asc_scene_add_node(BACKDROP_SCENE, node); |
|
121 } |
|
122 |
|
123 static void create_fps_counter(void) { |
130 static void create_fps_counter(void) { |
124 asc_font(ASC_FONT_REGULAR, 12); |
131 asc_font(ASC_FONT_REGULAR, 12); |
125 asc_ink_rgb(255, 255, 255); |
132 asc_ink_rgb(255, 255, 255); |
126 AscSceneNode *node = asc_text(.name = "FPS Counter"); |
133 AscSceneNode *node = asc_text(.name = "FPS Counter"); |
127 asc_behavior_add(node, .func = update_fps_counter, .interval = asc_seconds(1)); |
134 asc_behavior_add(node, .func = update_fps_counter, .interval = asc_seconds(1)); |
141 } |
148 } |
142 |
149 |
143 static void move_spaceship(AscBehavior *behavior) { |
150 static void move_spaceship(AscBehavior *behavior) { |
144 AscSceneNode *node = behavior->node; |
151 AscSceneNode *node = behavior->node; |
145 Spaceship *spaceship = node->user_data; |
152 Spaceship *spaceship = node->user_data; |
146 float speed = 32.f * asc_context.frame_factor; |
153 float speed = 32.f * spaceship->speed * asc_context.frame_factor; |
147 asc_vec2f movement = asc_vec2f_scale(directions[spaceship->direction], speed); |
154 asc_vec2f movement = asc_vec2f_scale(directions[spaceship->direction], speed); |
148 asc_scene_node_move2f(node, movement); |
155 asc_scene_node_move2f(node, movement); |
149 asc_scene_node_set_rotation(node, rotations[spaceship->direction]); |
156 asc_scene_node_set_rotation(node, rotations[spaceship->direction]); |
150 } |
157 } |
151 |
158 |
152 static Spaceship *create_spaceship(void) { |
159 static Spaceship *create_spaceship(void) { |
153 AscSceneNode *sprite = asc_sprite( |
160 AscSceneNode *sprite = asc_sprite( |
154 .name = "Player", |
161 .name = "Player", |
155 .texture = TEXTURE_SHIP, |
162 .texture = TEXTURE_SHIP, |
156 .x = 250, |
163 // TODO: introduce a function to set the position of a space ship |
157 .y = 300, |
164 .x = game_field_tile_size * 8 - game_field_tile_size / 2, |
158 .width = 32, |
165 .y = game_field_tile_size * 12 - game_field_tile_size / 2, |
159 .height = 32, |
166 .width = game_field_tile_size, |
160 .origin_x = 16, |
167 .height = game_field_tile_size, |
161 .origin_y = 16, |
168 .origin_x = game_field_tile_size / 2, |
|
169 .origin_y = game_field_tile_size / 2, |
162 ); |
170 ); |
163 asc_scene_add_node(MAIN_SCENE, sprite); |
171 asc_scene_add_node(MAIN_SCENE, sprite); |
164 asc_scene_node_allocate_data(sprite, sizeof(Spaceship)); |
172 Spaceship *ship = asc_scene_node_allocate_data(sprite, sizeof(Spaceship)); |
|
173 ship->speed = 2.f; // start with 2 tiles/sec |
165 asc_behavior_add(sprite, move_spaceship); |
174 asc_behavior_add(sprite, move_spaceship); |
166 return sprite->user_data; |
175 return sprite->user_data; |
|
176 } |
|
177 |
|
178 static void create_gamefield() { |
|
179 // TODO: create a proper data structure and a more interesting map than just a basic grid |
|
180 AscSceneNode *gamefield = asc_scene_node_empty(); |
|
181 for (unsigned x = 0; x < game_field_size; x+=game_field_tile_size) { |
|
182 for (unsigned y = 0; y < game_field_size; y+=game_field_tile_size) { |
|
183 asc_ink_rgb(0, 128, 255); |
|
184 AscSceneNode *tile = asc_rectangle( |
|
185 .x = x, .y = y, .filled = true, .thickness = 1, |
|
186 .width = game_field_tile_size, .height = game_field_tile_size, |
|
187 .border_color = ASC_RGB(64, 196, 255), |
|
188 ); |
|
189 asc_scene_node_link(gamefield, tile); |
|
190 } |
|
191 } |
|
192 asc_scene_node_set_zindex(gamefield, -2); |
|
193 asc_scene_add_node(MAIN_SCENE, gamefield); |
167 } |
194 } |
168 |
195 |
169 static asc_rect update_viewport_for_window_resize(asc_vec2u window_size) { |
196 static asc_rect update_viewport_for_window_resize(asc_vec2u window_size) { |
170 // Compute scaling and offsets |
197 // Compute scaling and offsets |
171 unsigned viewport_size, offset_x = 0, offset_y = 0; |
198 unsigned viewport_size, offset_x = 0, offset_y = 0; |
201 |
228 |
202 // create window |
229 // create window |
203 AscWindowSettings settings; |
230 AscWindowSettings settings; |
204 asc_window_settings_init_defaults(&settings); |
231 asc_window_settings_init_defaults(&settings); |
205 settings.title = "Snake"; |
232 settings.title = "Snake"; |
|
233 settings.dimensions = ASC_VEC2U(800, 800); |
206 asc_window_initialize(0, &settings); |
234 asc_window_initialize(0, &settings); |
207 asc_ui_scale_auto(); |
235 asc_ui_scale_auto(); |
208 |
236 |
209 // load textures |
237 // load textures |
210 init_textures(); |
238 init_textures(); |
211 |
239 |
212 // initialize the scenes |
240 // initialize the scenes |
213 const int game_field_size = 512; |
|
214 asc_scene_init(BACKDROP_SCENE, |
241 asc_scene_init(BACKDROP_SCENE, |
215 .type = ASC_CAMERA_ORTHO, |
242 .type = ASC_CAMERA_ORTHO, |
216 .projection_update_func = asc_camera_ortho_update_size |
243 .projection_update_func = asc_camera_ortho_update_size |
217 ); |
244 ); |
218 asc_ink_rgb(0, 128, 90); |
245 asc_ink_rgb(0, 128, 90); |
219 asc_scene_init(MAIN_SCENE, |
246 asc_scene_init(MAIN_SCENE, |
220 .type = ASC_CAMERA_ORTHO, |
247 .type = ASC_CAMERA_ORTHO, |
221 .ortho.rect = ASC_RECT(0, 0, game_field_size, game_field_size), |
248 .ortho.rect = ASC_RECT( |
|
249 -game_field_tile_size/2, |
|
250 -game_field_tile_size/2, |
|
251 game_field_size+game_field_tile_size, |
|
252 game_field_size+game_field_tile_size |
|
253 ), |
222 .viewport_clear = true, |
254 .viewport_clear = true, |
223 .viewport_update_func = update_viewport_for_window_resize |
255 .viewport_update_func = update_viewport_for_window_resize |
224 ); |
256 ); |
225 |
257 |
226 // backdrop for letterbox/pillarbox |
258 // backdrop for letterbox/pillarbox |
227 create_backdrop(); |
259 create_backdrop(); |
|
260 |
|
261 // the game field |
|
262 create_gamefield(); |
228 |
263 |
229 // create UI elements |
264 // create UI elements |
230 create_fps_counter(); |
265 create_fps_counter(); |
231 create_score_counter(); |
266 create_score_counter(); |
232 |
267 |