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; }
/// <summary> /// Flip the JelloClosedShape verticaly. /// </summary> /// /// <dl class="example"><dt>Example</dt></dl> /// ~~~{.c} /// //turn a body around when it hits a ceiling /// /// JelloBody body; /// void handleCollisionEnter(JelloCollisionManifold manifold) /// { /// if(manifold.GetOtherBody(body).gameObject.tag == "ceiling") /// { /// body.flipY(); /// //also reverse movement direction /// } /// } /// ~~~ public void flipY() //TODO check into this --> will i need to retriangulate? because mesh triangles may need to always be wound in a certain direction. { Vector2[] tempVertices = new Vector2[mEdgeVertices.Length]; for(int i = 0; i < mEdgeVertices.Length; i++) { mEdgeVertices[i] = new Vector2(mEdgeVertices[i].x, mEdgeVertices[i].y + 2 * (Center.x - mEdgeVertices[i].x)); tempVertices[mEdgeVertices.Length - i - 1] = mEdgeVertices[i]; } mEdgeVertices = tempVertices; tempVertices = new Vector2[mInternalVertices.Length]; for(int i = 0; i < mInternalVertices.Length; i++) { mInternalVertices[i] = new Vector2(mInternalVertices[i].x, mInternalVertices[i].y + 2 * (Center.x - mInternalVertices[i].x)); tempVertices[mInternalVertices.Length - i - 1] = mInternalVertices[i]; } mInternalVertices = tempVertices; if(winding == Winding.Clockwise) { winding = Winding.CounterClockwise; } else if(winding == Winding.CounterClockwise) { winding = Winding.Clockwise; } else { if(JelloShapeTools.HasClockwiseWinding(mEdgeVertices)) winding = Winding.Clockwise; else winding = Winding.CounterClockwise; } //finish (); }
/// <summary> /// Finish adding vertices to this JeloClosedShape, and choose whether to convert into local space. /// JelloClosedShape.winding and JelloClosedShape.Triangles will be set. /// Make sure there are no duplicate points before calling this. use JelloShapeTools.RemoveDuplicatePoints(). /// </summary> /// <param name="recenter">whether to convert the positions of the JelloClosedShape into local space.</param> /// /// <dl class="example"><dt>Example</dt></dl> /// ~~~{.c} /// //Create a closed shape square /// JelloClosedShape shape = new JelloClosedShape(); /// /// shape.begin(); /// /// shape.addPoint(new Vector2(-1,1)); //top left /// shape.addPoint(new Vector2(-1,1)); //top right /// shape.addPoint(new Vector2(-1,1)); //bottom right /// shape.addPoint(new Vector2(-1,1)); //bottom left /// /// shape.finish(); /// ~~~ public void finish(bool recenter = true) { if(mInternalVertices != null && mInternalVertices.Length > 0) { //dont allow duplicate points mInternalVertices = JelloShapeTools.RemoveDuplicatePoints(mInternalVertices); //dont allow points outside of the perimiter for(int i = 0; i < mInternalVertices.Length; i++) { if(!JelloShapeTools.Contains(mEdgeVertices, mInternalVertices[i])) { mInternalVertices[i] = Vector2.one * Mathf.Infinity; } } //dont allow points on the perimiter. (this will also remove any null points) mInternalVertices = JelloShapeTools.RemovePointsOnPerimeter(mEdgeVertices, mInternalVertices); } mCenter = JelloShapeTools.FindCenter(mEdgeVertices); if (recenter) { // now subtract this from each element, to get proper "local" coordinates. for (int i = 0; i < mEdgeVertices.Length; i++) mEdgeVertices[i] -= mCenter; if(mInternalVertices != null) for (int i = 0; i < mInternalVertices.Length; i++) mInternalVertices[i] -= mCenter; } if(JelloShapeTools.HasClockwiseWinding(mEdgeVertices)) winding = Winding.Clockwise; else winding = Winding.CounterClockwise; Triangulate(); }
/// <summary> /// Change the positions of the vertices of the JelloClosedShape. Be sure to call JelloClosedShape.finish() after this. /// Will fail if number of vertices do not match. /// </summary> /// <param name="edgeVertices">The new edge vertex positions.</param> /// <param name="internalVertices">The new internal vertex positions.</param> /// /// <dl class="example"><dt>Example</dt></dl> /// ~~~{.c} /// //create a closed shape in the form of a square and then change it into a rectangle /// Vector2[] square; /// Vector2[] rectangle; /// /// JelloClosedShape shape = new JelloClosedShape(square); /// /// shape.changeVertices(rectangle, new Vector2[0], true); /// ~~~ public void changeVertices(Vector2[] edgeVertices, Vector2[] internalVertices) { if(edgeVertices.Length == mEdgeVertices.Length) { for(int i = 0 ; i < edgeVertices.Length; i++) mEdgeVertices[i] = edgeVertices[i]; bool[] valid = new bool[internalVertices.Length]; int num = 0; for(int i = 0 ; i < internalVertices.Length; i++) { if(JelloShapeTools.Contains(mEdgeVertices, internalVertices[i])) { valid[i] = true; num++; } else { valid[i] = false; } } mInternalVertices = new Vector2[num]; num = 0; for(int i = 0 ; i < internalVertices.Length; i++) { if(valid[i]) { mInternalVertices[num] = internalVertices[i]; num++; } } } else { Debug.LogWarning("new vertices count less than current vertices count"); } }
public void DrawPointMasses(JelloBody body, bool editable) { Handles.color = new Color(0.75f, 0.75f, 0.2f, 0.5f); for(int i = 0; i < body.Shape.EdgeVertexCount; i++) { Vector2 pos = body.transform.TransformPoint (body.Shape.EdgeVertices[i]); if(editable) { int hot = GUIUtility.hotControl; Handles.FreeMoveHandle(pos, Quaternion.identity, HandleUtility.GetHandleSize(pos) * 0.075f, Vector3.zero, Handles.DotCap); if(GUIUtility.hotControl != hot) { if(currentSubEditor == 1)//point mass editor! { subEditors[currentSubEditor].SetEditIndex(i); Repaint(); } } } else { Handles.color = new Color(0.5f, 0.5f, 0.5f, 0.5f); Handles.DotCap(3, pos, Quaternion.identity, HandleUtility.GetHandleSize(pos) * 0.075f); } } for(int i = 0; i < body.Shape.InternalVertexCount; i++) { Handles.color = new Color(0.75f, 0f, 0.75f, 0.5f); Vector2 pos = body.transform.TransformPoint (body.Shape.InternalVertices[i]); if(editable) { int hot = GUIUtility.hotControl; EditorGUI.BeginChangeCheck(); pos = Handles.FreeMoveHandle(pos, Quaternion.identity, HandleUtility.GetHandleSize(pos) * 0.075f, Vector3.zero, Handles.DotCap); if(EditorGUI.EndChangeCheck()) { if(!JelloShapeTools.Contains(body.Shape.EdgeVertices, body.transform.InverseTransformPoint(pos)) || JelloShapeTools.PointOnPerimeter(body.Shape.EdgeVertices, body.transform.InverseTransformPoint(pos))) { JelloClosedShape newShape = new JelloClosedShape(body.Shape.EdgeVertices, null, false); for(int a = 0; a < body.Shape.InternalVertexCount; a++) { //dont add this point if(a == i) continue; newShape.addInternalVertex(body.Shape.InternalVertices[a]); } newShape.finish(false); body.smartSetShape(newShape, JelloBody.ShapeSettingOptions.MovePointMasses, smartShapeSettingOptions); EditorUtility.SetDirty(body); GUIUtility.hotControl = 0; subEditors[currentSubEditor].SetEditIndex(-1); Repaint(); break; } body.Shape.changeInternalVertexPosition(i, body.transform.InverseTransformPoint(pos)); body.Shape.finish(false); EditorUtility.SetDirty(body); } if(GUIUtility.hotControl != hot && GUIUtility.hotControl != 0) { if(currentSubEditor == 1)//point mass editor! { subEditors[currentSubEditor].SetEditIndex(i + body.EdgePointMassCount); Repaint(); } } } else { Handles.color = new Color(0.5f, 0.5f, 0.5f, 0.5f); Handles.DotCap(3, pos, Quaternion.identity, HandleUtility.GetHandleSize(pos) * 0.075f); } } }
//todo add onenable and ondisable events to body. public virtual void DrawEditorGUI() { //check polycollider vs pointmasscount if(!Application.isPlaying) //TODO have this be handled by a class that extends the polycollider and recognises changes? { for(int b = 0; b < targets.Length; b++) { JelloBody body = (JelloBody)targets[b]; body.setComponentReferences(); body.polyCollider.points = JelloShapeTools.RemoveDuplicatePoints(body.polyCollider.points); JelloClosedShape shape = new JelloClosedShape(body.polyCollider.points, null, false); if(body.Shape != null) { for(int i = 0; i < body.Shape.InternalVertexCount; i++) shape.addInternalVertex(body.Shape.InternalVertices[i]); shape.finish(false); } if(shape.EdgeVertexCount != body.Shape.EdgeVertexCount || shape.InternalVertexCount != body.Shape.InternalVertexCount) body.smartSetShape(shape, JelloBody.ShapeSettingOptions.MovePointMasses, smartShapeSettingOptions); else body.setShape(shape, JelloBody.ShapeSettingOptions.MovePointMasses); //will i need to do this for constraints as well? for(int i = 0; i < body.AttachPointCount; i++) { body.GetAttachPoint(i).UpdateEditorMode(); } } } serializedObject.Update(); EditorGUI.showMixedValue = eMass.hasMultipleDifferentValues; EditorGUI.BeginChangeCheck(); EditorGUILayout.PropertyField(eMass, massContent); if(EditorGUI.EndChangeCheck()) { for(int i = 0; i < serializedObject.targetObjects.Length; i++) { JelloBody b = (JelloBody)serializedObject.targetObjects[i]; b.Mass = eMass.floatValue; } serializedObject.UpdateIfDirtyOrScript(); } EditorGUI.showMixedValue = false; if(!tar.IsStatic) { EditorGUILayout.BeginHorizontal(); EditorGUI.showMixedValue = eAffectedByGravity.hasMultipleDifferentValues; EditorGUILayout.PropertyField(eAffectedByGravity, useGravContent); EditorGUI.showMixedValue = false; EditorGUILayout.EndHorizontal(); if(eAffectedByGravity.boolValue) { EditorGUI.indentLevel++; EditorGUI.showMixedValue = eOverrideGravity.hasMultipleDifferentValues; EditorGUILayout.PropertyField(eOverrideGravity, overrideGravContent); EditorGUI.showMixedValue = false; if(eOverrideGravity.boolValue) { EditorGUI.indentLevel++; EditorGUI.showMixedValue = eGravity.hasMultipleDifferentValues; EditorGUILayout.PropertyField(eGravity, customGravContent); EditorGUI.showMixedValue = false; EditorGUI.indentLevel--; } EditorGUI.indentLevel--; } EditorGUI.showMixedValue = eKinematic.hasMultipleDifferentValues; EditorGUILayout.PropertyField(eKinematic, kinematicContent); EditorGUI.showMixedValue = false; } EditorGUI.showMixedValue = eTrigger.hasMultipleDifferentValues; EditorGUILayout.PropertyField(eTrigger, triggerContent); EditorGUI.showMixedValue = false; EditorGUI.showMixedValue = eAwake.hasMultipleDifferentValues; EditorGUILayout.PropertyField(eAwake, awakeContent); EditorGUI.showMixedValue = false; if(tar.meshLink == null || tar.meshLink.canModifyPivotPoint) { EditorGUI.indentLevel++; EditorGUILayout.BeginHorizontal(); SerializedProperty ePivotOffset = serializedObject.FindProperty("pivotOffset"); GUIStyle pivotStyle = new GUIStyle(EditorStyles.foldout); if(ePivotOffset.prefabOverride) pivotStyle.fontStyle = FontStyle.Bold; showPivot = EditorGUILayout.Foldout(showPivot, pivotFoldoutContent, pivotStyle); if(GUILayout.Button(centerPivotContent, EditorStyles.miniButton)) { Undo.RecordObjects(serializedObject.targetObjects, "Center Pivot"); for(int i = 0; i < serializedObject.targetObjects.Length; i++) { JelloBody jb = (JelloBody)serializedObject.targetObjects[i]; Undo.RecordObject(jb.gameObject.transform, "Center Pivot transform"); if(jb.meshLink != null) { Undo.RecordObject(jb.meshLink, "Center Pivot mesh"); Undo.RecordObject(jb.polyCollider, "Center Pivot collider"); Undo.RecordObject(jb.GetComponent<Renderer>(), "Center Pivot renderer"); Undo.RecordObject(jb.meshLink.LinkedMeshFilter, "Center Pivot filter"); } } for(int i = 0; i < serializedObject.targetObjects.Length; i++) { JelloBody bod = (JelloBody)serializedObject.targetObjects[i]; CenterPivot(bod); EditorUtility.SetDirty(bod.gameObject); EditorUtility.SetDirty(bod.meshLink); //serializedObject.UpdateIfDirtyOrScript(); } SceneView.RepaintAll(); } EditorGUILayout.EndHorizontal(); if(showPivot) { if(!serializedObject.isEditingMultipleObjects) { pivot = EditorGUILayout.Vector2Field("Position", pivot); if(pivot != Vector2.zero) { EditorGUILayout.BeginHorizontal(); if(GUILayout.Button(applyPivotContent, EditorStyles.miniButton)) { JelloBody jb = (JelloBody)serializedObject.targetObject; Undo.RecordObject(jb, "Change Pivot"); Undo.RecordObject(jb.gameObject.transform, "Change Pivot transform"); if(jb.meshLink != null) { Undo.RecordObject(jb.meshLink, "Change Pivot mesh"); Undo.RecordObject(jb.polyCollider, "Change Pivot collider"); Undo.RecordObject(jb.GetComponent<Renderer>(), "Change Pivot renderer"); Undo.RecordObject(jb.meshLink.LinkedMeshFilter, "Change Pivot filter"); } ChangePivot(tar); EditorUtility.SetDirty(tar.gameObject); EditorUtility.SetDirty(tar.meshLink); // serializedObject.UpdateIfDirtyOrScript(); } if(GUILayout.Button(cancelPivotContent, EditorStyles.miniButton)) pivot = Vector2.zero; SceneView.RepaintAll(); EditorGUILayout.EndHorizontal(); } } else { EditorGUILayout.HelpBox("Pivot Points may only be centered when multiple Game Objects are selected", MessageType.Info); } } EditorGUI.indentLevel--; } serializedObject.ApplyModifiedProperties(); }
//TODO draw some info for the other body as well? like an outline? public void DrawjointSceneGUI() { mainEditor.DrawPointMasses(body, false); Vector3 pos; //hovered over joint if(drawIndex >= 0 && drawIndex < body.JointCount && body.GetJoint(drawIndex).bodyA != null) { JelloJoint joint = body.GetJoint(drawIndex); Vector3 posA = body.transform.TransformPoint(joint.GetAnchorPointA(true)); posA.z = body.transform.position.z; Handles.color = Color.magenta; for(int i = 0; i < joint.affectedIndicesA.Length; i++) { Handles.DrawLine(posA, body.transform.TransformPoint(body.Shape.getVertex(joint.affectedIndicesA[i]))); Handles.DotCap(3, body.transform.TransformPoint(body.Shape.getVertex(joint.affectedIndicesA[i])), Quaternion.identity, HandleUtility.GetHandleSize(body.transform.TransformPoint(body.Shape.getVertex(joint.affectedIndicesA[i]))) * 0.05f); } Handles.color = Color.blue; Handles.DotCap(3, posA, Quaternion.identity, HandleUtility.GetHandleSize(posA) * 0.075f); Vector3 posB = joint.GetAnchorPointB(true); if(joint.TransformB != null) { posB = joint.TransformB.TransformPoint(posB); if(joint.bodyB != null) { if(joint.affectedIndicesB != null) { Handles.color = Color.magenta; for(int i = 0; i < body.GetJoint(drawIndex).affectedIndicesB.Length; i++) { Handles.DrawLine(posB, joint.bodyB.transform.TransformPoint(joint.bodyB.Shape.getVertex(joint.affectedIndicesB[i]))); Handles.DotCap(3, joint.bodyB.transform.TransformPoint(joint.bodyB.Shape.getVertex(joint.affectedIndicesB[i])), Quaternion.identity, HandleUtility.GetHandleSize(joint.bodyB.transform.TransformPoint(joint.bodyB.Shape.getVertex(joint.affectedIndicesB[i]))) * 0.05f); } Handles.color = Color.blue; } } } Handles.DotCap(3, posB, Quaternion.identity, HandleUtility.GetHandleSize(posB) * 0.075f); Handles.color = Color.red; Handles.DrawLine(posA, posB); } //selected joint if(editIndex >= 0 && editIndex < body.JointCount && body.GetJoint(editIndex).affectedIndicesA != null) { JelloJoint joint = body.GetJoint(editIndex); int num = 2 + joint.affectedIndicesA.Length; if(joint.TransformB != null && joint.bodyB != null) num += joint.affectedIndicesB.Length; //first get handle sizes... //need global handle positions Vector3[] globalHandlePositions = new Vector3[num]; globalHandlePositions[0] = body.transform.TransformPoint(handlePositions[0]); for(int i = 0; i < joint.affectedIndicesA.Length; i++) globalHandlePositions[i + 2] = body.transform.TransformPoint(handlePositions[i + 2]); if(joint.TransformB != null) { globalHandlePositions[1] = joint.TransformB.TransformPoint(handlePositions[1]); if(joint.bodyB != null) { for(int i = 0; i < joint.affectedIndicesB.Length; i++) { globalHandlePositions[i + 2 + joint.affectedIndicesA.Length] = joint.TransformB.TransformPoint(handlePositions[i + 2 + joint.affectedIndicesA.Length]); } } } else { globalHandlePositions[1] = joint.globalAnchorB; } CalculateHandleSizes(globalHandlePositions); bool mouseUp = false; if(Event.current.type == EventType.mouseUp) mouseUp = true; Handles.color = Color.cyan; EditorGUI.BeginChangeCheck(); handlePositions[0] = body.transform.InverseTransformPoint( Handles.FreeMoveHandle(body.transform.TransformPoint(handlePositions[0]), Quaternion.identity, handleSizes[0], Vector3.zero, Handles.CircleCap)); if(EditorGUI.EndChangeCheck()) { Vector2[] affectedPoints = new Vector2[joint.affectedIndicesA.Length]; for(int i = 0; i < affectedPoints.Length; i++) affectedPoints[i] = body.Shape.getVertex(joint.affectedIndicesA[i]); joint.RebuildAnchor ( handlePositions[0], true, true, joint.affectedIndicesA, affectedPoints ); SetEditIndex(editIndex); EditorUtility.SetDirty(body); SceneView.RepaintAll(); } for(int i = 0; i < joint.affectedIndicesA.Length; i++) { Handles.color = Color.blue; handlePositions[i + 2] = body.transform.InverseTransformPoint(Handles.FreeMoveHandle(body.transform.TransformPoint(handlePositions[i + 2]), Quaternion.identity, handleSizes[i + 2], Vector3.zero, Handles.CircleCap)); if(mouseUp) { if((Vector2)handlePositions[i + 2] != body.Shape.getVertex(joint.affectedIndicesA[i])) { Vector2[] points = new Vector2[body.Shape.VertexCount]; for(int s = 0; s < body.Shape.VertexCount; s++) points[s] = body.Shape.getVertex(s); int index = JelloShapeTools.FindClosestVertexOnShape(handlePositions[i + 2], points); bool indexInUse = false; for(int u = 0; u < joint.affectedIndicesA.Length; u++) if(index == joint.affectedIndicesA[u]) indexInUse = true; if(!indexInUse) { joint.affectedIndicesA[i] = index; Vector2[] affectedVertices = new Vector2[joint.affectedIndicesA.Length]; for(int v = 0; v < affectedVertices.Length; v++) affectedVertices[v] = body.Shape.getVertex(joint.affectedIndicesA[v]); handlePositions[i + 2] = body.Shape.getVertex(index); joint.RebuildAnchor(joint.localAnchorA, true, true, null, affectedVertices); Vector2 newPosition = Vector2.zero; for(int v = 0; v < affectedVertices.Length; v++) newPosition += affectedVertices[v] * joint.scalarsA[v]; handlePositions[0] = newPosition; EditorUtility.SetDirty(body); SceneView.RepaintAll(); } else { handlePositions[i + 2] = body.Shape.getVertex(joint.affectedIndicesA[i]); } } } Handles.color = Color.black; Handles.DrawLine(body.transform.TransformPoint(handlePositions[0]), body.transform.TransformPoint( handlePositions[i + 2])); } //other object's GUI Handles.color = Color.magenta; if(joint.TransformB != null) { EditorGUI.BeginChangeCheck(); handlePositions[1] = joint.TransformB.InverseTransformPoint( Handles.FreeMoveHandle(joint.TransformB.TransformPoint(handlePositions[1]), Quaternion.identity, handleSizes[1], Vector3.zero, Handles.CircleCap)); if(EditorGUI.EndChangeCheck()) { Vector2[] affectedPoints = new Vector2[0]; if(joint.bodyB != null) { affectedPoints = new Vector2[joint.affectedIndicesB.Length]; for(int i = 0; i < affectedPoints.Length; i++) affectedPoints[i] = joint.bodyB.Shape.getVertex(joint.affectedIndicesB[i]); } joint.RebuildAnchor ( handlePositions[1], false, true, joint.affectedIndicesB, affectedPoints ); SetEditIndex(editIndex); EditorUtility.SetDirty(body); SceneView.RepaintAll(); } if(joint.bodyB != null && joint.affectedIndicesB != null) { int numAffectedA = joint.affectedIndicesA.Length; for(int i = 0; i < joint.affectedIndicesB.Length; i++) { int offsetIndex = i + numAffectedA + 2; Handles.color = Color.red; handlePositions[offsetIndex] = joint.TransformB.InverseTransformPoint(Handles.FreeMoveHandle(joint.TransformB.TransformPoint(handlePositions[offsetIndex]), Quaternion.identity, handleSizes[offsetIndex], Vector3.zero, Handles.CircleCap)); if(mouseUp) { if((Vector2)handlePositions[offsetIndex] != joint.bodyB.Shape.getVertex(joint.affectedIndicesB[i])) { Vector2[] points = new Vector2[joint.bodyB.Shape.VertexCount]; for(int s = 0; s < joint.bodyB.Shape.VertexCount; s++) points[s] = joint.bodyB.Shape.getVertex(s); int index = JelloShapeTools.FindClosestVertexOnShape(handlePositions[offsetIndex], points); bool indexInUse = false; for(int u = 0; u < joint.affectedIndicesB.Length; u++) if(index == joint.affectedIndicesB[u]) indexInUse = true; if(!indexInUse) { joint.affectedIndicesB[i] = index; Vector2[] affectedVertices = new Vector2[joint.affectedIndicesB.Length]; for(int v = 0; v < affectedVertices.Length; v++) affectedVertices[v] = joint.bodyB.Shape.getVertex(joint.affectedIndicesB[v]); handlePositions[offsetIndex] = joint.bodyB.Shape.getVertex(index); joint.RebuildAnchor(joint.localAnchorB, false, true, null, affectedVertices); Vector2 newPosition = Vector2.zero; for(int v = 0; v < affectedVertices.Length; v++) newPosition += affectedVertices[v] * joint.scalarsB[v]; handlePositions[1] = newPosition; EditorUtility.SetDirty(body); SceneView.RepaintAll(); } else { handlePositions[offsetIndex] = joint.bodyB.Shape.getVertex(joint.affectedIndicesB[i]); } } } Handles.color = Color.grey; Handles.DrawLine(joint.bodyB.transform.TransformPoint(handlePositions[1]), joint.bodyB.transform.TransformPoint( handlePositions[offsetIndex])); } } Handles.color = Color.yellow; Handles.DrawLine(joint.TransformA.TransformPoint(handlePositions[0]), joint.TransformB.TransformPoint(handlePositions[1])); } else { //TODO this should be handlepositions[1]??? EditorGUI.BeginChangeCheck(); joint.globalAnchorB = Handles.FreeMoveHandle(joint.globalAnchorB, Quaternion.identity, handleSizes[1], Vector3.zero, Handles.CircleCap); if(EditorGUI.EndChangeCheck()) { EditorUtility.SetDirty(body); } Handles.color = Color.yellow; Handles.DrawLine(joint.TransformA.TransformPoint(handlePositions[0]), joint.globalAnchorB); } } //add new joint logic if(newSubComponentState == AddSubComponentState.initiated) { int controlID = GUIUtility.GetControlID(GetHashCode(), FocusType.Passive); if(Event.current.type == EventType.Layout) HandleUtility.AddDefaultControl(controlID); pos = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition).origin; //need where this ray intersects the zplane Plane plane = new Plane(Vector3.forward, new Vector3(0, 0, body.transform.position.z)); Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); float dist = 0f; plane.Raycast(ray, out dist); pos = ray.GetPoint(dist); Vector3 mousePosWorld = new Vector3(pos.x, pos.y, body.transform.position.z); Handles.color = Color.blue; Handles.CircleCap(3, mousePosWorld, Quaternion.identity, HandleUtility.GetHandleSize(mousePosWorld) * 0.15f); if(Event.current.type == EventType.MouseUp) { body.AddJoint(new JelloJoint(body.transform, null, body.transform.InverseTransformPoint(mousePosWorld), Vector2.zero, true, true)); newSubComponentState = AddSubComponentState.inactive; SetEditIndex(body.JointCount - 1); EditorUtility.SetDirty(body); } SceneView.RepaintAll(); } }
public override void DrawSceneGUI() { if (springBody == null || multiEditing) { return; } //draw the hovered over spring if (drawIndex != -1) { JelloSpring spring = springBody.getSpring(drawIndex); Vector3 posA; Vector3 posB; posA = springBody.transform.TransformPoint(springBody.Shape.getVertex(spring.pointMassA)); posB = springBody.transform.TransformPoint(springBody.Shape.getVertex(spring.pointMassB)); Handles.color = Color.magenta; if (spring.lengthMultiplier != 1f) { float dist = Vector2.Distance(posA, posB) * spring.lengthMultiplier; Vector3 mid = (posA + posB) * 0.5f; posA = mid + (mid - posA).normalized * dist * 0.5f; posB = mid + (mid - posB).normalized * dist * 0.5f; } Handles.DrawLine(posA, posB); } //TODO make it remember the selected spring? //draw the currently selected spring if (editIndex != -1 && editIndex < springBody.SpringCount) { JelloSpring spring = springBody.getSpring(editIndex); Handles.color = Color.cyan; Vector3[] globalHandlePositions = new Vector3[2]; for (int i = 0; i < handlePositions.Length; i++) { globalHandlePositions[i] = springBody.transform.TransformPoint(handlePositions[i]); } CalculateHandleSizes(handlePositions); bool mouseUp = false; if (Event.current.type == EventType.mouseUp) { mouseUp = true; } for (int i = 0; i < handlePositions.Length; i++) { handlePositions[i] = springBody.transform.InverseTransformPoint(Handles.FreeMoveHandle(springBody.transform.TransformPoint(handlePositions[i]), Quaternion.identity, handleSizes[i], Vector3.zero, Handles.CircleCap)); } //handlePositions[1] = springBody.transform.InverseTransformPoint( Handles.FreeMoveHandle(springBody.transform.TransformPoint(handlePositions[1]), Quaternion.identity, HandleUtility.GetHandleSize(handlePositions[1]) * 0.15f, Vector3.zero, Handles.CircleCap)); Handles.color = Color.magenta; Handles.DrawLine(springBody.transform.TransformPoint(handlePositions[0]), springBody.transform.TransformPoint(handlePositions[1])); if (mouseUp) { if ((Vector2)handlePositions[0] != springBody.Shape.getVertex(spring.pointMassA)) { Vector2[] points = new Vector2[springBody.Shape.VertexCount]; for (int i = 0; i < springBody.Shape.VertexCount; i++) { points[i] = springBody.Shape.getVertex(i); } spring.pointMassA = JelloShapeTools.FindClosestVertexOnShape(handlePositions[0], points); handlePositions[0] = springBody.Shape.getVertex(spring.pointMassA); spring.length = Vector2.Distance(springBody.Shape.getVertex(spring.pointMassA), springBody.Shape.getVertex(spring.pointMassB)); EditorUtility.SetDirty(springBody); } if ((Vector2)handlePositions[1] != springBody.Shape.getVertex(spring.pointMassB)) { Vector2[] points = new Vector2[springBody.Shape.VertexCount]; for (int i = 0; i < springBody.Shape.VertexCount; i++) { points[i] = springBody.Shape.getVertex(i); } spring.pointMassB = JelloShapeTools.FindClosestVertexOnShape(handlePositions[1], points); handlePositions[1] = springBody.Shape.getVertex(spring.pointMassB); spring.length = Vector2.Distance(springBody.Shape.getVertex(spring.pointMassA), springBody.Shape.getVertex(spring.pointMassB)); EditorUtility.SetDirty(springBody); } } Vector3 posA = springBody.transform.TransformPoint(springBody.Shape.getVertex(spring.pointMassA)); Vector3 posB = springBody.transform.TransformPoint(springBody.Shape.getVertex(spring.pointMassB)); if (spring.lengthMultiplier != 1f) { float dist = Vector2.Distance(posA, posB) * spring.lengthMultiplier; Vector3 mid = (posA + posB) * 0.5f; posA = mid + (mid - posA).normalized * dist * 0.5f; posB = mid + (mid - posB).normalized * dist * 0.5f; } Handles.color = Color.blue; Handles.DrawLine(posA, posB); } if (newSubComponentState != AddSubComponentState.inactive) { if (Event.current.isKey && Event.current.keyCode == KeyCode.Escape) { newSubComponentState = AddSubComponentState.inactive; } int controlID = GUIUtility.GetControlID(GetHashCode(), FocusType.Passive); if (Event.current.type == EventType.Layout) { HandleUtility.AddDefaultControl(controlID); } Handles.color = Color.red; Vector3 pos = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition).origin; //need where this ray intersects the zplane Plane plane = new Plane(Vector3.forward, new Vector3(0, 0, springBody.transform.position.z)); Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); float dist = 0f; plane.Raycast(ray, out dist); pos = ray.GetPoint(dist); Vector3 mousePosWorld = new Vector3(pos.x, pos.y, springBody.transform.position.z); if (newSubComponentState == AddSubComponentState.assignedFirst) { pos = springBody.transform.TransformPoint(springBody.Shape.getVertex(newSpring.pointMassA)); Handles.CircleCap(3, pos, Quaternion.identity, HandleUtility.GetHandleSize(pos) * 0.15f); Handles.DrawLine(pos, mousePosWorld); Handles.color = Color.blue; Handles.CircleCap(3, mousePosWorld, Quaternion.identity, HandleUtility.GetHandleSize(mousePosWorld) * 0.15f); if (Event.current.type == EventType.MouseUp) { Vector2[] points = new Vector2[springBody.Shape.VertexCount]; for (int i = 0; i < springBody.Shape.VertexCount; i++) { points[i] = springBody.Shape.getVertex(i); } newSpring.pointMassB = JelloShapeTools.FindClosestVertexOnShape(springBody.transform.InverseTransformPoint(mousePosWorld), points); newSpring.length = Vector2.Distance(springBody.Shape.getVertex(newSpring.pointMassA), springBody.Shape.getVertex(newSpring.pointMassB)); newSpring.stiffness = springBody.DefaultCustomSpringStiffness; newSpring.damping = springBody.DefaultCustomSpringDamping; editIndex = springBody.SpringCount; springBody.addCustomSpring(newSpring); newSubComponentState = AddSubComponentState.inactive; handlePositions[0] = springBody.Shape.getVertex(newSpring.pointMassA); handlePositions[1] = springBody.Shape.getVertex(newSpring.pointMassB); eCustomSprings.isExpanded = true; eEdgeSprings.isExpanded = false; eInternalSprings.isExpanded = false; EditorUtility.SetDirty(springBody); } } if (newSubComponentState == AddSubComponentState.initiated) { Handles.CircleCap(3, mousePosWorld, Quaternion.identity, HandleUtility.GetHandleSize(mousePosWorld) * 0.15f); if (Event.current.type == EventType.MouseUp) { Vector2[] points = new Vector2[springBody.Shape.VertexCount]; for (int i = 0; i < springBody.Shape.VertexCount; i++) { points[i] = springBody.Shape.getVertex(i); } newSpring = new JelloSpring(); newSpring.pointMassA = JelloShapeTools.FindClosestVertexOnShape(springBody.transform.InverseTransformPoint(mousePosWorld), points); newSubComponentState = AddSubComponentState.assignedFirst; } } SceneView.RepaintAll(); } if (newSubComponentState != AddSubComponentState.inactive || editIndex != -1) { Handles.color = new Color(0.5f, 0.5f, 0.5f, 0.5f); for (int i = springBody.EdgeSpringCount; i < springBody.SpringCount; i++) { if (editIndex == i) { continue; } Handles.DrawLine(springBody.transform.TransformPoint(springBody.Shape.getVertex(springBody.getSpring(i).pointMassA)), springBody.transform.TransformPoint(springBody.Shape.getVertex(springBody.getSpring(i).pointMassB))); } mainEditor.DrawPointMasses(springBody, false); } }
/// <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); }
public void DrawAttachPointSceneGUI() { //TODO i have an error when reverting to prefab. If the handles are ind a different place, it sets dirty and messes up the seleced edit attach point. mainEditor.DrawPointMasses(body, false); Vector3 pos; //the attach point hovered over in the editor if(drawIndex >= 0 && drawIndex < body.AttachPointCount && body.GetAttachPoint(drawIndex).body != null) { pos = body.transform.TransformPoint(body.GetAttachPoint(drawIndex).point); Handles.color = Color.magenta; for(int i = 0; i < body.GetAttachPoint(drawIndex).affectedIndices.Length; i++) { Handles.DrawLine(pos, body.transform.TransformPoint(body.Shape.getVertex(body.GetAttachPoint(drawIndex).affectedIndices[i]))); Handles.DotCap(3, body.transform.TransformPoint(body.Shape.getVertex(body.GetAttachPoint(drawIndex).affectedIndices[i])), Quaternion.identity, HandleUtility.GetHandleSize(body.transform.TransformPoint(body.Shape.getVertex(body.GetAttachPoint(drawIndex).affectedIndices[i]))) * 0.05f); } Handles.color = Color.blue; Handles.DotCap(3, pos, Quaternion.identity, HandleUtility.GetHandleSize(pos) * 0.075f); } //the attach point currently selected in the editor if(editIndex != -1 && editIndex < body.AttachPointCount && body.GetAttachPoint(editIndex).body != null) { //handle sizes int num = body.GetAttachPoint(editIndex).affectedIndices.Length + 1; Vector3[] globalHandlePositions = new Vector3[num]; globalHandlePositions[0] = body.transform.TransformPoint(handlePositions[0]); for(int i = 0; i < body.GetAttachPoint(editIndex).affectedIndices.Length; i++) globalHandlePositions[i + 1] = body.transform.TransformPoint(handlePositions[i + 1]); CalculateHandleSizes(globalHandlePositions); bool mouseUp = false; if(Event.current.type == EventType.mouseUp) mouseUp = true; Handles.color = Color.green; EditorGUI.BeginChangeCheck(); handlePositions[0] = body.transform.InverseTransformPoint( Handles.FreeMoveHandle(body.transform.TransformPoint(handlePositions[0]), Quaternion.identity, handleSizes[0], Vector3.zero, Handles.CircleCap)); if(EditorGUI.EndChangeCheck()) { body.GetAttachPoint(editIndex).Rebuild(handlePositions[0], body, body.GetAttachPoint(editIndex).affectedIndices); SetEditIndex(editIndex); EditorUtility.SetDirty(body); //modified in scene } Handles.color = Color.white; Handles.DotCap(3, body.transform.TransformPoint(handlePositions[0]), Quaternion.identity, handleSizes[0] * 0.5f); //start at one because the point occupies the first position. //for(int i = 1; i < handlePositions.Length; i++) for(int i = 1; i < body.GetAttachPoint(editIndex).affectedIndices.Length + 1; i++) { Handles.color = Color.blue; handlePositions[i] = body.transform.InverseTransformPoint( Handles.FreeMoveHandle(body.transform.TransformPoint(handlePositions[i]), Quaternion.identity, handleSizes[i], Vector3.zero, Handles.CircleCap)); if(mouseUp) { if((Vector2)handlePositions[i] != body.Shape.getVertex(body.GetAttachPoint(editIndex).affectedIndices[i - 1])) { Vector2[] points = new Vector2[body.Shape.VertexCount]; for(int s = 0; s < body.Shape.VertexCount; s++) points[s] = body.Shape.getVertex(s); int index = JelloShapeTools.FindClosestVertexOnShape(handlePositions[i], points); bool occupied = false; for(int n = 0; n < body.GetAttachPoint(editIndex).affectedIndices.Length; n++) if(index == body.GetAttachPoint(editIndex).affectedIndices[n]) occupied = true; if(!occupied) { body.GetAttachPoint(editIndex).affectedIndices[i - 1] = index; handlePositions[i] = body.Shape.getVertex(index); body.GetAttachPoint(editIndex).Rebuild(body.GetAttachPoint(editIndex).point, body, body.GetAttachPoint(editIndex).affectedIndices); handlePositions[0] = body.GetAttachPoint(editIndex).point; EditorUtility.SetDirty(body); } else { handlePositions[i] = body.Shape.getVertex(body.GetAttachPoint(editIndex).affectedIndices[i - 1]); } } } Handles.color = Color.black; Handles.DrawLine(body.transform.TransformPoint(handlePositions[0]), body.transform.TransformPoint( handlePositions[i])); } } //logic to add a new attach point if(newSubComponentState == AddSubComponentState.initiated) { int controlID = GUIUtility.GetControlID(GetHashCode(), FocusType.Passive); if(Event.current.type == EventType.Layout) HandleUtility.AddDefaultControl(controlID); pos = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition).origin; //need where this ray intersects the zplane Plane plane = new Plane(Vector3.forward, new Vector3(0, 0, body.transform.position.z)); Ray ray = HandleUtility.GUIPointToWorldRay(Event.current.mousePosition); float dist = 0f; plane.Raycast(ray, out dist); pos = ray.GetPoint(dist); Vector3 mousePosWorld = new Vector3(pos.x, pos.y, body.transform.position.z); Handles.color = Color.blue; Handles.CircleCap(3, mousePosWorld, Quaternion.identity, HandleUtility.GetHandleSize(mousePosWorld) * 0.15f); if(Event.current.type == EventType.MouseUp)//TODO not working correctly...? { body.AddAttachPoint(new JelloAttachPoint(body.transform.InverseTransformPoint(mousePosWorld), body, true)); newSubComponentState = AddSubComponentState.inactive; SetEditIndex(body.AttachPointCount - 1); EditorUtility.SetDirty(body); } SceneView.RepaintAll(); } }
/// <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; }
//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); } } } } }
/// <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; } }
/// <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; } }