50 MOVE_DOWN, |
50 MOVE_DOWN, |
51 MOVE_RIGHT |
51 MOVE_RIGHT |
52 }; |
52 }; |
53 |
53 |
54 static asc_transform rotations[4]; |
54 static asc_transform rotations[4]; |
55 static asc_vec2f directions[4]; |
55 static asc_vec2i directions[4]; |
56 |
56 |
57 typedef struct { |
57 typedef struct { |
58 enum MoveDirection direction; |
58 enum MoveDirection direction; |
59 enum MoveDirection target_direction; |
59 enum MoveDirection target_direction; |
60 /** |
60 /** |
61 * The speed in tiles per second. |
61 * The speed in tiles per second. |
62 */ |
62 */ |
63 float speed; |
63 float speed; |
64 } Spaceship; |
64 } Spaceship; |
65 |
65 |
66 static const unsigned game_field_size = 512; |
66 static const unsigned game_field_size = 16; |
67 static const unsigned game_field_tile_size = 32; |
67 static const unsigned game_field_tile_size = 32; |
68 |
68 |
69 static void init_globals(void) { |
69 static void init_globals(void) { |
70 asc_transform_identity(rotations[MOVE_UP]); |
70 asc_transform_identity(rotations[MOVE_UP]); |
71 asc_transform_roll(rotations[MOVE_LEFT], asc_rad(-90)); |
71 asc_transform_roll(rotations[MOVE_LEFT], asc_rad(-90)); |
72 asc_transform_roll(rotations[MOVE_RIGHT], asc_rad(90)); |
72 asc_transform_roll(rotations[MOVE_RIGHT], asc_rad(90)); |
73 asc_transform_roll(rotations[MOVE_DOWN], asc_rad(180)); |
73 asc_transform_roll(rotations[MOVE_DOWN], asc_rad(180)); |
74 directions[MOVE_UP] = ASC_VEC2F(0, -1); |
74 directions[MOVE_UP] = ASC_VEC2I(0, -1); |
75 directions[MOVE_LEFT] = ASC_VEC2F(-1, 0); |
75 directions[MOVE_LEFT] = ASC_VEC2I(-1, 0); |
76 directions[MOVE_DOWN] = ASC_VEC2F(0, 1); |
76 directions[MOVE_DOWN] = ASC_VEC2I(0, 1); |
77 directions[MOVE_RIGHT] = ASC_VEC2F(1, 0); |
77 directions[MOVE_RIGHT] = ASC_VEC2I(1, 0); |
78 } |
78 } |
79 |
79 |
80 static void destroy_textures(void) { |
80 static void destroy_textures(void) { |
81 asc_texture_destroy(tex2d, TEX2D_COUNT); |
81 asc_texture_destroy(tex2d, TEX2D_COUNT); |
82 } |
82 } |
151 } |
151 } |
152 |
152 |
153 static void move_spaceship(AscBehavior *behavior) { |
153 static void move_spaceship(AscBehavior *behavior) { |
154 AscSceneNode *node = behavior->node; |
154 AscSceneNode *node = behavior->node; |
155 Spaceship *spaceship = node->user_data; |
155 Spaceship *spaceship = node->user_data; |
156 const float ts = (float) game_field_tile_size; |
156 const int ts = (int) game_field_tile_size; |
157 const float speed = ts * spaceship->speed * asc_context.frame_factor; |
157 const float fts = (float) ts; |
158 const asc_vec2f dvec = directions[spaceship->direction]; |
158 const float speed = fts * spaceship->speed * asc_context.frame_factor; |
159 const asc_vec2f movement = asc_vec2f_scale(dvec, speed); |
159 const asc_vec2i dir = directions[spaceship->direction]; |
|
160 const asc_vec2f movement = asc_vec2f_scale(asc_vec2_itof(dir), speed); |
|
161 // check if we are supposed to change the direction |
160 if (spaceship->direction == spaceship->target_direction) { |
162 if (spaceship->direction == spaceship->target_direction) { |
161 // no change of direction - keep moving |
163 // move without changing the direction |
162 asc_scene_node_move2f(node, movement); |
164 asc_scene_node_move2f(node, movement); |
163 } else { |
165 } else { |
164 // identify the tile we are currently in |
166 // determine axis |
165 int x = (int) (node->position.x / ts); |
167 // and check if we are about to cross the center |
166 int y = (int) (node->position.y / ts); |
168 // this relies on positive positions! |
167 const asc_vec2f tcenter = ASC_VEC2F(x*ts, y*ts); |
169 bool rotate = false; |
168 // calculate the (squared) distance to the tile's center |
170 if (movement.x == 0) { |
169 float cdist = asc_vec2f_sqrlen(asc_vec2f_sub(tcenter, ASC_VEC2F(node->position.x, node->position.y))); |
171 // vertical movement |
170 // if it is less than squared length of the movement vector, snap to the center and rotate |
172 const int y0 = (int)node->position.y / ts; |
171 // TODO: think about if we should allow changing direction only when we haven't passed the center yet |
173 const int y1 = (int)(node->position.y+movement.y) / ts; |
172 if (cdist < asc_vec2f_sqrlen(dvec)) { |
174 rotate = y0 != y1 && asc_sgn(y1-y0) == dir.y; |
173 asc_scene_node_set_position2f(node, tcenter); |
175 } else { |
|
176 // horizontal movement |
|
177 const int x0 = (int)node->position.x / ts; |
|
178 const int x1 = (int)(node->position.x+movement.x) / ts; |
|
179 rotate = x0 != x1 && asc_sgn(x1-x0) == dir.x; |
|
180 } |
|
181 if (rotate) { |
|
182 // snap position to the center of the tile |
|
183 node->position.x = roundf(node->position.x / fts) * fts; |
|
184 node->position.y = roundf(node->position.y / fts) * fts; |
174 spaceship->direction = spaceship->target_direction; |
185 spaceship->direction = spaceship->target_direction; |
175 asc_scene_node_set_rotation(node, rotations[spaceship->direction]); |
186 asc_scene_node_set_rotation(node, rotations[spaceship->direction]); |
176 // TODO: this is losing some speed - improve the calculation and add partial movement after rotation |
|
177 } else { |
187 } else { |
178 // too far away from center, continue normal movement |
188 // changing the direction not permitted, yet, continue movement |
179 asc_scene_node_move2f(node, movement); |
189 asc_scene_node_move2f(node, movement); |
180 } |
190 } |
181 } |
191 } |
182 } |
192 } |
183 |
193 |
201 } |
211 } |
202 |
212 |
203 static void create_gamefield() { |
213 static void create_gamefield() { |
204 // TODO: create a proper data structure and a more interesting map than just a basic grid |
214 // TODO: create a proper data structure and a more interesting map than just a basic grid |
205 AscSceneNode *gamefield = asc_scene_node_empty(); |
215 AscSceneNode *gamefield = asc_scene_node_empty(); |
206 for (unsigned x = 0; x < game_field_size; x+=game_field_tile_size) { |
216 for (unsigned x = 1; x <= game_field_size; x++) { |
207 for (unsigned y = 0; y < game_field_size; y+=game_field_tile_size) { |
217 for (unsigned y = 1; y <= game_field_size; y++) { |
208 AscSceneNode *tile = asc_rectangle( |
218 AscSceneNode *tile = asc_rectangle( |
209 .x = x, .y = y, .filled = true, .thickness = 1, |
219 .x = x*game_field_tile_size, .y = y*game_field_tile_size, .filled = true, .thickness = 1, |
210 .origin_x = game_field_tile_size / 2, .origin_y = game_field_tile_size / 2, |
220 .origin_x = game_field_tile_size / 2, .origin_y = game_field_tile_size / 2, |
211 .width = game_field_tile_size, .height = game_field_tile_size, |
221 .width = game_field_tile_size, .height = game_field_tile_size, |
212 .color = ASC_RGB(0, 128, 255), |
222 .color = ASC_RGB(0, 128, 255), |
213 .border_color = ASC_RGB(64, 196, 255), |
223 .border_color = ASC_RGB(64, 196, 255), |
214 ); |
224 ); |
268 .type = ASC_CAMERA_ORTHO, |
278 .type = ASC_CAMERA_ORTHO, |
269 .projection_update_func = asc_camera_ortho_update_size |
279 .projection_update_func = asc_camera_ortho_update_size |
270 ); |
280 ); |
271 asc_scene_init(MAIN_SCENE, |
281 asc_scene_init(MAIN_SCENE, |
272 .type = ASC_CAMERA_ORTHO, |
282 .type = ASC_CAMERA_ORTHO, |
273 .ortho.rect = ASC_RECT( |
283 .ortho.rect = ASC_RECT(0, 0, |
274 -game_field_tile_size, |
284 (game_field_size+1)*game_field_tile_size, |
275 -game_field_tile_size, |
285 (game_field_size+1)*game_field_tile_size |
276 game_field_size+game_field_tile_size, |
|
277 game_field_size+game_field_tile_size |
|
278 ), |
286 ), |
279 .viewport_clear = true, |
287 .viewport_clear = true, |
280 .clear_color = ASC_RGB(0, 128, 90), |
288 .clear_color = ASC_RGB(0, 128, 90), |
281 .viewport_update_func = update_viewport_for_window_resize |
289 .viewport_update_func = update_viewport_for_window_resize |
282 ); |
290 ); |