Simplified SeekSteer and made my own script for moving objects between waypoints. The MovingPlatform now works much better.
/** * Attach to object. Moves object between waypoints. */ using UnityEngine; using System.Collections; public class WaypointsMover : MonoBehaviour { public Transform[] waypoints; public float waypointRadius = 1.0f; public bool loop = true; public float speed = 2.0f; private Vector3 currentHeading,targetHeading; private int targetwaypoint; private Transform _transform; protected void Start () { enabled = false; _transform = transform; if(waypoints.Length <= 0) { Debug.Log("No waypoints on " + name); enabled = false; } targetwaypoint = 0; } protected void Update() { if(Vector3.Distance(_transform.position, waypoints[targetwaypoint].position) <= waypointRadius) { targetwaypoint++; if(targetwaypoint >= waypoints.Length) { targetwaypoint = 0; if(!loop) enabled = false; } } _transform.position = Vector3.MoveTowards(_transform.position, waypoints[targetwaypoint].position, Time.deltaTime * speed); } // Draws red line between waypoints, and sphere with radius public void OnDrawGizmos() { if(waypoints == null) return; for(int i=0;i< waypoints.Length;i++) { Gizmos.color = new Color(0.9f, 0, 0, 0.3f); Gizmos.DrawSphere(waypoints[i].position, waypointRadius); Gizmos.color = Color.red; Vector3 pos = waypoints[i].position; if(i>0) { Vector3 prev = waypoints[i-1].position; Gizmos.DrawLine(prev,pos); } } } }
So I wanted to use an interface reference as a public variable, but it wouldn’t show up in the inspector. After many hours researching and trying different things, I finally settled for using abstract classes instead, and using the unity way of adding scripts to objects as my interface.
I made a pad with a button on it. This button is my switch. When something (player or box) moves onto it, it should trigger an event in another target object. So I wanted to have a SwitchTrigger interface for the target of my switch object.
class TargetObject : MonoBehaviour, ISwitchTrigger { ... void OnSwitchTrigger(bool on) { // This object has been turned on/off. } }
What I did instead was the following:
/* This should have been an interface, but Unity don't * allow interface objects as public references in the gui. * */ using UnityEngine; public abstract class SwitchTriggerTarget : MonoBehaviour { public abstract void OnTriggerSwitch(bool on); }
Then I have to create an explicit class inheriting this abstract class for the specific GameObject I want it on.
public class MovingPlatformTriggerTarget : SwitchTriggerTarget { public override void OnTriggerSwitch(bool on) { Debug.Log("Platform got trigger=" + on); GetComponent<SeekSteer>().enabled = on; } }
I then add the script SwitchTriggerTarget to my MovingPlatform object.
MovingPlatform object also has a MovingPlatform script, which basically just makes sure other objects on MovingPlatform object follows it when it moves. This is done by parenting.
public class MovingPlatform: MonoBehaviour { // TODO: Add objects on platform to an array. // Save old parent on enter, reattach old parent on exit. void OnTriggerEnter(Collider other) { other.transform.parent = gameObject.transform; } void OnTriggerExit(Collider other) { other.transform.parent = null; } }
The platform movement is done by another script. Just add the modules you want onto the GameObject, and then make a prefab of it. Modular and nice.
Now, my SwitchPad (the one you walk on to trigger the button), looks like this.
public class SwitchTrigger : MonoBehaviour { public SwitchTriggerTarget triggerObject; public AnimationClip onClip; public AnimationClip offClip; private int cnt; void Awake() { cnt = 0; if (onClip) GetComponent<Animation>().AddClip(onClip, "on"); if (offClip) GetComponent<Animation>().AddClip(offClip, "off"); } void OnTriggerEnter(Collider other) { cnt++; if (cnt == 1) { // Send trigger message to linked object. if (triggerObject) { triggerObject.OnTriggerSwitch(true); } else { Debug.Log("No trigger object attached."); } // Play on animation, if available. if (onClip) GetComponent<Animation>().Play("on"); } } void OnTriggerExit(Collider other) { cnt--; if (cnt == 0) { // Send trigger message to linked object. if (triggerObject) triggerObject.OnTriggerSwitch(false); // Play off animation, if available. if (offClip) GetComponent<Animation>().Play("off"); } } }
The highlighted row: By using the abstract class as the type, only GameObjects with scripts inheriting from SwitchTarget, like MovablePlatformSwitchTarget, can be dragged onto the target in the inspector.
This works, but everything would have been easier if an interface could be used as type and shown in inspector…
Recent Comments