using System.Collections; using System.Collections.Generic; using UnityEngine; using Obi; /** * Sample component that procedurally generates a net using rigidbodies and ropes. */ public class RopeNet : MonoBehaviour { public Material material; public Vector2Int resolution = new Vector2Int(5, 5); public Vector2 size = new Vector2(0.5f, 0.5f); public float nodeSize = 0.2f; void Awake() { // create an object containing both the solver and the updater: GameObject solverObject = new GameObject("solver", typeof(ObiSolver)); ObiSolver solver = solverObject.GetComponent(); solver.substeps = 2; // adjust solver settings: solver.particleCollisionConstraintParameters.enabled = false; solver.distanceConstraintParameters.iterations = 8; solver.pinConstraintParameters.iterations = 4; solver.parameters.sleepThreshold = 0.001f; solver.PushSolverParameters(); // create the net (ropes + rigidbodies) CreateNet(solver); } private void CreateNet(ObiSolver solver) { ObiCollider[,] nodes = new ObiCollider[resolution.x + 1, resolution.y + 1]; for (int x = 0; x <= resolution.x; ++x) { for (int y = 0; y <= resolution.y; ++y) { GameObject rb = GameObject.CreatePrimitive(PrimitiveType.Cube); rb.transform.position = new Vector3(x, y, 0) * size; rb.transform.localScale = new Vector3(nodeSize, nodeSize, nodeSize); rb.AddComponent(); nodes[x, y] = rb.AddComponent(); nodes[x, y].Filter = 1; } } nodes[0, resolution.y].GetComponent().isKinematic = true; nodes[resolution.x, resolution.y].GetComponent().isKinematic = true; for (int x = 0; x <= resolution.x; ++x) { for (int y = 0; y <= resolution.y; ++y) { Vector3 pos = new Vector3(x, y, 0) * size; if (x < resolution.x) { Vector3 offset = new Vector3(nodeSize * 0.5f, 0, 0); var rope = CreateRope(pos + offset, pos + new Vector3(size.x, 0, 0) - offset); rope.transform.parent = solver.transform; PinRope(rope, nodes[x, y], nodes[x + 1, y]); } if (y < resolution.y) { Vector3 offset = new Vector3(0, nodeSize * 0.5f, 0); var rope = CreateRope(pos + offset, pos + new Vector3(0, size.y, 0) - offset); rope.transform.parent = solver.transform; PinRope(rope, nodes[x, y], nodes[x, y + 1]); } } } } private void PinRope(ObiRope rope, ObiCollider bodyA, ObiCollider bodyB) { var A = rope.gameObject.AddComponent(); var B = rope.gameObject.AddComponent(); A.attachmentType = ObiParticleAttachment.AttachmentType.Dynamic; B.attachmentType = ObiParticleAttachment.AttachmentType.Dynamic; A.target = bodyA.transform; B.target = bodyB.transform; A.particleGroup = rope.ropeBlueprint.groups[0]; B.particleGroup = rope.ropeBlueprint.groups[1]; } // Creates a rope between two points in world space: private ObiRope CreateRope(Vector3 pointA, Vector3 pointB) { // Create a rope var ropeObject = new GameObject("solver", typeof(ObiRope), typeof(ObiRopeLineRenderer)); var rope = ropeObject.GetComponent(); var ropeRenderer = ropeObject.GetComponent(); rope.GetComponent().material = material; rope.GetComponent().decimation = 0.1f; ropeRenderer.uvScale = new Vector2(1, 5); // Setup a blueprint for the rope: var blueprint = ScriptableObject.CreateInstance(); blueprint.resolution = 0.15f; blueprint.thickness = 0.02f; blueprint.pooledParticles = 0; // convert both points to the rope's local space: pointA = rope.transform.InverseTransformPoint(pointA); pointB = rope.transform.InverseTransformPoint(pointB); // Procedurally generate the rope path (a simple straight line): Vector3 direction = (pointB - pointA) * 0.25f; blueprint.path.Clear(); blueprint.path.AddControlPoint(pointA, -direction, direction, Vector3.up, 0.1f, 0.1f, 1, 1, Color.white, "A"); blueprint.path.AddControlPoint(pointB, -direction, direction, Vector3.up, 0.1f, 0.1f, 1, 1, Color.white, "B"); blueprint.path.FlushEvents(); rope.ropeBlueprint = blueprint; return rope; } }