Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Help  extanding the rope from its end towards a diractino using the RopeCurser
#1
sorry for the long messy code, ive been trying to make a rope that shoot form the place i want towards a diraction and connects both ends for the last couple of days and i had alot of problems but the main one i have now and cant solve is i cant get the rope curses to extend the way i want it to,here my code:

using System.Collections.Generic;
using UnityEngine;
using Obi;

public class ChainPowerUpVersion3_ObiRope : PowerUpConstructor
{
    //public override int UsegeNumber { get{return 2;} }
    public GameObject ExpusedOutfit;
    public override GameObject Outfit { get { return ExpusedOutfit; } }
    bool tryToTurnOff = false;
    PowerUpHandeler HandlerIns;
    public List<string> objectsToTurnOff;
    public override List<string> ObjectToTurnOf { get { return objectsToTurnOff; } }
    public float MaxShotDst = 20f;
    public GameObject ObiRopeSolver;
    public bool AtchObject = false;
    float timeC = 0;
    bool ShotRope = false;
    public float ShotingSpeed = 30f;
    float length = 0;

  ObiSolver SolverComponent;
    public List<intindexList = new List<int>();

    public ObiRope rope;

    public ObiActor actor;

    public GameObject Player;

    public ObiRopeCursor RopeCurser;

    Vector3 RopeTarget;
    public GameObject SolverObject;

    private void Update()
    {


        if (ShotRope)
        {
            //set velocity to zero
            for (int i = 0; i < actor.activeParticleCount; ++i)
            {
                SolverComponent.velocities[actor.solverIndices[i]] = Vector3.zero;
            }

            //extandrope
            int solverIndex = actor.solverIndices[actor.activeParticleCount - 1];
            Vector3 LastPoint = SolverComponent.positions[solverIndex];
            if (Vector3.Distance(LastPoint, RopeTarget) > 0.1f)
            {
                int solverIndex2 = actor.solverIndices[actor.activeParticleCount - 2];
                Vector3 SecoundLastPoint = SolverComponent.positions[solverIndex2];
                float dis = Vector3.Distance(LastPoint, SecoundLastPoint);
                Vector3 WorldPos = SolverObject.transform.TransformPoint(SecoundLastPoint);

                SolverComponent.positions[solverIndex] = SolverObject.transform.
                InverseTransformPoint(WorldPos + (RopeTarget - WorldPos).normalized * (dis));

                length += ShotingSpeed * Time.deltaTime;
                RopeCurser.ChangeLength(length);
            }
            else
            {
                ShotRope = false;
                SolverComponent.gravity = Vector3.down * 9.81f;
            }

        }


    }

  
    public override void ActivatePowerUp(GameObject player, Vector3 AimVector)
    {
        Player = player;

        RaycastHit hit;
        if (Physics.Raycast(player.transform.position, AimVector, out hit, 20f))
        {
            Vector3 StartPos = player.transform.position + player.transform.forward * 0.3f;
            SolverObject = Instantiate(ObiRopeSolver, Vector3.zero, Quaternion.identity);
            rope = SolverObject.transform.GetChild(0).GetComponent<ObiRope>();
            SolverComponent = SolverObject.GetComponent<ObiSolver>();
            actor = SolverComponent.actors[0];
            SolverComponent.gravity = Vector3.zero;
            RopeTarget = hit.point;

            for (int i = 0; i < actor.activeParticleCount; ++i)
            {
                int solverIndex = actor.solverIndices[i];
                indexList.Add(solverIndex);
            }

            SolverComponent.positions[indexList[0]] = SolverObject.transform.
            InverseTransformPoint(player.transform.position + player.transform.forward * 0.3f);

            SolverComponent.positions[indexList[indexList.Count - 1]] = SolverObject.transform.
            InverseTransformPoint(player.transform.position + player.transform.forward * 0.4f);

            RopeCurser = SolverComponent.GetComponentInChildren<ObiRopeCursor>();

            ObiParticleAttachment atch = rope.gameObject.AddComponent<ObiParticleAttachment>();
            ObiParticleGroup particalGroup = rope.ropeBlueprint.groups[0];
            //ObiParticleGroup particalGroup = actor.blueprint.AppendNewParticleGroup("End Point");
            atch.particleGroup = particalGroup;
            atch.attachmentType = ObiParticleAttachment.AttachmentType.Dynamic;
            atch.target = Player.transform.GetChild(1).transform;

            ShotRope = true;

    
        }
    }

}
Reply
#2
(11-01-2022, 03:30 AM)almog1752 Wrote: i had alot of problems but the main one i have now and cant solve is i cant get the rope curses to extend the way i want it to,here my code:

Hi!

I'd need to at least know what the problem is, or why the way this works isn't the way you want it to. Otherwise I don't know what to do to test this! Sonrisa

However I can see an issue in your code: you're assuming particle indices are consecutive, which is only true if the rope is never cut or resized. You're using a cursor, so you cannot assume this. The following code:

Code:
int solverIndex = actor.solverIndices[actor.activeParticleCount - 1];
Vector3 LastPoint = SolverComponent.positions[solverIndex];

Doesn't return the last particle in the rope, as implied. When you change the length of a rope using a cursor, particles are appended to the rope at different places (depending on where the cursor is placed) so the last particle in the solverIndices[] array might be in the middle of the rope or even at the beginning. In these circumstances, you need to use rope elements. These are the "links" in-between particles, and are always guaranteed to be consecutive. Each element joins two particles. So the first particle in the rope is the first particle of the first element, and the last particle in the rope is the second particle of the last element. Like this:

Code:
var LastPoint = SolverComponent.positions[rope.elements[rope.elements.Count-1].particle2];

kind regards,
Reply
#3
(12-01-2022, 08:55 AM)josemendez Wrote: hi like i wrote at the start of my post, ive been trying to make a rope that shoot form the place i want towards a diraction and connects both ends.
i did the change you suggested but the outcome didnt change at all, the rope moves in a very wierd pattern and not in a stright line as expected
Reply
#4
Hi,

There’s nothing in your code that would make the rope shoot in a straight line :/. In the Update() method you remove the velocity from all particles in the rope, and change the position of the last particle.

Then you change the rest lenght of the rope using the cursor. This will simply add extra particles to your rope, but will not place them in a line (specially not if you set their velocities to zero!). Also note that changing the lenght using a cursor might add/remove more than one particle per frame, depending on the difference between the previous length and the new length.


If you want to override the simulation when the rope is being shot, and make the rope extend in a straight line, you need to set the position of *all* rope particles so that they follow a line, or at the very least all particles added by the cursor since last frame.

Will write some sample code for you tomorrow morning. Kind regards,
Reply
#5
(12-01-2022, 06:55 PM)josemendez Wrote: ohhh i though the cursor would add particles at the end of the rope in the diractin of the last particals when i set it to 1\1 and update every frame, i would appreciate a code example and im also having trouble with ataching objects at both ends after adding particles and changing length,if you can give me code example for that as well it would be amazing
Reply
#6
Quote:i would appreciate a code example and im also having trouble with ataching objects at both ends after adding particles and changing length,if you can give me code example for that as well it would be amazing

There's code for this used in the GrapplingHook sample scene. I believe it's basically the same thing you want, except the rope extends instantly.

Will modify it to add extension over time and get back to you.
Reply
#7
Hi,

Please find attached a modified version of the grappling hook that extends over time:

.cs   ExtendableGrapplingHook.cs (Size: 7.79 KB / Downloads: 13)

To change how fast the rope shoots out of the character, change the public "hookShootSpeed" variable. It's expressed in meters/second.

Besides the boilerplate code to create the actor, blueprint, set materials, etc. the code is very simple and I have commented it. The important bit is the extension code, which I will paste here:

Code:
        // set masses to zero, as we're going to override positions while we extend the rope:
        for (int i = 0; i < rope.activeParticleCount; ++i)
            solver.invMasses[rope.solverIndices[i]] = 0;

        float currentLength = 0;

        // while the last particle hasn't reached the hit, extend the rope:
        while (true)
        {
            // calculate rope origin in solver space:
            Vector3 origin = solver.transform.InverseTransformPoint(rope.transform.position);

            // update direction and distance to hook point:
            Vector3 direction = hookAttachment.point - origin;
            float distance = direction.magnitude;
            direction.Normalize();

            // increase length:
            currentLength += hookShootSpeed * Time.deltaTime;

            // if we have reached the desired length, break the loop:
            if (currentLength >= distance)
            {
                cursor.ChangeLength(distance);
                break;
            }

            // change rope length (clamp to distance between rope origin and hook to avoid overshoot)
            cursor.ChangeLength(Mathf.Min(distance, currentLength));

            // iterate over all particles in sequential order, placing them in a straight line while
            // respecting element length:
            float length = 0;
            for (int i = 0; i < rope.elements.Count; ++i)
            {
                solver.positions[rope.elements[i].particle1] = origin + direction * length;
                solver.positions[rope.elements[i].particle2] = origin + direction * (length + rope.elements[i].restLength);
                length += rope.elements[i].restLength;
            }

            // wait one frame:
            yield return null;
        }

        // restore masses so that the simulation takes over now that the rope is in place:
        for (int i = 0; i < rope.activeParticleCount; ++i)
            solver.invMasses[rope.solverIndices[i]] = 10; // 1/0.1 = 10

These are the steps taken:

1) disable simulation for all particles by giving them infinite mass.
in a coroutine loop
{
2) calculate the vector from the character to the point on the wall
3) increase rope length, if it is long enough exit loop.
4) place particles in a straight line.
5) wait until next frame
}
6) re-enable simulation by giving non-infinite mass to particles.

Here's a video of it:


let me know if I can be of further help. cheers,
Reply
#8
(13-01-2022, 02:29 PM)josemendez Wrote: Hi,

Thank you soo much for the help,it helped me a lot!!
i have a few quastions:

1. why do you set the mass to 0 and not infinty? its kinda counter intoative
2.is there a way for obi rope to interact with noraml unity colliders? or do they need to have the obi collider?

and also i had a problem with an error in line 155 of the obichain renderer when the tangent was 0
i just solved it by adding a line:
if(tangent != Vector3.zero)
 linkTransform.rotation = Quaternion.LookRotation(tangent)
Reply
#9
Quote:1. why do you set the mass to 0 and not infinty? its kinda counter intoative

It's not mass, it's inverse mass. That is, 1/mass.

If you set the inverse mass to zero, you're effectively setting the mass to infinite since the limit 1/x when x tends to 0 is infinite.

The reason many engines store inverse mass instead of mass is performance and convenience: internally, it's quite common to divide stuff by mass. By storing 1/mass you can just multiply instead and also avoid division by zero.

Quote:2.is there a way for obi rope to interact with noraml unity colliders? or do they need to have the obi collider?

A ObiCollider is a wrapper over a regular Unity collider. Unity doesn't allow to extend or modify the built-in colliders, so the only way to add additional functionality to a collider is using composition: adding an extra component to it. As a result, all physics engines that aren't built into Unity either use their own collider components or wrap around the existing ones. Take for instance ECS physics (uses its own colliders), MagicaCloth (uses its own colliders), Havok (uses its own colliders), etc.
Reply