using UnityEngine; namespace NanoBrain.Unity.Braitenberg { /// /// A powered wheel collider, controlled by a NanoBrain::Neuron /// [RequireComponent(typeof(WheelCollider))] public class Motor : MonoBehaviour { /// /// The name of the NanoBrain::Neuron to control this wheel /// /// This is used to connect the motor to the right output neuron of the Vehicle::brain [Tooltip("The name of the Nanobrain Neuron to control this wheel")] public string outputNeuronName; /// /// The speed of the motor in rotations per second /// [Tooltip("The speed of the motor in rotations per second")] public float speed { get; protected set; } /// /// The maximum torque used to drive the wheel collider /// [Tooltip("The maximum torque used to drive the wheel collider")] public float maxTorque = 1; /// /// The wheel collider used to drive the car /// /// \see [Unity WheelCollider](https://docs.unity3d.com/ScriptReference/WheelCollider.html) [Tooltip("The wheel collider used to drive the car")] public WheelCollider wheelCollider; /// /// The NanoBrain::Neuron to control this wheel /// [Tooltip("The NanoBrain Neuron to control this wheel")] public Neuron motorNeuron; /// /// Unity calls Awake when loading an instance of a script component. /// protected virtual void Awake() { wheelCollider = GetComponent(); GetMotorNeuron(); } /// /// Retrieve the motor neuron from the outputNeuronName; /// private void GetMotorNeuron() { if (motorNeuron != null) return; Vehicle vehicle = GetComponentInParent(); if (vehicle == null) return; Cluster brain = vehicle.brain; if (brain != null) motorNeuron = brain.GetNeuron(outputNeuronName); } /// /// Update called at regular, fixed intervals as part of Unity's physics update loop. /// void FixedUpdate() { if (motorNeuron == null) return; this.speed = motorNeuron.outputValue.z; Debug.DrawRay(this.transform.position, this.transform.forward * this.speed, Color.blue); float desiredRpm = speed * 60; // target wheel RPM float currentRpm = wheelCollider.rpm; float rpmError = desiredRpm - currentRpm; float kP = 0.02f; // proportional gain float torque = wheelCollider.motorTorque + kP * rpmError; wheelCollider.motorTorque = Mathf.Clamp(torque, -maxTorque, maxTorque); } } }