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 }