implement that your own trace kills you default tip

Sun, 25 Jan 2026 19:45:24 +0100

author
Mike Becker <universe@uap-core.de>
date
Sun, 25 Jan 2026 19:45:24 +0100
changeset 297
02ce7c6251a9
parent 296
f4f7886f10f0

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

mercurial