#include "duet.h" void player_position(float angle, float *x1, float *y1, float *x2, float *y2) { int x=PLAYER_X, y=DHEIGHT/2; float sin, cos; sincosf(angle, &sin, &cos); if(x1) *x1 = x + sin * PLAYER_R; if(y1) *y1 = y + cos * PLAYER_R; if(x2) *x2 = x - sin * PLAYER_R; if(y2) *y2 = y - cos * PLAYER_R; } bool player_collision(game_t const *game) { float x1, y1, x2, y2; player_position(game->player_rota, &x1, &y1, &x2, &y2); for(int i = 0; i < game->rect_count; i++) { if(rect_circle_collide(&game->rects[i], x1, y1, PLAYER_SIZE)) return true; if(rect_circle_collide(&game->rects[i], x2, y2, PLAYER_SIZE)) return true; } return false; } bool rect_circle_collide(rect_t const *r, int cx0, int cy0, int cr) { /* Translate so that rectangle center is (0,0) */ cx0 -= r->x; cy0 -= r->y; /* Rotate so that rectangle is flat */ float sin, cos; sincosf(-r->r, &sin, &cos); float cx = cx0 * cos + cy0 * sin; float cy = -cx0 * sin + cy0 * cos; /* Determine point of rectangle closest to center of circle */ float clx=cx, cly=cy; if(clx < -r->w/2) clx = -r->w/2; if(clx > r->w/2) clx = r->w/2; if(cly < -r->h/2) cly = -r->h/2; if(cly > r->h/2) cly = r->h/2; /* Determine whether that point is in the circle */ return (clx - cx) * (clx - cx) + (cly - cy) * (cly - cy) <= cr * cr; } void rect_load(rect_t *r, rectmeta_t const *meta) { r->w = 0; r->h = 0; switch(meta->shape) { case Shape_Square: r->w = 0.4; r->h = 0.5; break; case Shape_SmallBar: r->w = 0.2; r->h = 0.5; break; case Shape_MediumBar: r->w = 0.2; r->h = 0.62; break; case Shape_NormalBar: r->w = 0.2; r->h = 1.0; break; case Shape_LongBar: r->w = 0.2; r->h = 1.15; break; case Shape_HugeBar: r->w = 0.2; r->h = 1.5; break; case Shape_LongVertical: r->w = 0.8; r->h = 0.2; break; } r->w *= 2 * PLAYER_R; r->h *= 2 * PLAYER_R; switch(meta->position) { case Position_Left: if(meta->shape == Shape_Square) r->y_init = DHEIGHT/2 - 0.22*CORRIDOR_SIZE; else if(meta->shape == Shape_HugeBar) r->y_init = DHEIGHT/2 - 0.38*CORRIDOR_SIZE; else r->y_init = DHEIGHT/2 - CORRIDOR_SIZE/2 + r->h/2; break; case Position_Right: if(meta->shape == Shape_Square) r->y_init = DHEIGHT/2 + 0.22*CORRIDOR_SIZE; else if(meta->shape == Shape_HugeBar) r->y_init = DHEIGHT/2 + 0.38*CORRIDOR_SIZE; else r->y_init = DHEIGHT/2 + CORRIDOR_SIZE/2 - r->h/2; break; case Position_Middle: r->y_init = DHEIGHT/2; break; } r->y = r->y_init; r->opacity = 256; } float cubic_ease(float t) { return (t <= 0.5) ? 4 * t * t * t : 1 - 4 * (1 - t) * (1 - t) * (1 - t); } void rect_physics(rect_t *r, rectmeta_t const *meta, float absolute_time) { float time = absolute_time - meta->time; /* <= 0 most of the time */ r->x = PLAYER_X - RECT_SPEED * time; r->y = r->y_init; r->r = 0; /* Action */ if(meta->action == Action_RotateLeft) { float vr = 2.0; /* rad/tempo */ r->r = -0.3 + time * vr; } else if(meta->action == Action_RotateRight) { float vr = 2.0; /* rad/tempo */ r->r = 0.3 - time * vr; } else if(meta->action == Action_Speed1) { /* Double speed between -4 and -2 to skip 2 tempi */ float speeding_period = fminf(2.0, fmaxf(0.0, time + 4.0)); r->x -= RECT_SPEED * (speeding_period - 2.0); } else if(meta->action == Action_OuterRotateLeft) { float vr = 0.7; /* rad/tempo */ r->r = time * vr; } else if(meta->action == Action_OuterRotateRight) { float vr = 0.7; /* rad/tempo */ r->r = -time * vr; } else if(meta->action == Action_Slide) { float amp = 2 * (DHEIGHT/2 - r->y_init); /* Nothing happens until -7.5 */ if(time <= -7.5) {} /* Slide to the opposite side between -7.5 and -4.5 */ else if(time <= -4.5) r->y += amp * cubic_ease((time + 7.5) / 3); /* Stay there until -3.5 */ else if(time <= -3.5) r->y += amp; /* Slide back between -3.5 and -0.5 */ else if(time <= -0.5) r->y += amp * (1 - cubic_ease((time + 3.5) / 3)); /* Stay there until +0.5 */ else if(time <= +0.5) {} /* Move back between +0.5 and +3.5 */ else if(time <= +3.5) r->y += amp * cubic_ease((time - 0.5) / 3); /* Stay there indefinitely */ else r->y += amp; } #if 0 else if(meta->action == Action_Speed2) { /* Speed x1.5 permanently */ r->x -= RECT_SPEED * time * 0.5; } else if(meta->action == Action_Speed3) { // TODO } #endif else if(meta->action == Action_Slow) { /* Speed x2/3 until they come close enough to you */ if(time <= -1.0) r->x += RECT_SPEED * (time + 1) / 3; } /* Fadeout */ if(meta->fadeout == Fadeout_2) { /* Reduce opacity to 0 between -4 and -2.5 */ if(time > -2.5) r->opacity = 0; else if(time >= -4.0) r->opacity = 256 * (1 - (time + 4) / 1.5); else r->opacity = 256; } if(meta->fadeout == Fadeout_3) { /* Reduce opacity to 0 between -1 and 0.5 */ if(time > 0.5) r->opacity = 0; else if(time >= -1.0) r->opacity = 256 * (1 - (time + 1) / 1.5); else r->opacity = 256; } }