I've encountered a situation where I need to change the rest length of a rope that is already present in the scene.
I think I've figured out the solution, and the code seems to work, but I wanted to have you look over it to make sure I'm doing everything correctly (or if there's a better way).
I've added the following method inside ObiRopeBlueprintBase:
Since I'm doing this after the rope has been made, I get the feeling I might not need to do this from the blueprint. But as far as I know this is where the "data" for the rope is stored, whereas the rope itself represents an instance. (RopeBlueprint is to Rope as Mesh is to MeshFilter/MeshRenderer)
Do I, for example, need to call ObiActorBlueprint.OnBlueprintGenerate after making this modification?
On a side note, if my analogy between blueprints and actors vs. meshes and mesh renderers is accurate, I have a suggestion: (Ignore this section if this comparison is way off.) I noticed that ObiRopeBase.cs contains a "restLength" property that is recalculated under some conditions. It seems to me that since all ropes that share the same blueprint would have the same rest length, this data should be stored and calculated inside the blueprint:
I think I've figured out the solution, and the code seems to work, but I wanted to have you look over it to make sure I'm doing everything correctly (or if there's a better way).
I've added the following method inside ObiRopeBlueprintBase:
Code:
public void SetRestLength(float newLength)
{
if(path == null)
{
Debug.LogError("Cannot set length because the path is null.", this);
return;
}
if(path.Length == 0)
{
Debug.LogError("Cannot set length because it is currently 0.", this);
return;
}
float multiplier = newLength / path.Length;
if(float.IsInfinity(multiplier) || float.IsNaN(multiplier))
{
Debug.LogError($"Cannot set length due to floating point error. Old length: {m_RestLength} New length: {newLength}", this);
return;
}
m_InterParticleDistance *= multiplier;
m_RestLength *= multiplier;
if(restLengths != null)
{
int count = restLengths.Length;
for(int i = 0; i < count; i++)
{
restLengths[i] *= multiplier;
}
}
else
{
Debug.LogError($"{nameof(restLengths)} is null. Perhaps it wasn't initialized?", this);
}
var ssData = stretchShearConstraintsData;
if(ssData != null)
{
var batches = ssData.batches;
var batchesCount = batches.Count;
for(int iBatch = 0; iBatch < batchesCount; iBatch++)
{
var batch = batches[iBatch];
var rlenList = batch.restLengths;
var rlenListCount = rlenList.count;
for(int iRest = 0; iRest < rlenListCount; iRest++)
{
rlenList[iRest] *= multiplier;
}
}
}
var dData = distanceConstraintsData;
if(dData != null)
{
var batches = dData.batches;
var batchesCount = batches.Count;
for(int iBatch = 0; iBatch < batchesCount; iBatch++)
{
var batch = batches[iBatch];
var rlenList = batch.restLengths;
var rlenListCount = rlenList.count;
for(int iRest = 0; iRest < rlenListCount; iRest++)
{
rlenList[iRest] *= multiplier;
}
}
}
}
Since I'm doing this after the rope has been made, I get the feeling I might not need to do this from the blueprint. But as far as I know this is where the "data" for the rope is stored, whereas the rope itself represents an instance. (RopeBlueprint is to Rope as Mesh is to MeshFilter/MeshRenderer)
Do I, for example, need to call ObiActorBlueprint.OnBlueprintGenerate after making this modification?
On a side note, if my analogy between blueprints and actors vs. meshes and mesh renderers is accurate, I have a suggestion: (Ignore this section if this comparison is way off.) I noticed that ObiRopeBase.cs contains a "restLength" property that is recalculated under some conditions. It seems to me that since all ropes that share the same blueprint would have the same rest length, this data should be stored and calculated inside the blueprint:
- All ropes using the blueprint will have the correct restLength value automatically the next time they read the property.
- No need to recalculate the same value for multiple ropes sharing the same blueprint.
- No need to use a callback to update the rope instances using the blueprint when it changes. (I don't know to trigger these.)
- Could be useful during blueprint generation (as I had encountered before in a previous thread).
- All the data about the blueprint (and common to all ropes that share the blueprint) is organized in one location.
- The existing property can remain as a shortcut to writing rope.blueprint.restLength.