# GravityObject.cs

May 15th, 2017
729
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
1. using UnityEngine;
2. using System.Collections.Generic;
3.
4. /// <summary>Pull a PlayerControl (https://pastebin.com/9M9qyBmP) GameObject toward a Collider.
5. /// Will work with a MeshCollider, but a SphereCollider or BoxCollider is optimal
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 GravityObject : GravitySource {
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]) {
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
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
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 GravitySource : 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<PlayerControl>()); }
462.     }
463.     public void OnTriggerEnter(Collider col) {
464.         if(entangleOnTrigger) { EntanglePlayer(col.GetComponent<PlayerControl>()); }
465.     }
466.     public void EntanglePlayer(PlayerControl p) {
467.         if(p && p.gravityApplication != PlayerControl.GravityState.none) {
468.             GravityPuller gp = p.gameObject.GetComponent<GravityPuller>();
469.             if(!gp) { gp = p.gameObject.AddComponent<GravityPuller>(); }
470.             if(gp.gravitySource != this) { gp.Init(this); } else { gp.Refresh(); }
471.         }
472.     }
473. }
474. #endregion // Base GravitySource
475.
476. #region Gravity Puller (additional script for PlayerControl)
477. public class GravityPuller : MonoBehaviour {
478.     public GravitySource gravitySource;
479.     private GravitySource lastGravitySource;
480.     private float timeOfLastSource;
481.     private PlayerControl p;
482.     [Tooltip("If true, will re-orient velocity to match any changes to gravity. useful for making tight video-gamey motion on small gravity wells.")]
483.     public bool velocityFollowsGravity = true;
484.
485.     public void Init(GravitySource gs) {
486.         if(gs != this && (gs != lastGravitySource || Time.time > timeOfLastSource+1)) {
487.             timeOfLastSource = Time.time;
488.             lastGravitySource = gravitySource;
489.             gravitySource = gs;
490.             p = GetComponent<PlayerControl>();
491.             Refresh();
492.         }
493.     }
494.     public void Refresh() {
495.         Vector3 nextDir = gravitySource.CalculateGravityDirectionFrom(transform.position);
496.         Rigidbody rb = p.rb;
497.         if(velocityFollowsGravity && nextDir != p.gravity.dir && rb != null) {
498.             Vector3 localVelocity = p.transform.InverseTransformDirection(rb.velocity);
499.             float angle = Vector3.Angle(nextDir, p.gravity.dir);
500.             Vector3 axis = Vector3.Cross(p.gravity.dir, nextDir).normalized;
501.             Quaternion q = Quaternion.AngleAxis(angle, axis);
502.             p.transform.rotation = Quaternion.LookRotation(q*transform.forward, q*transform.up);
503.             rb.velocity = p.transform.TransformDirection (localVelocity);
504.         }
505.         p.gravity.dir = nextDir;
506.         if (gravitySource.forceGravitypower) {
507.             p.gravity.power = gravitySource.power;
508.         }
509.     }
510.     void FixedUpdate() { Refresh(); }
511.     public Vector3 PullAsIfFrom(Vector3 alternateLocation) {
512.         return gravitySource.CalculateGravityDirectionFrom(alternateLocation);
513.     }
514. }
515. #endregion // Gravity Puller (additional script for PlayerControl)