|
@@ -3,196 +3,172 @@ using System.Collections;
|
|
|
using System.Collections.Generic;
|
|
|
using System.Linq;
|
|
|
using UnityEngine;
|
|
|
+using UnityEngine.EventSystems;
|
|
|
+using UnityEngine.Serialization;
|
|
|
using Valve.VR.InteractionSystem;
|
|
|
|
|
|
-public enum Controller
|
|
|
-{
|
|
|
- Sensors,
|
|
|
- SpeedSensorOnly,
|
|
|
- Keyboard,
|
|
|
- KeyboardSpeedPolarSteer
|
|
|
-}
|
|
|
|
|
|
public class BicycleController : MonoBehaviour
|
|
|
{
|
|
|
- [Header("GameObjects")] public GameObject rearWheel;
|
|
|
+ [Header("Visible Game Objects")] public GameObject rearWheel;
|
|
|
public GameObject frontWheel;
|
|
|
public GameObject crank;
|
|
|
-
|
|
|
- public GameObject bike;
|
|
|
-
|
|
|
- //public GameObject pedalL;
|
|
|
- //public GameObject pedalR;
|
|
|
+ public GameObject pedalL;
|
|
|
+ public GameObject pedalR;
|
|
|
public GameObject fork;
|
|
|
- public Transform centerOfMass;
|
|
|
+ public GameObject bike;
|
|
|
|
|
|
- [Header("Configuration")] public Controller controller = Controller.Sensors;
|
|
|
+ [Header("Game Objects for Physics")] public Transform centerOfMass;
|
|
|
+ [FormerlySerializedAs("rb")] public Rigidbody rigidBody;
|
|
|
+ public WheelConfig wheelConfig;
|
|
|
|
|
|
- [Header("Values")] public float oneRotationSpeed = 2.7f;
|
|
|
+ [Header("Values")] public float offsetCollidersFromWheel = 0.25f;
|
|
|
+ public float oneRotationSpeed = 2.7f;
|
|
|
public float crankMultiplier = 2f;
|
|
|
- public List<AxleInfo> axleInfos;
|
|
|
public float maxMotorTorque = 1000;
|
|
|
public float maxSteeringAngle = 5f;
|
|
|
[Range(0, 1)] public float relativeLeanAmount = 0.01f;
|
|
|
- public Transform leftWheels;
|
|
|
- public Transform rightWheels;
|
|
|
|
|
|
- private float currentSteerAngle = 0f;
|
|
|
- private float desiredSpeed = 0f;
|
|
|
- private float currentLeaningAngle = 0f;
|
|
|
- public float rotSpeed = 10;
|
|
|
+ private WheelCollider[] allWheelColliders;
|
|
|
+
|
|
|
+
|
|
|
+ public float CurrentSteerAngle { get; set; } = 0f;
|
|
|
+
|
|
|
+ public float CurrentMotorTorque { get; set; } = 0f;
|
|
|
+
|
|
|
+ public float CurrentBrakeTorque { get; set; } = 0f;
|
|
|
+
|
|
|
+ public float CurrentLeaningAngle { get; set; } = 0f;
|
|
|
+
|
|
|
|
|
|
- private Vector3[] wheelPositions;
|
|
|
- public Rigidbody rb;
|
|
|
private Quaternion startForkRot;
|
|
|
private Vector3 upDirection = Vector3.up;
|
|
|
|
|
|
private float calculatedWheelSpeed;
|
|
|
+ private float initialWheelColliderY;
|
|
|
|
|
|
- private float currentMotorTorque;
|
|
|
|
|
|
- private readonly float maxSpeed = 11.111f;
|
|
|
+ private void OnGUI()
|
|
|
+ {
|
|
|
+ GUI.TextField(new Rect(300, 10, 700, 40),
|
|
|
+ $"Motor Torque = {CurrentMotorTorque}; Brake Torque = {CurrentBrakeTorque}; Leaning Angle = {CurrentLeaningAngle}; Steering Angle = {CurrentSteerAngle}");
|
|
|
|
|
|
+ }
|
|
|
|
|
|
// Start is called before the first frame update
|
|
|
void Start()
|
|
|
{
|
|
|
- //rb = GetComponent<Rigidbody>();
|
|
|
- rb.centerOfMass = centerOfMass.localPosition;
|
|
|
- //startForkRot = fork.transform.localRotation;
|
|
|
- wheelPositions = new Vector3[axleInfos.Count];
|
|
|
- for (int i = 0; i < axleInfos.Count; i++)
|
|
|
- {
|
|
|
- wheelPositions[i] = axleInfos[i].wheel.center;
|
|
|
- }
|
|
|
- }
|
|
|
+ rigidBody.centerOfMass = centerOfMass.localPosition;
|
|
|
+ allWheelColliders = wheelConfig.AllWheels;
|
|
|
+ wheelConfig.AdjustToGameObjects(frontWheel.transform, rearWheel.transform, offsetCollidersFromWheel);
|
|
|
+ initialWheelColliderY = allWheelColliders[0].transform.localPosition.y;
|
|
|
|
|
|
- private void OnGUI()
|
|
|
- {
|
|
|
- GUI.TextField(new Rect(114, 10, 280, 20),
|
|
|
- $"Wanted speed {(desiredSpeed * 3.6):n2} km/h; Current Speed {(rb.velocity.magnitude * 3.6):n2}");
|
|
|
+ //startForkRot = fork.transform.localRotation; wheelPositions = new Vector3[wheelColliders.Count];
|
|
|
}
|
|
|
|
|
|
- // Update is called once per frame
|
|
|
void Update()
|
|
|
{
|
|
|
- if (controller == Controller.Keyboard || controller == Controller.KeyboardSpeedPolarSteer)
|
|
|
- {
|
|
|
- desiredSpeed = Input.GetAxis("Vertical") * 4.3333f;
|
|
|
- }
|
|
|
-
|
|
|
- if (controller == Controller.Keyboard)
|
|
|
- {
|
|
|
- currentSteerAngle = Input.GetAxis("Horizontal") * maxSteeringAngle;
|
|
|
- }
|
|
|
-
|
|
|
RotateMeshes();
|
|
|
//RotateFork();
|
|
|
- Debug.Log("rotation: " + currentSteerAngle);
|
|
|
+ Debug.Log("rotation: " + CurrentSteerAngle);
|
|
|
}
|
|
|
|
|
|
|
|
|
- public void FixedUpdate()
|
|
|
+ void FixedUpdate()
|
|
|
{
|
|
|
- ApplyWheelForce();
|
|
|
+ ApplyColliderForces();
|
|
|
Lean();
|
|
|
//RotateStraight();
|
|
|
}
|
|
|
|
|
|
- void RotateMeshes()
|
|
|
- {
|
|
|
- //RotateObject(crank, 1);
|
|
|
- //RotateObject(pedalL, -1);
|
|
|
- //RotateObject(pedalR, -1);
|
|
|
- RotateObject(rearWheel, crankMultiplier);
|
|
|
- RotateObject(frontWheel, crankMultiplier);
|
|
|
- }
|
|
|
-
|
|
|
- void RotateFork()
|
|
|
- {
|
|
|
- fork.transform.localRotation = startForkRot;
|
|
|
- fork.transform.RotateAround(fork.transform.position, fork.transform.up, maxSteeringAngle * currentSteerAngle);
|
|
|
- }
|
|
|
-
|
|
|
- void Lean()
|
|
|
+ private void ApplyColliderForces()
|
|
|
{
|
|
|
- upDirection = Vector3.Normalize(Vector3.up + transform.right *
|
|
|
- (maxSteeringAngle * relativeLeanAmount * currentSteerAngle * rb.velocity.magnitude) / 100);
|
|
|
+ ControlSteer(new[] {wheelConfig.frontLeft, wheelConfig.frontRight});
|
|
|
+ ControlTorque(new[] {wheelConfig.rearLeft, wheelConfig.rearRight});
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- void ApplyWheelForce()
|
|
|
+ private void ControlSteer(IEnumerable<WheelCollider> colliders)
|
|
|
{
|
|
|
- ControlSteer(axleInfos.Where(a => a.steering).Select(a => a.wheel));
|
|
|
- ControlTorque(axleInfos.Where(a => a.motor).Select(a => a.wheel));
|
|
|
+ //float steering = maxSteeringAngle * CurrentSteerAngle * 0.2f;
|
|
|
+ //leftWheels.localPosition = -Vector3.up * (relativeLeanAmount * CurrentSteerAngle * rigidBody.velocity.magnitude * 0.2f);
|
|
|
+ //rightWheels.localPosition = Vector3.up * (relativeLeanAmount * CurrentSteerAngle * rigidBody.velocity.magnitude * 0.2f);
|
|
|
+ colliders.ForEach(c => c.steerAngle = CurrentSteerAngle);
|
|
|
}
|
|
|
|
|
|
- private void ControlSteer(IEnumerable<WheelCollider> colliders)
|
|
|
+ private void ControlTorque(IEnumerable<WheelCollider> colliders)
|
|
|
{
|
|
|
- float steering = maxSteeringAngle * currentSteerAngle * 0.2f;
|
|
|
- leftWheels.localPosition = -Vector3.up * (relativeLeanAmount * currentSteerAngle * rb.velocity.magnitude * 0.2f);
|
|
|
- rightWheels.localPosition = Vector3.up * (relativeLeanAmount * currentSteerAngle * rb.velocity.magnitude * 0.2f);
|
|
|
- colliders.ForEach(c => c.steerAngle = steering);
|
|
|
+ foreach (var c in colliders)
|
|
|
+ {
|
|
|
+ c.motorTorque = CurrentMotorTorque;
|
|
|
+ c.brakeTorque = CurrentBrakeTorque;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- private void ControlTorque(IEnumerable<WheelCollider> colliders)
|
|
|
+ private void Lean()
|
|
|
{
|
|
|
- var currentSpeed = rb.velocity.magnitude;
|
|
|
- var speedDif = desiredSpeed - currentSpeed;
|
|
|
- var ratio = speedDif / maxSpeed;
|
|
|
- var torque = maxMotorTorque * ratio;
|
|
|
- if (speedDif >= .1f) // 0.36 km/h
|
|
|
+ //reset all wheels to being centered
|
|
|
+ if (CurrentLeaningAngle == 0) //TODO: maybe add a threshold for leaning, e.g. < -0.05 and > 0.05
|
|
|
{
|
|
|
- Debug.Log($"SpeedDif = {speedDif} -> applying Torque {torque} (Ratio: {ratio})");
|
|
|
- colliders.ForEach(c =>
|
|
|
- {
|
|
|
- c.brakeTorque = 0;
|
|
|
- c.motorTorque = torque;
|
|
|
- });
|
|
|
+ //leaning left, left wheels up, right wheels down
|
|
|
+ ApplyOffsetToTransform(wheelConfig.frontLeft.transform, initialWheelColliderY);
|
|
|
+ ApplyOffsetToTransform(wheelConfig.rearLeft.transform, initialWheelColliderY);
|
|
|
+ ApplyOffsetToTransform(wheelConfig.frontRight.transform, initialWheelColliderY);
|
|
|
+ ApplyOffsetToTransform(wheelConfig.rearRight.transform, initialWheelColliderY);
|
|
|
}
|
|
|
- else if (speedDif <= -.1f)
|
|
|
+ //CurrentLeaningAngle < 0 -> leaning left, > 0 -> right
|
|
|
+ var leaningAbs = Mathf.Abs(CurrentLeaningAngle * Mathf.Deg2Rad);
|
|
|
+
|
|
|
+ //calculate offset for wheels; description Docu folder
|
|
|
+ //1.57079633 rad = 90 deg
|
|
|
+ var verticalOffset = offsetCollidersFromWheel * Mathf.Sin(leaningAbs) / Mathf.Sin(1.57079633f - leaningAbs);
|
|
|
+ var yPlusOffset = initialWheelColliderY + verticalOffset;
|
|
|
+ var yMinusOffset = initialWheelColliderY - verticalOffset;
|
|
|
+
|
|
|
+ if (CurrentLeaningAngle < 0) //TODO: maybe add a threshold for leaning, e.g. < -0.05 and > 0.05
|
|
|
{
|
|
|
- Debug.Log($"SpeedDif = {speedDif} -> applying brake Torque {torque} (Ratio: {ratio})");
|
|
|
- colliders.ForEach(c =>
|
|
|
- {
|
|
|
- c.motorTorque = 0;
|
|
|
- c.brakeTorque = -torque;
|
|
|
- });
|
|
|
+ //leaning left, left wheels up, right wheels down
|
|
|
+ ApplyOffsetToTransform(wheelConfig.frontLeft.transform, yPlusOffset);
|
|
|
+ ApplyOffsetToTransform(wheelConfig.rearLeft.transform, yPlusOffset);
|
|
|
+ ApplyOffsetToTransform(wheelConfig.frontRight.transform, yMinusOffset);
|
|
|
+ ApplyOffsetToTransform(wheelConfig.rearRight.transform, yMinusOffset);
|
|
|
+ }
|
|
|
+ else if (CurrentLeaningAngle > 0)
|
|
|
+ {
|
|
|
+ //leaning right, right wheels up, left wheels down
|
|
|
+ ApplyOffsetToTransform(wheelConfig.frontLeft.transform, yMinusOffset);
|
|
|
+ ApplyOffsetToTransform(wheelConfig.rearLeft.transform, yMinusOffset);
|
|
|
+ ApplyOffsetToTransform(wheelConfig.frontRight.transform, yPlusOffset);
|
|
|
+ ApplyOffsetToTransform(wheelConfig.rearRight.transform, yPlusOffset);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-
|
|
|
- public void SetSpeed(float speed)
|
|
|
+ private void ApplyOffsetToTransform(Transform t, float newY)
|
|
|
{
|
|
|
- if (controller == Controller.Keyboard || controller == Controller.KeyboardSpeedPolarSteer) return;
|
|
|
- desiredSpeed = speed;
|
|
|
+ var oldPos = t.localPosition;
|
|
|
+ t.localPosition = new Vector3(oldPos.x, newY, oldPos.z);
|
|
|
}
|
|
|
|
|
|
- public void SetLeaningAngle(float angle)
|
|
|
+ private void RotateMeshes()
|
|
|
{
|
|
|
- if (controller == Controller.Keyboard) return;
|
|
|
- currentLeaningAngle = angle;
|
|
|
+ //RotateObject(crank, 1);
|
|
|
+ //RotateObject(pedalL, -1);
|
|
|
+ //RotateObject(pedalR, -1);
|
|
|
+ RotateObject(rearWheel, crankMultiplier);
|
|
|
+ RotateObject(frontWheel, crankMultiplier);
|
|
|
}
|
|
|
|
|
|
- public void SetSteeringAngle(float angle)
|
|
|
+ private void RotateFork()
|
|
|
{
|
|
|
- if (controller == Controller.Keyboard || controller == Controller.SpeedSensorOnly) return;
|
|
|
- currentSteerAngle = angle;
|
|
|
+ fork.transform.localRotation = startForkRot;
|
|
|
+ fork.transform.RotateAround(fork.transform.position, fork.transform.up, maxSteeringAngle * CurrentSteerAngle);
|
|
|
}
|
|
|
|
|
|
+
|
|
|
//rotates the meshes
|
|
|
void RotateObject(GameObject obj, float multiplier)
|
|
|
{
|
|
|
- obj.transform.Rotate(Time.deltaTime * rb.velocity.magnitude * (360f / oneRotationSpeed) * multiplier, 0, 0);
|
|
|
+ obj.transform.Rotate(Time.deltaTime * rigidBody.velocity.magnitude * (360f / oneRotationSpeed) * multiplier, 0,
|
|
|
+ 0);
|
|
|
//obj.transform.Rotate(Time.deltaTime * rotSpeed * (360f / oneRotationSpeed) * multiplier, 0, 0);
|
|
|
}
|
|
|
-
|
|
|
-
|
|
|
- [System.Serializable]
|
|
|
- public class AxleInfo
|
|
|
- {
|
|
|
- public WheelCollider wheel;
|
|
|
- public bool motor; // is this wheel attached to motor?
|
|
|
- public bool steering; // does this wheel apply steer angle?
|
|
|
- }
|
|
|
}
|