/// <summary> /// Create a verlet cluster. /// </summary> /// <param name="world">Verlet world</param> /// <param name="centerPosition">Center position</param> /// <param name="pointCount">Point count</param> /// <param name="diameter">Cluster diameter</param> /// <param name="gravityScale">Gravity scale</param> /// <param name="tearSensitivityFactor">Distance factor required to break the cloth. Use `-1` to create an unbreakable cloth.</param> /// <param name="stiffness">Stiffness of the cloth</param> /// <param name="drawPoints">Draw points</param> /// <param name="pointRadius">Verlet point radius</param> public VerletCluster(VerletWorld world, Vector2 centerPosition, int pointCount, float diameter, float gravityScale = 1, float tearSensitivityFactor = -1, float stiffness = 0.1f, bool drawPoints = true, float pointRadius = 10f) { Points = new List <VerletPoint>(); for (int i = 0; i < pointCount; ++i) { var position = centerPosition + new Vector2((float)GD.RandRange(-1, 1), (float)GD.RandRange(-1, 1)); var point = world.CreatePoint(); point.GravityScale = gravityScale; point.Radius = pointRadius; point.Visible = drawPoints; point.MoveToPosition(position); Points.Add(point); } for (int i = 0; i < Points.Count - 1; ++i) { for (int j = i + 1; j < Points.Count; ++j) { var a = Points[i]; var b = Points[j]; var link = world.CreateLink(a, b); link.RestingDistance = diameter; link.TearSensitivity = diameter * tearSensitivityFactor; link.Stiffness = stiffness; } } }
/// <summary> /// Create a verlet chain builder. /// </summary> /// <param name="world">Verlet world</param> /// <param name="pinFirst">Pin first chain point</param> /// <param name="pinLast">Pin last chain point</param> /// <param name="drawIntermediatePoints">Draw chain intermediate points</param> public VerletChainBuilder(VerletWorld world, bool pinFirst = true, bool pinLast = false, bool drawIntermediatePoints = false) { this.world = world; this.pinFirst = pinFirst; this.pinLast = pinLast; this.drawIntermediatePoints = drawIntermediatePoints; points = new List <VerletPoint>(); }
/// <summary> /// Create a verlet ragdoll. /// </summary> /// <param name="world">Verlet world</param> /// <param name="centerPosition">Center position</param> /// <param name="height">Body height</param> /// <param name="gravityScale">Gravity scale</param> /// <param name="tearSensitivityFactor">Distance factor required to break links. Use '-1' to create an unbreakable ragdoll</param> /// <param name="pointRadius">Point radius</param> /// <param name="drawIntermediatePoints">Draw all ragdoll points</param> /// <param name="drawSupportLinks">Draw support links</param> public VerletRagdoll(VerletWorld world, Vector2 centerPosition, float height, float gravityScale = 1, float tearSensitivityFactor = -1, float pointRadius = 10f, bool drawIntermediatePoints = false, bool drawSupportLinks = false) { Vector2 genPos() { return(centerPosition + MathUtils.RandVector2(-5, 5, -5, 5)); } VerletPoint createPoint(float mass, float?radius = null, bool?visible = null) { var point = world.CreatePoint(genPos(), mass: mass, radius: radius ?? pointRadius, visible: visible ?? drawIntermediatePoints); point.GravityScale = gravityScale; return(point); } var headSize = pointRadius * 3; var handSize = pointRadius * 2; var footSize = pointRadius * 1.5f; var headLength = height / 7.5f; head = createPoint(4, radius: headSize, visible: true); shoulder = createPoint(26); world.CreateLink(head, shoulder, restingDistance: 5 / 4 * headLength, tearSensitivityFactor: tearSensitivityFactor, stiffness: 1); elbowLeft = createPoint(2); elbowRight = createPoint(2); world.CreateLink(elbowLeft, shoulder, restingDistance: 3 / 2 * headLength, tearSensitivityFactor: tearSensitivityFactor, stiffness: 1); world.CreateLink(elbowRight, shoulder, restingDistance: 3 / 2 * headLength, tearSensitivityFactor: tearSensitivityFactor, stiffness: 1); handLeft = createPoint(2, radius: handSize, visible: true); handRight = createPoint(2, radius: handSize, visible: true); world.CreateLink(handLeft, elbowLeft, restingDistance: 2 * headLength, tearSensitivityFactor: tearSensitivityFactor, stiffness: 1); world.CreateLink(handRight, elbowRight, restingDistance: 2 * headLength, tearSensitivityFactor: tearSensitivityFactor, stiffness: 1); pelvis = createPoint(15); world.CreateLink(pelvis, shoulder, restingDistance: 3.5f * headLength, tearSensitivityFactor: tearSensitivityFactor, stiffness: 0.8f); world.CreateLink(pelvis, head, restingDistance: 4.75f * headLength, tearSensitivityFactor: tearSensitivityFactor, stiffness: 0.02f, visible: drawSupportLinks, color: Colors.LightBlue.WithAlpha(64)); kneeLeft = createPoint(10); kneeRight = createPoint(10); world.CreateLink(kneeLeft, pelvis, restingDistance: 2 * headLength, tearSensitivityFactor: tearSensitivityFactor, stiffness: 1); world.CreateLink(kneeRight, pelvis, restingDistance: 2 * headLength, tearSensitivityFactor: tearSensitivityFactor, stiffness: 1); footLeft = createPoint(20, radius: footSize, visible: true); footRight = createPoint(20, radius: footSize, visible: true); world.CreateLink(footLeft, kneeLeft, restingDistance: 2 * headLength, tearSensitivityFactor: tearSensitivityFactor, stiffness: 1); world.CreateLink(footRight, kneeRight, restingDistance: 2 * headLength, tearSensitivityFactor: tearSensitivityFactor, stiffness: 1); world.CreateLink(footLeft, shoulder, restingDistance: 7.5f * headLength, tearSensitivityFactor: tearSensitivityFactor, stiffness: 0.001f, visible: drawSupportLinks, color: Colors.LightBlue.WithAlpha(64)); world.CreateLink(footRight, shoulder, restingDistance: 7.5f * headLength, tearSensitivityFactor: tearSensitivityFactor, stiffness: 0.001f, visible: drawSupportLinks, color: Colors.LightBlue.WithAlpha(64)); }
/// <summary> /// Create a simple verlet link. /// </summary> /// <param name="world">World</param> /// <param name="a">Point A</param> /// <param name="b">Point B</param> public VerletLink(VerletWorld world, VerletPoint a, VerletPoint b) { A = a; B = b; this.world = world; PositionA = A.GlobalPosition; PositionB = B.GlobalPosition; if (RestingDistance == 0) { // Calculate resting distance from points position RestingDistance = (PositionB - PositionA).Length(); } }
/// <summary> /// Create an uninitialized verlet link. /// </summary> public VerletLink() { this.world = null; }
/// <summary> /// Create a verlet cloth. /// </summary> /// <param name="world">Verlet world</param> /// <param name="topLeftPosition">Top-left position</param> /// <param name="pointCount">X/Y point count</param> /// <param name="separation">Separation</param> /// <param name="pinMode">Pin mode</param> /// <param name="tearSensitivityFactor">Distance factor required to break the cloth. Use `-1` to create an unbreakable cloth.</param> /// <param name="stiffness">Stiffness of the cloth</param> /// <param name="drawPoints">Draw verlet points</param> /// <param name="pointRadius">Verlet point radius</param> public VerletCloth(VerletWorld world, Vector2 topLeftPosition, Vector2 pointCount, float separation, PinModeEnum pinMode = PinModeEnum.TopCorners, float tearSensitivityFactor = 2, float stiffness = 1, bool drawPoints = false, float pointRadius = 10f) { points = new List <VerletPoint>(); for (int j = 0; j < pointCount.y; ++j) { for (int i = 0; i < pointCount.x; ++i) { var position = topLeftPosition + new Vector2(separation * i, separation * j); var point = world.CreatePoint(); point.Radius = pointRadius; point.Visible = drawPoints; point.MoveToPosition(position); if (pinMode == PinModeEnum.AllCorners) { if ((j == 0 || j == pointCount.y - 1) && (i == 0 || i == pointCount.x - 1)) { point.PinToCurrentPosition(); } } else if (pinMode == PinModeEnum.TopCorners) { if (j == 0 && (i == 0 || i == pointCount.x - 1)) { point.PinToCurrentPosition(); } } else if (pinMode == PinModeEnum.Top) { if (j == 0) { point.PinToCurrentPosition(); } } points.Add(point); } } if (points.Count == 0) { GD.PrintErr("Bad points length for cloth. Need to be > 0"); return; } for (int j = 0; j < pointCount.y; ++j) { for (int i = 0; i < pointCount.x; ++i) { if (i > 0) { // Right to left int pAIdx = i - 1 + (j * (int)pointCount.x); int pBIdx = i + (j * (int)pointCount.x); var link = world.CreateLink(points[pAIdx], points[pBIdx]); link.RestingDistance = separation; link.TearSensitivity = separation * tearSensitivityFactor; link.Stiffness = stiffness; } if (j > 0) { // Bottom to top int pAIdx = i + ((j - 1) * (int)pointCount.x); int pBIdx = i + (j * (int)pointCount.x); var link = world.CreateLink(points[pAIdx], points[pBIdx]); link.RestingDistance = separation; link.TearSensitivity = separation * tearSensitivityFactor; link.Stiffness = stiffness; } } } }