using System; using System.Collections.Generic; using Passer.LinearAlgebra; namespace RoboidControl { /// /// A thing is the primitive building block /// [Serializable] public class Thing { #region Types #endregion Types #region Properties public delegate void ChangeHandler(); public delegate void SphericalHandler(Spherical v); public delegate void ThingHandler(Thing t); /// /// The participant to which this thing belongs /// public RemoteParticipant owner; /// /// The network ID of this thing. /// public byte networkId; /// /// The ID of this thing /// public byte id; /// /// Predefined thing types /// public enum Type { Undetermined, // Sensor Switch, DistanceSensor, DirectionalSensor, TemperatureSensor, TouchSensor, // Motor ControlledMotor, UncontrolledMotor, Servo, // Other Roboid, Humanoid, ExternalSensor }; /// /// The type of this thing. This can be either a Thing::Type (needs casting) /// or a byte value for custom types. /// public byte type; /// /// Event which is triggered when the parent changes /// public event ChangeHandler OnParentChanged = delegate { }; private Thing _parent; /// /// The parent of this thing /// public Thing parent { get => _parent; set { if (_parent == value) return; if (value == null) { _parent?.RemoveChild(this); _parent = null; } else { value.AddChild(this); OnParentChanged?.Invoke(); } } } /// /// Attach a thing as a child of this thing /// /// The thing to attach as a child public void AddChild(Thing child) { if (children.Find(thing => thing == child) != null) return; child._parent = this; children.Add(child); } /// /// Remove the given thing as a child of this thing /// /// The child to remove public void RemoveChild(Thing child) { children.Remove(child); } /// /// The list of children of this thing /// [NonSerialized] public List children = new List(); /// /// Event which is triggered when the name changes /// public event ChangeHandler OnNameChanged = delegate { }; private string _name = ""; /// /// The name of the thing /// public virtual string name { get => _name; set { if (_name != value) { _name = value; OnNameChanged?.Invoke(); } } } /// /// An URL pointing to the location where a model of the thing can be found /// public string modelUrl = ""; /// /// Event triggered when the position has changed /// public event ChangeHandler OnPositionChanged = delegate { }; private Spherical _position = Spherical.zero; /// /// The position of the thing in local space, in meters. /// public Spherical position { get { return _position; } set { if (_position != value) { _position = value; OnPositionChanged?.Invoke(); } } } public bool hasPosition = false; /// /// Event triggered when the orientation has changed /// public event ChangeHandler OnOrientationChanged = delegate { }; private SwingTwist _orientation = SwingTwist.zero; /// /// The orientation of the thing in local space /// public SwingTwist orientation { get { return _orientation; } set { if (_orientation != value) { _orientation = value; OnOrientationChanged?.Invoke(); } } } /// /// Event triggered when the linear velocity has changed /// public event SphericalHandler OnLinearVelocityChanged = delegate { }; private Spherical _linearVelocity = Spherical.zero; /// /// The linear velocity of the thing in local space in meters per second /// public Spherical linearVelocity { get => _linearVelocity; set { if (_linearVelocity != value) { _linearVelocity = value; OnLinearVelocityChanged?.Invoke(_linearVelocity); } } } /// /// The angular velocity of the thing in local space /// public Spherical angularVelocity = Spherical.zero; #if UNITY_5_3_OR_NEWER /// /// A reference to the representation of the thing in Unity /// [NonSerialized] public Unity.Thing component = null; #endif #endregion Properties #region Init /// /// Create a new thing for the given participant /// /// The participant for which this thing is created /// True when a new thing event should be triggered public Thing(RemoteParticipant participant, bool invokeEvent = false) { this.owner = participant; if (invokeEvent) InvokeNewThing(this); } /// /// Create a new thing for the given participant /// /// The participant for which this thing is created /// The network ID of the thing /// The ID of the thing /// The type of thing public Thing(RemoteParticipant participant, byte networkId, byte thingId, byte thingType = 0) { this.owner = participant; this.id = thingId; this.type = thingType; this.networkId = networkId; } /// /// Function which can be used to create components in external engines. /// /// Currently this is used to create GameObjects in Unity public virtual void CreateComponent() { #if UNITY_5_3_OR_NEWER this.component = Unity.Thing.Create(this); this.component.core = this; #endif } #endregion Init #region Update #if UNITY_5_3_OR_NEWER /// /// Convience function for use in Unity which removes the need for a currentTime argument /// public void Update() { Update((ulong)UnityEngine.Time.time * 1000); } #endif /// /// Update this thing /// /// The current time in milliseconds public virtual void Update(ulong currentTime) { // should recurse over children... } /// /// Function used to generate binary data for this thing /// /// a byte array with the binary data /// @sa Passer::RoboidControl::BinaryMsg public virtual byte[] GenerateBinary() { return new byte[0]; } /// /// Function used to process binary data received for this thing /// /// The binary data public virtual void ProcessBinary(byte[] bytes) { } #endregion Update /// /// Event triggered when a new thing has been created /// public static event ThingHandler OnNewThing = delegate { }; /// /// Trigger the creation for the given thing /// /// The created thing public static void InvokeNewThing(Thing thing) { OnNewThing?.Invoke(thing); } /// /// Check if the thing has the given properaties /// /// The thing to check /// The network ID to compare to /// The thing ID to compare to /// True when the thing has the given properties public static bool IsThing(Thing thing, byte networkId, byte thingId) { if (thing == null) return false; return (thing.networkId == networkId) && (thing.id == thingId); } } }