31-07-2023, 10:37 AM
(This post was last modified: 31-07-2023, 10:47 AM by Alexander34.)
Hi, I wanted to achieve the visual effect of pumping liquid or air up a rope. To do this, I wrote a script -
public class RopeBump : MonoBehaviour
{
[SerializeField]
private ObiRopeBlueprint _obiRopeBlueprint;
[SerializeField, Range(0.5f, 2f)]
private float _bumpSpeed = 1;
[SerializeField]
private int _framesSkipAnimation;
private bool _isBumping;
[Button]
private async UniTask BumpAsync(float value, bool reverse)
{
if (_isBumping)
return;
_isBumping = true;
var thicknesses = _obiRopeBlueprint.path.thicknesses;
int start = reverse ? thicknesses.Count - 1 : 0;
int end = reverse ? -1 : thicknesses.Count;
int step = reverse ? -1 : 1;
for (int i = start; i != end; i += step)
{
float cachedThickness = thicknesses[i];
float direction = cachedThickness < value ? 1f : -1f;
while (true)
{
thicknesses[i] += _bumpSpeed * direction;
if ((direction == 1f && thicknesses[i] >= value) || (direction == -1f && thicknesses[i] <= cachedThickness))
{
if (direction == -1f)
break;
direction = -1f;
}
_obiRopeBlueprint.path.FlushEvents();
await UniTask.DelayFrame(_framesSkipAnimation);
}
}
for (int i = 0; i < thicknesses.Count; i++)
thicknesses[i] = 1;
_isBumping = false;
}
private void OnEnable()
{
for (int i = 0; i < _obiRopeBlueprint.path.thicknesses.Count; i++)
{
_obiRopeBlueprint.path.thicknesses[i] = 1;
_obiRopeBlueprint.path.FlushEvents();
}
}
private void OnDisable()
{
for (int i = 0; i < _obiRopeBlueprint.path.thicknesses.Count; i++)
{
_obiRopeBlueprint.path.thicknesses[i] = 1;
_obiRopeBlueprint.path.FlushEvents();
}
}
https://dropmefiles.com/H4YYi
In this script I achieved the desired visual, but there were some difficulties, namely -
1 - FPS sag, most likely because of the call FlushEvents() after changing thicknesses[i].
2 - when moving the object, to which the rope is tied, and pumping the rope - the anchor point shifts.
Maybe there is some easier or more obvious way to accomplish the same thing? For example, pick up the rendering of particles and change their thickness asynchronously there? Or something else?
public class RopeBump : MonoBehaviour
{
[SerializeField]
private ObiRopeBlueprint _obiRopeBlueprint;
[SerializeField, Range(0.5f, 2f)]
private float _bumpSpeed = 1;
[SerializeField]
private int _framesSkipAnimation;
private bool _isBumping;
[Button]
private async UniTask BumpAsync(float value, bool reverse)
{
if (_isBumping)
return;
_isBumping = true;
var thicknesses = _obiRopeBlueprint.path.thicknesses;
int start = reverse ? thicknesses.Count - 1 : 0;
int end = reverse ? -1 : thicknesses.Count;
int step = reverse ? -1 : 1;
for (int i = start; i != end; i += step)
{
float cachedThickness = thicknesses[i];
float direction = cachedThickness < value ? 1f : -1f;
while (true)
{
thicknesses[i] += _bumpSpeed * direction;
if ((direction == 1f && thicknesses[i] >= value) || (direction == -1f && thicknesses[i] <= cachedThickness))
{
if (direction == -1f)
break;
direction = -1f;
}
_obiRopeBlueprint.path.FlushEvents();
await UniTask.DelayFrame(_framesSkipAnimation);
}
}
for (int i = 0; i < thicknesses.Count; i++)
thicknesses[i] = 1;
_isBumping = false;
}
private void OnEnable()
{
for (int i = 0; i < _obiRopeBlueprint.path.thicknesses.Count; i++)
{
_obiRopeBlueprint.path.thicknesses[i] = 1;
_obiRopeBlueprint.path.FlushEvents();
}
}
private void OnDisable()
{
for (int i = 0; i < _obiRopeBlueprint.path.thicknesses.Count; i++)
{
_obiRopeBlueprint.path.thicknesses[i] = 1;
_obiRopeBlueprint.path.FlushEvents();
}
}
https://dropmefiles.com/H4YYi
In this script I achieved the desired visual, but there were some difficulties, namely -
1 - FPS sag, most likely because of the call FlushEvents() after changing thicknesses[i].
2 - when moving the object, to which the rope is tied, and pumping the rope - the anchor point shifts.
Maybe there is some easier or more obvious way to accomplish the same thing? For example, pick up the rendering of particles and change their thickness asynchronously there? Or something else?