Banjo API 1.0.0-rc.2
Low-level C99 game development API
Loading...
Searching...
No Matches
physics_kinematics.c
Go to the documentation of this file.
1
16
17#include <banjo/app.h>
18#include <banjo/main.h>
19#include <banjo/draw.h>
20#include <banjo/event.h>
21#include <banjo/log.h>
22#include <banjo/physics_2d.h>
23#include <banjo/pixel.h>
24#include <banjo/system.h>
25#include <banjo/time.h>
26#include <banjo/vec.h>
27#include <banjo/window.h>
28
29#include <stdlib.h>
30#include <time.h>
31
32#define SCREEN_WIDTH 800
33#define SCREEN_HEIGHT 600
34
36// Framebuffer pixel mode. Used with bj_get_pixel_value so we can
37// pre-compute colours at setup before the first draw callback fires
38// (when the framebuffer would otherwise be reachable).
39#define FB_PIXEL_MODE BJ_PIXEL_MODE_XRGB8888
40
41#define BALLS_LEN 1000
42#define BALLS_RADIUS BJ_F(3.0)
43#define GRAVITY BJ_F(50.0)
44
45// Each ball tracks its initial conditions and elapsed time. Kinematics needs:
46// - initial_position (shared by all balls here)
47// - initial_velocity (unique per ball)
48// - acceleration (gravity, shared)
49// - time_alive (how long since launch)
50// From these, we can compute exact position at any time.
51struct {
52 bj_vec2 initial_velocity;
53 bj_vec2 position;
54 uint32_t color;
55 double time_alive;
59
60// Setting up a projectile: choose initial velocity based on desired direction
61// and speed. For realistic projectile arcs, use angle and magnitude.
62// Angle: -90° points straight up, 0° points right (here: -90° to 0° for fountain effect)
63// Magnitude: initial speed in pixels/second
64static void reset_ball(size_t at) {
65 const uint8_t r = (uint8_t)(128 + rand() % 128);
66 const uint8_t g = (uint8_t)(128 + rand() % 128);
67 const uint8_t b = (uint8_t)(128 + rand() % 128);
68
69 switch (rand() % 3) {
70 case 0: balls[at].color = bj_get_pixel_value(FB_PIXEL_MODE, 100, g, b); break;
71 case 1: balls[at].color = bj_get_pixel_value(FB_PIXEL_MODE, r, 100, b); break;
72 default: balls[at].color = bj_get_pixel_value(FB_PIXEL_MODE, r, g, 100); break;
73 }
74
75 // Random angle from -90° to 0° (straight up to straight right).
76 const bj_real angle_rand = (bj_real)rand() / (bj_real)RAND_MAX;
77 const bj_real angle = -BJ_PI / BJ_F(2.0) + angle_rand * (BJ_PI / BJ_F(2.0));
78
79 // Random speed between 100 and 200 pixels/second.
80 const bj_real magnitude = BJ_F(100.0) + ((bj_real)rand() / (bj_real)RAND_MAX) * BJ_F(100.0);
81
82 // Convert angle + magnitude to velocity vector (vx, vy).
83 balls[at].initial_velocity.x = bj_cos(angle) * magnitude;
84 balls[at].initial_velocity.y = bj_sin(angle) * magnitude;
85 balls[at].time_alive = 0;
86}
87
88static void initialize_balls() {
89
90 // Gravity acceleration: (0, 50) means 50 pixels/second² downward.
91 // Positive y is down in screen coordinates, so gravity pulls objects down.
92 // Adjust this value to make physics feel heavier or lighter.
93 gravity = (bj_vec2){0, GRAVITY};
94
95 // All balls start from the bottom-left corner.
97
98 for(size_t b = 0 ; b < BALLS_LEN ; ++b) {
99 reset_ball(b);
100 }
101
102}
103
104// Update physics: accumulate time and compute exact positions using kinematics.
105// dt is delta time (seconds since last frame) for frame-rate independence.
106static void update(bj_real dt) {
107 for(size_t b = 0 ; b < BALLS_LEN ; ++b) {
108 // Track total time since this ball was launched.
109 balls[b].time_alive += dt;
110
111 // bj_compute_kinematics_2d() computes position from:
112 // - initial_position: where the ball started
113 // - initial_velocity: how fast it was moving at launch
114 // - gravity: constant acceleration
115 // - time_alive: elapsed time since launch
116 // Returns exact position using: p = p₀ + v₀*t + ½*a*t²
117 // This is more accurate than integrating velocity frame-by-frame.
118 balls[b].position = bj_compute_kinematics_2d(
120 balls[b].initial_velocity,
121 gravity,
122 balls[b].time_alive
123 );
124
125 const bj_real x = balls[b].position.x;
126 const bj_real y = balls[b].position.y;
127
128 // Reset balls that leave the screen.
131 ) {
132 reset_ball(b);
133 }
134
135
136 }
137}
138
139static void draw(bj_bitmap* framebuffer) {
140 bj_clear_bitmap(framebuffer);
141
142 for(size_t b = 0 ; b < BALLS_LEN ; ++b) {
143 bj_draw_filled_circle(framebuffer,
144 balls[b].position.x, balls[b].position.y, BALLS_RADIUS,
145 balls[b].color
146 );
147 }
148}
149
150static void on_draw(
151 struct bj_window* w,
152 struct bj_render_target* target,
153 const struct bj_rect* dirty,
154 void* user_data
155) {
156 (void)w; (void)dirty; (void)user_data;
158}
159
160static void* setup(struct bj_app* app, void* init_data) {
161 (void)init_data;
162 srand((unsigned)time(NULL));
163
164 if (!bj_begin(BJ_VIDEO_SYSTEM, 0)) {
165 bj_quit_app(app, 1);
166 return 0;
167 }
168
169 window = bj_bind_window("2D Kinematics", 100, 100, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0);
170
173
175 return 0;
176}
177
178// Physics runs at the fixed-step rate (60 Hz by default) regardless of
179// how often step gets to fire. tick.delta is constant (1 / rate), which
180// keeps projectile motion identical across machines.
181static void fixed_step(struct bj_app* app, struct bj_tick_info tick, void* user_data) {
182 (void)app; (void)user_data;
183 update(tick.delta);
184}
185
186static void step(struct bj_app* app, struct bj_tick_info tick, void* user_data) {
187 (void)tick; (void)user_data;
190
192 bj_quit_app(app, 0);
193 }
194}
195
196static void teardown(struct bj_app* app, void* user_data) {
197 (void)user_data;
199 bj_end();
200}
201
202int main(int argc, char* argv[]) {
203 (void)argc; (void)argv;
205}
Application lifecycle: callback-driven setup, step, and teardown.
int main(int argc, char *argv[])
Definition audio_pcm.c:177
static void step(struct bj_app *app, struct bj_tick_info tick, void *user_data)
Definition audio_pcm.c:144
static void teardown(struct bj_app *app, void *user_data)
Definition audio_pcm.c:170
static void * setup(struct bj_app *app, void *init_data)
Definition audio_pcm.c:107
static void on_draw(struct bj_window *w, struct bj_render_target *target, const struct bj_rect *dirty, void *user_data)
Definition bitmap_blit.c:32
bj_window * window
Definition bitmap_blit.c:24
Header file for Bitmap drawing functions.
void draw(bj_bitmap *bmp)
Definition drawing_2d.c:133
Sytem event management API.
bj_real delta
Definition app.h:107
int bj_run_app(bj_app_setup_fn setup, bj_app_step_fn step, bj_app_fixed_step_fn fixed_step, bj_app_teardown_fn teardown, void *init_data)
Drive the application lifecycle.
void bj_quit_app(struct bj_app *app, int exit_code)
Signal the given application to exit on the next iteration.
Timing snapshot handed to the step and fixed-step callbacks.
Definition app.h:106
void bj_clear_bitmap(struct bj_bitmap *bitmap)
Fills the entire bitmap with the clear colour.
struct bj_render_target bj_render_target
Definition api.h:346
struct bj_bitmap bj_bitmap
Definition api.h:328
struct bj_window bj_window
Definition api.h:354
void bj_draw_filled_circle(struct bj_bitmap *bitmap, int cx, int cy, int radius, uint32_t color)
Draw a filled circle onto a bitmap.
void bj_dispatch_events(void)
Poll and dispatch all pending events.
void bj_close_on_escape(struct bj_window *window, const struct bj_key_event *event, void *user_data)
Handle the ESC key to close a window.
bj_key_callback_fn bj_set_key_callback(bj_key_callback_fn callback, void *user_data)
Set the global callback for keyboard key events.
#define BJ_PI
PI in the selected bj_real precision.
Definition math.h:111
#define bj_sin
Sine.
Definition math.h:246
#define bj_cos
Cosine.
Definition math.h:237
#define BJ_F(x)
Literal suffix helper for bj_real when float is selected.
Definition math.h:78
float bj_real
Selected real type for float configuration.
Definition math.h:76
Axis-aligned rectangle: a top-left corner plus a width and height.
Definition rect.h:33
2D vector of bj_real components.
Definition vec.h:51
struct bj_vec2 bj_compute_kinematics_2d(struct bj_vec2 position, struct bj_vec2 velocity, struct bj_vec2 acceleration, bj_real time)
Integrate constant-acceleration 2D kinematics: position at time t.
uint32_t bj_get_pixel_value(enum bj_pixel_mode mode, uint8_t red, uint8_t green, uint8_t blue)
Returns an opaque value representing a pixel colour, given its RGB composition.
bj_bool bj_begin(int systems, struct bj_error **error)
Initialises the system.
void bj_end(void)
De-initialises the system.
@ BJ_VIDEO_SYSTEM
Definition system.h:81
void bj_set_draw_callback(struct bj_window *window, bj_window_draw_fn fn, void *user_data)
Register the redraw callback for window.
static void bj_invalidate_window(struct bj_window *window)
Mark the whole window as needing a repaint.
Definition window.h:470
struct bj_window * bj_bind_window(const char *title, uint16_t x, uint16_t y, uint16_t width, uint16_t height, uint8_t flags, struct bj_error **error)
Create a new struct bj_window with the specified attributes.
struct bj_bitmap * bj_render_target_bitmap(struct bj_render_target *target)
Reach the software framebuffer behind a render target.
bj_bool bj_should_close_window(struct bj_window *window)
Get the close flag state of a window.
void bj_unbind_window(struct bj_window *window)
Deletes a struct bj_window object and releases associated memory.
static void fixed_step(struct bj_app *app, struct bj_tick_info tick, void *ud)
Logging utility functions.
Portable main() replacement with platform-aware entry shim.
Physics helpers (SI units, but dimensionally consistent with any unit system).
#define SCREEN_WIDTH
#define BALLS_RADIUS
bj_vec2 gravity
static void initialize_balls()
#define BALLS_LEN
#define GRAVITY
#define SCREEN_HEIGHT
#define FB_PIXEL_MODE
static void reset_ball(size_t at)
struct @075336127262265255345326341123106263042221024322 balls[1000]
static void update(bj_real dt)
bj_vec2 initial_position
Header file for general pixel manipulation facilities.
Header file for system interactions.
Header file for time manipulation utilities.
Fixed-size vector types (2D, 3D, 4D) and inline operations.
Header file for bj_window type.