Duet/src/physics.c

220 lines
5.9 KiB
C

#include "duet.h"
void player_position(float angle,
float *x1, float *y1, float *x2, float *y2, int r)
{
int x=PLAYER_X, y=DHEIGHT/2;
float sin, cos;
sincosf(angle, &sin, &cos);
if(x1) *x1 = x + sin * r;
if(y1) *y1 = y + cos * r;
if(x2) *x2 = x - sin * r;
if(y2) *y2 = y - cos * r;
}
bool player_collision(game_t const *game)
{
float x1, y1, x2, y2;
player_position(game->player_rota, &x1, &y1, &x2, &y2, PLAYER_R);
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_1) {
/* 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_2) {
/* Reduce opacity to 0 between -2.5 and -1 */
if(time > -1)
r->opacity = 0;
else if(time >= -2.5)
r->opacity = 256 * (1 - (time + 2.5) / 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;
}
}