using UnityEngine; using System.Collections; using System.Collections.Generic; using System; [Serializable] public class GravityRayConfig{ public float radius = 0.5f; public float length = 5.0f; public float tileLength = 3.0f; public static bool operator==(GravityRayConfig c1, GravityRayConfig c2){ return c1.radius == c2.radius && c1.length == c2.length && c1.tileLength == c2.tileLength; } public static bool operator!=(GravityRayConfig c1, GravityRayConfig c2){ return c1.radius != c2.radius || c1.length != c2.length || c1.tileLength != c2.tileLength; } public void AssignFrom(GravityRayConfig other){ radius = other.radius; length = other.length; tileLength = other.tileLength; } } [ExecuteInEditMode] public class GravityRayBody : MonoBehaviour { public GravityRayConfig config; private GravityRayConfig lastConfig = new GravityRayConfig(); private const string rayObjectName = "Beam"; public Material beamMaterial; GameObject ray = null; List capturedObjects = new List(); public float centeringForce = 0.5f; public float dragForce = 0.5f; // Use this for initialization void Start () { RebuildRay (); lastConfig = config; } void RebuildRay(){ lastConfig.AssignFrom (config); if (ray == null) { ray = AdvancedUtils.FindChild(gameObject, rayObjectName); } if (ray == null) { ray = AdvancedUtils.CreateMeshObject(rayObjectName); ray.transform.parent = transform; ray.transform.localPosition = Vector3.zero; ray.transform.localRotation = Quaternion.identity; ray.transform.localScale = Vector3.one; } CapsuleCollider c = gameObject.GetComponent (); if (c == null) { c = gameObject.AddComponent(); } c.center = new Vector3 (0, config.length * 0.5f, 0); c.radius = config.radius; c.height = config.length; c.direction = 1; c.isTrigger = true; var mf = ray.GetComponent (); var m = mf.sharedMesh; Vector3[] vertices; Vector3[] normals; int[] indices; Vector2[] uvs; AdvancedUtils.GenerateCylinder (config.radius, config.length, 33, 1,2, config.length / config.tileLength, out vertices, out indices, out uvs, out normals); m.vertices = vertices; m.SetIndices (indices, MeshTopology.Triangles, 0); m.normals = normals; m.uv = uvs; m.RecalculateBounds (); ray.renderer.sharedMaterial = beamMaterial; } // Update is called once per frame void FixedUpdate () { if (ray != null) { ray.transform.Rotate (Vector3.up, Time.deltaTime * -90.0f); } if(lastConfig != config){ RebuildRay(); } foreach (var obj in capturedObjects) { Vector3 a; Vector3 b; GetCylinderPoints(out a, out b); Vector3 n = (b - a).normalized; Vector3 p = AdvancedMath.LineNearestPoint(a, b, obj.transform.position); Vector3 centeringDir = (p - obj.transform.position).normalized; //Debug.Log(centeringDir); obj.rigidbody.velocity += centeringDir * centeringForce * Time.deltaTime; float forwardSpeed = Vector3.Dot(n, obj.rigidbody.velocity); float diff = dragForce - forwardSpeed; obj.rigidbody.velocity += n * dragForce * Time.deltaTime * 0.9f * diff; //obj.rigidbody.velocity =obj.rigidbody.velocity * 0.9f * Time.deltaTime + centeringDir * centeringForce * Time.deltaTime + n * dragForce * Time.deltaTime; } } void GetCylinderPoints(out Vector3 a, out Vector3 b){ a = ray.transform.position; b = ray.transform.position + ray.transform.up * config.length; } void OnTriggerEnter(Collider other){ if (other.rigidbody!= null && !other.rigidbody.isKinematic && !capturedObjects.Contains (other.gameObject)) { capturedObjects.Add(other.gameObject); other.rigidbody.useGravity = false; other.rigidbody.velocity = Vector3.zero; Debug.Log("Beam captured object: " + other.name); } } void OnTriggerExit(Collider other){ if (capturedObjects.Contains (other.gameObject)) { capturedObjects.Remove(other.gameObject); other.rigidbody.useGravity = true; Debug.Log("Beam lost object: " + other.name); } } void OnDrawGizmos(){ if(lastConfig != config){ RebuildRay(); } if(ray != null){ Vector3 a; Vector3 b; GetCylinderPoints(out a, out b); Gizmos.DrawWireSphere(a, 0.2f); Gizmos.DrawWireSphere(b, 0.2f); } } }