public override MovementCalculator CreateMovementCalculator(AvatarController avatar) { float angularVelocity = 0; var acceleration = Vector2.zero; float boostGatheringDuration = 0; float boostExecutionDuration = 0; float maximumBoostExecutionDuration = 0; return(deltaTime => { float currentAngle = avatar.physics.rotationAngle; var targetDirection = avatar.intentions.intendedFlight == Vector2.zero ? avatar.physics.rotatedForward : avatar.intentions.intendedFlight; float targetAngle = Vector2.SignedAngle(avatar.physics.forward, targetDirection); if (directionsNormalized) { targetAngle = AngleUtil.RoundAngle(targetAngle, directionRange); } var currentVelocity = avatar.physics.velocity; (Vector2, float, int) boost() { avatar.physics.drag = boostDrag; boostExecutionDuration++; if (boostExecutionDuration >= maximumBoostExecutionDuration) { boostExecutionDuration = 0; avatar.broom.isBoosting = false; angularVelocity = 0; return glide(); } float angle = Mathf.SmoothDampAngle(currentAngle, targetAngle, ref angularVelocity, boostRotationDuration, maximumRotationSpeed, deltaTime); var rotation = Quaternion.Euler(0, 0, angle); var targetVelocity = (Vector2)(rotation * Vector2.right * currentVelocity.magnitude); var velocity = targetVelocity; return (velocity, angle, avatar.physics.facing); } (Vector2, float, int) glide() { float angle = Mathf.SmoothDampAngle(currentAngle, targetAngle, ref angularVelocity, rotationDuration, maximumRotationSpeed, deltaTime); var rotation = Quaternion.Euler(0, 0, angle); var velocityRotation = AngleUtil.DirectionalRotation(currentVelocity); float alignment = AngleUtil.Alignment(rotation, velocityRotation); float alignDuration = GetAlignDuration(alignment); var targetVelocity = rotation * Vector2.right * currentVelocity.magnitude; avatar.physics.drag = GetDrag(alignment); avatar.broom.isAligned = alignment > requiredAlignment; avatar.broom.isDiving = currentVelocity.y < requiredYSpeed; bool intendsBoost = targetAngle <= 180; if (intendsBoost) { if (avatar.broom.canBoost) { avatar.broom.canBoost = false; avatar.broom.isBoosting = true; maximumBoostExecutionDuration = Mathf.Abs(currentVelocity.y) * boostExecutionDurationMultiplier; onBoost.Invoke(avatar.gameObject); currentVelocity += currentVelocity.normalized * boostExecutionSpeed; angularVelocity = 0; return boost(); } } else { if (avatar.broom.isAligned && avatar.broom.isDiving) { if (!avatar.broom.canBoost && boostGatheringDuration < minimumBoostGatheringDuration) { boostGatheringDuration += deltaTime; if (boostGatheringDuration >= minimumBoostGatheringDuration) { boostGatheringDuration = 0; avatar.broom.canBoost = true; } } } } var velocity = Vector2.SmoothDamp(currentVelocity, targetVelocity, ref acceleration, alignDuration, maximumGlideAcceleration, deltaTime); velocity += GetAcceleration(alignment) * Time.deltaTime * (Vector2)(rotation * Vector3.right); velocity += avatar.physics.gravityStep; return (velocity, angle, avatar.physics.facing); } return avatar.broom.isBoosting ? boost() : glide(); }); }
public void TestRoundAngle(float angle, int directions, float roundedAngle) { Assert.AreEqual(roundedAngle, AngleUtil.RoundAngle(angle, directions)); }