/// <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;
	}
Пример #2
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;
	}
Пример #3
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);
					}
				}
			}
		}
	}
Пример #4
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;
        }
    }
Пример #5
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;
        }
    }