using System; using System.Collections.Generic; using Controller.Bicycle; using UnityEngine; namespace Animation { #region Helpers public enum WheelRotationDirection { Forward, Backward } [Serializable] public struct WheelAnimationConfig { public GameObject wheel; public Axis rotationAxis; public WheelRotationDirection rotationDirection; } #endregion [RequireComponent(typeof(IBicycleController))] public class BikeAnimation : MonoBehaviour { // Start is called before the first frame update private void Start() { bicycleController = GetComponentInParent(); initialPositions[crankSet] = crankSet.gameObject.transform.localPosition; initialPositions[fork] = fork.gameObject.transform.localPosition; initialRotations[crankSet] = crankSet.gameObject.transform.localRotation; initialRotations[fork] = fork.gameObject.transform.localRotation; } private void Update() { var cadence = /*BikeSensorData.Instance.PowermeterData?.InstantaneousCadence ??*/ defaultCadence * bicycleController.CurrentSpeed / 8; //rpm*/ var cadenceAngle = cadence / 60 * 360 * Time.deltaTime; //rps * 360 deg for one round if (!pause) { RotateWheels(); RotateAroundDefinedAxis(fork, bicycleController.CurrentSteerAngle); //Debug.Log($"Rotate cranks with angle {cadenceAngle}"); RotateAroundDefinedAxis(crankSet, cadenceAngle, false); } } private void RotateWheels() { var speed = bicycleController.CurrentSpeed; var rps = speed / wheelCircumference; var angle = rps * Time.deltaTime * 360f; RotateSingleWheel(frontWheel, angle); RotateSingleWheel(rearWheel, angle); } private void RotateSingleWheel(WheelAnimationConfig wheel, float angle) { var t = wheel.wheel.transform; var oldPos = t.localPosition; var axis = wheel.rotationAxis; var backwards = wheel.rotationDirection == WheelRotationDirection.Backward; var directedAngle = backwards ? -angle : angle; Vector3 rotateAxis; if (axis == Axis.X) rotateAxis = t.right; else if (axis == Axis.Y) rotateAxis = t.up; else rotateAxis = t.forward; t.RotateAround(t.position, rotateAxis, directedAngle); t.localPosition = oldPos; } private void RotateAroundDefinedAxis(Rotatable rotatable, float angle, bool resetBeforeRotate = true) { if (resetBeforeRotate) { rotatable.gameObject.transform.localPosition = initialPositions[rotatable]; rotatable.gameObject.transform.localRotation = initialRotations[rotatable]; } if (Mathf.Abs(angle) <= 0.2f) return; Vector3 axis; if (rotatable.rotateAxis == RotateAxis.Up) axis = rotatable.rotateAround.up; else if (rotatable.rotateAxis == RotateAxis.Forward) axis = rotatable.rotateAround.forward; else axis = rotatable.rotateAround.right; //Debug.Log($"rotatable.rotateAround.position = {rotatable.rotateAround.position}"); //Debug.Log($"axis = {axis}"); //Debug.DrawLine(rotatable.rotateAround.position, rotatable.rotateAround.position+axis*5, Color.yellow); rotatable.gameObject.transform.RotateAround(rotatable.rotateAround.position, axis, angle); } //rotates the meshes private void RotateObject(GameObject obj, float multiplier) { obj.transform.Rotate( Time.deltaTime * bicycleController.CurrentSpeed * (360f / 12f) * multiplier, 0, 0); //obj.transform.Rotate(Time.deltaTime * rotSpeed * (360f / oneRotationSpeed) * multiplier, 0, 0); } #region Variables public bool pause; //TODO: remove, only for debugging purposes [Header("Wheels - rotating around center")] public WheelAnimationConfig rearWheel; public WheelAnimationConfig frontWheel; [Header("Other with defined rotation axis")] public Rotatable crankSet; public Rotatable fork; [Header("Parameters")] public float wheelCircumference = 2.096f; public float defaultCadence = 80; private IBicycleController bicycleController; private readonly Dictionary initialPositions = new Dictionary(); private readonly Dictionary initialRotations = new Dictionary(); #endregion } }