bool matrix_3x3_square_to_quad(const float dx0, const float dy0, const float dx1, const float dy1, const float dx3, const float dy3, const float dx2, const float dy2, math_matrix_3x3 *mat) { float ax = dx0 - dx1 + dx2 - dx3; float ay = dy0 - dy1 + dy2 - dy3; if (floatIsZero(ax) && floatIsZero(ay)) { /* affine case */ matrix_3x3_inits(mat, dx1 - dx0, dy1 - dy0, 0, dx2 - dx1, dy2 - dy1, 0, dx0, dy0, 1); } else { float a, b, c, d, e, f, g, h; float ax1 = dx1 - dx2; float ax2 = dx3 - dx2; float ay1 = dy1 - dy2; float ay2 = dy3 - dy2; /* determinants */ float gtop = ax * ay2 - ax2 * ay; float htop = ax1 * ay - ax * ay1; float bottom = ax1 * ay2 - ax2 * ay1; if (!bottom) return false; g = gtop / bottom; h = htop / bottom; a = dx1 - dx0 + g * dx1; b = dx3 - dx0 + h * dx3; c = dx0; d = dy1 - dy0 + g * dy1; e = dy3 - dy0 + h * dy3; f = dy0; matrix_3x3_inits(mat, a, d, g, b, e, h, c, f, 1.f); } return true; }
/* Given: Points (x0, y0) and (x1, y1) * Return: TRUE if a solution exists, FALSE otherwise * Circle centers are written to (cx0, cy0) and (cx1, cy1) */ static VGboolean find_unit_circles(double x0, double y0, double x1, double y1, double *cx0, double *cy0, double *cx1, double *cy1) { /* Compute differences and averages */ double dx = x0 - x1; double dy = y0 - y1; double xm = (x0 + x1)/2; double ym = (y0 + y1)/2; double dsq, disc, s, sdx, sdy; /* Solve for intersecting unit circles */ dsq = dx*dx + dy*dy; if (dsq == 0.0) return VG_FALSE; /* Points are coincident */ disc = 1.0/dsq - 1.0/4.0; /* the precision we care about here is around float so if we're * around the float defined zero then make it official to avoid * precision problems later on */ if (floatIsZero(disc)) disc = 0.0; if (disc < 0.0) return VG_FALSE; /* Points are too far apart */ s = sqrt(disc); sdx = s*dx; sdy = s*dy; *cx0 = xm + sdy; *cy0 = ym - sdx; *cx1 = xm - sdy; *cy1 = ym + sdx; return VG_TRUE; }
bool matrix_3x3_invert(math_matrix_3x3 *mat) { float det = matrix_3x3_determinant(mat); if (floatIsZero(det)) return false; matrix_3x3_adjoint(mat); matrix_3x3_divide_scalar(mat, det); return true; }
static INLINE boolean is_affine(float *matrix) { return floatIsZero(matrix[2]) && floatIsZero(matrix[5]) && floatsEqual(matrix[8], 1); }
void Hero::update() { if (myIsDead) return; Entity::update(); if (mSpawnPoint.x < -100 && mSpawnPoint.y < -100) { mSpawnPoint = getPosition(); } if (mRopeState == RopeState_Dissapearing) { mRopeDissapearCounter++; if (mRopeDissapearCounter >= ROPE_DISSAPPEAR_TICKS) { mRopeState = RopeState_Retracted; } } float acceleration = mOnGround ? GROUND_ACCELERATION : AIR_ACCELERATION; bool airRunning = false; if (Input::isHeld(Button_Left)) { mVelocity.x -= acceleration; if (mRopeState == RopeState_Attached && !mOnGround) { mFacingDirection = Direction_Left; airRunning = true; mMovementState = MovementState_AirRun; } } if (Input::isHeld(Button_Right)) { mVelocity.x += acceleration; if (mRopeState == RopeState_Attached && !mOnGround) { mFacingDirection = Direction_Right; airRunning = true; mMovementState = MovementState_AirRun; } } if (Input::isPressed(Button_Jump)) { if (!mJumpPrepressed && mOnGround) Sound::playSample("data/sounds/jump.wav"); mJumpPrepressed = true; } if (mOnGround && mJumpPrepressed) { mVelocity.y = -JUMP_VELOCITY; if (mRopeState != RopeState_Attached) { mJumpHeld = true; } mJumpPrepressed = false; } if (Input::isReleased(Button_Jump)) { if (mJumpHeld && mVelocity.y < 0) { mVelocity.y *= 0.5f; } mJumpHeld = false; mJumpPrepressed = false; } if (Input::isReleased(Button_Fire)) { detachHook(); } if (mVelocity.y >= 0) { mJumpHeld = false; } if (!airRunning) { mMovementState = MovementState_Still; } if (mOnGround) { if (mVelocity.x > 0) { mFacingDirection = Direction_Right; } else if (mVelocity.x < 0) { mFacingDirection = Direction_Left; } if (abs(mVelocity.x) > GROUND_STOP_VELOCITY) { mMovementState = MovementState_Run; } } else if (!airRunning) { if (mVelocity.y > 0) mMovementState = MovementState_Jump; else mMovementState = MovementState_Fall; } if (mMovementState == MovementState_Still) { mVelocity.x = 0; } if (Input::isPressed(Button_Fire)) { Sound::playSample("data/sounds/rope.wav"); mRopeState = RopeState_Moving; mRopePosition = mPosition; mRopeVelocity = float2::ZERO; if (Input::isHeld(Button_Left)) { mRopeVelocity.x -= 1; } if (Input::isHeld(Button_Right)) { mRopeVelocity.x += 1; } if (Input::isHeld(Button_Up)) { mRopeVelocity.y -= 1; } if (Input::isHeld(Button_Down)) { mRopeVelocity.y += 1; } if (floatIsZero(mRopeVelocity)) { mRopeVelocity.x = (mFacingDirection == Direction_Left ? -1 : 1); } mRopeVelocity = adjustRopeDirection(normalize(mVelocity + normalize(mRopeVelocity) * ROPE_SPEED)) * ROPE_SPEED; if (mRopeVelocity.x < 0) { mFacingDirection = Direction_Left; } else if (mRopeVelocity.x > 0) { mFacingDirection = Direction_Right; } } if (mRopeState == RopeState_Moving) { const int substeps = 25; for (int i = 0; i < substeps; i++) { mRopePosition += mRopeVelocity / (substeps * Time::TicksPerSecond); int tileX = (int)(mRopePosition.x / mRoom->getTileWidth()); int tileY = (int)(mRopePosition.y / mRoom->getTileHeight()); if (mRoom->isHookable(tileX, tileY)) { //Sound::stopSample("data/sounds/rope.wav"); Sound::playSample("data/sounds/hook.wav"); mRopeState = RopeState_Attached; mJumpHeld = false; ParticleSystem* particleSystem = new ParticleSystem( mAnimationHookParticle, 2, 30, 10, 1, 50, 10, -normalize(mRopeVelocity)*10, 1.0); particleSystem->setPosition(mRopePosition); mRoom->addEntity(particleSystem); break; } if (length(mRopePosition-mPosition) > mRopeMaxLenghth) { detachHook(); Sound::playSample("data/sounds/no_hook.wav"); break; } if (mRoom->isCollidable(tileX, tileY)) { detachHook(); Sound::playSample("data/sounds/no_hook.wav"); break; } if (mRoom->damageDone((int)(mRopePosition.x), (int)(mRopePosition.y))) { detachHook(); break; } mHookedEntity = mRoom->findHookableEntity(mRopePosition); if (mHookedEntity != 0) { Sound::playSample("data/sounds/hook.wav"); mRopeState = RopeState_Attached; mJumpHeld = false; mHookedEntityOffset = mRopePosition - mHookedEntity->getPosition(); mHookedEntityOffset.x = floor(mHookedEntityOffset.x); mHookedEntityOffset.y = floor(mHookedEntityOffset.y); } } } if (mRopeState == RopeState_Attached) { if (mHookedEntity != 0) { mRopePosition = mHookedEntity->getPosition() + mHookedEntityOffset; } float2 ropeToHero = mPosition - mRopePosition; if (lengthCompare(ropeToHero, ROPE_REST_LENGTH) > 0) { float2 ropeRestPoint = mRopePosition + normalize(ropeToHero) * ROPE_REST_LENGTH; float2 heroToRestPoint = ropeRestPoint - mPosition; float2 ropeAcceleration = heroToRestPoint * ROPE_SPRING_CONSTANT; if (lengthCompare(ropeAcceleration, ROPE_MAX_ACCELERATION) > 0) { ropeAcceleration = normalize(ropeAcceleration) * ROPE_MAX_ACCELERATION; } mVelocity += ropeAcceleration; } if (Input::isHeld(Button_Up)) { mVelocity.y -= acceleration; } if (Input::isHeld(Button_Down)) { mVelocity.y += acceleration; } int ropeTileX = (int)(mRopePosition.x / mRoom->getTileWidth()); int ropeTileY = (int)(mRopePosition.y / mRoom->getTileWidth()); if (mHookedEntity == 0 && !mRoom->isHookable(ropeTileX, ropeTileY)) { detachHook(); } } unsigned int bumps = moveWithCollision(); if ((bumps & (Direction_Left | Direction_Right)) != 0) { mVelocity.x = 0; } if ((bumps & (Direction_Up | Direction_Down)) != 0) { mVelocity.y = 0; } float gravity = mJumpHeld ? JUMP_GRAVITY : GRAVITY; mVelocity.y += gravity; bool ground = ((bumps & Direction_Down) != 0); if (ground && !mOnGround && mRopeState != RopeState_Attached) { Sound::playSample("data/sounds/land.wav"); } mOnGround = ground; float drag = mOnGround ? GROUND_DRAG : AIR_DRAG; mVelocity *= drag; mFrame ++; if (mBlinkingTicksLeft) { mBlinkingTicksLeft --; } }
static VGboolean find_angles(struct arc *arc) { double vec0[2], vec1[2]; double lambda1, lambda2; double angle; struct matrix matrix; if (floatIsZero(arc->a) || floatIsZero(arc->b)) { return VG_FALSE; } /* map the points to an identity circle */ matrix_load_identity(&matrix); matrix_scale(&matrix, 1.f, arc->a/arc->b); matrix_rotate(&matrix, -arc->theta); matrix_map_point(&matrix, arc->x1, arc->y1, &arc->x1, &arc->y1); matrix_map_point(&matrix, arc->x2, arc->y2, &arc->x2, &arc->y2); matrix_map_point(&matrix, arc->cx, arc->cy, &arc->cx, &arc->cy); #if DEBUG_ARCS debug_printf("Matrix 3 [%f, %f, %f| %f, %f, %f| %f, %f, %f]\n", matrix.m[0], matrix.m[1], matrix.m[2], matrix.m[3], matrix.m[4], matrix.m[5], matrix.m[6], matrix.m[7], matrix.m[8]); debug_printf("Endpoints [%f, %f], [%f, %f]\n", arc->x1, arc->y1, arc->x2, arc->y2); #endif vec0[0] = arc->x1 - arc->cx; vec0[1] = arc->y1 - arc->cy; vec1[0] = arc->x2 - arc->cx; vec1[1] = arc->y2 - arc->cy; #if DEBUG_ARCS debug_printf("Vec is [%f, %f], [%f, %f], [%f, %f]\n", vec0[0], vec0[1], vec1[0], vec1[1], arc->cx, arc->cy); #endif lambda1 = vector_orientation(vec0); if (isnan(lambda1)) lambda1 = 0.f; if (arc->type == VG_SCWARC_TO || arc->type == VG_SCCWARC_TO) angle = vector_angles(vec0, vec1); else if (arc->type == VG_LCWARC_TO || arc->type == VG_LCCWARC_TO) { angle = 2*M_PI - vector_angles(vec0, vec1); } else abort(); if (isnan(angle)) angle = M_PI; if (arc->type == VG_SCWARC_TO || arc->type == VG_LCWARC_TO) lambda2 = lambda1 - angle; else lambda2 = lambda1 + angle; #if DEBUG_ARCS debug_printf("Angle is %f and (%f, %f)\n", angle, lambda1, lambda2); #endif #if 0 arc->eta1 = atan2(sin(lambda1) / arc->b, cos(lambda1) / arc->a); arc->eta2 = atan2(sin(lambda2) / arc->b, cos(lambda2) / arc->a); /* make sure we have eta1 <= eta2 <= eta1 + 2 PI */ arc->eta2 -= two_pi * floor((arc->eta2 - arc->eta1) / two_pi); /* the preceding correction fails if we have exactly et2 - eta1 = 2 PI it reduces the interval to zero length */ if ((lambda2 - lambda1 > M_PI) && (arc->eta2 - arc->eta1 < M_PI)) { arc->eta2 += 2 * M_PI; } #else arc->eta1 = lambda1; arc->eta2 = lambda2; #endif return VG_TRUE; }