Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  How can I make my ropes not float upwards?
#1
Pregunta 
Hello,

I am trying to figure out a way to have multiple pin points on my rope so I can move them like a snake.

I am unable to figure out what may cause this bug, my rope is floating on the non-kinematic end. For context, the selected object is a kinematic pin on my rope, the other golden balls are non-kinematic obi rigid bodies.

I am providing my solver settings alongside my result in the attachment.

Here's the code snippet I used to create the rope:

(It is messy but I use it for having pre-existing control points in the scene, and creating a rope blueprint and a rope out of these existing control points called "snake pieces")

Code:
using System;
using System.Collections.Generic;
using System.Linq;
using _Game.Scripts.GameplayElements.Snakes;
using Obi;
using UnityEngine;

namespace _Game.Scripts.Gameplay.Demo
{
    public class DemoSnake : MonoBehaviour
    {
        [SerializeField] private List<SnakePiece> snakePieces;
        [SerializeField] private ObiSolver solver;
        [SerializeField] private Material ropeMaterial;
        [SerializeField] private ObiRopeSection ropeSection;
        [SerializeField] private ObiCollisionMaterial collisionMaterial;
        [SerializeField] private float ropeThickness;
        [SerializeField] private ObiRope rope;
       
        private ObiCollider[] Colliders => snakePieces.Select(o => o.GetComponent<ObiCollider>()).ToArray();

        private void Start()
        {
            CreateSnake();
        }


        private void CreateSnake()
        {
            rope = CreateRopeProcedurally(this, Colliders, 0);
            PinRope(rope, Colliders);
        }
       
        public void PinRope(ObiRope rope, params ObiCollider[] colliders)
        {
            PinRopeEnds(rope, colliders);
           
            for (int i = 1; i < colliders.Length-1; i++)
            {
                var obiCollider = colliders[i];
                var attachment = rope.gameObject.AddComponent<ObiParticleAttachment>();
                attachment.attachmentType = ObiParticleAttachment.AttachmentType.Dynamic;
                attachment.target = obiCollider.transform;
                attachment.particleGroup = rope.ropeBlueprint.groups[i];
                attachment.compliance = 0F;
            }
        }

        public void PinRopeEnds(ObiRope rope, params ObiCollider[] colliders)
        {
            var colliderStart = colliders[0];
            var colliderEnd = colliders[^1];

            var startIndex = rope.ropeBlueprint.groups.FindIndex(g => g.name == "start");
            var endIndex = rope.ropeBlueprint.groups.FindIndex(g => g.name == "end");

            var attachmentStart = rope.gameObject.AddComponent<ObiParticleAttachment>();
            attachmentStart.attachmentType = ObiParticleAttachment.AttachmentType.Dynamic;
            attachmentStart.target = colliderStart.transform;
            attachmentStart.particleGroup = rope.ropeBlueprint.groups[startIndex];

            var attachmentEnd = rope.gameObject.AddComponent<ObiParticleAttachment>();
            attachmentEnd.attachmentType = ObiParticleAttachment.AttachmentType.Dynamic;
            attachmentEnd.target = colliderEnd.transform;
            attachmentEnd.particleGroup = rope.ropeBlueprint.groups[endIndex];
        }

        public ObiRope CreateRopeProcedurally(DemoSnake snake, ObiCollider[] controlPoints, int index = 0)
        {
            var ropeObject = new GameObject($"Rope_{index}");
            ropeObject.transform.parent = solver.transform;
           
            var rope = ropeObject.AddComponent<ObiRope>();
            var blueprint = CreateBlueprint(snake, controlPoints,out var length);
            rope.ropeBlueprint = blueprint;
            rope.distanceConstraintsEnabled = true;
            rope.stretchingScale = 0.5f;
            rope.surfaceCollisions = false;
            rope.collisionMaterial = collisionMaterial;
            rope.maxBending = 0.5f;
            rope.bendCompliance = 1f;
            rope.selfCollisions = true;
            var ropeRenderer = ropeObject.AddComponent<ObiRopeExtrudedRenderer>();
            ropeRenderer.material = ropeMaterial;
            ropeRenderer.section = ropeSection;
            var smoother = rope.GetComponent<ObiPathSmoother>();
            smoother.decimation = 0.1f;
            smoother.smoothing = 1;
            var ropeReel = ropeObject.AddComponent<ObiRopeReel>();
            ropeReel.enabled = false;
            ropeReel.outThreshold = 0.08f;
            ropeReel.inThreshold = 0.05f;
            ropeReel.outSpeed = 6f;
            ropeReel.inSpeed = 0.1f;
            ropeReel.maxLength = Mathf.Max(1f, length);
            var cursor = ropeObject.GetComponent<ObiRopeCursor>();
            cursor.cursorMu = 0.05f;
            cursor.sourceMu = 0.1f;
            return rope;
        }
       
        public ObiRopeBlueprint CreateBlueprint(DemoSnake snake, ObiCollider[] points, out float distance)
        {
            distance = 0;
            //Create the blueprint
            var blueprint = ScriptableObject.CreateInstance<ObiRopeBlueprint>();
            blueprint.resolution = 1f;
            blueprint.thickness = 0.03f;
            blueprint.pooledParticles = 0;
           
            //Convert ropePoints to controlPoints
            var controlPoints = new Vector3[points.Length];
            blueprint.path.Clear();
            blueprint.ClearParticleGroups();

            var placeholder = Vector3.back * 1000;

            for (int i = 0; i < controlPoints.Length; i++)
            {
                var point = points[i];
                var controlPoint = snake.transform.InverseTransformPoint(point.transform.position);
                controlPoints[i] = controlPoint;
                Vector3 previousPoint  =
                    i <= 0
                        ? placeholder
                        : controlPoints[i - 1];
                Vector3 nextPoint  =
                    i >= controlPoints.Length - 1
                        ? placeholder
                        : controlPoints[i + 1];
               
                previousPoint = previousPoint != placeholder
                    ? previousPoint
                    : controlPoint;
                nextPoint = nextPoint != placeholder
                    ? nextPoint
                    : controlPoint;
               
                if(i != 0) distance += Vector3.Distance(previousPoint, controlPoint);
               
                var inTangentVector = -(controlPoint - previousPoint) * 0.02f;
                var outTangentVector = (nextPoint - controlPoint) * 0.02f;
               
                blueprint.path.AddControlPoint(controlPoint, inTangentVector, outTangentVector,
                    Vector3.up, 0.1f, 0.1f, (i == 0 || i == controlPoints.Length-1 ? ropeThickness*0.8f : ropeThickness), 1, Color.white,
                    //i.ToString());
                    $"{(i == 0 ? "start" : i == controlPoints.Length - 1 ? "end" : i.ToString())}");
                blueprint.path.filters[i] = ObiUtils.MakeFilter(-1, 0);
            }
           
            blueprint.path.FlushEvents();
            return blueprint;
        }
    }
}
Reply
#2
Hi!

There's nothing attached to your post, so I only have the script you shared to go by.

Only thing that looks weird right away is the ObiUtils.MakeFilter(-1, 0) part at the end of the loop. A mask of "-1" doesn't make any sense, masks can range from 0 to 65536 (0x0000ffff). Either use a properly formed bit mask or one of the predefined values, eg. ObiUtils.CollideWithEverything/CollideWithNothing. Most likely, you want to set a value so that the rope doesn't collide against the ObiColliders you're using as control points.

Would it be possible for you to share your solver/rope settings, as well as a video/screenshot of the behavior you're describing?

kind regards,
Reply