commit 24091625e1a39f6df615f44416749ba5e0cfa6d2
parent ad942f879d3fa0060e08e1d16a5c3aec54ce77de
Author: Matsuda Kenji <info@mtkn.jp>
Date: Tue, 10 Jan 2023 09:28:42 +0900
add new files
Diffstat:
A | ex9/draw.c | | | 140 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | ex9/draw.h | | | 21 | +++++++++++++++++++++ |
A | ex9/object.c | | | 186 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | ex9/object.h | | | 63 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
4 files changed, 410 insertions(+), 0 deletions(-)
diff --git a/ex9/draw.c b/ex9/draw.c
@@ -0,0 +1,140 @@
+#include <stdio.h>
+#include <stdint.h>
+
+#include <X11/Xlib.h>
+
+#include "draw.h"
+
+Display *display;
+Atom wm_delete_window;
+GC gc;
+Window window;
+unsigned int win_width, win_height;
+
+/*
+ * Creates a window
+ * If succeeded, returns 0
+ * If error occured, returns -1
+ */
+int
+x_setup_window(int x, int y,
+ unsigned int w, unsigned int h,
+ unsigned long bc, char *win_name)
+{
+ if ((display = XOpenDisplay(NULL)) == NULL){
+ fprintf(stderr, "ERROR: could not open display\n");
+ return -1;
+ }
+ window = XCreateSimpleWindow(
+ display,
+ XDefaultRootWindow(display),
+ x, y,
+ w, h,
+ 0, 0, // I don't need border?
+ bc);
+ win_width = w;
+ win_height = h;
+
+ XStoreName(display, window, win_name);
+ gc = XCreateGC(display, window, 0, NULL);
+
+ wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", False);
+ XSetWMProtocols(display, window, &wm_delete_window, 1);
+
+ XSelectInput(display, window,
+ ExposureMask | KeyPressMask | KeyReleaseMask);
+
+ XMapWindow(display, window);
+ return 0;
+}
+
+/*
+ * Clears the window with the background color.
+ * I don't know what the return value of XClearArea means...
+ */
+void
+x_clear_area(void)
+{
+ XClearArea(display, window,
+ 0, 0,
+ win_width, win_height,
+ False);
+}
+
+/*
+ * Draws a string with specified color.
+ */
+void
+x_draw_string(unsigned long color, int x, int y, const char *str, int length)
+{
+ XSetForeground(display, gc, color);
+ XDrawString(display, window, gc, x, y, str, length);
+}
+
+void
+x_draw_rectangle(unsigned long color, int x, int y,
+ unsigned int w, unsigned int h)
+{
+ XSetForeground(display, gc, color);
+ XDrawRectangle(display, window, gc, x, y, w, h);
+}
+
+void
+x_flush(void)
+{
+ XFlush(display);
+}
+
+void
+x_clean_up(void)
+{
+ XCloseDisplay(display);
+}
+
+int
+x_next_event(char *c)
+{
+ XEvent event;
+ XWindowAttributes wattr;
+
+ XNextEvent(display, &event);
+ if (c == NULL)
+ return NOEVENT;
+ switch (event.type) {
+ case Expose:
+ XGetWindowAttributes(display, window, &wattr);
+ win_width = wattr.width;
+ win_height = wattr.height;
+ return XEXPOSE;
+ break;
+ case ClientMessage:
+ if ((Atom) event.xclient.data.l[0] == wm_delete_window) {
+ return XWINDEL;
+ }
+ break;
+ case KeyPress:
+ *c = XLookupKeysym(&event.xkey, 0);
+ return XKEYPRESS;
+ break;
+ case KeyRelease:
+ *c = XLookupKeysym(&event.xkey, 0);
+ return XKEYRELEASE;
+ break;
+ default:
+ break;
+ }
+ return NOEVENT;
+}
+
+int
+x_pending(void)
+{
+ return XPending(display);
+}
+
+void
+x_get_win_wh(int *w, int *h)
+{
+ *w = win_width;
+ *h = win_height;
+}
diff --git a/ex9/draw.h b/ex9/draw.h
@@ -0,0 +1,21 @@
+/*
+ * x.c
+ */
+enum event_type {
+ XKEYPRESS,
+ XKEYRELEASE,
+ XEXPOSE,
+ XWINDEL,
+ NOEVENT,
+};
+
+int x_setup_window(int, int, unsigned int, unsigned int, unsigned long, char *);
+void x_clear_area(void);
+void x_draw_string(unsigned long color, int x, int y, const char *str, int length);
+void x_draw_rectangle(unsigned long color, int x, int y,
+ unsigned int w, unsigned int h);
+void x_flush(void);
+void x_clean_up(void);
+int x_next_event(char *c);
+int x_pending(void);
+void x_get_win_wh(int *, int *);
diff --git a/ex9/object.c b/ex9/object.c
@@ -0,0 +1,186 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+
+#include "object.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 *);
+
+struct Object *
+create_object(enum object_type t, uint32_t color,
+ float px, float py, float vx, float vy, float ax, float ay,
+ int w, int h, int m)
+{
+ struct Object *o;
+ o = (struct Object *)malloc(sizeof(struct Object));
+ o->type = t;
+ o->color = color;
+ o->shape = SRECTANGLE;
+ o->pp.x = o->p.x = px;
+ o->pp.y = o->p.y = py;
+ o->v.x = vx;
+ o->v.y = vy;
+ o->a.x = ax;
+ o->a.y = ay;
+ o->body.rectangle.w = w;
+ o->body.rectangle.h = h;
+ o->m = m;
+ return o;
+}
+
+void
+free_object(struct Object *o)
+{
+ free(o);
+}
+
+/*
+ * 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 / 1e9;
+ o->v.y += o->a.y * ndt / 1e9;
+ o->p.x += o->v.x * ndt / 1e9;
+ o->p.y += o->v.y * ndt / 1e9;
+}
+
+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;
+ }
+
+}
+
+/*
+ * Test if object o is not on top of one of fb (floor blocks).
+ * o: object to be tested, fb: floor blocks, num_f: count of fb.
+ */
+int
+object_is_falling(struct Object *o, struct Object *fb, int num_f)
+{
+ struct Object p = *o;
+
+ p.v.x = 0; p.v.y = 1;
+ p.a.x = 0; p.a.y = 0;
+
+ next_tick(&p, 1e9);
+
+ for (int i = 0; i < num_f; i++)
+ if (test_collision(&p, &fb[i]))
+ return 0;
+ return 1;
+}
+
+int
+object_dist(struct Object *o1, struct Object *o2)
+{
+ return (o1->p.x - o2->p.x) * (o1->p.x - o2->p.x) +
+ (o1->p.y - o2->p.y) * (o1->p.y - o2->p.y);
+}
+
+int
+is_on_floor_before(struct Object *player, struct Object *floor)
+{
+ struct Object o = *player;
+ o.p.x = o.pp.x; o.p.y = o.pp.y;
+ o.v.x = 0; o.v.y = 5;
+ o.a.x = 0; o.a.y = 0;
+ next_tick(&o, 1e9);
+ int col = test_collision(&o, floor);
+ return col;
+}
+
+void handle_collision(struct Object *o0, struct Object *o1) {
+ (* col_func[o0->type][o1->type])(o0, o1);
+}
diff --git a/ex9/object.h b/ex9/object.h
@@ -0,0 +1,63 @@
+enum object_shape {
+ SRECTANGLE,
+ STRIANGLE,
+ SCIRCLE,
+};
+
+enum object_type {
+ TPLAYER,
+ TBLOCK,
+ TENEMY,
+ TFLAG,
+ NUM_OBJ_TYPE,
+};
+
+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_type type;
+ enum object_shape shape;
+ uint32_t color;
+ struct Point pp;
+ struct Point p;
+ struct Point v;
+ struct Point a;
+ union Body body;
+ int m;
+};
+
+extern void (* col_func[NUM_OBJ_TYPE][NUM_OBJ_TYPE])(struct Object *, struct Object *);
+
+int object_dist(struct Object *, struct Object *);
+void handle_collision(struct Object *, struct Object *);
+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 *);
+int object_is_falling(struct Object *o, struct Object *fb, int num_f);
+struct Object *create_object(enum object_type, uint32_t,
+ float, float, float, float, float, float,
+ int, int, int);
+void free_object(struct Object *);
+int is_on_floor_before(struct Object *, struct Object *);