Пример #1
0
    public static bool PointOnPerimeter(Vector2[] shape, Vector2 point)
    {
        bool hit = false;

        for (int a = 0; a < shape.Length; a++)
        {
            int b = a + 1 < shape.Length ? a + 1 : 0;

            if (JelloVectorTools.CrossProduct(point - shape[a], shape[b] - shape[a]) == 0f)
            {
                if (
                    point.x > Mathf.Max(shape[b].x, shape[a].x) ||
                    point.x <Mathf.Min(shape[b].x, shape[a].x) ||
                             point.y> Mathf.Max(shape[b].y, shape[a].y) ||
                    point.y < Mathf.Min(shape[b].y, shape[a].y)
                    )
                {
                    continue;
                }

                hit = true;
            }
        }


        return(hit);
    }
    public void ChangePivot(JelloBody t)
    {
        t.polyCollider.points = JelloShapeTools.RemoveDuplicatePoints(t.polyCollider.points);

        t.Shape.changeVertices(t.polyCollider.points, t.Shape.InternalVertices);

        Vector2 diff = pivot;

        diff = new Vector2(diff.x / t.Scale.x, diff.y / t.Scale.y);
        diff = JelloVectorTools.rotateVector(diff, -t.Angle);


        if (t.meshLink != null)
        {
            MonoBehaviour monoBehavior;
            if (t.meshLink.UpdatePivotPoint(diff, out monoBehavior))
            {
                EditorUtility.SetDirty(monoBehavior);
            }
        }

        for (int i = 0; i < t.Shape.VertexCount; i++)
        {
            t.Shape.setVertex(i, t.Shape.getVertex(i) - diff);
        }

        t.polyCollider.points = t.Shape.EdgeVertices;

        t.transform.position += (Vector3)JelloVectorTools.rotateVector(new Vector2(diff.x * t.Scale.x, diff.y * t.Scale.y), t.Angle);
        if (t.transform.childCount > 0)
        {
            for (int i = 0; i < t.transform.childCount; i++)
            {
                t.transform.GetChild(i).position -= (Vector3)diff;
            }
        }

        if (t.JointCount > 0)
        {
            for (int i = 0; i < t.JointCount; i++)
            {
                t.GetJoint(i).localAnchorA -= diff;
            }
        }

        if (t.AttachPointCount > 0)
        {
            for (int i = 0; i < t.AttachPointCount; i++)
            {
                t.GetAttachPoint(i).point -= diff;
            }
        }

        t.updateGlobalShape(true);

        EditorUtility.SetDirty(t);

        pivot = Vector2.zero;
    }
Пример #3
0
    /// <summary>
    /// Accumulates the forces internal to the JelloPressureBody.
    /// Calculates forces from gas pressure.
    /// Base class will calculate internal, edge, and custom JelloSpring forces.
    /// This is called JelloWorld.Iterations times per Time.FixedUpdate by JelloWorld.update();
    /// </summary>
    /// <param name="deltaTime">Amount of time to calculate forces over.</param>
    public override void accumulateInternalForces(float deltaTime)
    {
        //spring forces calculated here
        base.accumulateInternalForces(deltaTime);
        // internal forces based on pressure equations.  we need 2 loops to do this.  one to find the overall volume of the
        // body, and 1 to apply forces.  we will need the normals for the edges in both loops, so we will cache them and remember them.
        int     j;
        Vector2 edge;
        Vector2 pressureV;

        mVolume = 0f;

        if (prevScale != Scale)
        {
            scaleRatio = Vector2.Distance(Vector2.zero, (Vector2)Scale) * 0.8761f;
            prevScale  = Scale;
        }

        // first calculate the volume of the body, and cache normals as we go.
        for (int i = 0; i < mEdgePointMasses.Length; i++)
        {
            j = i + 1 < mEdgePointMasses.Length ? i + 1 : 0;

            edge = JelloVectorTools.getPerpendicular(mEdgePointMasses[j].Position - mEdgePointMasses[i].Position);

            //cache edge length
            mEdgeLengthList[i] = Vector2.Distance(Vector2.zero, edge);             //TODO consider incorporating collision info class?

            // cache normal
            mNormalList[i] = edge;
            if (mEdgeLengthList[i] != 0f)
            {
                mNormalList[i] /= mEdgeLengthList[i];
            }

            if (Shape.winding == JelloClosedShape.Winding.CounterClockwise)
            {
                mNormalList[i] *= -1f;
            }

            // add to volume
            mVolume += 0.5f * (mEdgePointMasses[j].Position.x - mEdgePointMasses[i].Position.x) * (mEdgePointMasses[j].Position.y + mEdgePointMasses[i].Position.y);
        }

        mVolume        = Mathf.Abs(mVolume);
        mInverseVolume = 1 / mVolume;

        // now loop through, adding forces!
        for (int i = 0; i < mEdgePointMasses.Length; i++)
        {
            j = i + 1 < mEdgePointMasses.Length ? i + 1 : 0;

            pressureV = mNormalList[i] * mInverseVolume * mEdgeLengthList[i] * mGasAmount * scaleRatio;

            mEdgePointMasses[i].force += pressureV;
            mEdgePointMasses[j].force += pressureV;
        }
    }
    public void CenterPivot(JelloBody t)
    {
        Vector2 center = new Vector2();

        t.polyCollider.points = JelloShapeTools.RemoveDuplicatePoints(t.polyCollider.points);
        t.Shape.changeVertices(t.polyCollider.points, t.Shape.InternalVertices);


        center = JelloShapeTools.FindCenter(t.Shape.EdgeVertices);        //using vertices instead of collider.points because need of assigning entire array at once


        if (t.meshLink != null)
        {
            MonoBehaviour monoBehavior;
            if (t.meshLink.UpdatePivotPoint(center, out monoBehavior))
            {
                EditorUtility.SetDirty(monoBehavior);
            }
        }

        for (int i = 0; i < t.Shape.VertexCount; i++)
        {
            t.Shape.setVertex(i, t.Shape.getVertex(i) - center);
        }

        t.polyCollider.points = t.Shape.EdgeVertices;

        t.transform.position += (Vector3)JelloVectorTools.rotateVector(new Vector2(center.x * t.Scale.x, center.y * t.Scale.y), t.Angle);
        if (t.transform.childCount > 0)
        {
            for (int i = 0; i < t.transform.childCount; i++)
            {
                t.transform.GetChild(i).position -= (Vector3)center;
            }
        }

        if (t.JointCount > 0)
        {
            for (int i = 0; i < t.JointCount; i++)
            {
                t.GetJoint(i).localAnchorA -= center;
            }
        }

        if (t.AttachPointCount > 0)
        {
            for (int i = 0; i < t.AttachPointCount; i++)
            {
                t.GetAttachPoint(i).point -= center;
            }
        }

        t.updateGlobalShape(true);

        EditorUtility.SetDirty(t);

        pivot = Vector2.zero;
    }
Пример #5
0
	/// <summary>
	/// Initialize the MeshLink.
	/// </summary>
	/// <param name="forceUpdate">Whether to force an update to the MeshLink and MeshLink.LinkedMeshFilter.sharedMesh.</param>
	public override void Initialize(bool forceUpdate = false)
	{
		base.Initialize();

		meshLinkType = MeshLinkType.TextureMeshLink;

		if(texture == null)
		{
			Debug.LogWarning("No texture found. exiting operation.");
			return;
		}

		if(LinkedMeshRenderer.sharedMaterial == null)
			LinkedMeshRenderer.sharedMaterial = new Material(Shader.Find("Unlit/Texture"));
		
		if(LinkedMeshRenderer.sharedMaterial.mainTexture == null)
			LinkedMeshRenderer.sharedMaterial.mainTexture = texture;

		if(forceUpdate || LinkedMeshFilter.sharedMesh.vertexCount != body.Shape.VertexCount)
		{
			
			if(LinkedMeshFilter.sharedMesh.vertexCount != body.Shape.VertexCount)
				LinkedMeshFilter.sharedMesh.Clear();
			
			vertices = new Vector3[body.Shape.VertexCount];
			for(int i = 0; i < vertices.Length; i++)
				vertices[i] = (Vector3)body.Shape.getVertex(i);

			Vector2[] uvPts = new Vector2[body.Shape.VertexCount];

			for(int i= 0; i < uvPts.Length; i++)
			{
				uvPts[i] = body.Shape.getVertex(i) - pivotOffset;
				uvPts[i] = JelloVectorTools.rotateVector(uvPts[i], angle);
				uvPts[i] = new Vector2(uvPts[i].x / scale.x, uvPts[i].y / scale.y);
				uvPts[i] -= offset;
			}
		
			LinkedMeshFilter.sharedMesh.vertices = vertices;
			LinkedMeshFilter.sharedMesh.uv = uvPts;
			LinkedMeshFilter.sharedMesh.triangles = body.Shape.Triangles;

			if(CalculateNormals)
				LinkedMeshFilter.sharedMesh.RecalculateNormals();
			if(CalculateTangents)
				calculateMeshTangents();
			
			LinkedMeshFilter.sharedMesh.RecalculateBounds();
			var o_112_3_636507003832678496 = LinkedMeshFilter.sharedMesh;
			LinkedMeshFilter.sharedMesh.MarkDynamic();
		}
	}
Пример #6
0
    /// <summary>
    /// Get an array of vertices by transformin the local vertices by the given position, angle, and scale.
    /// Transformation is applied in the following order:  scale -> rotation -> position.
    /// </summary>
    /// <param name="position">The position transform vertices to.</param>
    /// <param name="angle">The angle (in degrees) to rotate the vertices to.</param>
    /// <param name="scale">The scale to transform the vertices by.</param>
    /// <param name="vertices">A new array of transformed vertices.</param>
    /// <param name="includeInternal">Whether to include JelloClosedShape.InternalVertices.</param>
    public void transformVertices(ref Vector2 position, ref float angle, ref Vector2 scale, ref Vector2[] vertices, bool includeInternal = false)
    {
        if (includeInternal)
        {
            if (vertices.Length != mEdgeVertices.Length + mInternalVertices.Length)
            {
                vertices = new Vector2[mEdgeVertices.Length + mInternalVertices.Length];
            }

            for (int i = 0; i < mEdgeVertices.Length; i++)
            {
                // rotate the point, and then translate.
                vertices[i].x = mEdgeVertices[i].x * scale.x;
                vertices[i].y = mEdgeVertices[i].y * scale.y;

                JelloVectorTools.rotateVector(ref vertices[i], angle);

                vertices[i] += position;
            }
            for (int i = 0; i < mInternalVertices.Length; i++)
            {
                // rotate the point, and then translate.
                vertices[mEdgeVertices.Length + i].x = mInternalVertices[i].x * scale.x;
                vertices[mEdgeVertices.Length + i].y = mInternalVertices[i].y * scale.y;

                JelloVectorTools.rotateVector(ref vertices[mEdgeVertices.Length + i], angle);

                vertices[mEdgeVertices.Length + i] += position;
            }
        }
        else
        {
            if (vertices.Length != mEdgeVertices.Length)
            {
                vertices = new Vector2[mEdgeVertices.Length];
            }

            for (int i = 0; i < mEdgeVertices.Length; i++)
            {
                // rotate the point, and then translate.
                vertices[i].x = mEdgeVertices[i].x * scale.x;
                vertices[i].y = mEdgeVertices[i].y * scale.y;

                JelloVectorTools.rotateVector(ref vertices[i], angle);

                vertices[i] += position;
            }
        }
    }
Пример #7
0
    /// <summary>
    /// Removes the points on perimeter.
    /// </summary>
    /// <returns>The points on perimeter.</returns>
    /// <param name="shape">Shape.</param>
    /// <param name="points">Points.</param>
    public static Vector2[] RemovePointsOnPerimeter(Vector2[] shape, Vector2[] points)
    {
        int num = 0;

        for (int i = 0; i < points.Length; i++)
        {
            if (points[i].x == Mathf.Infinity)
            {
                num++;
                continue;
            }

            for (int a = 0; a < shape.Length; a++)
            {
                int b = a + 1 < shape.Length ? a + 1 : 0;

                if (JelloVectorTools.CrossProduct(points[i] - shape[a], shape[b] - shape[a]) == 0f)
                {
                    if (
                        points[i].x > Mathf.Max(shape[b].x, shape[a].x) ||
                        points[i].x <Mathf.Min(shape[b].x, shape[a].x) ||
                                     points[i].y> Mathf.Max(shape[b].y, shape[a].y) ||
                        points[i].y < Mathf.Min(shape[b].y, shape[a].y)
                        )
                    {
                        continue;
                    }

                    points[i] = Vector2.one * Mathf.Infinity;
                    num++;
                    break;
                }
            }
        }

        Vector2[] returnPoints = new Vector2[points.Length - num];
        num = 0;
        for (int i = 0; i < points.Length; i++)
        {
            if (points[i].x != Mathf.Infinity)
            {
                returnPoints[num] = points[i];
                num++;
            }
        }

        return(returnPoints);
    }
	/// <summary>
	/// Checks if two convex shapes overlap.
	/// Requires ClockWise winding. 
	/// Uses separating axis theorem.
	/// </summary>
	/// <param name="shapeA">The first convex shape.</param>
	/// <param name="shapeB">The second convex shape.</param>
	/// <returns>Whether the two convex shapes overlap.</returns>
	/// 
	/// <dl class="example"><dt>Example</dt></dl>
	/// ~~~{.c}
	/// //keep moving a triangle to the right until it no longer overlaps another one
	/// Vector2[] triangleOne, triangleTwo;
	/// 
	/// while(JelloShapeTools.Intersect_SAT(triangleOne, triangleTwo)))
	/// {
	/// 	foreach(Vector2 v in triangleOne)
	/// 	{
	/// 		v += Vector2.Right;
	/// 	}
	/// }
	/// ~~~
	public static bool IntersectSAT(Vector2[] shapeA, Vector2[] shapeB)
	{		
		float maxA = 0f,
				minA = 0f,
				maxB = 0f,
				minB = 0f,
				p = 0f;
		
		Vector2 axis = Vector2.zero;
		
		//project shapes onto each axis and compare max/min
		for(int i = 0; i < shapeA.Length + shapeB.Length; i++)
		{
			if(i < shapeA.Length)
				axis = JelloVectorTools.getPerpendicular(shapeA[i + 1 < shapeA.Length ? i + 1 : 0] - shapeA[i]);
			else
				axis = JelloVectorTools.getPerpendicular(shapeB[i + 1 - shapeA.Length < shapeB.Length ? i + 1 - shapeA.Length : 0] - shapeB[i - shapeA.Length]);
			
			maxA = Vector2.Dot (shapeA[0], axis);
			minA = maxA;
			for(int a = 1; a < shapeA.Length; a++)
			{
				p = Vector2.Dot (shapeA[a], axis);
				
				if(p  > maxA)
					maxA = p;
				if(p < minA)
					minA = p;
			}
									
			maxB = Vector2.Dot(shapeB[0], axis);
			minB = maxB;
			for(int a = 1; a < shapeB.Length; a++)
			{
				p = Vector2.Dot (shapeB[a], axis);

				if(p  > maxB)
					maxB = p;
				if(p < minB)
					minB = p;
			}						
			
			if(maxA < minB || minA > maxB)
				return false;
		}
		
		return true;
	}
    /// <summary>
    /// Get an array of vertices by transformin the local vertices by the given position, angle, and scale.
    /// Transformation is applied in the following order:  scale -> rotation -> position.
    /// </summary>
    /// <param name="position">The position transform vertices to.</param>
    /// <param name="angle">The angle (in degrees) to rotate the vertices to.</param>
    /// <param name="scale">The scale to transform the vertices by.</param>
	/// <param name="includeInternal">Whether to include JelloClosedShape.InternalVertices.</param>
    /// <returns>A new array of transformed vertices.</returns>
    public Vector2[] transformVertices(Vector2 position, float angle, Vector2 scale, bool includeInternal = false)     
	{
		Vector2[] ret;

		if(includeInternal)
		{
			ret = new Vector2[mEdgeVertices.Length + mInternalVertices.Length];
			
			for (int i = 0; i < mEdgeVertices.Length; i++)
			{
				// rotate the point, and then translate.
				ret[i].x = mEdgeVertices[i].x * scale.x;
				ret[i].y = mEdgeVertices[i].y * scale.y;
				
				JelloVectorTools.rotateVector(ref ret[i], angle);
				
				ret[i] += position;
			}
			for(int i = 0; i < mInternalVertices.Length; i++)
			{
				ret[mEdgeVertices.Length + i].x = mInternalVertices[i].x * scale.x;
				ret[mEdgeVertices.Length + i].y = mInternalVertices[i].y * scale.y;

				JelloVectorTools.rotateVector(ref ret[mEdgeVertices.Length + i], angle);

				ret[mEdgeVertices.Length + i] += position;
			}
		}
		else
		{
			ret = new Vector2[mEdgeVertices.Length];
			
			for (int i = 0; i < mEdgeVertices.Length; i++)
			{
				// rotate the point, and then translate.
				ret[i].x = mEdgeVertices[i].x * scale.x;
				ret[i].y = mEdgeVertices[i].y * scale.y;
				
				JelloVectorTools.rotateVector(ref ret[i], angle);
				
				ret[i] += position;
			}
		}

        return ret;
    }
	/// <summary>
	/// Find the closest edge on shape to a given point.
	/// </summary>
	/// <param name="point">The point to find the closest edge to.</param>
	/// <param name="shape">The shape to test against.</param>
	/// <returns>The closest edge on shape as indices of the shape.</returns>
	public static int[] FindClosestEdgeOnShape(Vector2 point, Vector2[] shape)
	{
		float distance = Mathf.Infinity;
		int[] indices = new int[2];

		for(int i = 0; i < shape.Length; i++)
		{
			int next = i + 1 < shape.Length ? i + 1 : 0;

			Vector2 hit;
			float dist = JelloVectorTools.getClosestPointOnSegmentSquared(point, shape[i], shape[next], out hit);
			if(dist < distance)
			{
				distance = dist;
				indices[0] = i;
				indices[1] = next;
			}
		}
		return indices;
	}
Пример #11
0
	/// <summary>
	/// Initialize the SpriteMeshLink.
	/// </summary>
	/// <param name="forceUpdate">Whether to force an update to the MeshLink and MeshLink.LinkedMeshFilter.sharedMesh.</param>
	public override void Initialize(bool forceUpdate = false)
	{
		base.Initialize(forceUpdate);

		meshLinkType = MeshLinkType.SpriteMeshLink;

		if(sprites == null || sprites.Length == 0 || texture == null)
		{
			Debug.LogWarning("No sprites and/or texture found. exiting operation.");
			return;
		}

		if(LinkedMeshRenderer.sharedMaterial == null)
			LinkedMeshRenderer.sharedMaterial = new Material(Shader.Find("Sprites/Default"));
		
		if(LinkedMeshRenderer.sharedMaterial.mainTexture == null)
			LinkedMeshRenderer.sharedMaterial.mainTexture = texture;


		if(selectedSprite < 0 || selectedSprite >= sprites.Length)
			selectedSprite = 0;

		Sprite sprite = sprites[selectedSprite];

		if(sprite == null)
			return;

		if(forceUpdate || LinkedMeshFilter.sharedMesh.vertexCount != body.Shape.VertexCount)
		{

			if(LinkedMeshFilter.sharedMesh.vertexCount != body.Shape.VertexCount)
				LinkedMeshFilter.sharedMesh.Clear();

			vertices = new Vector3[body.Shape.VertexCount];
			for(int i = 0; i < vertices.Length; i++)
				vertices[i] = (Vector3)body.Shape.getVertex(i);
		
			Vector2 length = new Vector2(sprite.texture.width, sprite.texture.height);
			float pixelsToUnits = sprite.textureRect.width / sprite.bounds.size.x;
			length /= pixelsToUnits;

			Vector2[] uvPts = new Vector2[body.Shape.VertexCount];

			for(int i= 0; i < uvPts.Length; i++)
			{
				uvPts[i] = body.Shape.getVertex(i) - pivotOffset;
				uvPts[i] = JelloVectorTools.rotateVector(uvPts[i], angle);
				uvPts[i] = new Vector2(uvPts[i].x / scale.x, uvPts[i].y / scale.y);
				uvPts[i] = new Vector2(0.5f + uvPts[i].x / length.x, 0.5f + uvPts[i].y / length.y);
				uvPts[i] -= offset;
			}

			LinkedMeshFilter.sharedMesh.vertices = vertices;
			LinkedMeshFilter.sharedMesh.uv = uvPts;
			LinkedMeshFilter.sharedMesh.triangles = body.Shape.Triangles;
			LinkedMeshFilter.sharedMesh.colors = null;
			if(CalculateNormals)
				LinkedMeshFilter.sharedMesh.RecalculateNormals();
			if(CalculateTangents)
				calculateMeshTangents();

			LinkedMeshFilter.sharedMesh.RecalculateBounds();
			var o_174_3_636386045451834383 = LinkedMeshFilter.sharedMesh;
			LinkedMeshFilter.sharedMesh.MarkDynamic();
		}
	}
	/// <summary>
	/// Processes the pull.
	/// </summary>
	/// <returns>IEnumerator.</returns>
	IEnumerator ProcessPull()
	{
		//Grab the closest point mass and process adjacent points.
		GrabPointMass();

		//could be true later if you are still pulling the body, but do not have a specific point grabbed.
		//this would happen if when you are holding down the mouse button, its position is within the jello body.
		bool waitingForNewGrab = false;

		//keep processing the pull as long as the mouse button is depressed.
		while(Input.GetMouseButton(0))
		{
//			if(requireGrounded && !grounded)
//				break;

			//wake up the body if its being grabbed.
			body.IsAwake = true;

			//find the mouses current position in world space.
			mousePosInWorld = Camera.main.ScreenToWorldPoint(Input.mousePosition);

			//If our mouse position is outside of the body's transformed base shape
			if(!JelloShapeTools.Contains(body.Shape.EdgeVertices, body.transform.InverseTransformPoint(mousePosInWorld)))
			{
				//if our mouse position was inside of the base shape last step, grab a new point mass.
				if(waitingForNewGrab)
				{
					GrabPointMass();
					waitingForNewGrab = false;
				}

				//the base shape position (local and global) respective to the selected point mass.
				Vector2 pt = body.Shape.EdgeVertices[pmIndex];
				Vector2 ptGlobal = (Vector2)body.transform.TransformPoint(pt);

				//if we want the body to rotate to align with the pull
				if(rotate)
				{
					//find the difference in angle between the two vector
					Vector2 dir1 = mousePosInWorld - body.Position; 																						//body position to mouse position
					Vector2 dir2 = (Vector2)body.transform.TransformPoint(body.Shape.EdgeVertices[pmIndex]) - body.Position; 	//body position to xformed base shape position
					float ang = Vector2.Angle(dir1, dir2);

					//correct our body angle only a bit at a time for smooth rotations.
					ang = Mathf.Clamp(ang, 0f, ang * rotateSpeed * Time.fixedDeltaTime);
					
					if(JelloVectorTools.CrossProduct(dir1, dir2) < 0f)
						ang *=  -1f;
					body.Angle -= ang;
				}
				else
				{
					//we dont want the body to rotate to align and will constrain the point mass to a cone.

					//find the two shape positions next to our selected shape position.
					Vector2 prev = body.Shape.EdgeVertices[pmIndex > 0 ? pmIndex - 1 : body.Shape.EdgeVertexCount - 1];
					Vector2 next = body.Shape.EdgeVertices[pmIndex + 1 < body.Shape.EdgeVertexCount ? pmIndex + 1: 0];

					//vectors to/from adjacent ponts
					Vector2 fromPrev = pt - prev;
					Vector2 toNext = next - pt;
					//normal created by adjacent vectors
					//this is the bisector of the angle created by the prev to pt to next vectors
					//and will be used as the bisector of the constraining cone.
					Vector2 ptNorm = JelloVectorTools.getPerpendicular(fromPrev + toNext);
					//correct normal direction by shape winding.
					ptNorm = body.Shape.winding == JelloClosedShape.Winding.Clockwise ? ptNorm : -ptNorm;

					//convert to global coordinates
					ptNorm = (Vector2)body.transform.TransformDirection(ptNorm);
					//find the angle between the our mouse and the bisector.
					float ang = Vector2.Angle (ptNorm, mousePosInWorld - ptGlobal);

					//if we exceed the constraint of the cone.
					if(ang > coneAngle * 0.5f) //0.5 because the bisector cuts the cone angle in half.
					{
						//find the vector representing the edge of the cone
						Vector2 limitVector;
						if(JelloVectorTools.CrossProduct (ptNorm, mousePosInWorld - ptGlobal) < 0f )//which side of the bisector are we on
							limitVector = JelloVectorTools.rotateVector(ptNorm, -coneAngle * 0.5f);
						else
							limitVector = JelloVectorTools.rotateVector(ptNorm, coneAngle * 0.5f);

						//move our position to the closest point on the limit vector. Handle max pull back at the same time.
						mousePosInWorld = JelloVectorTools.getClosestPointOnSegment(mousePosInWorld, ptGlobal, ptGlobal + limitVector.normalized * maxPullBack);
					}
				}

				//how far away from xformed base shape position we are.
				pullBackDistance = (mousePosInWorld - ptGlobal).sqrMagnitude;
				if(pullBackDistance != 0f)
				{
					//if we exceed the max pullback, set to the max pullback.
					if(pullBackDistance > maxPullBack * maxPullBack)
					{
						mousePosInWorld = ptGlobal + (mousePosInWorld - ptGlobal).normalized * maxPullBack; // still do this when angle is not right.
						pullBackDistance = maxPullBack * maxPullBack;
					}
				}

				//explicitly set the selected pointmass position and velocity.
				pointmass.Position = mousePosInWorld;
				pointmass.velocity = Vector2.zero;	
			}
			else//our mouse is down, but is inside the perimeter of the body.
			{
				ReleasePointMass();//release the selected point mass and restore its ajacent point masses
				waitingForNewGrab = true;//wait for a new grab. would occur if the mouse was dragged outside of the body again. 
			}
				
			//keep the body still while being pulled.
			body.Position = position;

			//sync up with fixed update
			yield return new WaitForFixedUpdate();
		}

		//mouse button has been released!
		//release the selected point mass.
		ReleasePointMass();
		//release the body and apply force if we had a point mass selected at the time.
		ReleaseBody(!waitingForNewGrab);
	}
Пример #13
0
    /// <summary>
    /// Rebuild this JelloAttachPoint.
    /// </summary>
    /// <param name="attachPoint">The point (local to the JelloAttachPoint.body) at which to attach the JelloAttachPoint.AttachedTransform.</param>
    /// <param name="jelloBody">The JelloBody to to be attached to.</param>
    /// <param name="useBaseShape">Whether to use the  JelloBody.Shape positions (instead of JelloPointMass.Position) when building the JelloAttachPoint.</param>
    /// <param name="numLegs">Number of JelloPointMass objects to use as "legs" (use 1, 2, or 3).</param>
    public void Rebuild(Vector2 attachPoint, JelloBody jelloBody, bool useBaseShape = true, int numLegs = 0)
    {
        body      = jelloBody;
        transform = body.transform;

        if (numLegs != 0)
        {
            if (numLegs < 0)
            {
                numLegs = 1;
            }
            if (numLegs > 3)
            {
                numLegs = 3;
            }

            affectedIndices = new int[numLegs];
        }
        else if (affectedIndices == null || affectedIndices.Length == 0 || affectedIndices.Length > 3)
        {
            affectedIndices = new int[2];            //default to 3?
        }
        Vector2[] shape = new Vector2[body.Shape.VertexCount];
        if (useBaseShape)
        {
            for (int i = 0; i < shape.Length; i++)
            {
                shape[i] = body.Shape.getVertex(i);
            }
        }
        else
        {
            attachPoint = transform.TransformPoint(attachPoint);

            for (int i = 0; i < shape.Length; i++)
            {
                shape[i] = body.getPointMass(i).Position;
            }
        }

        if (affectedIndices.Length == 1)
        {
            affectedIndices = JelloShapeTools.GetClosestIndices(attachPoint, shape, 1);
            scalars         = new float[1];
            scalars[0]      = 1f;
        }
        else if (affectedIndices.Length == 2)
        {
            Vector2 hit;
            affectedIndices = JelloShapeTools.FindClosestEdgeOnShape(attachPoint, shape);
            scalars         = new float[2];
            JelloVectorTools.getClosestPointOnSegmentSquared(attachPoint, shape[affectedIndices[0]], shape[affectedIndices[1]], out hit, out scalars[1]);
            scalars[0] = 1 - scalars[1];
        }
        else if (affectedIndices.Length == 3)
        {
            Vector2[] shapePerimeter = new Vector2[body.EdgePointMassCount];
            if (useBaseShape)
            {
                shapePerimeter = body.Shape.EdgeVertices;
            }
            else
            {
                for (int i = 0; i < shapePerimeter.Length; i++)
                {
                    shapePerimeter[i] = body.getEdgePointMass(i).Position;
                }
            }

            affectedIndices = JelloShapeTools.FindContainingTriangle(attachPoint, shape, shapePerimeter, body.Shape.Triangles, out scalars);
        }

        point = Vector2.zero;
        for (int i = 0; i < affectedIndices.Length; i++)
        {
            point += shape[affectedIndices[i]] * scalars[i];
        }


        if (!useBaseShape)
        {
            point = transform.InverseTransformPoint(point);
        }

        if (mAttachedTransform != null)
        {
            Vector3 newPos = transform.TransformPoint(point);
            newPos.z = mAttachedTransform.position.z;
            mAttachedTransform.position = newPos;
        }
    }
Пример #14
0
    /// <summary>
    /// Merge two given shapes.
    /// Does not support holes. Only call this if you already know the to shapes overlap.
    /// </summary>
    /// <param name="shapeA">The first shape.</param>
    /// <param name="shapeB">The second shape.</param>
    /// <returns>The silhouette of the overlapping shapes.</returns>
    ///
    /// <dl class="example"><dt>Example</dt></dl>
    /// ~~~{.c}
    /// //combine terrain shape and tree shape into a single shape and draw a glow around the resulting shape
    /// Vector2[] terrainShape, treeShape;
    ///
    /// if(JelloShapeTools.Intersect(terrainShape, treeShape))
    /// {
    ///     //only do this if you already know that the shapes overlap
    ///     Vector2[] shape = ShapeTools.Merge(terrainShape, treeShape);
    ///
    ///     DrawShapeGlow(shapes);
    /// }
    /// ~~~
    public static Vector2[] Merge(Vector2[] shapeA, Vector2[] shapeB)
    {
        //find the start point (bottom most point. if multiple bottom most, then left most)
        Vector2 startPoint = shapeA[0];
        int     index      = 0; //index of the shape that the startPoint represents

        //start at 1 becasue we already assigned it to 0
        for (int i = 1; i < shapeA.Length; i++)
        {
            if (shapeA[i].y < startPoint.y)
            {
                startPoint = shapeA[i];
                index      = i;
            }
            else if (shapeA[i].y == startPoint.y && shapeA[i].x < startPoint.x)
            {
                startPoint = shapeA[i];
                index      = i;
            }
        }

        bool startWithShapeB = false;

        for (int i = 0; i < shapeB.Length; i++)
        {
            if (shapeB[i].y < startPoint.y)
            {
                startPoint      = shapeB[i];
                startWithShapeB = true;
            }
            else if (shapeB[i].y == startPoint.y && shapeB[i].x < startPoint.x)
            {
                startPoint      = shapeB[i];
                startWithShapeB = true;
            }
        }

        Vector2[][] shapes = new Vector2[2][];
        if (!startWithShapeB)
        {
            shapes[0] = shapeA;
            shapes[1] = shapeB;
        }
        else
        {
            shapes[0] = shapeB;
            shapes[1] = shapeA;
        }

        List <Vector2> newShape = new List <Vector2>();

        int     iterations    = 0;
        bool    startWithHit  = false;
        Vector2 hitPointToAdd = new Vector2();

        while (iterations < 1000)
        {
            float dist    = Mathf.Infinity;
            bool  found   = false;
            int   edgenum = 0;
            int   numHits = 0;

            for (int b = index; b < shapes[0].Length + index; b++)
            {
                int i = b < shapes[0].Length ? b : b - shapes[0].Length;

                Vector2 thisPos1 = startWithHit ? hitPointToAdd : shapes[0][i];
                Vector2 nextPos1 = shapes[0][i + 1 < shapes[0].Length ? i + 1 : 0];

                if (newShape.Count > 0 && thisPos1 == newShape[0])
                {
                    return(newShape.ToArray());
                }

                if (!startWithHit)
                {
                    newShape.Add(thisPos1);
                }

                startWithHit  = false;
                hitPointToAdd = Vector2.zero;

                for (int a = 0; a < shapes[1].Length; a++)
                {
                    Vector2 thisPos2 = shapes[1][a];
                    Vector2 nextPos2 = shapes[1][a + 1 < shapes[1].Length ? a + 1 : 0];

                    Vector2 hitPt   = new Vector2();
                    float   distToA = 0f;
                    float   distToB = 0f;

                    //if(VectorTools.lineIntersect(thisPos1, nextPos1, thisPos2, nextPos2, out hitPt, out distToA, out distToB))
                    if (JelloVectorTools.LineSegmentsIntersect(thisPos1, nextPos1, thisPos2, nextPos2, out hitPt, out distToA, out distToB))
                    {
                        bool disregard = false;

                        if (newShape.Count > 0 && hitPt == newShape[newShape.Count - 1])
                        {
                            disregard = true;
                        }

                        if (!disregard)
                        {
                            found = true;
                            numHits++;

                            if (distToA < dist)
                            {
                                dist          = distToA;
                                hitPointToAdd = hitPt;
                                edgenum       = a;
                            }
                        }
                    }
                }

                if (found)
                {
                    startWithHit = true;

                    newShape.Add(hitPointToAdd);                        //reverse arays and break, set index to new edgenum

                    index = edgenum;

                    Vector2[] temp1 = shapes[0];
                    Vector2[] temp2 = shapes[1];

                    shapes[0] = temp2;
                    shapes[1] = temp1;

                    break;
                }
            }

            //this could only occur if the other shape is wholy inside this one.
            if (numHits == 0)
            {
                return(shapes[0]);
            }

            iterations++;
        }

        return(newShape.ToArray());
    }
Пример #15
0
    /// <summary>
    /// Rebuild this JelloAttachPoint.
    /// </summary>
    /// <param name="attachPoint">The point (local to the JelloAttachPoint.body) at which to attach the JelloAttachPoint.AttachedTransform.</param>
    /// <param name="jelloBody">The JelloBody to to be attached to.</param>
    /// <param name="indices">The JelloPointMass Indices. Should have a length of 1, 2, or 3.</param>
    /// <param name="useBaseShape">Whether to use the  JelloBody.Shape positions (instead of JelloPointMass.Position) when building the JelloAttachPoint.</param>
    public void Rebuild(Vector2 attachPoint, JelloBody jelloBody, int[] indices, bool useBaseShape = true)
    {
        body      = jelloBody;
        transform = body.transform;

        if (indices == null)
        {
            if (affectedIndices == null)
            {
                Rebuild(attachPoint, jelloBody, useBaseShape);
                return;
            }
            else
            {
                indices = affectedIndices;
            }
        }
        else if (indices.Length > 4)
        {
            affectedIndices = new int[3];
            for (int i = 0; i < 3; i++)
            {
                affectedIndices[i] = indices[i];
            }
        }
        else
        {
            affectedIndices = indices;
        }

        Vector2[] verts = new Vector2[3];

        if (useBaseShape)
        {
            for (int i = 0; i < affectedIndices.Length; i++)
            {
                verts[i] = body.Shape.getVertex(affectedIndices[i]);
            }
        }
        else
        {
            attachPoint = transform.TransformPoint(attachPoint);
            for (int i = 0; i < affectedIndices.Length; i++)
            {
                verts[i] = body.getPointMass(affectedIndices[i]).Position;
            }
        }

        if (affectedIndices.Length == 1)
        {
            scalars    = new float[1];
            scalars[0] = 1f;
        }
        else if (affectedIndices.Length == 2)
        {
            Vector2 hit;

            scalars = new float[2];
            JelloVectorTools.getClosestPointOnSegmentSquared(attachPoint, verts[0], verts[1], out hit, out scalars[1]);
            scalars[0] = 1 - scalars[1];
        }
        else if (affectedIndices.Length == 3)
        {
            scalars = JelloShapeTools.GetBarycentricCoords(attachPoint, verts);
        }

        //throw into for loop...
        point = Vector2.zero;
        for (int i = 0; i < affectedIndices.Length; i++)
        {
            point += scalars[i] * verts[i];
        }

        if (!useBaseShape)
        {
            point = transform.InverseTransformPoint(point);
        }

        if (mAttachedTransform != null)
        {
            Vector3 newPos = transform.TransformPoint(point);
            newPos.z = mAttachedTransform.position.z;
            mAttachedTransform.position = newPos;
        }
    }
Пример #16
0
	/// <summary>
	/// Solves the JelloJoint and applies velocities to each Rigidbody2D / JelloBody involved.
	/// This is called regularly by the simulation and should not need to be called by the user.
	/// </summary>
	/// <param name="deltaTime">The amount of time elapsed.</param>
	public void Solve(float deltaTime)
	{
		if(mTransformA == null && mTransformB == null)
		{
			destroyed = true;
			return;
		}

		Vector2 vap = Vector2.zero;
		Vector2 vbp = Vector2.zero;
		float aMassSum = Mathf.Infinity;
		float bMassSum = Mathf.Infinity;
		float invma = 0f;
		float invmb = 0f;
		Vector2 posA = Vector2.zero;
		Vector2 posB = Vector2.zero;
		Vector2 directionA = Vector2.zero;
		Vector2 directionB = Vector2.zero;

		if(TransformA != null)
		{
			if(bodyA != null)
			{
				for(int i = 0; i < affectedIndicesA.Length; i++)
				{
					vap += bodyA.getPointMass(affectedIndicesA[i]).velocity * scalarsA[i];
					invma += bodyA.getPointMass(affectedIndicesA[i]).InverseMass * scalarsA[i];
					aMassSum += bodyA.getPointMass(affectedIndicesA[i]).Mass * scalarsA[i];
					posA += bodyA.getPointMass(affectedIndicesA[i]).Position * scalarsA[i];
				}
			}
			else if (rigidbodyA != null)
			{
				posA = mTransformA.TransformPoint(localAnchorA);
				directionA = posA - (Vector2)mTransformA.position;
				vap = rigidbodyA.velocity + rigidbodyA.angularVelocity * Mathf.Deg2Rad * new Vector2(-directionA.y, directionA.x);
				
				if(rigidbodyA.mass != 0f && !rigidbodyA.isKinematic)
				{
					invma = 1f / rigidbodyA.mass;
					aMassSum = rigidbodyA.mass;
				}
			}
			else
			{
				posA = mTransformA.TransformPoint(localAnchorA);
				directionA = posA - (Vector2)mTransformA.position;
			}
		}
		else if(TransformB != null)
		{
			posA = globalAnchorA;
		}
		else
		{
			return;
		}

		if(mTransformB != null)
		{
			if(bodyB != null)
			{
				for(int i = 0; i < affectedIndicesB.Length; i++)
				{
					vbp += bodyB.getPointMass(affectedIndicesB[i]).velocity * scalarsB[i];
					invmb += bodyB.getPointMass(affectedIndicesB[i]).InverseMass * scalarsB[i];
					bMassSum += bodyB.getPointMass(affectedIndicesB[i]).Mass * scalarsB[i];
					posB += bodyB.getPointMass(affectedIndicesB[i]).Position * scalarsB[i];
				}
			}
			else if (rigidbodyB != null)
			{
				posB = TransformB.TransformPoint(localAnchorB);
				directionB = posB - (Vector2)mTransformB.position;
				vbp = rigidbodyB.velocity + rigidbodyB.angularVelocity * Mathf.Deg2Rad * new Vector2(-directionB.y, directionB.x);
				
				if(rigidbodyB.mass != 0f && !rigidbodyB.isKinematic)
				{
					invmb = 1f / rigidbodyB.mass;
					bMassSum = rigidbodyB.mass;
				}
			}
			else
			{
				posB = mTransformB.TransformPoint(localAnchorB);
				directionB = posB - (Vector2)mTransformB.position;
			}
		}
		else if(mTransformA != null)
		{
			posB = globalAnchorB;
		}
		else
		{
			return;
		}


		////////////////////////////////////////////////////////
		//Debug.DrawLine(posA, posB, Color.magenta);
		Vector2 normal = posA - posB; //this isnt normalized...

		float distance = normal.magnitude;

		if(distance != 0f)
			normal /= distance;

		Vector2 vab = vap - vbp;

		float invMomentInertiaA = aMassSum == Mathf.Infinity ? 0f : 1f;
		float invMomentInertiaB = bMassSum == Mathf.Infinity ? 0f : 1f;
		
		float denomA = 0f;
		float denomB = 0f;
		if(bodyA == null && aMassSum != Mathf.Infinity)
		{
			denomA = JelloVectorTools.CrossProduct(directionA, normal);
			denomA *= denomA * invMomentInertiaA;
		}
		if(bodyB == null && bMassSum != Mathf.Infinity)
		{
			denomB = JelloVectorTools.CrossProduct(directionB, normal);
			denomB *= denomB * invMomentInertiaB;
		}
		//constraint impulse scalar
		float j = -Vector2.Dot (vab, normal);

		j -= distance / deltaTime;//TODO assign all distance to bodies based on mass.......? 

		bool destroy = false;
		if(breakable && Mathf.Abs(j) > breakVelocity)
			destroy = true;

		float denom = invma + invmb + denomA + denomB; 
		if(denom == 0f)
			denom = 1f;
		j /= denom;

		////////////////////////////////////////////////////////

		if(bodyA != null)
		{
			for(int i = 0; i < affectedIndicesA.Length; i++)
				bodyA.getPointMass(affectedIndicesA[i]).velocity += j * normal * invma * scalarsA[i];
		}
		else if (rigidbodyA != null && !rigidbodyA.isKinematic)
		{
			rigidbodyA.velocity += j * normal * invma / (numSimilar > 0 ? numSimilar : 1f);
			rigidbodyA.angularVelocity += JelloVectorTools.CrossProduct(directionA, j * normal) * Mathf.Rad2Deg / (numSimilar > 0 ? numSimilar : 1f);
		}
		
		if(bodyB != null)
		{
			for(int i = 0; i < affectedIndicesB.Length; i++)
				bodyB.getPointMass(affectedIndicesB[i]).velocity -= j * normal * invmb * scalarsB[i];
		}
		else if (rigidbodyB != null && !rigidbodyB.isKinematic)
		{
			rigidbodyB.velocity -= j * normal * invmb / (numSimilar > 0 ? numSimilar : 1f);
			rigidbodyB.angularVelocity -= JelloVectorTools.CrossProduct(directionB, j * normal) * Mathf.Rad2Deg / (numSimilar > 0 ? numSimilar : 1f);
		}

		if(destroy)
			Destroy();
	}
Пример #17
0
	/// <summary>
	/// Set up the anchor.
	/// </summary>
	/// <returns>The anchor's position.</returns>
	/// <param name="xform">The Transform of the anchor.</param>
	/// <param name="anchor">The anchor point, local to the given Transform.</param>
	/// <param name="isAnchorA">Whether to set up the first anchor instead of the second.</param>
	/// <param name="useBaseShape">Whether to use JelloBody.Shape instead of its JelloPointMass objects. Has no effect if no JelloBody is attached to the Transform.</param>
	/// <param name="numPointsAffected">The number of PointMasses affected / affecting this anchor. Has no effect if no JelloBody is attached to the Transform.</param>
	public Vector2 SetupAnchor(Transform xform, Vector2 anchor, bool isAnchorA, bool useBaseShape, int numPointsAffected = 0)
	{
		if(isAnchorA)
			TransformA = xform;
		else
			TransformB = xform;

		if(xform == null)
		{
			if(isAnchorA)
			{
				affectedIndicesA = null;
				scalarsA = null;

				if(TransformB != null)
				{
					globalAnchorA = TransformB.TransformPoint(GetAnchorPointB(useBaseShape));
					return globalAnchorA;
				}
				else
				{
					return Vector2.zero;
				}
			}
			else
			{
				affectedIndicesB = null;
				scalarsB = null;

				if(TransformA != null)
				{
					globalAnchorB = TransformA.TransformPoint(GetAnchorPointA(useBaseShape));
					return globalAnchorB;
				}
				else
				{
					return Vector2.zero;
				}
			}


			//return Vector2.zero;
		}

		Vector2 returnPosition = anchor;

		if(numPointsAffected < 1)
			numPointsAffected = 2;
		else if(numPointsAffected > 3)
			numPointsAffected = 3;

		if(isAnchorA)
		{
			localAnchorA = anchor;

			if(bodyA != null)
			{
				Vector2[] shape = new Vector2[bodyA.Shape.VertexCount];
				if(useBaseShape) //TODO tighten this up a bit
				{
					for(int i = 0; i < shape.Length; i++)
						shape[i] = bodyA.Shape.getVertex(i);
				}
				else
				{
					for(int i = 0; i < bodyA.PointMassCount; i++)
						shape[i] = bodyA.getPointMass(i).Position;
				}

				Vector2 point = localAnchorA;
				if(!useBaseShape)
					point = xform.TransformPoint(point);

				if(numPointsAffected == 1)
				{
					affectedIndicesA = JelloShapeTools.GetClosestIndices(point, shape, 1);
					scalarsA = new float[1];
					scalarsA[0] = 1f;
					returnPosition = shape[affectedIndicesA[0]];
				}
				else if(numPointsAffected == 2)
				{
					Vector2 hit;
					affectedIndicesA = JelloShapeTools.FindClosestEdgeOnShape(point, shape);
					scalarsA = new float[2];
					JelloVectorTools.getClosestPointOnSegmentSquared (point, shape[affectedIndicesA[0]], shape[affectedIndicesA[1]], out hit, out scalarsA[1]);
					scalarsA[0] = 1 - scalarsA[1];
					returnPosition = shape[affectedIndicesA[0]] * scalarsA[0] + shape[affectedIndicesA[1]] * scalarsA[1]; 
				}
				else if(numPointsAffected == 3)
				{
					Vector2[] shapePerimeter = new Vector2[bodyA.EdgePointMassCount];
					if(useBaseShape)
					{
						shapePerimeter = bodyA.Shape.EdgeVertices;
					}
					else
					{
						for(int i = 0; i < shapePerimeter.Length; i++)
							shapePerimeter[i] = bodyA.getEdgePointMass(i).Position;
					}
					
					affectedIndicesA = JelloShapeTools.FindContainingTriangle(point, shape, shapePerimeter, bodyA.Shape.Triangles, out scalarsA);

					returnPosition = shape[affectedIndicesA[0]] * scalarsA[0] + shape[affectedIndicesA[1]] * scalarsA[1] + shape[affectedIndicesA[2]] * scalarsA[2];
				}

				if(!useBaseShape)
					returnPosition = mTransformA.InverseTransformPoint(returnPosition);
			}
		}
		else
		{
			localAnchorB = anchor;
			
			if(bodyB != null)
			{
				Vector2[] shape = new Vector2[bodyB.Shape.VertexCount];
				if(useBaseShape)
				{
					for(int i = 0; i < shape.Length; i++)
						shape[i] = bodyB.Shape.getVertex(i);
				}
				else
				{
					for(int i = 0; i < bodyB.PointMassCount; i++)
						shape[i] = bodyB.getPointMass(i).Position;
				}
			
				Vector2 point = localAnchorB;
				if(!useBaseShape)
					point = xform.TransformPoint(point);
				
				if(numPointsAffected == 1)
				{
					affectedIndicesB = JelloShapeTools.GetClosestIndices(point, shape, 1);
					scalarsB = new float[1];
					scalarsB[0] = 1f;
					returnPosition = shape[affectedIndicesB[0]] * scalarsB[0];
				}
				else if(numPointsAffected == 2)
				{
					Vector2 hit;
//					affectedIndicesB = JelloShapeTools.GetClosestIndices(point, shape, 2);
					affectedIndicesB = JelloShapeTools.FindClosestEdgeOnShape(point, shape);
					scalarsB = new float[2];
					JelloVectorTools.getClosestPointOnSegmentSquared (point, shape[affectedIndicesB[0]], shape[affectedIndicesB[1]], out hit, out scalarsB[1]);
					scalarsB[0] = 1 - scalarsB[1];
					returnPosition = shape[affectedIndicesB[0]] * scalarsB[0] + shape[affectedIndicesB[1]] * scalarsB[1];
				}
				else if(numPointsAffected == 3)
				{
					Vector2[] shapePerimeter = new Vector2[bodyB.EdgePointMassCount];
					if(useBaseShape)
					{
						shapePerimeter = bodyB.Shape.EdgeVertices;
					}
					else
					{
						for(int i = 0; i < shapePerimeter.Length; i++)
							shapePerimeter[i] = bodyB.getEdgePointMass(i).Position;
					}
					
					affectedIndicesB = JelloShapeTools.FindContainingTriangle(point, shape, shapePerimeter, bodyB.Shape.Triangles, out scalarsB);

					returnPosition = shape[affectedIndicesB[0]] * scalarsB[0] + shape[affectedIndicesB[1]] * scalarsB[1] + shape[affectedIndicesB[2]] * scalarsB[2];
				}

				if(!useBaseShape)
					returnPosition = mTransformB.InverseTransformPoint(returnPosition);}
		}

		return returnPosition;
	}
Пример #18
0
	//anchor is local //vertices are local //have vector2 return?
	/// <summary>
	/// Rebuilds the anchor.
	/// </summary>
	/// <param name="anchor">The anchor (In local space).</param>
	/// <param name="isAnchorA">Whether to rebuild the first anchor as opposed to rebuilding the second anchor.</param>
	/// <param name="useBaseShape">Whether use JelloBody.Shape instead of JelloPointMass.Position. Has no effect if Transform has no JelloBody attached.</param>
	/// <param name="affectedIndices">The indices of the affected / affecting JelloPointMass objects. Has no effect if Transform has no JelloBody attached.</param>
	/// <param name="affectedVertices">The positions (in local space) of the affected / affecting JelloPointMass objects. Has no effect if Transform has no JelloBody attached.</param>
	public void RebuildAnchor(Vector2 anchor, bool isAnchorA, bool useBaseShape, int[] affectedIndices = null, Vector2[] affectedVertices = null)
	{
		//Vector2 point;

		if(isAnchorA)
		{
			localAnchorA = anchor;

			if(mTransformA == null)
				return;

			if(bodyA != null)
			{
				if(affectedIndices == null)
					affectedIndices = affectedIndicesA;
				else
					affectedIndicesA = affectedIndices;

				if(affectedVertices == null)//grab from point mass positions?
				{
					if(useBaseShape)
					{
						affectedVertices = new Vector2[affectedIndicesA.Length];
						for(int i = 0; i < affectedIndicesA.Length; i++)
							affectedVertices[i] = bodyA.Shape.getVertex(affectedIndicesA[i]);
					}
					else
					{
						affectedVertices = new Vector2[affectedIndicesA.Length];
						for(int i = 0; i < affectedIndicesA.Length; i++)
							affectedVertices[i] = bodyA.getPointMass(affectedIndicesA[i]).LocalPosition;
					}
				}

				if(affectedIndices != null)
				{
					if(affectedIndices.Length == 1)
					{
						scalarsA = new float[1];
						scalarsA[0] = 1f;
					}
					else if(affectedIndices.Length == 2)
					{
						Vector2 hit;

						scalarsA = new float[2];
						JelloVectorTools.getClosestPointOnSegmentSquared (localAnchorA, affectedVertices[0], affectedVertices[1], out hit, out scalarsA[1]);
						scalarsA[0] = 1 - scalarsA[1];
					}
					else if(affectedIndices.Length == 3)
					{
						scalarsA = JelloShapeTools.GetBarycentricCoords(localAnchorA, affectedVertices);
					}
				}
			}
		}
		else
		{
			localAnchorB = anchor;
			
			if(mTransformB == null)
				return;
			
			if(bodyB != null)
			{
				if(affectedIndices == null)
					affectedIndices = affectedIndicesB;
				else
					affectedIndicesB = affectedIndices;
				
				if(affectedVertices == null)//grab from point mass positions?
				{
					if(useBaseShape)
					{
						affectedVertices = new Vector2[affectedIndicesB.Length];
						for(int i = 0; i < affectedIndicesB.Length; i++)
							affectedVertices[i] = bodyB.Shape.getVertex(affectedIndicesB[i]);
					}
					else
					{
						affectedVertices = new Vector2[affectedIndicesB.Length];
						for(int i = 0; i < affectedIndicesB.Length; i++)
							affectedVertices[i] = bodyB.getPointMass(affectedIndicesB[i]).LocalPosition;
					}
				}
				
				if(affectedIndices != null)
				{
					if(affectedIndices.Length == 1)
					{
						scalarsB = new float[1];
						scalarsB[0] = 1f;
					}
					else if(affectedIndices.Length == 2)
					{
						Vector2 hit;
						
						scalarsB = new float[2];
						JelloVectorTools.getClosestPointOnSegmentSquared (localAnchorB, affectedVertices[0], affectedVertices[1], out hit, out scalarsB[1]);
						scalarsB[0] = 1 - scalarsB[1];
					}
					else if(affectedIndices.Length == 3)
					{
						scalarsB = JelloShapeTools.GetBarycentricCoords(localAnchorB, affectedVertices);
					}
				}
			}
		}
	}