288 lines
11 KiB
C#
288 lines
11 KiB
C#
using UnityEngine;
|
|
using System.Collections;
|
|
|
|
|
|
namespace Obi
|
|
{
|
|
[AddComponentMenu("Physics/Obi/Obi Rope Cursor", 883)]
|
|
[RequireComponent(typeof(ObiRope))]
|
|
public class ObiRopeCursor : MonoBehaviour
|
|
{
|
|
ObiRope rope;
|
|
|
|
[Range(0, 1)]
|
|
[HideInInspector] [SerializeField] private float m_CursorMu;
|
|
|
|
[Range(0, 1)]
|
|
[HideInInspector] [SerializeField] private float m_SourceMu;
|
|
|
|
public bool direction = true;
|
|
|
|
ObiStructuralElement m_CursorElement = null;
|
|
private int m_SourceIndex = -1;
|
|
private float lengthChange = 0;
|
|
|
|
public float cursorMu
|
|
{
|
|
set
|
|
{
|
|
m_CursorMu = value;
|
|
UpdateCursor();
|
|
}
|
|
get { return m_CursorMu; }
|
|
}
|
|
|
|
public float sourceMu
|
|
{
|
|
set
|
|
{
|
|
m_SourceMu = value;
|
|
UpdateSource();
|
|
}
|
|
get { return m_SourceMu; }
|
|
}
|
|
|
|
public ObiStructuralElement cursorElement
|
|
{
|
|
get
|
|
{
|
|
if (m_CursorElement == null)
|
|
UpdateCursor();
|
|
return m_CursorElement;
|
|
}
|
|
}
|
|
|
|
public int sourceParticleIndex
|
|
{
|
|
get
|
|
{
|
|
if (m_SourceIndex < 0)
|
|
UpdateSource();
|
|
return m_SourceIndex;
|
|
}
|
|
}
|
|
|
|
private void OnEnable()
|
|
{
|
|
rope = GetComponent<ObiRope>();
|
|
|
|
rope.OnElementsGenerated += Actor_OnElementsGenerated;
|
|
rope.OnSimulationStart += Rope_OnSimulate;
|
|
if (rope.elements != null && rope.elements.Count > 0)
|
|
Actor_OnElementsGenerated(rope);
|
|
}
|
|
|
|
private void OnDisable()
|
|
{
|
|
rope.OnElementsGenerated -= Actor_OnElementsGenerated;
|
|
rope.OnSimulationStart -= Rope_OnSimulate;
|
|
}
|
|
|
|
private void Actor_OnElementsGenerated(ObiActor actor)
|
|
{
|
|
UpdateCursor();
|
|
UpdateSource();
|
|
}
|
|
|
|
private void Rope_OnSimulate(ObiActor actor, float simulatedTime, float substepTime)
|
|
{
|
|
if (!rope.isLoaded || Mathf.Abs(lengthChange) < ObiUtils.epsilon)
|
|
return;
|
|
|
|
var solver = rope.solver;
|
|
|
|
// remove:
|
|
if (lengthChange < 0)
|
|
{
|
|
lengthChange = -lengthChange;
|
|
|
|
while (lengthChange > m_CursorElement.restLength)
|
|
{
|
|
lengthChange -= m_CursorElement.restLength;
|
|
|
|
// if we subtracted the length of the last element, break out of the loop.
|
|
if (rope.elements.Count == 1)
|
|
break;
|
|
|
|
int index = rope.elements.IndexOf(m_CursorElement);
|
|
|
|
if (index >= 0)
|
|
{
|
|
// positive direction:
|
|
if (direction)
|
|
{
|
|
RemoveParticleAt(solver.particleToActor[m_CursorElement.particle2].indexInActor);
|
|
rope.elements.RemoveAt(index);
|
|
|
|
if (index < rope.elements.Count)
|
|
{
|
|
if (rope.elements[index].particle1 == m_CursorElement.particle2)
|
|
rope.elements[index].particle1 = m_CursorElement.particle1;
|
|
|
|
m_CursorElement = rope.elements[index];
|
|
}
|
|
else
|
|
m_CursorElement = rope.elements[Mathf.Max(0, index - 1)];
|
|
}
|
|
else // negative direction:
|
|
{
|
|
RemoveParticleAt(solver.particleToActor[m_CursorElement.particle1].indexInActor);
|
|
rope.elements.RemoveAt(index);
|
|
|
|
if (index > 0)
|
|
{
|
|
if (rope.elements[index - 1].particle2 == m_CursorElement.particle1)
|
|
rope.elements[index - 1].particle2 = m_CursorElement.particle2;
|
|
m_CursorElement = rope.elements[index - 1];
|
|
}
|
|
else
|
|
m_CursorElement = rope.elements[0];
|
|
}
|
|
}
|
|
}
|
|
|
|
// the remaining length is subtracted from the current constraint:
|
|
if (lengthChange > 0)
|
|
m_CursorElement.restLength = Mathf.Max(0, m_CursorElement.restLength - lengthChange);
|
|
|
|
}
|
|
// add
|
|
else
|
|
{
|
|
float lengthDelta = Mathf.Min(lengthChange, Mathf.Max(0, rope.ropeBlueprint.interParticleDistance - m_CursorElement.restLength));
|
|
|
|
// extend the current element, if possible:
|
|
if (lengthDelta > 0)
|
|
{
|
|
m_CursorElement.restLength += lengthDelta;
|
|
lengthChange -= lengthDelta;
|
|
}
|
|
|
|
// once the current element has been extended, see if we must add new elements, if there's enough particles left:
|
|
while (rope.activeParticleCount < rope.sourceBlueprint.particleCount &&
|
|
m_CursorElement.restLength + lengthChange > rope.ropeBlueprint.interParticleDistance)
|
|
{
|
|
// calculate added length:
|
|
lengthDelta = Mathf.Min(lengthChange, rope.ropeBlueprint.interParticleDistance);
|
|
lengthChange -= lengthDelta;
|
|
|
|
if (direction)
|
|
{
|
|
// add new particle:
|
|
int newParticleSolverIndex = AddParticleAt(solver.particleToActor[m_CursorElement.particle1].indexInActor);
|
|
|
|
// set position of the new particle:
|
|
solver.positions[newParticleSolverIndex] = solver.positions[m_CursorElement.particle1] +
|
|
(solver.positions[m_CursorElement.particle2] - solver.positions[m_CursorElement.particle1]) * lengthDelta;
|
|
|
|
// insert a new element:
|
|
ObiStructuralElement newElement = new ObiStructuralElement();
|
|
newElement.restLength = lengthDelta;
|
|
newElement.particle1 = m_CursorElement.particle1;
|
|
newElement.particle2 = newParticleSolverIndex;
|
|
m_CursorElement.particle1 = newParticleSolverIndex;
|
|
int index = rope.elements.IndexOf(m_CursorElement);
|
|
rope.elements.Insert(index, newElement);
|
|
|
|
m_CursorElement = newElement;
|
|
}
|
|
else
|
|
{
|
|
// add new particle:
|
|
int newParticleSolverIndex = AddParticleAt(solver.particleToActor[m_CursorElement.particle2].indexInActor);
|
|
|
|
// set position of the new particle:
|
|
solver.positions[newParticleSolverIndex] = solver.positions[m_CursorElement.particle2] +
|
|
(solver.positions[m_CursorElement.particle1] - solver.positions[m_CursorElement.particle2]) * lengthDelta;
|
|
|
|
// insert a new element:
|
|
ObiStructuralElement newElement = new ObiStructuralElement();
|
|
newElement.restLength = lengthDelta;
|
|
newElement.particle1 = newParticleSolverIndex;
|
|
newElement.particle2 = m_CursorElement.particle2;
|
|
m_CursorElement.particle2 = newParticleSolverIndex;
|
|
int index = rope.elements.IndexOf(m_CursorElement);
|
|
rope.elements.Insert(index + 1, newElement);
|
|
|
|
m_CursorElement = newElement;
|
|
}
|
|
}
|
|
|
|
// the remaining length is added to the current constraint:
|
|
if (lengthChange > 0)
|
|
m_CursorElement.restLength += lengthChange;
|
|
|
|
}
|
|
|
|
// recalculate rest positions and length prior to constraints (bend constraints need rest positions):
|
|
rope.RecalculateRestPositions();
|
|
rope.RecalculateRestLength();
|
|
|
|
// rebuild constraints:
|
|
rope.RebuildConstraintsFromElements();
|
|
|
|
lengthChange = 0;
|
|
}
|
|
|
|
public void UpdateCursor()
|
|
{
|
|
rope = GetComponent<ObiRope>();
|
|
m_CursorElement = null;
|
|
if (rope.isLoaded)
|
|
{
|
|
float elmMu;
|
|
m_CursorElement = rope.GetElementAt(cursorMu, out elmMu);
|
|
}
|
|
}
|
|
|
|
public void UpdateSource()
|
|
{
|
|
rope = GetComponent<ObiRope>();
|
|
m_SourceIndex = -1;
|
|
if (rope.isLoaded)
|
|
{
|
|
float elmMu;
|
|
var elm = rope.GetElementAt(sourceMu, out elmMu);
|
|
if (elm != null && rope.solver != null)
|
|
{
|
|
m_SourceIndex = elmMu < 0.5f ? elm.particle1 : elm.particle2;
|
|
}
|
|
}
|
|
}
|
|
|
|
private int AddParticleAt(int index)
|
|
{
|
|
int targetIndex = rope.activeParticleCount;
|
|
|
|
// Copy data from the particle where we will insert new particles, to the particles we will insert:
|
|
rope.CopyParticle(rope.solver.particleToActor[m_SourceIndex].indexInActor, targetIndex);
|
|
|
|
// Move the new particle to the one at the place where we will insert it:
|
|
rope.TeleportParticle(targetIndex, rope.solver.positions[rope.solverIndices[index]]);
|
|
|
|
// Activate the particle:
|
|
rope.ActivateParticle();
|
|
rope.SetRenderingDirty(Oni.RenderingSystemType.AllRopes);
|
|
|
|
return rope.solverIndices[targetIndex];
|
|
}
|
|
|
|
private void RemoveParticleAt(int index)
|
|
{
|
|
rope.DeactivateParticle(index);
|
|
rope.SetRenderingDirty(Oni.RenderingSystemType.AllRopes);
|
|
}
|
|
|
|
public float ChangeLength(float lengthChange)
|
|
{
|
|
// clamp new length to sane limits:
|
|
//newLength = Mathf.Clamp(newLength, 0, (rope.sourceBlueprint.particleCount - 1) * rope.ropeBlueprint.interParticleDistance);
|
|
|
|
// accumulate length change, we'll reset it to zero after it has been applied.
|
|
this.lengthChange += lengthChange;
|
|
|
|
// return new length:
|
|
return this.lengthChange + rope.restLength;
|
|
}
|
|
}
|
|
} |