xlib_playground

Xlib playground for experiments.
Log | Files | Refs

object.c (7187B)


      1 #include <stdio.h>
      2 #include <stdlib.h>
      3 #include <stdint.h>
      4 
      5 #include "list.h"
      6 #include "object.h"
      7 
      8 /*
      9  * Pair of two objects with their distance.
     10  * Used by lhandle_collision();
     11  */
     12 typedef struct LLD {
     13 	Object *o0;
     14 	Object *o1;
     15 	float dist;
     16 } LLD;
     17 
     18 static int test_collision_rr(Object *, Object *);
     19 static void rect_next_tick(Object *, long);
     20 static void rect_handle_collision_mf(Object *, Object *);
     21 static LLD *create_lld(void);
     22 static void lldfree(LLD *);
     23 
     24 static int obj_count = 0;
     25 static int lld_count = 0;
     26 
     27 
     28 Object *
     29 create_object(enum object_type t, uint32_t color,
     30               float px, float py, float vx, float vy, float ax, float ay,
     31               int w, int h, int m,
     32 			  void (*next_tick)(Object *, long))
     33 {
     34 	obj_count++;
     35 
     36 	Object *o;
     37 	o = (Object *)malloc(sizeof(Object));
     38 	o->type = t;
     39 	o->color = color;
     40 	o->shape = SRECTANGLE;
     41 	o->pp.x = o->p.x = px;
     42 	o->pp.y = o->p.y = py;
     43 	o->v.x = vx;
     44 	o->v.y = vy;
     45 	o->a.x = ax;
     46 	o->a.y = ay;
     47 	o->body.rectangle.w = w;
     48 	o->body.rectangle.h = h;
     49 	o->m = m;
     50 	o->on_floor = 0;
     51 	if (next_tick == NULL)
     52 		next_tick = *o_next_tick;
     53 	o->next_tick = next_tick;
     54 	return o;
     55 }
     56 
     57 void
     58 free_object(Object *o)
     59 {
     60 	obj_count--;
     61 	free(o);
     62 }
     63 
     64 int
     65 get_obj_count(void)
     66 {
     67 	return obj_count;
     68 }
     69 
     70 /*
     71  * 1 if collide, 0 if not
     72  */
     73 int
     74 test_collision(Object *o1, Object *o2)
     75 {
     76 	if (o1->shape == SRECTANGLE && o2->shape == SRECTANGLE)
     77 		return test_collision_rr(o1, o2);
     78 	else {
     79 		fprintf(stderr, "test_collision for other shapes is not implemented yet\n");
     80 		return -1;
     81 	}
     82 }
     83 
     84 static int
     85 test_collision_rr(Object *o1, Object *o2)
     86 {
     87 	if (o1->shape != SRECTANGLE || o2->shape != SRECTANGLE) {
     88 		fprintf(stderr, "test_collision_rr: invalid objects\n");
     89 		return -1;
     90 	}
     91 	return o1->p.x < o2->p.x + o2->body.rectangle.w &&
     92 		   o2->p.x < o1->p.x + o1->body.rectangle.w &&
     93 	       o2->p.y < o1->p.y + o1->body.rectangle.h &&
     94 		   o1->p.y < o2->p.y + o2->body.rectangle.h;
     95 }
     96 
     97 void
     98 o_next_tick(Object *o, long ndt)
     99 {
    100 	switch (o->shape) {
    101 	case SRECTANGLE:
    102 		rect_next_tick(o, ndt);
    103 		break;
    104 	default:
    105 		fprintf(stderr, "next_tick: not implemented for other shapes\n");
    106 		break;
    107 	}
    108 }
    109 
    110 static void
    111 rect_next_tick(Object *o, long ndt)
    112 {
    113 	if (o->shape != SRECTANGLE) {
    114 		fprintf(stderr, "rect_next_tick: invalid object shape\n");
    115 		return;
    116 	}
    117 	o->pp.x = o->p.x;
    118     o->pp.y = o->p.y;
    119     o->v.x += o->a.x * ndt / 1e9;
    120     o->v.y += o->a.y * ndt / 1e9;
    121     o->p.x += o->v.x * ndt / 1e9;
    122     o->p.y += o->v.y * ndt / 1e9;
    123 }
    124 
    125 void
    126 handle_collision_mf(Object *om, Object *of)
    127 {
    128 	// TODO: too many testing?
    129 	if (!test_collision(om, of))
    130 		return;
    131 	if (om->shape == SRECTANGLE && of->shape == SRECTANGLE)
    132 		rect_handle_collision_mf(om, of);
    133 	else {
    134 		fprintf(stderr, "handle_collision_mf: not implemented for other shapes\n");
    135 		return;
    136 	}
    137 }
    138 
    139 /*
    140  * Handle collision of a moving rect against fixed rect
    141  */
    142 static void
    143 rect_handle_collision_mf(Object *om, Object *of)
    144 {
    145 	// TODO: too many testing?
    146     if (!test_collision(om, of))
    147         return;
    148     if (om->pp.x + om->body.rectangle.w <= of->pp.x &&
    149         of->p.x < om->p.x + om->body.rectangle.w) {
    150         // collisioin from left to right
    151         om->p.x = of->p.x - om->body.rectangle.w;
    152         om->v.x = 0;
    153     }
    154     if (of->pp.x + of->body.rectangle.w <= om->pp.x &&
    155         om->p.x < of->p.x + of->body.rectangle.w) {
    156         // collision from right to left
    157         om->p.x = of->p.x + of->body.rectangle.w;
    158         om->v.x = 0;
    159     }
    160 
    161     if (om->pp.y + om->body.rectangle.h <= of->pp.y &&
    162         of->p.y < om->p.y + om->body.rectangle.h) {
    163         // collision from up to down
    164         om->p.y = of->p.y - om->body.rectangle.h;
    165         om->v.y = 0;
    166     }
    167     if (of->pp.y + of->body.rectangle.h <= om->pp.y &&
    168         om->p.y < of->p.y + of->body.rectangle.h) {
    169         // collision from down to up
    170         om->p.y = of->p.y + of->body.rectangle.h;
    171         om->v.y = 0;
    172     }
    173 
    174 }
    175 
    176 int
    177 object_dist(Object *o1, Object *o2)
    178 {
    179     return (o1->p.x - o2->p.x) * (o1->p.x - o2->p.x) +
    180            (o1->p.y - o2->p.y) * (o1->p.y - o2->p.y);
    181 }
    182 
    183 int
    184 is_on_floor(Object *p, Object *f)
    185 {
    186 	if (p->p.x + p->body.rectangle.w < f->p.x ||
    187 		f->p.x + f->body.rectangle.w < p->p.x)
    188 		return 0;
    189 	return p->p.y + p->body.rectangle.h == f->p.y;
    190 }
    191 
    192 int
    193 is_on_floor_before(Object *p, Object *f)
    194 {
    195 	if (p->pp.x + p->body.rectangle.w < f->pp.x ||
    196 		f->pp.x + f->body.rectangle.w < p->pp.x)
    197 		return 0;
    198 	return p->pp.y + p->body.rectangle.h == f->pp.y;
    199 }
    200 
    201 void
    202 ohandle_collision(Object *o0, Object *o1)
    203 {
    204 	if (col_func[o0->type][o1->type] == NULL)
    205 		return;
    206 	(* col_func[o0->type][o1->type])(o0, o1);
    207 }
    208 
    209 void
    210 oprint(Object *o)
    211 {
    212 	printf("[%d: (%4.0f, %4.0f)]", o->type, o->p.x, o->p.y);
    213 }
    214 
    215 /*
    216  * Compare object's x coordinate.
    217  */
    218 int
    219 olcmpx(Object *p, Object *q)
    220 {
    221 	if(p->p.x < q->p.x)
    222 		return -1;
    223 	else if(p->p.x == q->p.x)
    224 		return 0;
    225 	else
    226 		return 1;
    227 }
    228 
    229 /*
    230  * sort list of object according to the objects x coordinate.
    231  * TODO: change name to better one.
    232  */
    233 void
    234 olqsortx(List *p)
    235 {
    236 	lqsort(p, (int (*)(void *, void *))&olcmpx);
    237 }
    238 
    239 static int
    240 lldcmpdst(LLD *p, LLD *q)
    241 {
    242 	if (p->dist < q->dist)
    243 		return -1;
    244 	else if (p->dist == q->dist)
    245 		return 0;
    246 	else
    247 		return 1;
    248 }
    249 
    250 static void
    251 lldprint(LLD *p)
    252 {
    253 	printf("{");
    254 	oprint(p->o0);
    255 	printf(", ");
    256 	oprint(p->o1);
    257 	printf(", %2.0f}", p->dist);
    258 }
    259 
    260 static LLD *
    261 create_lld(void)
    262 {
    263 	LLD *p = NULL;
    264 	p = (LLD *)malloc(sizeof(LLD));
    265 
    266 	lld_count++;
    267 	return p;
    268 }
    269 
    270 static void
    271 lldfree(LLD *p)
    272 {
    273 	lld_count--;
    274 	free(p);
    275 }
    276 
    277 int
    278 get_lld_count(void)
    279 {
    280 	return lld_count;
    281 }
    282 
    283 /*
    284  * The order of list p will be changed.
    285  */
    286 void
    287 lhandle_collision(List *p)
    288 {
    289 	olqsortx(p);
    290 	List *stack, *tmp;
    291 	stack = NULL;
    292 	for (; p != NULL; p = p->next) {
    293 		// If p doesn't have intersection in x coodinate
    294 		// with an item in the stack
    295 		if (stack != NULL &&
    296 			((Object *)stack->item)->p.x +
    297 			((Object *)stack->item)->body.rectangle.w <=
    298 			((Object *)p->item)->p.x) {
    299 			// Handle collision among the items in the stack.
    300 			// LLD: {Object *o0, Object *o1, float dist}
    301 			// Sort LLD according to dist.
    302 			List *lld, *tmplld;
    303 			List *s, *t;
    304 			lld = NULL;
    305 			for (s = stack; s != NULL && s->next != NULL; s = s->next) {
    306 				for (t = s->next; t != NULL; t = t->next) {
    307 					LLD *l = NULL;
    308 					if((l = create_lld()) == NULL) {
    309 						fprintf(stderr, "lhandle_collision: Error. creating"
    310 							"lld.\n");
    311 						exit(1);
    312 					}
    313 					l->o0 = (Object *)s->item;
    314 					l->o1 = (Object *)t->item;
    315 					l->dist = object_dist((Object *)s->item,
    316 							(Object *)t->item);
    317 					if((tmplld = laddfront(lld, l)) == NULL){
    318 						fprintf(stderr, "lhandle_collision: Error. Could not"
    319 							"add item to lld\n");
    320 						exit(1);
    321 					}
    322 					lld = tmplld;
    323 				}
    324 			}
    325 			lqsort(lld, (int (*)(void *, void *))&lldcmpdst);
    326 			for (tmplld = lld; tmplld != NULL; tmplld = tmplld->next) {
    327 				if (test_collision(((LLD *)tmplld->item)->o0,
    328 					((LLD *)tmplld->item)->o1)) {
    329 					ohandle_collision(((LLD *)tmplld->item)->o0,
    330 						((LLD *)tmplld->item)->o1);
    331 				}
    332 			}
    333 			lfreei(lld, (void (*)(void *))&lldfree);
    334 			lfree(stack);
    335 			stack = NULL;
    336 		}
    337 		if ((tmp = laddfront(stack, p->item)) == NULL) {
    338 			fprintf(stderr, "lhandle_collision: Error. add item to stack\n");
    339 			exit(1);
    340 		}
    341 		stack = tmp;
    342 	}
    343 	lfree(stack);
    344 	return;
    345 }