Posts: 5
Threads: 2
Joined: Jul 2024
Reputation:
0
25-07-2024, 03:07 PM
(This post was last modified: 25-07-2024, 04:26 PM by Ferhat123.)
Hi,
After cutting the rope into two, I want to attach gameobjects to the ends of each rope piece.
I guess I can't add control points at runtime to attach these gameobjects so how can I do it.
Thank you,
Posts: 6,216
Threads: 23
Joined: Jun 2017
Reputation:
392
Obi Owner:
25-07-2024, 04:27 PM
(This post was last modified: 25-07-2024, 04:31 PM by josemendez.)
(25-07-2024, 03:07 PM)Ferhat123 Wrote: Hi,
I want to attach gameobjects to the ends of both ropes after tearing them apart. I want to do this every time I tear up any rope.
I guess I can't add control points at runtime to attach these gameobjects, so maybe the solution is to generate two separate ropes at runtime when I cut the original rope.
How can I do it?
Thank you,
Hi!
Attachments take a particle group (not a control point) as argument, and you can create particle groups at runtime just fine. See:
https://obi.virtualmethodstudio.com/manu...ments.html
So you can just get both particles involved in a tear operation, create one particle group for each and attach them.
Also note that using attachments in this way only makes sense if you’re attaching rigidbodies and you need two-way coupling with the rope, if you just want to set the position of a gameObject to follow the cut ends you can do so like the ElectricWires sample scene does.
Let me know if you need further help,
Kind regards
Posts: 5
Threads: 2
Joined: Jul 2024
Reputation:
0
Thank you for your answer.
I tried your suggestion. I'm encountering a strange situation as shown in the video I shared.
https://drive.google.com/file/d/1Bd3HLS5...sp=sharing
As shown in the video, there is a yellow cylinder that is already attached. After cutting, I attach one cylinder to the end of the rope fixed to the wall and another cylinder to the beginning of the falling piece.
Here is my code:
Code: private void ScreenSpaceCut(Vector2 lineStart, Vector2 lineEnd)
{
// keep track of whether the rope was cut or not.
bool cut = false;
int leftParticles = -1;
int rightParticle = -1;
// iterate over all elements and test them for intersection with the line:
for (int i = 0; i < rope.elements.Count; ++i)
{
// project the both ends of the element to screen space.
Vector3 screenPos1 = cam.WorldToScreenPoint(rope.solver.positions[rope.elements[i].particle1]);
Vector3 screenPos2 = cam.WorldToScreenPoint(rope.solver.positions[rope.elements[i].particle2]);
// test if there's an intersection:
if (SegmentSegmentIntersection(screenPos1, screenPos2, lineStart, lineEnd, out float r, out float s))
{
leftParticles = rope.elements[i].particle1;
rightParticle = rope.elements[i].particle2;
cut = true;
rope.Tear(rope.elements[i]);
}
}
// If the rope was cut at any point, rebuilt constraints:
if (cut)
{
rope.RebuildConstraintsFromElements();
obiTest.AddNewSolidModel(leftParticles, rightParticle);
}
}
Code: public void AddNewSolidModel(int leftParticle, int rightParticle)
{
AttachSolidModel(leftParticle, "Left");
AttachSolidModel(rightParticle, "Right");
}
private void AttachSolidModel(int particle, string groupName)
{
var go = Instantiate(solidModel);
go.transform.position = rope.solver.positions[particle];
go.transform.rotation = transform.rotation;
var group = ScriptableObject.CreateInstance<ObiParticleGroup>();
group.particleIndices.Add(particle);
group.name = groupName;
var particleAttachment = gameObject.AddComponent<ObiParticleAttachment>();
particleAttachment.particleGroup = group;
particleAttachment.attachmentType = ObiParticleAttachment.AttachmentType.Dynamic;
particleAttachment.target = go.transform;
}
Posts: 6,216
Threads: 23
Joined: Jun 2017
Reputation:
392
Obi Owner:
25-07-2024, 06:01 PM
(This post was last modified: 25-07-2024, 06:05 PM by josemendez.)
(25-07-2024, 05:28 PM)Ferhat123 Wrote: Thank you for your answer.
I tried your suggestion. I'm encountering a strange situation as shown in the video I shared.
https://drive.google.com/file/d/1Bd3HLS5...sp=sharing
As shown in the video, there is a yellow cylinder that is already attached. After cutting, I attach one cylinder to the end of the rope fixed to the wall and another cylinder to the beginning of the falling piece.
Here is my code:
Code: private void ScreenSpaceCut(Vector2 lineStart, Vector2 lineEnd)
{
// keep track of whether the rope was cut or not.
bool cut = false;
int leftParticles = -1;
int rightParticle = -1;
// iterate over all elements and test them for intersection with the line:
for (int i = 0; i < rope.elements.Count; ++i)
{
// project the both ends of the element to screen space.
Vector3 screenPos1 = cam.WorldToScreenPoint(rope.solver.positions[rope.elements[i].particle1]);
Vector3 screenPos2 = cam.WorldToScreenPoint(rope.solver.positions[rope.elements[i].particle2]);
// test if there's an intersection:
if (SegmentSegmentIntersection(screenPos1, screenPos2, lineStart, lineEnd, out float r, out float s))
{
leftParticles = rope.elements[i].particle1;
rightParticle = rope.elements[i].particle2;
cut = true;
rope.Tear(rope.elements[i]);
}
}
// If the rope was cut at any point, rebuilt constraints:
if (cut)
{
rope.RebuildConstraintsFromElements();
obiTest.AddNewSolidModel(leftParticles, rightParticle);
}
}
Code: public void AddNewSolidModel(int leftParticle, int rightParticle)
{
AttachSolidModel(leftParticle, "Left");
AttachSolidModel(rightParticle, "Right");
}
private void AttachSolidModel(int particle, string groupName)
{
var go = Instantiate(solidModel);
go.transform.position = rope.solver.positions[particle];
go.transform.rotation = transform.rotation;
var group = ScriptableObject.CreateInstance<ObiParticleGroup>();
group.particleIndices.Add(particle);
group.name = groupName;
var particleAttachment = gameObject.AddComponent<ObiParticleAttachment>();
particleAttachment.particleGroup = group;
particleAttachment.attachmentType = ObiParticleAttachment.AttachmentType.Dynamic;
particleAttachment.target = go.transform;
}
Hi,
Ropes only consider particle positions, not rotations/orientation. Only rods consider rotation.
How are you attaching the first cylinder to the rope? The only way to do this in a rope is to use two attachments, as that removes two rotational degrees of freedom (only one line passes trough two points in space). If this is what you’re doing for ths first cylinder, you should follow the same method for the dynamically attached cylinders.
Kind regards,
Posts: 5
Threads: 2
Joined: Jul 2024
Reputation:
0
25-07-2024, 07:28 PM
(This post was last modified: 01-08-2024, 09:41 AM by Ferhat123.)
Yes I attached first cylinder as you mentioned. I used two attachments.
To do the same thing in code, I create two attachment and particleGroup for each seperated ropes. If element's particle1 = 6 and particle2 = 7 then after tear up left rope's last particle would be 6 and second rope's first particle would be newly created particle, lets say 10.
So I create two attachment for particle 5,6 and two attachment for 10,7 and I create particleGroup for each attachment. My code looks like this.
Code: public void AddNewSolidModel((int, int) particlesleft, (int, int) particlesRight)
{
var leftGo = Instantiate(solidModel);
AttachSolidModel(particlesleft, "Left", leftGo);
var rightGo = Instantiate(solidModel);
AttachSolidModel(particlesRight, "Right", rightGo);
}
private void AttachSolidModel((int, int) particles, string groupName, GameObject go)
{
go.transform.position = rope.solver.positions[particles.Item1];
InstantiateAttachments(particles.Item1, go.transform, groupName + "1");
InstantiateAttachments(particles.Item2, go.transform, groupName + "2");
}
private void InstantiateAttachments(int particle, Transform target, string groupName)
{
var group = ScriptableObject.CreateInstance<ObiParticleGroup>();
group.particleIndices.Add(particle);
group.name = groupName;
var particleAttachment = gameObject.AddComponent<ObiParticleAttachment>();
particleAttachment.particleGroup = group;
particleAttachment.attachmentType = ObiParticleAttachment.AttachmentType.Dynamic;
particleAttachment.target = target;
}
Code: private void ScreenSpaceCut(Vector2 lineStart, Vector2 lineEnd)
{
// keep track of whether the rope was cut or not.
bool cut = false;
(int, int) particlesBefore = (-1, -1);
(int, int) particlesAfter = (-1, -1);
// iterate over all elements and test them for intersection with the line:
for (int i = 0; i < rope.elements.Count; ++i)
{
// project the both ends of the element to screen space.
Vector3 screenPos1 = cam.WorldToScreenPoint(rope.solver.positions[rope.elements[i].particle1]);
Vector3 screenPos2 = cam.WorldToScreenPoint(rope.solver.positions[rope.elements[i].particle2]);
// test if there's an intersection:
if (SegmentSegmentIntersection(screenPos1, screenPos2, lineStart, lineEnd, out float r, out float s))
{
particlesBefore = (rope.elements[i].particle1, rope.elements[i].particle2);
cut = true;
rope.Tear(rope.elements[i]);
particlesAfter = (rope.elements[i].particle1, rope.elements[i].particle2);
}
}
// If the rope was cut at any point, rebuilt constraints:
if (cut)
{
rope.RebuildConstraintsFromElements();
obiTest.AddNewSolidModel(particlesBefore, particlesAfter);
}
}
Here is ss of created attachments after cut:
https://drive.google.com/file/d/13z00AwX...sp=sharing
Here is new recorded video:
https://drive.google.com/file/d/1QqmHQR7...sp=sharing
For this video I add little delay before attaching gameobjects:
https://drive.google.com/file/d/1hvtCFxs...sp=sharing
Edit:
I was attaching gameobject to rope after I cut it. I needed to wait one frame to attach objects.
Code: [Button("Tear")]
public void TearCable()
{
rope.Tear(rope.elements[elementIndex]);
rope.RebuildConstraintsFromElements();
StartCoroutine(AddModelAfterCutEnumerator());
}
private IEnumerator AddModelAfterCutEnumerator()
{
yield return new WaitForEndOfFrame();
var element = rope.elements[elementIndex - 1];
AddNewSolidModel((element.particle1, element.particle2));
}
|