test/snake/snake.c

changeset 217
4b3c974eab44
parent 216
943980fa37b5
equal deleted inserted replaced
216:943980fa37b5 217:4b3c974eab44
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 );
304 asc_clear_error(); 312 asc_clear_error();
305 asc_context_quit(); 313 asc_context_quit();
306 } 314 }
307 315
308 // player rotation 316 // player rotation
317 // TODO: queue up to two movement commands (for sharp 90° turns)
309 if (asc_key_pressed(ASC_KEY(LEFT))) { 318 if (asc_key_pressed(ASC_KEY(LEFT))) {
310 if (spaceship->direction != MOVE_RIGHT) { 319 if (spaceship->direction != MOVE_RIGHT) {
311 spaceship->target_direction = MOVE_LEFT; 320 spaceship->target_direction = MOVE_LEFT;
312 } 321 }
313 } 322 }

mercurial