xlib_playground

Xlib playground for experiments.
Log | Files | Refs

commit dca94e2f1913c38d316fa9048b43d2ac31045574
parent 5c0c731128a68d41743235c7054ab099eb5abfed
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Thu, 29 Dec 2022 14:56:15 +0900

Clean up:
Move object related stuff to a separate file.
It's not completed yet.

Diffstat:
Mex7/ex7.c | 355++++++++++++-------------------------------------------------------------------
Aex7/physics.c | 111+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aex7/physics.h | 61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 223 insertions(+), 304 deletions(-)

diff --git a/ex7/ex7.c b/ex7/ex7.c @@ -3,10 +3,10 @@ #include <time.h> #include <unistd.h> #include <string.h> -#include <math.h> #include "x.h" #include "world_map.h" +#include "physics.h" /* macros */ #define FPS (60) @@ -38,48 +38,9 @@ enum next_menu { QUIT, }; -struct Point { - float x; - float y; -}; - -struct Rectangle { - struct Point min; - struct Point max; -}; - -struct Circle { - struct Point c; - float r; -}; -/* -struct Obj { - enum object_type type; - union obj {Circle, Rectangle}; - void (* next_tick)(long ndt); -}; -*/ -struct rect { - struct Point pp; - struct Point p; - struct Point v; - struct Point a; - int w, h; - int m; -}; - -struct circle { - struct Point pp; - struct Point p; - struct Point v; - struct Point a; - int r; - int m; -}; - /* variables */ -struct rect block[NUM_RECT]; -struct rect player; +struct Object block[NUM_RECT]; +struct Object player; int player_is_falling; enum next_menu next_menu = START_MENU; @@ -93,15 +54,9 @@ void game_over(void); /* events */ void receive_events(enum key_state[]); void handle_inputs(enum key_state[]); -void update_falling_status(struct rect *, long); +void update_falling_status(struct Object *, long); /* physics */ void rect_next_tick(struct rect *, long); -int rect_test_collision(struct rect *, struct rect *); -void rect_handle_collision_mf(struct rect *, struct rect *); -void rect_handle_collision(struct rect *, struct rect *); -void rect_handle_collision_elastic(struct rect *, struct rect *); -void circle_next_tick(struct circle *, long); -int circle_test_collision(struct circle *, struct circle *); void start_menu(void) @@ -257,252 +212,28 @@ handle_inputs(enum key_state key_state[]) player.v.y = -450; } -void -rect_next_tick(struct rect *s, long ndt) // nano second -{ - s->pp.x = s->p.x; - s->pp.y = s->p.y; - s->v.x += s->a.x * ndt / 1000 / 1000 / 1000; - s->v.y += s->a.y * ndt / 1000 / 1000 / 1000; - s->p.x += s->v.x * ndt / 1000 / 1000 / 1000; - s->p.y += s->v.y * ndt / 1000 / 1000 / 1000; - - // bind within the world - if (s->p.x < 0) { - s->p.x = 0; - //s->v.x *= -1; - } - if (WORLD_WIDTH * BLOCK_SIZE < s->p.x + s->w) { - s->p.x = WORLD_WIDTH * BLOCK_SIZE - s->w; - //s->v.x *= -1; - } - /* - if (s->p.y < 0) { - s->p.y = 0; - s->v.y *= -1; - } - if (WORLD_HEIGHT * BLOCK_SIZE < s->p.y + s->h) { - s->p.y = WORLD_HEIGHT * BLOCK_SIZE - s->h; - s->v.y *= -1; - } - */ - // game over when fall out of the screen - if (s->p.y > WORLD_HEIGHT * BLOCK_SIZE) - next_menu = GAME_OVER; -} - -void -circle_next_tick(struct circle *c, long ndt) -{ - - c->pp.x = c->p.x; - c->pp.y = c->p.y; - c->v.x += c->a.x * ndt / 1000 / 1000 / 1000; - c->v.y += c->a.y * ndt / 1000 / 1000 / 1000; - c->p.x += c->v.x * ndt / 1000 / 1000 / 1000; - c->p.y += c->v.y * ndt / 1000 / 1000 / 1000; - - // bind within the world - if (c->p.x - c->r < 0) { - c->p.x = c->r; - c->v.x *= -1; - } - if (WORLD_WIDTH * BLOCK_SIZE < c->p.x + c->r) { - c->p.x = WORLD_WIDTH * BLOCK_SIZE - c->r; - c->v.x *= -1; - } - if (c->p.y - c->r < 0) { - c->p.y = c->r; - c->v.y *= -1; - } - if (WORLD_HEIGHT * BLOCK_SIZE < c->p.y + c->r) { - c->p.y = WORLD_HEIGHT * BLOCK_SIZE - c->r; - c->v.y *= -1; - } -} - -int -rect_test_collision(struct rect *s1, struct rect *s2) -{ - return s1->p.x < s2->p.x + s2->w && s2->p.x < s1->p.x + s1->w && - s2->p.y < s1->p.y + s1->h && s1->p.y < s2->p.y + s2->h; -} - -int -circle_test_collision(struct circle *c1, struct circle *c2) -{ - return (c1->p.x - c2->p.x) * (c1->p.x - c2->p.x) + - (c1->p.y - c2->p.y) * (c1->p.y - c2->p.y) < - (c1->r + c2->r) * (c1->r + c2->r); -} - -/* - * Handle collision of a moving rect against fixed rect - */ -void -rect_handle_collision_mf(struct rect *sm, struct rect *sf) -{ - if (!rect_test_collision(sm, sf)) - return; - if (sm->pp.x + sm->w <= sf->pp.x && sf->p.x < sm->p.x + sm->w) { - // collisioin from left to right - sm->p.x = sf->p.x - sm->w; - sm->v.x = 0; - } - if (sf->pp.x + sf->w <= sm->pp.x && sm->p.x < sf->p.x + sf->w) { - // collision from right to left - sm->p.x = sf->p.x + sf->w; - sm->v.x = 0; - } - - if (sm->pp.y + sm->h <= sf->pp.y && sf->p.y < sm->p.y + sm->h) { - // collision from up to down - sm->p.y = sf->p.y - sm->h; - sm->v.y = 0; - } - if (sf->pp.y + sf->h <= sm->pp.y && sm->p.y < sf->p.y + sf->h) { - // collision from dohn to up - sm->p.y = sf->p.y + sf->h; - sm->v.y = 0; - } - -} - -/* - * Handle collision of a moving rect against another moving rect - */ -void -rect_handle_collision_mm(struct rect *s1, struct rect *s2) -{ - if (!rect_test_collision(s1, s2)) - return; - - float lapx = min(s1->p.x + s1->w, s2->p.x + s2->w) - max(s1->p.x, s2->p.x); - float lapy = min(s1->p.y + s1->h, s2->p.y + s2->h) - max(s1->p.y, s2->p.y); - - if (lapx < lapy) { - if (s1->p.x + s1->w < s2->p.x + s2->w / 2) { - s1->p.x -= lapx / 2; - s2->p.x += lapx / 2; - } else { - s1->p.x += lapx / 2; - s2->p.x -= lapx / 2; - } - } else { - if (s1->p.y + s1->h < s2->p.y + s2->h / 2) { - s1->p.y -= lapy / 2; - s2->p.y += lapy / 2; - } else { - s1->p.y += lapy / 2; - s2->p.y -= lapy / 2; - } - } -} - -void -circle_handle_collision_mm(struct circle *c1, struct circle *c2) -{ - if (!circle_test_collision(c1, c2)) - return; - - float col_px = c2->p.x - c1->p.x; - float col_py = c2->p.y - c1->p.y; - float col_pr = sqrtf(col_px * col_px + col_py * col_py); - col_px /= col_pr; - col_py /= col_pr; - - c1->p.x = c1->p.x - col_px / 2; - c1->p.y = c1->p.y - col_py / 2; - c2->p.x = c2->p.x + col_px / 2; - c2->p.y = c2->p.y + col_py / 2; -} - -void -rect_handle_collision_elastic(struct rect *s1, struct rect *s2) -{ - if(!rect_test_collision(s1, s2)) - return; - - rect_handle_collision_mm(s1, s2); - - float v1, v2; - float m1 = s1->m; - float m2 = s2->m; - - float lapx = min(s1->p.x + s1->w, s2->p.x + s2->w) - max(s1->p.x, s2->p.x); - float lapy = min(s1->p.y + s1->h, s2->p.y + s2->h) - max(s1->p.y, s2->p.y); - - if (lapx < lapy) { - v1 = s1->v.x; - v2 = s2->v.x; - s1->v.x = 2*m2/(m1+m2)*v2 + (m1-m2)/(m1+m2)*v1; - s2->v.x = 2*m1/(m1+m2)*v1 + (m2-m1)/(m1+m2)*v2; - } else { - v1 = s1->v.y; - v2 = s2->v.y; - s1->v.y = 2*m2/(m1+m2)*v2 + (m1-m2)/(m1+m2)*v1; - s2->v.y = 2*m1/(m1+m2)*v1 + (m2-m1)/(m1+m2)*v2; - } -} - -void -circle_handle_collision_elastic(struct circle *c1, struct circle *c2) -{ - if(!circle_test_collision(c1, c2)) - return; - - circle_handle_collision_mm(c1, c2); - - float col_px = c2->p.x - c1->p.x; - float col_py = c2->p.y - c1->p.y; - float col_pr = sqrtf(col_px * col_px + col_py * col_py); - col_px /= col_pr; - col_py /= col_pr; - float nor_px = col_py; - float nor_py = -col_px; - - float m1 = c1->m; - float m2 = c2->m; - - float col_1v = c1->v.x * col_px + c1->v.y * col_py; - float col_2v = c2->v.x * col_px + c2->v.y * col_py; - - float col_1vxn = (2*m2/(m1+m2)*col_2v + (m1-m2)/(m1+m2)*col_1v) * col_px; - float col_1vyn = (2*m2/(m1+m2)*col_2v + (m1-m2)/(m1+m2)*col_1v) * col_py; - float col_2vxn = (2*m1/(m1+m2)*col_1v + (m2-m1)/(m1+m2)*col_2v) * col_px; - float col_2vyn = (2*m1/(m1+m2)*col_1v + (m2-m1)/(m1+m2)*col_2v) * col_py; - - float nor_1vx = nor_px * (c1->v.x * nor_px + c1->v.y * nor_py); - float nor_1vy = nor_py * (c1->v.x * nor_px + c1->v.y * nor_py); - float nor_2vx = nor_px * (c2->v.x * nor_px + c2->v.y * nor_py); - float nor_2vy = nor_py * (c2->v.x * nor_px + c2->v.y * nor_py); - - c1->v.x = col_1vxn + nor_1vx; - c1->v.y = col_1vyn + nor_1vy; - c2->v.x = col_2vxn + nor_2vx; - c2->v.y = col_2vyn + nor_2vy; -} void -update_falling_status(struct rect *player, long ndt) +update_falling_status(struct Object *player, long ndt) { int collision = 0; - struct rect r = {0}; - r.pp.x = player->pp.x; - r.pp.y = player->pp.y; - r.p.x = player->p.x; - r.p.y = player->p.y; - r.v.x = 0; - r.v.y = 0; - r.a.x = 0; - r.a.y = GRAVITY; - r.w = player->w; - r.h = player->h; - r.m = player->m; - - rect_next_tick(&r, ndt); + struct Object o = {0}; + o.shape = player->shape; + o.pp.x = player->pp.x; + o.pp.y = player->pp.y; + o.p.x = player->p.x; + o.p.y = player->p.y; + o.v.x = 0; + o.v.y = 0; + o.a.x = 0; + o.a.y = GRAVITY; + o.body.rectangle.w = player->body.rectangle.w; + o.body.rectangle.h = player->body.rectangle.h; + o.m = player->m; + + next_tick(&o, ndt); for (int i = 0; i < NUM_RECT; i++) - if (rect_test_collision(&r, &block[i])) + if (test_collision(&o, &block[i])) collision = 1; if (collision == 1) @@ -530,8 +261,10 @@ game_play(void) block[bi].a.y = 0; block[bi].v.x = 0; block[bi].v.y = 0; - block[bi].w = block[bi].h = BLOCK_SIZE; - block[bi].m = block[bi].w * block[bi].h; + block[bi].body.rectangle.w = BLOCK_SIZE; + block[bi].body.rectangle.h = BLOCK_SIZE; + block[bi].m = block[bi].body.rectangle.w * + block[bi].body.rectangle.h; bi++; } else if (world_map[i] == 'p') { player.pp.x = player.p.x = i % WORLD_WIDTH * BLOCK_SIZE; @@ -540,8 +273,8 @@ game_play(void) player.v.y = 0; player.a.x = 0; player.a.y = GRAVITY; - player.w = player.h = BLOCK_SIZE; - player.m = player.w * player.h; + player.body.rectangle.w = player.body.rectangle.h = BLOCK_SIZE; + player.m = player.body.rectangle.w * player.body.rectangle.h; } } @@ -555,22 +288,35 @@ game_play(void) clock_gettime(CLOCK_MONOTONIC, &ts); t0 = ts.tv_nsec; - int collision[NUM_RECT] = {0}; for (int k = 0; k < SUB_TICK; k++) { update_falling_status(&player, 1000 * 1000 * 1000 / FPS / SUB_TICK); if (player_is_falling) player.a.y = GRAVITY; else player.a.y = 0; - rect_next_tick(&player, 1000 * 1000 * 1000 / FPS / SUB_TICK); - for (int i = 0; i < NUM_RECT; i++) - rect_next_tick(&block[i], 1000 * 1000 * 1000 / FPS / SUB_TICK); + next_tick(&player, 1000 * 1000 * 1000 / FPS / SUB_TICK); - for (int i = 0; i < NUM_RECT; i++){ - rect_handle_collision_mf(&player, &block[i]); - if (rect_test_collision(&player, &block[i])) - collision[i] = 1; + // game over when fall out of the screen + if (player.p.y > WORLD_HEIGHT * BLOCK_SIZE) { + next_menu = GAME_OVER; + break; + } + // bind within the world + if (player.p.x < 0) { + player.p.x = 0; } + if (WORLD_WIDTH * BLOCK_SIZE < player.p.x + + player.body.rectangle.w) { + player.p.x = WORLD_WIDTH * BLOCK_SIZE - + player.body.rectangle.w; + } + + + for (int i = 0; i < NUM_RECT; i++) + next_tick(&block[i], 1000 * 1000 * 1000 / FPS / SUB_TICK); + + for (int i = 0; i < NUM_RECT; i++) + handle_collision_mf(&player, &block[i]); } // fix fps @@ -595,11 +341,12 @@ game_play(void) for (int i = 0; i < NUM_RECT; i++) { x_draw_rectangle(0x00FF00, block[i].p.x, block[i].p.y, // position - block[i].w, block[i].h); + block[i].body.rectangle.w, + block[i].body.rectangle.h); } x_draw_rectangle(0x009FFF, player.p.x, player.p.y, // position - player.w, player.h); + player.body.rectangle.w, player.body.rectangle.h); char status_string[128]; snprintf(status_string, 128, "falling: %d", player_is_falling); x_draw_string(0x00FFFF, diff --git a/ex7/physics.c b/ex7/physics.c @@ -0,0 +1,111 @@ +#include <stdio.h> + +#include "physics.h" + +static int test_collision_rr(struct Object *, struct Object *); +static void rect_next_tick(struct Object *, long); +static void rect_handle_collision_mf(struct Object *, struct Object *); + +/* + *1 if collide, 0 if not + */ +int +test_collision(struct Object *o1, struct Object *o2) +{ + if (o1->shape == SRECTANGLE && o2->shape == SRECTANGLE) + return test_collision_rr(o1, o2); + else { + fprintf(stderr, "test_collision for other shapes is not implemented yet\n"); + return -1; + } +} + +static int +test_collision_rr(struct Object *o1, struct Object *o2) +{ + if (o1->shape != SRECTANGLE || o2->shape != SRECTANGLE) { + fprintf(stderr, "test_collision_rr: invalid objects\n"); + return -1; + } + return o1->p.x < o2->p.x + o2->body.rectangle.w && o2->p.x < o1->p.x + o1->body.rectangle.w && + o2->p.y < o1->p.y + o1->body.rectangle.h && o1->p.y < o2->p.y + o2->body.rectangle.h; +} + +void +next_tick(struct Object *o, long ndt) +{ + switch (o->shape) { + case SRECTANGLE: + rect_next_tick(o, ndt); + break; + default: + fprintf(stderr, "next_tick: not implemented for other shapes\n"); + break; + } +} + +static void +rect_next_tick(struct Object *o, long ndt) +{ + if (o->shape != SRECTANGLE) { + fprintf(stderr, "rect_next_tick: invalid object shape\n"); + return; + } + o->pp.x = o->p.x; + o->pp.y = o->p.y; + o->v.x += o->a.x * ndt / 1000 / 1000 / 1000; + o->v.y += o->a.y * ndt / 1000 / 1000 / 1000; + o->p.x += o->v.x * ndt / 1000 / 1000 / 1000; + o->p.y += o->v.y * ndt / 1000 / 1000 / 1000; +} + +void +handle_collision_mf(struct Object *om, struct Object *of) +{ + // TODO: too many testing? + if (!test_collision(om, of)) + return; + if (om->shape == SRECTANGLE && of->shape == SRECTANGLE) + rect_handle_collision_mf(om, of); + else { + fprintf(stderr, "handle_collision_mf: not implemented for other shapes\n"); + return; + } +} + +/* + * Handle collision of a moving rect against fixed rect + */ +static void +rect_handle_collision_mf(struct Object *om, struct Object *of) +{ + // TODO: too many testing? + if (!test_collision(om, of)) + return; + if (om->pp.x + om->body.rectangle.w <= of->pp.x && + of->p.x < om->p.x + om->body.rectangle.w) { + // collisioin from left to right + om->p.x = of->p.x - om->body.rectangle.w; + om->v.x = 0; + } + if (of->pp.x + of->body.rectangle.w <= om->pp.x && + om->p.x < of->p.x + of->body.rectangle.w) { + // collision from right to left + om->p.x = of->p.x + of->body.rectangle.w; + om->v.x = 0; + } + + if (om->pp.y + om->body.rectangle.h <= of->pp.y && + of->p.y < om->p.y + om->body.rectangle.h) { + // collision from up to down + om->p.y = of->p.y - om->body.rectangle.h; + om->v.y = 0; + } + if (of->pp.y + of->body.rectangle.h <= om->pp.y && + om->p.y < of->p.y + of->body.rectangle.h) { + // collision from down to up + om->p.y = of->p.y + of->body.rectangle.h; + om->v.y = 0; + } + +} diff --git a/ex7/physics.h b/ex7/physics.h @@ -0,0 +1,61 @@ +enum object_shape { + SRECTANGLE, + STRIANGLE, + SCIRCLE, +}; + +struct Point { + float x; + float y; +}; + +struct Rectangle { // origin is top left corner + int w, h; +}; + +struct Triangle { + struct Point v2; + struct Point v3; +}; + +struct Circle { // origin is center + float r; +}; + +union Body { + struct Circle circle; + struct Triangle triangle; + struct Rectangle rectangle; +}; + +struct Object { + enum object_shape shape; + struct Point pp; + struct Point p; + struct Point v; + struct Point a; + union Body body; + int m; +}; + +struct rect { + struct Point pp; + struct Point p; + struct Point v; + struct Point a; + int w, h; + int m; +}; + +struct circle { + struct Point pp; + struct Point p; + struct Point v; + struct Point a; + int r; + int m; +}; + +int test_collision(struct Object *, struct Object *); // 1 if collide, 0 if not +void next_tick(struct Object *o, long); +void handle_collision_mf(struct Object *, struct Object *);