demo/snake/snake.c

changeset 297
02ce7c6251a9
parent 296
f4f7886f10f0
equal deleted inserted replaced
296:f4f7886f10f0 297:02ce7c6251a9
88 #define GAME_FIELD_TILE_SIZE 32 88 #define GAME_FIELD_TILE_SIZE 32
89 89
90 /** The bit in the tile data indicating if the tile exists. */ 90 /** The bit in the tile data indicating if the tile exists. */
91 #define GAME_FIELD_TILE_EXISTS_FLAG 0x80 91 #define GAME_FIELD_TILE_EXISTS_FLAG 0x80
92 /** The bits in the tile data that identify the owner. */ 92 /** The bits in the tile data that identify the owner. */
93 #define GAME_FIELD_TILE_OWNER_MASK 0xF 93 #define GAME_FIELD_TILE_OWNER_MASK 0x0F
94 94
95 typedef struct { 95 typedef struct {
96 AscSceneNode *nodes[GAME_FIELD_SIZE][GAME_FIELD_SIZE]; 96 AscSceneNode *nodes[GAME_FIELD_SIZE][GAME_FIELD_SIZE];
97 int8_t tile_data[GAME_FIELD_SIZE][GAME_FIELD_SIZE]; 97 uint8_t tile_data[GAME_FIELD_SIZE][GAME_FIELD_SIZE];
98 } GameField; 98 } GameField;
99 99
100 100
101 #define GAME_STATE_MENU 0 101 #define GAME_STATE_MENU 0
102 #define GAME_STATE_PLAYING 1 102 #define GAME_STATE_PLAYING 1
228 asc_ui_add_node(node); 228 asc_ui_add_node(node);
229 229
230 return node; 230 return node;
231 } 231 }
232 232
233 static bool game_field_tile_chown(asc_vec2u coords, Player *player) { 233 static bool game_field_tile_occupied(asc_vec2u coords) {
234 unsigned x = coords.x, y = coords.y;
235 return game.field->tile_data[x][y] & GAME_FIELD_TILE_OWNER_MASK;
236 }
237
238 static void game_field_tile_chown(asc_vec2u coords, Player *player) {
234 unsigned x = coords.x, y = coords.y; 239 unsigned x = coords.x, y = coords.y;
235 asc_ptr_cast(AscRectangle, tile, game.field->nodes[x][y]); 240 asc_ptr_cast(AscRectangle, tile, game.field->nodes[x][y]);
236 int old_owner = game.field->tile_data[x][y] & GAME_FIELD_TILE_OWNER_MASK;
237 if (player == NULL) { 241 if (player == NULL) {
238 asc_clear_flag(game.field->tile_data[x][y], GAME_FIELD_TILE_OWNER_MASK); 242 asc_clear_flag(game.field->tile_data[x][y], GAME_FIELD_TILE_OWNER_MASK);
239 tile->color = ASC_RGBi(16, 50, 160); 243 tile->color = ASC_RGBi(16, 50, 160);
240 } else { 244 } else {
241 asc_set_flag_masked(game.field->tile_data[x][y], GAME_FIELD_TILE_OWNER_MASK, player->number); 245 asc_set_flag_masked(game.field->tile_data[x][y], GAME_FIELD_TILE_OWNER_MASK, player->number);
242 tile->color = player->color; 246 tile->color = player->color;
243 } 247 }
244 int new_owner = game.field->tile_data[x][y] & GAME_FIELD_TILE_OWNER_MASK;
245 return old_owner != new_owner;
246 } 248 }
247 249
248 static void game_field_create() { 250 static void game_field_create() {
249 // TODO: create a more interesting map than just a basic grid 251 // TODO: create a more interesting map than just a basic grid
250 AscSceneNode *node = asc_scene_node_empty(); 252 AscSceneNode *node = asc_scene_node_empty();
351 static void player_move(AscBehavior *behavior) { 353 static void player_move(AscBehavior *behavior) {
352 AscSceneNode *node = behavior->node; 354 AscSceneNode *node = behavior->node;
353 Player *player = node->user_data; 355 Player *player = node->user_data;
354 356
355 const float ts = (float) GAME_FIELD_TILE_SIZE; 357 const float ts = (float) GAME_FIELD_TILE_SIZE;
358
359 // determine the current tile's coordinates
360 const asc_vec2u old_tile = game_field_tile_at_position(node->position);
356 361
357 // check if the position is set programmatically 362 // check if the position is set programmatically
358 if (player->reset_position) { 363 if (player->reset_position) {
359 asc_scene_node_set_position2f(node, 364 asc_scene_node_set_position2f(node,
360 ASC_VEC2F( 365 ASC_VEC2F(
411 } 416 }
412 } 417 }
413 418
414 // die when leaving the game field 419 // die when leaving the game field
415 if (node->position.x < 0 || node->position.y < 0 || 420 if (node->position.x < 0 || node->position.y < 0 ||
416 node->position.x > GAME_FIELD_SIZE*GAME_FIELD_TILE_SIZE || 421 node->position.x > GAME_FIELD_SIZE*ts ||
417 node->position.y > GAME_FIELD_SIZE*GAME_FIELD_TILE_SIZE) { 422 node->position.y > GAME_FIELD_SIZE*ts) {
418 // TODO: replace setting health to zero with a "kill" event 423 // TODO: replace setting health to zero with a "kill" event
419 player->health = 0; 424 player->health = 0;
420 return; 425 return;
421 } 426 }
422 427
423 // TODO: collision detection 428 // TODO: collision with other players
424 429
425 // update the trace, if necessary. 430 // determine the new tile's coordinates
426 // remark: some calculations are repeated here, but they are cheap enough 431 const asc_vec2u new_tile = game_field_tile_at_position(node->position);
427 { 432
428 const asc_vec2u tile_coords = game_field_tile_at_position(node->position); 433 // tile did not change - stop here
429 if (tile_coords.x > GAME_FIELD_SIZE || tile_coords.y > GAME_FIELD_SIZE) return; 434 if (asc_vec2u_eq(old_tile, new_tile)) return;
430 if (game_field_tile_chown(tile_coords, player)) { 435
431 // new owner of the tile! 436 // die when colliding with a player's trace
432 asc_vec2u p = tile_coords; 437 if (game_field_tile_occupied(new_tile)) {
433 cxListAdd(player->trace, &p); 438 // TODO: replace setting health to zero with a "kill" event
434 if (cxListSize(player->trace) > 7) { 439 player->health = 0;
435 // TODO: implement power-up which makes the trace longer 440 return;
436 cxListRemove(player->trace, 0); 441 }
437 } 442
438 } 443 // update own trace
444 game_field_tile_chown(old_tile, player);
445 cxListAdd(player->trace, &old_tile);
446 if (cxListSize(player->trace) > 7) {
447 // TODO: implement power-up which makes the trace longer
448 cxListRemove(player->trace, 0);
439 } 449 }
440 } 450 }
441 451
442 static void player_controls(AscBehavior *behavior) { 452 static void player_controls(AscBehavior *behavior) {
443 Player *player = behavior->node->user_data; 453 Player *player = behavior->node->user_data;

mercurial