xlib_playground

Xlib playground for experiments.
Log | Files | Refs

commit 1fa061078ffd1d1b625d96c08c92321d553f2a2a
parent 8d3953956f7cca1dc5b3064155a8d32251658139
Author: Matsuda Kenji <info@mtkn.jp>
Date:   Sun, 25 Dec 2022 13:05:35 +0900

add circle collision

Diffstat:
Mex5/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);