From 5299fa66afc9cf6c9ee01a7de821bbbb43683be8 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Fri, 5 Dec 2025 13:14:33 -0600 Subject: [PATCH] multiple balls --- include/state.h | 15 ++++++--- include/update.hpp | 1 + src/main.c | 20 +++++++++++- src/render.cpp | 9 ++++-- src/update.cpp | 78 +++++++++++++++++++++++++++++----------------- 5 files changed, 86 insertions(+), 37 deletions(-) diff --git a/include/state.h b/include/state.h index 720c367..4d51e21 100644 --- a/include/state.h +++ b/include/state.h @@ -10,6 +10,15 @@ extern "C" { double destroyed_time; }; + struct ball_state { + float ball_x; + float ball_y; + float ball_dx; + float ball_dy; + }; + + #define MAX_BALLS 20 + struct game_state { struct block_state blocks[28 * 13]; const uint8_t * level; @@ -18,10 +27,8 @@ extern "C" { float paddle_x; float paddle_y; - float ball_x; - float ball_y; - float ball_dx; - float ball_dy; + struct ball_state balls[MAX_BALLS]; + int balls_launched; double start_time; double time; diff --git a/include/update.hpp b/include/update.hpp index 547e465..757802e 100644 --- a/include/update.hpp +++ b/include/update.hpp @@ -6,6 +6,7 @@ extern "C" { #endif + void launch_ball(struct game_state * state); void reset_level(struct game_state * state); void update(struct game_state * state, double time); diff --git a/src/main.c b/src/main.c index a83e6f0..b863263 100644 --- a/src/main.c +++ b/src/main.c @@ -163,7 +163,7 @@ int main() double frames = 1; const char * last_gamepad_name = NULL; - struct game_state state; + struct game_state state = {0}; reset_level(&state); state.start_time = glfwGetTime(); @@ -179,14 +179,27 @@ int main() float paddle_dx = 0.0; //float paddle_dy = 0.0; + static bool last_x_press = false; + bool x_press = false; for (int i = 0; i < 16; i++) { int present = glfwJoystickPresent(GLFW_JOYSTICK_1 + i); int is_gamepad = glfwJoystickIsGamepad(GLFW_JOYSTICK_1 + i); int count; const float * axes = glfwGetJoystickAxes(GLFW_JOYSTICK_1 + i, &count); + //printf("present, %d %d %s %d\n", i, count, name, is_gamepad); if (present && is_gamepad && count == 6) { + const unsigned char * buttons = glfwGetJoystickButtons(GLFW_JOYSTICK_1 + i, &count); + /* + printf("buttons count %d\n", count); + for (int i = 0; i < count; i++) { + printf("[% 2d % 2d] ", i, buttons[i]); + } + printf("\n"); + */ + x_press = buttons[0] != 0; + const char * name = glfwGetJoystickName(GLFW_JOYSTICK_1 + i); if (name != last_gamepad_name) { printf("active gamepad: `%s`; axes: %d\n", name, count); @@ -204,6 +217,11 @@ int main() } } + if (!last_x_press && x_press) { + launch_ball(&state); + } + last_x_press = x_press; + float extent = 0.25; state.paddle_x += paddle_dx; if (state.paddle_x < extent) diff --git a/src/render.cpp b/src/render.cpp index ed72215..092564a 100644 --- a/src/render.cpp +++ b/src/render.cpp @@ -222,12 +222,15 @@ void render(mesh paddle_mesh, } ////////////////////////////////////////////////////////////////////// - // render ball + // render balls ////////////////////////////////////////////////////////////////////// - { + for (int i = 0; i < state->balls_launched; i++) { + struct ball_state& ball = state->balls[i]; + mat4x4 rx = rotate_y(PI / 2.0f); - mat4x4 t = translate(vec3(state->ball_x * 4.0f, -state->ball_y * 2.0f, 0.0)); + vec3 ball_position = vec3(ball.ball_x * 4.0f, -ball.ball_y * 2.0f, 0.0); + mat4x4 t = translate(ball_position); mat4x4 trans = a * t * rx; mat3x3 normal_trans = submatrix(rx, 3, 3); diff --git a/src/update.cpp b/src/update.cpp index dcd067a..af6f761 100644 --- a/src/update.cpp +++ b/src/update.cpp @@ -12,16 +12,26 @@ #include "math/float_types.hpp" #include "math/transform.hpp" +void launch_ball(struct game_state * state) +{ + if (state->balls_launched >= MAX_BALLS) + return; + + struct ball_state& ball = state->balls[state->balls_launched]; + ball.ball_x = state->paddle_x; + ball.ball_y = 25.0; + ball.ball_dx = 0.1; + ball.ball_dy = -0.1; + + state->balls_launched += 1; +} + void reset_level(struct game_state * state) { state->paddle_x = 0.0; state->paddle_y = 26.0; - state->ball_x = 0.0; - state->ball_y = 25.0; - - state->ball_dx = 0.1; - state->ball_dy = 0.1; + launch_ball(state); state->start_time = 0.0; @@ -36,19 +46,19 @@ void reset_level(struct game_state * state) } } -static inline void ball_collision_response(struct game_state * state, +static inline void ball_collision_response(struct ball_state& ball, struct collision_data& cd) { - state->ball_x = cd.escape_position.x / 4.0f; - state->ball_y = -cd.escape_position.y / 2.0f; - vec3 vel = reflect(vec3(state->ball_dx, state->ball_dy, 0), cd.bounds_normal); - state->ball_dx = vel.x; - state->ball_dy = vel.y; + ball.ball_x = cd.escape_position.x / 4.0f; + ball.ball_y = -cd.escape_position.y / 2.0f; + vec3 vel = reflect(vec3(ball.ball_dx, ball.ball_dy, 0), cd.bounds_normal); + ball.ball_dx = vel.x; + ball.ball_dy = vel.y; } -void update(struct game_state * state, double time) +void update_ball(struct game_state * state, struct ball_state& ball, double time) { - vec3 ball_position = vec3(state->ball_x * 4.0f, -state->ball_y * 2.0f, 0.0); + vec3 ball_position = vec3(ball.ball_x * 4.0f, -ball.ball_y * 2.0f, 0.0); ////////////////////////////////////////////////////////////////////// // block collision @@ -70,7 +80,7 @@ void update(struct game_state * state, double time) struct collision_data cd; bool collided = aabb_circle_collision(block_position, ball_position, block_bounds, &cd); if (collided) { - ball_collision_response(state, cd); + ball_collision_response(ball, cd); state->blocks[block_ix].destroyed_time = time; } } @@ -86,31 +96,41 @@ void update(struct game_state * state, double time) struct collision_data cd; bool collided = aabb_circle_collision(paddle_position, ball_position, paddle_bounds, &cd); if (collided) { - ball_collision_response(state, cd); + ball_collision_response(ball, cd); } } ////////////////////////////////////////////////////////////////////// // arena collision ////////////////////////////////////////////////////////////////////// - if ((state->ball_x + state->ball_dx * 0.4) > 12.25f) { - state->ball_x = 12.25f; - state->ball_dx = -state->ball_dx; - } else if ((state->ball_x + state->ball_dx * 0.4) < -0.25f) { - state->ball_x = -0.25f; - state->ball_dx = -state->ball_dx; + if ((ball.ball_x + ball.ball_dx * 0.4) > 12.25f) { + ball.ball_x = 12.25f; + ball.ball_dx = -ball.ball_dx; + } else if ((ball.ball_x + ball.ball_dx * 0.4) < -0.25f) { + ball.ball_x = -0.25f; + ball.ball_dx = -ball.ball_dx; } - if ((state->ball_y + state->ball_dy * 0.4) > 27.0f) { - //state->ball_y = 27.0f; - //state->ball_dy = -state->ball_dy; - } else if ((state->ball_y + state->ball_dy * 0.4) < 0.0f) { - state->ball_y = 0.0f; - state->ball_dy = -state->ball_dy; + if ((ball.ball_y + ball.ball_dy * 0.4) > 27.0f) { + //ball.ball_y = 27.0f; + //ball.ball_dy = -ball.ball_dy; + } else if ((ball.ball_y + ball.ball_dy * 0.4) < 0.0f) { + ball.ball_y = 0.0f; + ball.ball_dy = -ball.ball_dy; } - state->ball_x += state->ball_dx; - state->ball_y += state->ball_dy; + ball.ball_x += ball.ball_dx; + ball.ball_y += ball.ball_dy; +} + +void update(struct game_state * state, double time) +{ + for (int i = 0; i < state->balls_launched; i++) { + if (state->balls[i].ball_y > 30.0f) + continue; + + update_ball(state, state->balls[i], time); + } state->time = time; state->remaining = 20.0 - (time - state->start_time);