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