| 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; |