Advertisement
mvaganov

GravObject.cs

Jun 14th, 2017
205
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 20.51 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections.Generic;
  3.  
  4. /// <summary>Pull a MovingEntity (https://pastebin.com/xFUD4tk2) GameObject toward a Collider.
  5. /// Will work with a MeshCollider, but a SphereCollider or BoxCollider is optimal
  6. /// Latest version at: https://pastebin.com/...</summary>
  7. /// <description>MIT License - TL;DR - This code is free, don't bother me about it!</description>
  8. /// <author email="mvaganov@hotmail.com">Michael Vaganov</author>
  9. public class GravObject : GravSource {
  10.     #region public API
  11.     [Tooltip("If false, gravity will be based on the transform.position of this object, not it's collider")]
  12.     public bool useColliderGravity = true;
  13.  
  14.     public override Vector3 CalculateGravityDirectionFrom(Vector3 point) {
  15.         if(!useColliderGravity) { return (transform.position - point).normalized; }
  16.         Vector3 dir = Vector3.zero;
  17.         switch(colliderType) {
  18.         case ColliderType.box: {
  19.                 Vector3 p = NearestPointToBox(myCollider as BoxCollider, point);
  20.                 Vector3 delta = p - point;
  21.                 dir = delta.normalized;
  22.             }
  23.             break;
  24.         case ColliderType.mesh: {
  25.                 Vector3 normal;
  26.                 Vector3 p = nearestPointOnMeshCalculationObject.NearestPointTo(point, out normal);
  27.                 dir = (p - point).normalized;
  28.             }
  29.             break;
  30.         case ColliderType.sphere: {
  31.                 SphereCollider sc = myCollider as SphereCollider;
  32.                 Vector3 p = transform.position + sc.center;
  33.                 dir = (p - point).normalized;
  34.             }
  35.             break;
  36.         default:
  37.             dir = (transform.position - point).normalized;
  38.             break;
  39.         }
  40.         return dir;
  41.     }
  42.     public static Vector3 NearestPointToBox(BoxCollider box, Vector3 point) {
  43.         Transform t = box.transform;
  44.         Quaternion rot = t.rotation;
  45.         Vector3 delta = point - t.position;
  46.         Vector3 rotatedPoint = (Quaternion.Inverse(rot) * delta) + t.position;
  47.         t.rotation = Quaternion.identity;
  48.         Vector3 nearestPoint = box.ClosestPointOnBounds(rotatedPoint);
  49.         t.rotation = rot;
  50.         delta = nearestPoint - t.position;
  51.         delta = rot * delta;
  52.         nearestPoint = t.position + delta;
  53.         return nearestPoint;
  54.     }
  55.     #endregion
  56.     #region Calculate near-points
  57.     private enum ColliderType { none, mesh, box, sphere };
  58.     private ColliderType colliderType = ColliderType.none;
  59.     private Collider myCollider;
  60.     NearestPointOnMeshCalculationObject nearestPointOnMeshCalculationObject = null;
  61.  
  62.     public class NearestPointOnMeshCalculationObject {
  63.         Mesh mesh;
  64.         Vector3[] verts;
  65.         Vector3[] norms;
  66.         VertTriList vt;
  67.         KDTree kd;
  68.         Transform transform;
  69.  
  70.         public NearestPointOnMeshCalculationObject(GameObject go) {
  71.             transform = go.transform;
  72.             mesh = go.GetComponent<MeshFilter>().mesh;
  73.             verts = mesh.vertices;
  74.             norms = mesh.normals;
  75.             vt = new VertTriList(mesh);
  76.             kd = KDTree.MakeFromPoints(verts);
  77.         }
  78.         public Vector3 NearestVertexTo(Vector3 point) {
  79.             // convert point to local space
  80.             point = transform.InverseTransformPoint(point);
  81.             float minDistanceSqr = Mathf.Infinity;
  82.             Vector3 nearestVertex = Vector3.zero;
  83.             // scan all vertices to find nearest
  84.             foreach(Vector3 vertex in verts) {
  85.                 Vector3 diff = point-vertex;
  86.                 float distSqr = diff.sqrMagnitude;
  87.                 if(distSqr < minDistanceSqr) {
  88.                     minDistanceSqr = distSqr;
  89.                     nearestVertex = vertex;
  90.                 }
  91.             }
  92.             // convert nearest vertex back to world space
  93.             return transform.TransformPoint(nearestVertex);
  94.         }
  95.         public Vector3 NearestPointTo(Vector3 point, out Vector3 ptNormal) {
  96.             Vector3 objSpacePt = transform.InverseTransformPoint(point);
  97.             Vector3 meshPt = NearestPointOnMesh(objSpacePt, verts, kd, mesh.triangles, vt, out ptNormal);
  98.             Vector3 closest = transform.TransformPoint(meshPt);
  99.             ptNormal = transform.TransformVector(ptNormal).normalized;
  100.             return closest;
  101.         }
  102.         public Vector3 NearestPointTo(Vector3 point) {
  103.             Vector3 objSpacePt = transform.InverseTransformPoint(point);
  104.             Vector3 meshPt = NearestPointOnMesh(objSpacePt, verts, mesh.triangles, vt);
  105.             Vector3 closest = transform.TransformPoint(meshPt);
  106.             return closest;
  107.         }
  108.         public static float GetDistPointToLine(Vector3 origin, Vector3 direction, Vector3 point) {
  109.             Vector3 point2origin = origin - point;
  110.             Vector3 point2closestPointOnLine = point2origin - Vector3.Dot(point2origin, direction) * direction;
  111.             return point2closestPointOnLine.magnitude;
  112.         }
  113.         Vector3 NearestPointOnMesh(Vector3 pt, Vector3[] verts, KDTree vertProx, int[] tri, VertTriList vt, out Vector3 pointNormal) {
  114.             //  find nearest vertex (point must be on triangle useing this vertex if the mesh is convex)
  115.             int nearest = vertProx.FindNearest(pt);
  116.             pointNormal = Vector3.zero;
  117.             //  Get the list of triangles in which the nearest vert "participates".
  118.             int[] nearTris = vt[nearest];
  119.             Vector3 nearestPt = Vector3.zero;
  120.             float nearestSqDist = float.PositiveInfinity;
  121.             TriangleSection ts;
  122.             for(int i = 0; i < nearTris.Length; i++) {
  123.                 int triOff = nearTris[i] * 3;
  124.                 Vector3 a = verts[tri[triOff]], b = verts[tri[triOff + 1]], c = verts[tri[triOff + 2]];
  125.                 Vector3 possNearestPt = NearestPointOnTri(pt, a, b, c, out ts);
  126.                 float possNearestSqDist = (pt - possNearestPt).sqrMagnitude;
  127.                 if(possNearestSqDist < nearestSqDist) {
  128.                     nearestPt = possNearestPt;
  129.                     nearestSqDist = possNearestSqDist;
  130.                     switch(ts) {
  131.                     case TriangleSection.side_ab: {
  132.                             Vector3 norm1 = norms[tri[triOff+0]], norm2 = norms[tri[triOff+1]];
  133.                             pointNormal = (norm1+norm2)/2;
  134.                         }
  135.                         break;
  136.                     case TriangleSection.side_bc: {
  137.                             Vector3 norm1 = norms[tri[triOff+1]], norm2 = norms[tri[triOff+2]];
  138.                             pointNormal = (norm1+norm2)/2;
  139.                         }
  140.                         break;
  141.                     case TriangleSection.side_ca: {
  142.                             Vector3 norm1 = norms[tri[triOff+2]], norm2 = norms[tri[triOff+0]];
  143.                             pointNormal = (norm1+norm2)/2;
  144.                         }
  145.                         break;
  146.                     case TriangleSection.surface: {
  147.                             Vector3 AB = b - a, AC = c - a;
  148.                             pointNormal = Vector3.Normalize(Vector3.Cross(AB, AC));
  149.                         }
  150.                         break;
  151.                     }
  152.                 }
  153.             }
  154.             return nearestPt;
  155.         }
  156.         /// <summary>easier if we don't need to get the normal!</summary>
  157.         Vector3 NearestPointOnMesh(Vector3 pt, Vector3[] verts, int[] tri, VertTriList vt) {
  158.             //  find nearest vertex (point must be on triangle useing this vertex if the mesh is convex)
  159.             int nearest = -1;
  160.             float nearestSqDist = float.PositiveInfinity;
  161.             for(int i = 0; i < verts.Length; i++) {
  162.                 float sqDist = (verts[i] - pt).sqrMagnitude;
  163.                 if(sqDist < nearestSqDist) {
  164.                     nearest = i;
  165.                     nearestSqDist = sqDist;
  166.                 }
  167.             }
  168.             //  Get the list of triangles in which the nearest vert "participates".
  169.             int[] nearTris = vt[nearest];
  170.             Vector3 nearestPt = Vector3.zero;
  171.             nearestSqDist = float.PositiveInfinity;
  172.             TriangleSection ts;
  173.             for(int i = 0; i < nearTris.Length; i++) {
  174.                 int triOff = nearTris[i] * 3;
  175.                 Vector3 a = verts[tri[triOff]];
  176.                 Vector3 b = verts[tri[triOff + 1]];
  177.                 Vector3 c = verts[tri[triOff + 2]];
  178.                 Vector3 possNearestPt = NearestPointOnTri(pt, a, b, c, out ts);
  179.                 float possNearestSqDist = (pt - possNearestPt).sqrMagnitude;
  180.                 if(possNearestSqDist < nearestSqDist) {
  181.                     nearestPt = possNearestPt;
  182.                     nearestSqDist = possNearestSqDist;
  183.                 }
  184.             }
  185.             return nearestPt;
  186.         }
  187.  
  188.         public enum TriangleSection { unknown, surface, side_ab, side_bc, side_ca };
  189.         /// <param name="ptNormal">Point normal. If on the triangle surface, returns the surface normal</param>
  190.         public Vector3 NearestPointOnTri(Vector3 pt, Vector3 a, Vector3 b, Vector3 c, out TriangleSection pointDetail) {
  191.             pointDetail = TriangleSection.unknown;
  192.             Vector3 edge1 = b - a;
  193.             Vector3 edge2 = c - a;
  194.             Vector3 edge3 = c - b;
  195.             float edge1Len = edge1.magnitude;
  196.             float edge2Len = edge2.magnitude;
  197.             float edge3Len = edge3.magnitude;
  198.             Vector3 ptLineA = pt - a;
  199.             Vector3 ptLineB = pt - b;
  200.             Vector3 ptLineC = pt - c;
  201.             Vector3 xAxis = edge1 / edge1Len;
  202.             Vector3 zAxis = Vector3.Cross(edge1, edge2).normalized;
  203.             Vector3 yAxis = Vector3.Cross(zAxis, xAxis);
  204.             Vector3 edge1Cross = Vector3.Cross(edge1, ptLineA);
  205.             Vector3 edge2Cross = Vector3.Cross(edge2, -ptLineC);
  206.             Vector3 edge3Cross = Vector3.Cross(edge3, ptLineB);
  207.             bool edge1On = Vector3.Dot(edge1Cross, zAxis) > 0f;
  208.             bool edge2On = Vector3.Dot(edge2Cross, zAxis) > 0f;
  209.             bool edge3On = Vector3.Dot(edge3Cross, zAxis) > 0f;
  210.             //  If the point is inside the triangle then return its coordinate.
  211.             if(edge1On && edge2On && edge3On) {
  212.                 pointDetail = TriangleSection.surface;
  213.                 float xExtent = Vector3.Dot(ptLineA, xAxis);
  214.                 float yExtent = Vector3.Dot(ptLineA, yAxis);
  215.                 return a + xAxis * xExtent + yAxis * yExtent;
  216.             }
  217.             //  Otherwise, the nearest point is somewhere along one of the edges.
  218.             Vector3 edge1Norm = xAxis;
  219.             Vector3 edge2Norm = edge2.normalized;
  220.             Vector3 edge3Norm = edge3.normalized;
  221.             float edge1Ext = Mathf.Clamp(Vector3.Dot(edge1Norm, ptLineA), 0f, edge1Len);
  222.             float edge2Ext = Mathf.Clamp(Vector3.Dot(edge2Norm, ptLineA), 0f, edge2Len);
  223.             float edge3Ext = Mathf.Clamp(Vector3.Dot(edge3Norm, ptLineB), 0f, edge3Len);
  224.             Vector3 edge1Pt = a + edge1Ext * edge1Norm;
  225.             Vector3 edge2Pt = a + edge2Ext * edge2Norm;
  226.             Vector3 edge3Pt = b + edge3Ext * edge3Norm;
  227.             float sqDist1 = (pt - edge1Pt).sqrMagnitude;
  228.             float sqDist2 = (pt - edge2Pt).sqrMagnitude;
  229.             float sqDist3 = (pt - edge3Pt).sqrMagnitude;
  230.             if(sqDist1 < sqDist2) {
  231.                 if(sqDist1 < sqDist3) {
  232.                     pointDetail = TriangleSection.side_ab;
  233.                     return edge1Pt;
  234.                 } else {
  235.                     pointDetail = TriangleSection.side_bc;
  236.                     return edge3Pt;
  237.                 }
  238.             } else if(sqDist2 < sqDist3) {
  239.                 pointDetail = TriangleSection.side_ca;
  240.                 return edge2Pt;
  241.             } else {
  242.                 pointDetail = TriangleSection.side_bc;
  243.                 return edge3Pt;
  244.             }
  245.         }
  246.     }
  247.     #endregion // Calculate near-points
  248.     #region VertTriList
  249.     //  lookup table for a mesh identifying which vertexes reference which triangles
  250.     public class VertTriList {
  251.         public int[][] list;
  252.         public int[] aliases;
  253.  
  254.         //  Indexable - use "vertTri[i]" to get the list of triangles for vertex i.
  255.         public int[] this[int index] {
  256.             get { return list[aliases[index]]; }
  257.         }
  258.         public VertTriList(int[] tri, Vector3[] verts) { Init(tri, verts); }
  259.         public VertTriList(Mesh mesh) { Init(mesh.triangles, mesh.vertices); }
  260.         public void Init(int[] tri, Vector3[] verts) {
  261.             int numVerts = verts.Length;
  262.             // find duplicate verts, since many meshes are created with dups for rendering purposes
  263.             List<int>[] duplicates = new List<int>[verts.Length];
  264.             // create an alias table, so duplicate vertexes can point to the same triangles
  265.             aliases = new int[verts.Length];
  266.             for(int i = 0; i < duplicates.Length; ++i) { duplicates[i] = new List<int>(); }
  267.             for(int i = 0; i < verts.Length; ++i) {
  268.                 for(int j = i + 1; j < verts.Length; ++j) {
  269.                     if(verts[i] == verts[j]) {
  270.                         if(!duplicates[i].Contains(j)) duplicates[i].Add(j);
  271.                         if(!duplicates[j].Contains(i)) duplicates[j].Add(i);
  272.                     }
  273.                 }
  274.             }
  275.             // sort duplicates, so the earliest verts are first, and add that as an aliases
  276.             for(int i = 0; i < duplicates.Length; ++i) {
  277.                 duplicates[i].Sort();
  278.                 aliases[i] = (duplicates[i].Count>0) ? Mathf.Min(i, duplicates[i][0]) : i;
  279.             }
  280.             // go through the triangles, keeping a count of how many times each vert is used
  281.             int[] counts = new int[numVerts];
  282.             for(int i = 0; i < tri.Length; i++) { counts[tri[i]]++; }
  283.             // merge aliases into earliest counts
  284.             for(int i = 0; i < aliases.Length; ++i) {
  285.                 if(aliases[i] < i) {
  286.                     int earliestIndex = aliases[i];
  287.                     counts[earliestIndex] += counts[i];
  288.                     counts[i] = 0;
  289.                 }
  290.             }
  291.             // initialise empty jagged array with appropriate number of elements for each vert.
  292.             list = new int[numVerts][];
  293.             for(int i = 0; i < counts.Length; i++) {
  294.                 if(counts[i] > 0) { list[i] = new int[counts[i]]; }
  295.             }
  296.             // assign appropriate triangle number each time given vert is encountered in triangles list
  297.             for(int i = 0; i < tri.Length; i++) {
  298.                 int vert = tri[i];
  299.                 vert = aliases[vert]; // take aliases into account
  300.                 list[vert][--counts[vert]] = i / 3;
  301.             }
  302.         }
  303.     }
  304.     #endregion // VertTriList
  305.     #region KDTree
  306.     // KDTree.cs - A Stark, September 2009.
  307.     //  This class implements a data structure that stores a list of points in space.
  308.     //  A common task in game programming is to take a supplied point and discover which
  309.     //  of a stored set of points is nearest to it. For example, in path-plotting, it is often
  310.     //  useful to know which waypoint is nearest to the player's current
  311.     //  position. The kd-tree allows this "nearest neighbour" search to be carried out quickly,
  312.     //  or at least much more quickly than a simple linear search through the list.
  313.     //  At present, the class only allows for construction (using the MakeFromPoints static method)
  314.     //  and nearest-neighbour searching (using FindNearest). More exotic kd-trees are possible, and
  315.     //  this class may be extended in the future if there seems to be a need.
  316.     //  nearest-neighbour search returns integer index
  317.     public class KDTree {
  318.         public KDTree[] lr;
  319.         public Vector3 pivot;
  320.         public int pivotIndex, axis;
  321.         //  faster if 2, for X,Y search
  322.         const int numDims = 3;
  323.  
  324.         public KDTree() { lr = new KDTree[2]; }
  325.         //  Make a new tree from a list of points.
  326.         public static KDTree MakeFromPoints(params Vector3[] points) {
  327.             int[] indices = Iota(points.Length);
  328.             return MakeFromPointsInner(0, 0, points.Length - 1, points, indices);
  329.         }
  330.         //  Recursively build a tree by separating points at plane boundaries.
  331.         static KDTree MakeFromPointsInner(int depth, int stIndex, int enIndex, Vector3[] points, int[] inds) {
  332.             KDTree root = new KDTree();
  333.             root.axis = depth % numDims;
  334.             int splitPoint = FindPivotIndex(points, inds, stIndex, enIndex, root.axis);
  335.             root.pivotIndex = inds[splitPoint];
  336.             root.pivot = points[root.pivotIndex];
  337.             int leftEndIndex = splitPoint - 1;
  338.             if(leftEndIndex >= stIndex) {
  339.                 root.lr[0] = MakeFromPointsInner(depth + 1, stIndex, leftEndIndex, points, inds);
  340.             }
  341.             int rightStartIndex = splitPoint + 1;
  342.             if(rightStartIndex <= enIndex) {
  343.                 root.lr[1] = MakeFromPointsInner(depth + 1, rightStartIndex, enIndex, points, inds);
  344.             }
  345.             return root;
  346.         }
  347.         static void SwapElements(int[] arr, int a, int b) {
  348.             int temp = arr[a];
  349.             arr[a] = arr[b];
  350.             arr[b] = temp;
  351.         }
  352.         //  Simple "median of three" heuristic to find a reasonable splitting plane.
  353.         static int FindSplitPoint(Vector3[] points, int[] inds, int stIndex, int enIndex, int axis) {
  354.             float a = points[inds[stIndex]][axis];
  355.             float b = points[inds[enIndex]][axis];
  356.             int midIndex = (stIndex + enIndex) / 2;
  357.             float m = points[inds[midIndex]][axis];
  358.             if(a > b) {
  359.                 if(m > a) { return stIndex; }
  360.                 if(b > m) { return enIndex; }
  361.                 return midIndex;
  362.             } else {
  363.                 if(a > m) { return stIndex; }
  364.                 if(m > b) { return enIndex; }
  365.                 return midIndex;
  366.             }
  367.         }
  368.         //  a new pivot index from range by splitting points falling at either side of its plane.
  369.         public static int FindPivotIndex(Vector3[] points, int[] inds, int stIndex, int enIndex, int axis) {
  370.             int splitPoint = FindSplitPoint(points, inds, stIndex, enIndex, axis);
  371.             // int splitPoint = Random.Range(stIndex, enIndex);
  372.             Vector3 pivot = points[inds[splitPoint]];
  373.             SwapElements(inds, stIndex, splitPoint);
  374.             int currPt = stIndex + 1;
  375.             int endPt = enIndex;
  376.             while(currPt <= endPt) {
  377.                 Vector3 curr = points[inds[currPt]];
  378.                 if((curr[axis] > pivot[axis])) {
  379.                     SwapElements(inds, currPt, endPt);
  380.                     endPt--;
  381.                 } else {
  382.                     SwapElements(inds, currPt - 1, currPt);
  383.                     currPt++;
  384.                 }
  385.             }
  386.             return currPt - 1;
  387.         }
  388.         public static int[] Iota(int num) {
  389.             int[] result = new int[num];
  390.             for(int i = 0; i < num; i++) { result[i] = i; }
  391.             return result;
  392.         }
  393.         //  Find the nearest point in the set to the supplied point.
  394.         public int FindNearest(Vector3 pt) {
  395.             float bestSqDist = float.PositiveInfinity;
  396.             int bestIndex = -1;
  397.             Search(pt, ref bestSqDist, ref bestIndex);
  398.             return bestIndex;
  399.         }
  400.         //  Recursively search the tree.
  401.         void Search(Vector3 pt, ref float bestSqSoFar, ref int bestIndex) {
  402.             float mySqDist = (pivot - pt).sqrMagnitude;
  403.             if(mySqDist < bestSqSoFar) {
  404.                 bestSqSoFar = mySqDist;
  405.                 bestIndex = pivotIndex;
  406.             }
  407.             float planeDist = pt[axis] - pivot[axis]; //DistFromSplitPlane(pt, pivot, axis);
  408.             int selector = planeDist <= 0 ? 0 : 1;
  409.             if(lr[selector] != null) {
  410.                 lr[selector].Search(pt, ref bestSqSoFar, ref bestIndex);
  411.             }
  412.             selector = (selector + 1) % 2;
  413.             float sqPlaneDist = planeDist * planeDist;
  414.             if((lr[selector] != null) && (bestSqSoFar > sqPlaneDist)) {
  415.                 lr[selector].Search(pt, ref bestSqSoFar, ref bestIndex);
  416.             }
  417.         }
  418.         //  Get a point's distance from an axis-aligned plane.
  419.         float DistFromSplitPlane(Vector3 pt, Vector3 planePt, int axis) {
  420.             return pt[axis] - planePt[axis];
  421.         }
  422.         //  Simple output of tree structure - mainly useful for getting a rough
  423.         //  idea of how deep the tree is (and therefore how well the splitting
  424.         //  heuristic is performing).
  425.         public string Dump(int level) {
  426.             string result = pivotIndex.ToString().PadLeft(level) + "\n";
  427.             if(lr[0] != null) { result += lr[0].Dump(level + 2); }
  428.             if(lr[1] != null) { result += lr[1].Dump(level + 2); }
  429.             return result;
  430.         }
  431.     }
  432.     #endregion // KDTree
  433.     #region MonoBehaviour
  434.     void Start() {
  435.         myCollider = GetComponent<Collider>();
  436.         if(myCollider is BoxCollider) { colliderType = ColliderType.box; } else if(myCollider is SphereCollider) { colliderType = ColliderType.sphere; } else if(myCollider is MeshCollider) {
  437.             nearestPointOnMeshCalculationObject = new NearestPointOnMeshCalculationObject(gameObject);
  438.             colliderType = ColliderType.mesh;
  439.         }
  440.     }
  441.     #endregion // MonoBehaviour
  442. }
  443.  
  444. #region Base GravitySource
  445. public class GravSource : MonoBehaviour {
  446.     [Tooltip("apply gravity if player hits this collider")]
  447.     public bool entangleOnCollision = true;
  448.     [Tooltip("apply gravity if player enters this collider trigger")]
  449.     public bool entangleOnTrigger = true;
  450.     [Tooltip("apply gravity power on player")]
  451.     public bool forceGravitypower = false;
  452.     [Tooltip("How much acceleration to apply to the PlayerControl, if gravity power is forced")]
  453.     public float power = 9.81f;
  454.  
  455.     public virtual Vector3 CalculateGravityDirectionFrom(Vector3 point) {
  456.         Vector3 delta = transform.position - point;
  457.         return delta.normalized;
  458.     }
  459.     public void OnCollisionEnter(Collision col) {
  460.         if(!enabled) return;
  461.         if(entangleOnCollision) { EntanglePlayer(col.gameObject.GetComponent<MovingEntity>()); }
  462.     }
  463.     public void OnTriggerEnter(Collider col) {
  464.         if(!enabled) return;
  465.         if(entangleOnTrigger) { EntanglePlayer(col.GetComponent<MovingEntity>()); }
  466.     }
  467.     public void EntanglePlayer(MovingEntity p) {
  468.         if(p && p.gravityApplication != MovingEntity.GravityState.none) {
  469.             GravPuller gp = p.gameObject.GetComponent<GravPuller>();
  470.             if(!gp) { gp = p.gameObject.AddComponent<GravPuller>(); }
  471.             if(gp.gravitySource != this) { gp.Init(this); } else { gp.Refresh(); }
  472.         }
  473.     }
  474. }
  475. #endregion // Base GravitySource
  476.  
  477. #region Gravity Puller (additional script for MovingEntity)
  478. public class GravPuller : MonoBehaviour {
  479.     public GravSource gravitySource;
  480.     private GravSource lastGravitySource;
  481.     private float timeOfLastSource;
  482.     private MovingEntity p;
  483.     [Tooltip("If true, will re-orient velocity to match any changes to gravity. useful for making tight video-gamey motion on small gravity wells.")]
  484.     public bool velocityFollowsGravity = true;
  485.  
  486.     public void Init(GravSource gs) {
  487.         if(gs != this && (gs != lastGravitySource || Time.time > timeOfLastSource+1)) {
  488.             timeOfLastSource = Time.time;
  489.             lastGravitySource = gravitySource;
  490.             gravitySource = gs;
  491.             p = GetComponent<MovingEntity>();
  492.             Refresh();
  493.         }
  494.     }
  495.     public void Refresh() {
  496.         if(p.gravityApplication == MovingEntity.GravityState.none) return;
  497.         Vector3 nextDir = gravitySource.CalculateGravityDirectionFrom(transform.position);
  498.         Rigidbody rb = p.rb;
  499.         if(velocityFollowsGravity && nextDir != p.gravity.dir && rb != null) {
  500.             Vector3 localVelocity = p.transform.InverseTransformDirection(rb.velocity);
  501.             float angle = Vector3.Angle(nextDir, p.gravity.dir);
  502.             Vector3 axis = Vector3.Cross(p.gravity.dir, nextDir).normalized;
  503.             Quaternion q = Quaternion.AngleAxis(angle, axis);
  504.             p.transform.rotation = Quaternion.LookRotation(q*transform.forward, q*transform.up);
  505.             rb.velocity = p.transform.TransformDirection (localVelocity);
  506.         }
  507.         p.gravity.dir = nextDir;
  508.         if (gravitySource.forceGravitypower) {
  509.             p.gravity.power = gravitySource.power;
  510.         }
  511.     }
  512.     void FixedUpdate() { Refresh(); }
  513.     public Vector3 PullAsIfFrom(Vector3 alternateLocation) {
  514.         return gravitySource.CalculateGravityDirectionFrom(alternateLocation);
  515.     }
  516. }
  517. #endregion // Gravity Puller (additional script for MovingEntity)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement