public override MovementCalculator CreateMovementCalculator(AvatarController avatar) { float angularVelocity = 0; return(deltaTime => { var velocityOrientation = new AvatarOrientation(avatar.physics.velocityAngle); var currentOrientation = new AvatarOrientation(avatar.physics.rotationAngle); var velocity = avatar.physics.velocity; var direction = avatar.intentions.intendedFlight == Vector2.zero ? avatar.physics.rotatedForward : avatar.intentions.intendedFlight.normalized; float angle = Vector2.SignedAngle(avatar.physics.forward, direction); if (!avatar.canFlyLooping) { //angle = Mathf.Clamp(angle, -90, 90); } var oldRotation = currentOrientation.rotation; currentOrientation.angle = Mathf.SmoothDampAngle(currentOrientation.angle, angle, ref angularVelocity, rotationDuration, maxRotationSpeed, deltaTime); // Gliding float alignment = AngleUtil.Alignment(velocityOrientation.rotation, currentOrientation.rotation); bool isAligned = alignment >= alignmentDeadZone; if (isAligned && Mathf.Abs(angularVelocity) > angularDeadZone) { velocity = velocity.magnitude * (currentOrientation.rotation * avatar.physics.forward).SwizzleXY(); avatar.broom.isBoosting = true; } else { avatar.broom.isBoosting = false; } // Drag avatar.physics.drag = GetDrag(alignment); velocity += avatar.physics.dragStep; // Gravity velocity += avatar.physics.gravityStep; // Thrust if (isAligned) { float thrustAcceleration = GetThrust(alignment); var thrustDirection = (currentOrientation.rotation * avatar.physics.forward).SwizzleXY(); velocity += thrustAcceleration * deltaTime * thrustDirection; } // Visuals avatar.broom.isAligned = isAligned; return (velocity, currentOrientation.angle, avatar.physics.facing); }); }
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 TestAlignment(float angleA, float angleB, float alignment) { Assert.AreEqual(alignment, AngleUtil.Alignment(Quaternion.Euler(0, 0, angleA), Quaternion.Euler(0, 0, angleB)), 0.001f); }