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:
M | ex7/ex7.c | | | 355 | ++++++++++++------------------------------------------------------------------- |
A | ex7/physics.c | | | 111 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | ex7/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 *);