Sun, 25 Jan 2026 19:45:24 +0100
implement that your own trace kills you
| demo/snake/snake.c | file | annotate | diff | comparison | revisions | |
| src/ascension/datatypes.h | file | annotate | diff | comparison | revisions |
--- a/demo/snake/snake.c Sun Jan 25 15:37:23 2026 +0100 +++ b/demo/snake/snake.c Sun Jan 25 19:45:24 2026 +0100 @@ -90,11 +90,11 @@ /** The bit in the tile data indicating if the tile exists. */ #define GAME_FIELD_TILE_EXISTS_FLAG 0x80 /** The bits in the tile data that identify the owner. */ -#define GAME_FIELD_TILE_OWNER_MASK 0xF +#define GAME_FIELD_TILE_OWNER_MASK 0x0F typedef struct { AscSceneNode *nodes[GAME_FIELD_SIZE][GAME_FIELD_SIZE]; - int8_t tile_data[GAME_FIELD_SIZE][GAME_FIELD_SIZE]; + uint8_t tile_data[GAME_FIELD_SIZE][GAME_FIELD_SIZE]; } GameField; @@ -230,10 +230,14 @@ return node; } -static bool game_field_tile_chown(asc_vec2u coords, Player *player) { +static bool game_field_tile_occupied(asc_vec2u coords) { + unsigned x = coords.x, y = coords.y; + return game.field->tile_data[x][y] & GAME_FIELD_TILE_OWNER_MASK; +} + +static void game_field_tile_chown(asc_vec2u coords, Player *player) { unsigned x = coords.x, y = coords.y; asc_ptr_cast(AscRectangle, tile, game.field->nodes[x][y]); - int old_owner = game.field->tile_data[x][y] & GAME_FIELD_TILE_OWNER_MASK; if (player == NULL) { asc_clear_flag(game.field->tile_data[x][y], GAME_FIELD_TILE_OWNER_MASK); tile->color = ASC_RGBi(16, 50, 160); @@ -241,8 +245,6 @@ asc_set_flag_masked(game.field->tile_data[x][y], GAME_FIELD_TILE_OWNER_MASK, player->number); tile->color = player->color; } - int new_owner = game.field->tile_data[x][y] & GAME_FIELD_TILE_OWNER_MASK; - return old_owner != new_owner; } static void game_field_create() { @@ -354,6 +356,9 @@ const float ts = (float) GAME_FIELD_TILE_SIZE; + // determine the current tile's coordinates + const asc_vec2u old_tile = game_field_tile_at_position(node->position); + // check if the position is set programmatically if (player->reset_position) { asc_scene_node_set_position2f(node, @@ -413,29 +418,34 @@ // die when leaving the game field if (node->position.x < 0 || node->position.y < 0 || - node->position.x > GAME_FIELD_SIZE*GAME_FIELD_TILE_SIZE || - node->position.y > GAME_FIELD_SIZE*GAME_FIELD_TILE_SIZE) { + node->position.x > GAME_FIELD_SIZE*ts || + node->position.y > GAME_FIELD_SIZE*ts) { // TODO: replace setting health to zero with a "kill" event player->health = 0; return; } - // TODO: collision detection + // TODO: collision with other players + + // determine the new tile's coordinates + const asc_vec2u new_tile = game_field_tile_at_position(node->position); + + // tile did not change - stop here + if (asc_vec2u_eq(old_tile, new_tile)) return; - // update the trace, if necessary. - // remark: some calculations are repeated here, but they are cheap enough - { - const asc_vec2u tile_coords = game_field_tile_at_position(node->position); - if (tile_coords.x > GAME_FIELD_SIZE || tile_coords.y > GAME_FIELD_SIZE) return; - if (game_field_tile_chown(tile_coords, player)) { - // new owner of the tile! - asc_vec2u p = tile_coords; - cxListAdd(player->trace, &p); - if (cxListSize(player->trace) > 7) { - // TODO: implement power-up which makes the trace longer - cxListRemove(player->trace, 0); - } - } + // die when colliding with a player's trace + if (game_field_tile_occupied(new_tile)) { + // TODO: replace setting health to zero with a "kill" event + player->health = 0; + return; + } + + // update own trace + game_field_tile_chown(old_tile, player); + cxListAdd(player->trace, &old_tile); + if (cxListSize(player->trace) > 7) { + // TODO: implement power-up which makes the trace longer + cxListRemove(player->trace, 0); } }
--- a/src/ascension/datatypes.h Sun Jan 25 15:37:23 2026 +0100 +++ b/src/ascension/datatypes.h Sun Jan 25 19:45:24 2026 +0100 @@ -357,11 +357,13 @@ } /** + * Rounds a floating point to exactly zero when it is near zero. * * @param x the floating point * @return if @p x is near zero, returns zero, returns @p x otherwise */ static inline float asc_fround_zero(float x) { + // TODO: check if it makes sense to compare against FLT_EPSILON if (fabsf(x) < FLT_EPSILON) { return 0.f; } else { @@ -377,6 +379,10 @@ return asc_fround_zero(x) < 0 ? -1 : 1; } +static inline bool asc_eqf(float x, float y) { + return asc_fround_zero(x - y) == 0.f; +} + /** * Returns the cosine of x. * @@ -506,6 +512,22 @@ return ASC_VEC3F(a.x+b.x, a.y+b.y, a.z+b.z); } +static inline bool asc_vec2u_eq(asc_vec2u a, asc_vec2u b) { + return a.x == b.x && a.y == b.y; +} + +static inline bool asc_vec2i_eq(asc_vec2i a, asc_vec2i b) { + return a.x == b.x && a.y == b.y; +} + +static inline bool asc_vec2f_eq(asc_vec2f a, asc_vec2f b) { + return asc_eqf(a.x, b.x) && asc_eqf(a.y, b.y); +} + +static inline bool asc_vec3f_eq(asc_vec3f a, asc_vec3f b) { + return asc_eqf(a.x, b.x) && asc_eqf(a.y, b.y) && asc_eqf(a.z, b.z); +} + // -------------------------------------------------------------------------- // Matrix Functions // --------------------------------------------------------------------------