Token spawns in same place every time!

I expanded on the axe game to have safe zones on either side of the screen and a token the player must collect. When the player collects the token, they must make it back to the safe zone to score a point.
I have a function that generates random coordinates for the token to spawn at, which is similar to the functions which generate the coordinates for the axes. My issue is the token spawns in the exact same spot every time!
I cannot for the life of me figure out why. The axes spawn differently and use pretty much the same code.

axe-game.cpp:

#include "raylib.h"
#include "raymath.h"    
#include "rlgl.h"
#include "./axe-game.h"
#include <stdio.h>
#include <time.h>

int main(void) {

    /* initialize random seed */
    srand (time(NULL));

    SetTargetFPS(60);
    InitWindow(screen_width, screen_height, "AXE GAME");

    bool collision_detected{false};
    bool token_collected{false};
    int score{0};

    axe_t axe_1;
    axe_1.axe_x = get_random_axe_x();
    axe_1.axe_y = get_random_axe_y();
    axe_1.axe_speed = get_random_speed();

    axe_t axe_2;
    axe_2.axe_x = get_random_axe_x();
    axe_2.axe_y = get_random_axe_y();
    axe_2.axe_speed = get_random_speed();

    axe_t axe_3;
    axe_3.axe_x = get_random_axe_x();
    axe_3.axe_y = get_random_axe_y();
    axe_3.axe_speed = get_random_speed();

    while (!WindowShouldClose()) {
        BeginDrawing();
        ClearBackground(background_colour);
        draw_safezones();

        if (collision_detected) {
            DrawText("Game Over!", screen_width/2 - 150, 200, 50, RED);
            DrawText(TextFormat("You scored %d", score), screen_width/2 - 200, 300, 50, RED);
        } else {

            // Draw Player
            DrawCircle(circle_x, circle_y, circle_radius, circle_colour);

            // Spawn Token if not spawned and not collected
            if (!token_spawned && !token_collected && IsPlayerInSafezone()) 
                spawn_token();

            // Draw Token if not collected
            if (!token_collected)
                DrawCircle(token_x, token_y, token_radius, token_colour);
            
            // Draw Axe
            draw_axe(&axe_1);
            draw_axe(&axe_2);
            draw_axe(&axe_3);

            // Draw Score
            DrawText(TextFormat("%d", score), screen_width/2, 20, 50, RED);

            // Movement
            move_player();
            move_axe(&axe_1); 
            move_axe(&axe_2); 
            move_axe(&axe_3);    

            // Collision detection
            collision_detected = collision_with_axe(&axe_1) ||
            collision_with_axe(&axe_2) ||
            collision_with_axe(&axe_3);

            // Check if token collected
            if (!token_collected)
                token_collected = is_collect_token();

            // Increase score if token collected and play in safezone
            if (token_collected && IsPlayerInSafezone()) {
                score++;
                token_collected = false;
            }

        }
            
        EndDrawing();
    }
}

int get_distance() {
    return IsKeyDown(KEY_LEFT_SHIFT) ? move_speed * run_multiplier : move_speed;
}

void move_player() {
    int distance = get_distance();

    if (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT)) 
        circle_x = limit_bounds(circle_x + distance, screen_width);

    if (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT))
        circle_x = limit_bounds(circle_x - distance, screen_width);

    if (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN))
        circle_y = limit_bounds(circle_y + distance, screen_height);

    if (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))
        circle_y = limit_bounds(circle_y - distance, screen_height);

    
    circle_edge_xl = circle_x - circle_radius;
    circle_edge_xr = circle_x + circle_radius;
    circle_edge_yt = circle_y - circle_radius;
    circle_edge_yb = circle_y + circle_radius;
}

int limit_bounds(int input, int max) {
    return Clamp(input, circle_radius, max - circle_radius);
}

void move_axe(axe_t *instance) {
    instance->axe_y += instance->axe_speed;

    if (instance->axe_y > screen_height - axe_height || instance->axe_y < 0)
        instance->axe_speed = -instance->axe_speed;

    instance->axe_edge_xl = instance->axe_x;
    instance->axe_edge_xr = instance->axe_x + axe_width;
    instance->axe_edge_yt = instance->axe_y;
    instance->axe_edge_yb = instance->axe_y + axe_height;
}

bool collision_with_axe(axe_t *instance) {
    return (
        (instance->axe_edge_xl <= circle_edge_xr) &&
        (instance->axe_edge_xr >= circle_edge_xl) &&
        (instance->axe_edge_yt <= circle_edge_yb) &&
        (instance->axe_edge_yb >= circle_edge_yt)
    );
}

void draw_safezones() {
    DrawRectangle(0, 0, boundary_width, screen_height, safezone_colour);
    DrawRectangle(boundary_right, 0, boundary_width, screen_height, safezone_colour);    
}

bool IsPlayerInSafezone() {
    return (circle_x >= screen_width - circle_radius || circle_x <= circle_radius);    
}

void draw_axe(axe_t *instance) {
    if (instance->axe_y < 0) {
        instance->axe_x = get_random_axe_x();
        instance->axe_speed = get_random_speed();
    }
    DrawRectangle(instance->axe_x, instance->axe_y, axe_width, axe_height, axe_colour);
}

int get_random_axe_x(void) {
    return boundary_width + rand() % (boundary_right - axe_width - boundary_width);
}

int get_random_axe_y(void) {
    return rand() % (screen_height - axe_height);
}

int get_random_token_x(void) {
    return boundary_width + token_radius + rand() % (boundary_right - (2*token_radius) - boundary_width);
}

int get_random_token_y(void) {
    return token_radius + rand() % (screen_height - (2*token_radius));
}

int get_random_speed(void) {
    return 10 + rand() % 10;
}

bool is_collect_token(void) {
    return (
        (token_edge_xl <= circle_edge_xr) &&
        (token_edge_xr >= circle_edge_xl) &&
        (token_edge_yt <= circle_edge_yb) &&
        (token_edge_yb >= circle_edge_yt)
    );
}

void spawn_token(void) {
    token_x = get_random_token_x();
    token_y = token_radius + (get_random_token_y() - token_radius);
    token_edge_xl = token_x - token_radius;
    token_edge_xr = token_x + token_radius;
    token_edge_yt = token_y - token_radius;
    token_edge_yb = token_y + token_radius;
    token_spawned = true;
}

axe-game.h:

    #ifndef AXE_GAME_H
    #define AXE_GAME_H
    #include "raylib.h"
    
    /***** Variables *****/

    /* Colours */
    Color background_colour{LIME};
    Color circle_colour{ORANGE};
    Color axe_colour{RED};
    Color safezone_colour{BLUE};
    Color token_colour{YELLOW};

    /* Screen */
    int screen_width{1280};
    int screen_height{720};
    int boundary_width{50};
    int boundary_right{screen_width - boundary_width};

    /* Circle */
    int circle_radius{25};
    int circle_x{circle_radius};
    int circle_y{screen_height/2};
    int circle_edge_xl{circle_x - circle_radius};
    int circle_edge_xr{circle_x + circle_radius};
    int circle_edge_yt{circle_y - circle_radius};
    int circle_edge_yb{circle_y + circle_radius};

    /* Token */
    int token_radius{25};
    int token_x;
    int token_y;
    int token_edge_xl;
    int token_edge_xr;
    int token_edge_yt;
    int token_edge_yb;
    bool token_collected{false};
    bool token_spawned{false};

    int move_speed{3};
    int run_multiplier{3};

    /* Axe */

    int axe_width{50};
    int axe_height{50};

    typedef struct axe
    {
        int axe_x;
        int axe_y;
        int axe_edge_xl;
        int axe_edge_xr;
        int axe_edge_yt;
        int axe_edge_yb;
        int axe_speed{10};
    }  axe_t;


    /***** Function Definitions *****/
    int get_distance(void);
    void move_player(void);
    void move_axe(axe_t*);
    int limit_bounds(int, int);
    bool collision_with_axe(axe_t*);
    void draw_safezones(void);
    bool IsPlayerInSafezone(void);
    void draw_axe(axe_t*);
    int get_random_axe_x(void);
    int get_random_axe_y(void);
    int get_random_token_x(void);
    int get_random_token_y(void);
    int get_random_speed(void);
    bool is_collect_token(void);
    void spawn_token(void);

    #endif

Ok, I solved it. I made a bunch of changes, including making the token a struct like the axes. It probably wasn’t necessary, but due to them being similar in a way I thought it might be easier to figure out.
Below is the new code with all the changes.

axe-game.cpp:

#include "raylib.h"
#include "raymath.h"    
#include "rlgl.h"
#include "./axe-game.h"
#include <stdio.h>
#include <time.h>

int main(void) {

    /* initialize random seed */
    srand (time(NULL));

    SetTargetFPS(60);
    InitWindow(screen_width, screen_height, "AXE GAME");

    bool collision_detected{false};
    int score{0};

    axe_t axe_1;
    axe_1.axe_x = get_random_axe_x();
    axe_1.axe_y = get_random_axe_y();
    axe_1.axe_speed = get_random_speed();

    axe_t axe_2;
    axe_2.axe_x = get_random_axe_x();
    axe_2.axe_y = get_random_axe_y();
    axe_2.axe_speed = get_random_speed();

    axe_t axe_3;
    axe_3.axe_x = get_random_axe_x();
    axe_3.axe_y = get_random_axe_y();
    axe_3.axe_speed = get_random_speed();

    token_t token_1;
    token_1.token_x = get_random_token_x();
    token_1.token_y = get_random_token_y();

    while (!WindowShouldClose()) {
        BeginDrawing();
        ClearBackground(background_colour);
        draw_safezones();

        if (collision_detected) {
            DrawText("Game Over!", screen_width/2 - 150, 200, 50, RED);
            DrawText(TextFormat("You scored %d", score), screen_width/2 - 200, 300, 50, RED);
        } else {

            // Draw Player
            DrawCircle(circle_x, circle_y, circle_radius, circle_colour);

            // Draw Token if not collected
            if (!token_1.token_collected)
                draw_token(&token_1);
            
            // Draw Axe
            draw_axe(&axe_1);
            draw_axe(&axe_2);
            draw_axe(&axe_3);

            // Draw Score
            DrawText(TextFormat("%d", score), screen_width/2, 20, 50, RED);

            // Movement
            move_player();
            move_axe(&axe_1); 
            move_axe(&axe_2); 
            move_axe(&axe_3);    

            // Collision detection
            collision_detected = collision_with_axe(&axe_1) ||
            collision_with_axe(&axe_2) ||
            collision_with_axe(&axe_3);

            // Check if token collected
            if (!token_1.token_collected) {
                token_1.token_collected = collision_with_token(&token_1);
                if (token_1.token_collected) 
                    token_1.token_spawned = false;
            }

            // Increase score if token collected and play in safezone
            if (token_1.token_collected && IsPlayerInSafezone()) {
                score++;
                token_1.token_collected = false;
            }

        }
            
        EndDrawing();
    }
}

int get_distance() {
    return IsKeyDown(KEY_LEFT_SHIFT) ? move_speed * run_multiplier : move_speed;
}

void move_player() {
    int distance = get_distance();

    if (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT)) 
        circle_x = limit_bounds(circle_x + distance, screen_width);

    if (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT))
        circle_x = limit_bounds(circle_x - distance, screen_width);

    if (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN))
        circle_y = limit_bounds(circle_y + distance, screen_height);

    if (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))
        circle_y = limit_bounds(circle_y - distance, screen_height);

    
    circle_edge_xl = circle_x - circle_radius;
    circle_edge_xr = circle_x + circle_radius;
    circle_edge_yt = circle_y - circle_radius;
    circle_edge_yb = circle_y + circle_radius;
}

int limit_bounds(int input, int max) {
    return Clamp(input, circle_radius, max - circle_radius);
}

void move_axe(axe_t *instance) {
    instance->axe_y += instance->axe_speed;

    if (instance->axe_y > screen_height - axe_height || instance->axe_y < 0)
        instance->axe_speed = -instance->axe_speed;

    instance->axe_edge_xl = instance->axe_x;
    instance->axe_edge_xr = instance->axe_x + axe_width;
    instance->axe_edge_yt = instance->axe_y;
    instance->axe_edge_yb = instance->axe_y + axe_height;
}

bool collision_with_axe(axe_t *instance) {
    return (
        (instance->axe_edge_xl <= circle_edge_xr) &&
        (instance->axe_edge_xr >= circle_edge_xl) &&
        (instance->axe_edge_yt <= circle_edge_yb) &&
        (instance->axe_edge_yb >= circle_edge_yt)
    );
}

void draw_safezones() {
    DrawRectangle(0, 0, boundary_width, screen_height, safezone_colour);
    DrawRectangle(boundary_right, 0, boundary_width, screen_height, safezone_colour);    
}

bool IsPlayerInSafezone() {
    return (circle_x >= screen_width - circle_radius || circle_x <= circle_radius);    
}

void draw_axe(axe_t *instance) {
    if (instance->axe_y < 0) {
        instance->axe_x = get_random_axe_x();
        instance->axe_speed = get_random_speed();
    }
    DrawRectangle(instance->axe_x, instance->axe_y, axe_width, axe_height, axe_colour);
}

void draw_token(token_t *instance) {
    // Spawn Token if not spawned and player in safe zone
    if (!instance->token_spawned && IsPlayerInSafezone()) {
        instance->token_x = get_random_token_x();
        instance->token_y = get_random_token_y();
        instance->token_edge_xl = instance->token_x - token_radius;
        instance->token_edge_xr = instance->token_x + token_radius;
        instance->token_edge_yt = instance->token_y - token_radius;
        instance->token_edge_yb = instance->token_y + token_radius;
        instance->token_spawned = true;
    }

    DrawCircle(instance->token_x, instance->token_y, token_radius, token_colour);
}

int get_random_axe_x(void) {
    return boundary_width + rand() % (boundary_right - axe_width - boundary_width);
}

int get_random_axe_y(void) {
    return rand() % (screen_height - axe_height);
}

int get_random_token_x(void) {
    return boundary_width + token_radius + rand() % (boundary_right - (2*token_radius) - boundary_width);
}

int get_random_token_y(void) {
    return token_radius + rand() % (screen_height - (2*token_radius));
}

int get_random_speed(void) {
    return 10 + rand() % 10;
}

bool collision_with_token(token_t *instance) {
    return (
        (instance->token_edge_xl <= circle_edge_xr) &&
        (instance->token_edge_xr >= circle_edge_xl) &&
        (instance->token_edge_yt <= circle_edge_yb) &&
        (instance->token_edge_yb >= circle_edge_yt)
    );
}

axe-game.h:

    #ifndef AXE_GAME_H
    #define AXE_GAME_H
    #include "raylib.h"
    
    /***** Variables *****/

    /* Colours */
    Color background_colour{LIME};
    Color circle_colour{ORANGE};
    Color axe_colour{RED};
    Color safezone_colour{BLUE};
    Color token_colour{YELLOW};

    /* Screen */
    int screen_width{1280};
    int screen_height{720};
    int boundary_width{50};
    int boundary_right{screen_width - boundary_width};

    /* Circle */
    int circle_radius{25};
    int circle_x{circle_radius};
    int circle_y{screen_height/2};
    int circle_edge_xl{circle_x - circle_radius};
    int circle_edge_xr{circle_x + circle_radius};
    int circle_edge_yt{circle_y - circle_radius};
    int circle_edge_yb{circle_y + circle_radius};

    /* Token */

    int token_radius{25};

    typedef struct token
    {
        int token_x;
        int token_y;
        int token_edge_xl;
        int token_edge_xr;
        int token_edge_yt;
        int token_edge_yb;
        bool token_collected{false};
        bool token_spawned{false};
    }  token_t;


    int move_speed{3};
    int run_multiplier{3};

    /* Axe */

    int axe_width{50};
    int axe_height{50};

    typedef struct axe
    {
        int axe_x;
        int axe_y;
        int axe_edge_xl;
        int axe_edge_xr;
        int axe_edge_yt;
        int axe_edge_yb;
        int axe_speed{10};
    }  axe_t;


    /***** Function Definitions *****/
    int get_distance(void);
    void move_player(void);
    void move_axe(axe_t*);
    int limit_bounds(int, int);
    bool collision_with_axe(axe_t*);
    void draw_safezones(void);
    bool IsPlayerInSafezone(void);
    void draw_axe(axe_t*);
    void draw_token(token_t*);
    int get_random_axe_x(void);
    int get_random_axe_y(void);
    int get_random_token_x(void);
    int get_random_token_y(void);
    int get_random_speed(void);
    bool collision_with_token(token_t*);
    void spawn_token(token_t*);

    #endif

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms