commit 1fa061078ffd1d1b625d96c08c92321d553f2a2a
parent 8d3953956f7cca1dc5b3064155a8d32251658139
Author: Matsuda Kenji <info@mtkn.jp>
Date: Sun, 25 Dec 2022 13:05:35 +0900
add circle collision
Diffstat:
M | ex5/ex5.c | | | 214 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------ |
1 file changed, 166 insertions(+), 48 deletions(-)
diff --git a/ex5/ex5.c b/ex5/ex5.c
@@ -12,7 +12,7 @@
#define INIT_HEIGHT (600)
#define FPS (60)
#define SUB_TICK (4)
-#define NUM_SQUARE (500)
+#define NUM_RECT (100)
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
@@ -38,20 +38,29 @@ enum next_menu {
QUIT,
};
-struct square {
+struct rect {
float ppx, ppy; // previous position
- float px, py;
+ float px, py; // top left corner
float vx, vy;
int w, h;
+ int m;
+};
+
+struct circle {
+ float ppx, ppy;
+ float px, py;
+ float vx, vy;
+ int r;
+ int m;
};
/* variables */
Display *display;
Window window;
unsigned int win_width = INIT_WIDTH, win_height = INIT_HEIGHT;
-GC gc, sgc[NUM_SQUARE];
+GC gc, sgc[NUM_RECT];
Atom wm_delete_window;
-struct square square[NUM_SQUARE];
+struct circle circle[NUM_RECT];
int next_menu = START_MENU;
@@ -62,11 +71,13 @@ void start_menu(void);
void game_play(void);
void receive_events(int[]);
void handle_inputs(int[]);
-void next_tick(struct square *, long);
-int test_collision(struct square *, struct square *);
-void handle_collision_mf(struct square *, struct square *);
-void handle_collision(struct square *, struct square *);
-void handle_collision_elastic(struct square *, struct square *);
+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 game_over(void);
@@ -87,7 +98,7 @@ setup(void)
XStoreName(display, window, "UNKO");
gc = XCreateGC(display, window, 0, NULL);
XSetForeground(display, gc, 0x00FFFF);
- for (int i = 0; i < NUM_SQUARE; i++){
+ for (int i = 0; i < NUM_RECT; i++){
sgc[i] = XCreateGC(display, window, 0, NULL);
XSetForeground(display, sgc[i], 0x00FF00);
}
@@ -233,20 +244,20 @@ handle_inputs(int key_state[])
return;
}
/*
- square[0].vx = square[0].vy = 0;
+ circle[0].vx = circle[0].vy = 0;
if (key_state[KEY_D] == KEY_DOWN)
- square[0].vx += 300;
+ circle[0].vx += 300;
if (key_state[KEY_A] == KEY_DOWN)
- square[0].vx += -300;
+ circle[0].vx += -300;
if (key_state[KEY_S] == KEY_DOWN)
- square[0].vy += 300;
+ circle[0].vy += 300;
if (key_state[KEY_W] == KEY_DOWN)
- square[0].vy += -300;
+ circle[0].vy += -300;
*/
}
void
-next_tick(struct square *s, long ndt) // nano second
+rect_next_tick(struct rect *s, long ndt) // nano second
{
s->ppx = s->px;
s->ppy = s->py;
@@ -272,20 +283,55 @@ next_tick(struct square *s, long ndt) // nano second
}
}
+void
+circle_next_tick(struct circle *c, long ndt)
+{
+ c->ppx = c->px;
+ c->ppy = c->py;
+ c->px = c->px + c->vx * ndt / 1000 / 1000 / 1000;
+ c->py = c->py + c->vy * ndt / 1000 / 1000 / 1000;
+
+ // bind within the window
+ if (c->px - c->r < 0) {
+ c->px = c->r;
+ c->vx *= -1;
+ }
+ if (win_width < c->px + c->r) {
+ c->px = win_width - c->r;
+ c->vx *= -1;
+ }
+ if (c->py - c->r < 0) {
+ c->py = c->r;
+ c->vy *= -1;
+ }
+ if (win_height < c->py + c->r) {
+ c->py = win_height - c->r;
+ c->vy *= -1;
+ }
+}
+
int
-test_collision(struct square *s1, struct square* s2)
+rect_test_collision(struct rect *s1, struct rect *s2)
{
return s1->px < s2->px + s2->w && s2->px < s1->px + s1->w &&
s2->py < s1->py + s1->h && s1->py < s2->py + s2->h;
}
+int
+circle_test_collision(struct circle *c1, struct circle *c2)
+{
+ return (c1->px - c2->px) * (c1->px - c2->px) +
+ (c1->py - c2->py) * (c1->py - c2->py) <
+ (c1->r + c2->r) * (c1->r + c2->r);
+}
+
/*
- * Handle collision of a moving square against fixed square
+ * Handle collision of a moving rect against fixed rect
*/
void
-handle_collision_mf(struct square *sm, struct square *sf)
+rect_handle_collision_mf(struct rect *sm, struct rect *sf)
{
- if (!test_collision(sm, sf))
+ if (!rect_test_collision(sm, sf))
return;
if (sm->ppx + sm->w <= sf->ppx && sf->px < sm->px + sm->w)
// collisioin from left to right
@@ -303,12 +349,12 @@ handle_collision_mf(struct square *sm, struct square *sf)
}
/*
- * Handle collision of a moving square against another moving square
+ * Handle collision of a moving rect against another moving rect
*/
void
-handle_collision_mm(struct square *s1, struct square *s2)
+rect_handle_collision_mm(struct rect *s1, struct rect *s2)
{
- if (!test_collision(s1, s2))
+ if (!rect_test_collision(s1, s2))
return;
float lapx = min(s1->px + s1->w, s2->px + s2->w) - max(s1->px, s2->px);
@@ -334,16 +380,34 @@ handle_collision_mm(struct square *s1, struct square *s2)
}
void
-handle_collision_elastic(struct square *s1, struct square *s2)
+circle_handle_collision_mm(struct circle *c1, struct circle *c2)
{
- if(!test_collision(s1, s2))
+ if (!circle_test_collision(c1, c2))
return;
- handle_collision_mm(s1, s2);
+ float col_px = c2->px - c1->px;
+ float col_py = c2->py - c1->py;
+ float col_pr = sqrtf(col_px * col_px + col_py * col_py);
+ col_px /= col_pr;
+ col_py /= col_pr;
+
+ c1->px = c1->px - col_px / 2;
+ c1->py = c1->py - col_py / 2;
+ c2->px = c2->px + col_px / 2;
+ c2->py = c2->py + 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->w * s1->h;
- float m2 = s2->w * s2->h;
+ float m1 = s1->m;
+ float m2 = s2->m;
float lapx = min(s1->px + s1->w, s2->px + s2->w) - max(s1->px, s2->px);
float lapy = min(s1->py + s1->h, s2->py + s2->h) - max(s1->py, s2->py);
@@ -362,6 +426,43 @@ handle_collision_elastic(struct square *s1, struct square *s2)
}
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->px - c1->px;
+ float col_py = c2->py - c1->py;
+ 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->vx * col_px + c1->vy * col_py;
+ float col_2v = c2->vx * col_px + c2->vy * 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->vx * nor_px + c1->vy * nor_py);
+ float nor_1vy = nor_py * (c1->vx * nor_px + c1->vy * nor_py);
+ float nor_2vx = nor_px * (c2->vx * nor_px + c2->vy * nor_py);
+ float nor_2vy = nor_py * (c2->vx * nor_px + c2->vy * nor_py);
+
+ c1->vx = col_1vxn + nor_1vx;
+ c1->vy = col_1vyn + nor_1vy;
+ c2->vx = col_2vxn + nor_2vx;
+ c2->vy = col_2vyn + nor_2vy;
+}
+void
game_play(void)
{
int key_state[NUM_KEY];
@@ -371,14 +472,29 @@ game_play(void)
#endif
struct timespec ts;
- for(int i = 0; i < NUM_SQUARE; i++){
- square[i].ppx = square[i].px = (float)rand() * win_width / RAND_MAX;
- square[i].ppy = square[i].py = (float)rand() * win_height / RAND_MAX;
- square[i].vx = (float)rand() * 300 / RAND_MAX - 150;
- square[i].vy = (float)rand() * 300 / RAND_MAX - 150;
- square[i].w = square[i].h = (float)rand() * 30 / RAND_MAX;
+ for(int i = 0; i < NUM_RECT; i++){
+ circle[i].ppx = circle[i].px = rand() * (float)win_width / (float)RAND_MAX;
+ circle[i].ppy = circle[i].py = rand() * (float)win_height / (float)RAND_MAX;
+ circle[i].vx = rand() * 300.0 / (float)RAND_MAX - 150;
+ circle[i].vy = rand() * 300.0 / (float)RAND_MAX - 150;
+ circle[i].r = rand() * 30.0 / (float)RAND_MAX + 5;
+ circle[i].m = circle[i].r * circle[i].r;
}
-
+/*
+ circle[0].ppx = circle[0].px = 100;
+ circle[0].ppy = circle[0].py = 400;
+ circle[0].vx = 100;
+ circle[0].vy = -100;
+ circle[0].r = 100;
+ circle[0].m = circle[0].r * circle[0].r;
+ circle[1].ppx = circle[1].px = 400;
+ circle[1].ppy = circle[1].py = 100;
+ circle[1].vx = -100;
+ circle[1].vy = 200;
+ circle[1].r = 100;
+ circle[1].m = circle[1].r * circle[1].r;
+
+*/
while (next_menu == GAME_PLAY){
clock_gettime(CLOCK_MONOTONIC, &ts);
@@ -390,19 +506,19 @@ game_play(void)
clock_gettime(CLOCK_MONOTONIC, &ts);
t0 = ts.tv_nsec;
- int collision[NUM_SQUARE] = {0};
+ int collision[NUM_RECT] = {0};
for (int j = 0; j < SUB_TICK; j++) {
- for (int i = 0; i < NUM_SQUARE; i++)
- next_tick(&square[i], 1000 * 1000 * 1000 / FPS / SUB_TICK);
+ for (int i = 0; i < NUM_RECT; i++)
+ circle_next_tick(&circle[i], 1000 * 1000 * 1000 / FPS / SUB_TICK);
- for (int i = 0; i < NUM_SQUARE; i++)
- for (int j = i + 1; j < NUM_SQUARE; j++) {
- handle_collision_elastic(&square[i], &square[j]);
- if (test_collision(&square[i], &square[j]))
+ for (int i = 0; i < NUM_RECT; i++)
+ for (int j = i + 1; j < NUM_RECT; j++) {
+ circle_handle_collision_elastic(&circle[i], &circle[j]);
+ if (circle_test_collision(&circle[i], &circle[j]))
collision[i] = collision[j] = 1;
}
}
- for (int i = 0; i < NUM_SQUARE; i++)
+ for (int i = 0; i < NUM_RECT; i++)
if (collision[i] == 1)
XSetForeground(display, sgc[i], 0xFFFF00);
else
@@ -430,10 +546,12 @@ game_play(void)
0, 0, // position
win_width, win_height, // width and height
False);
- for (int i = 0; i < NUM_SQUARE; i++) {
- XDrawRectangle(display, window, sgc[i],
- square[i].px, square[i].py, // position
- square[i].w, square[i].h); // width and height
+ for (int i = 0; i < NUM_RECT; i++) {
+ XDrawArc(display, window, sgc[i],
+ circle[i].px - circle[i].r,
+ circle[i].py - circle[i].r, // position
+ circle[i].r * 2, circle[i].r * 2,
+ 0, 360 << 6); // width and height
}
}
XSetForeground(display, gc, 0x00FFFF);