Files
Fishing2/Assets/Scripts/ThirdParty/Rope/Helpers/SimpleRopeInteraction.cs
2025-11-04 23:11:56 +08:00

172 lines
5.9 KiB
C#

using UnityEngine;
using Unity.Mathematics;
using System.Collections.Generic;
namespace NBF
{
public class SimpleRopeInteraction : MonoBehaviour
{
[Tooltip("The mesh to show on the picked particle position. May be empty.")]
public Mesh pickedMesh;
[Tooltip("The mesh to show on the target position. May be empty.")]
public Mesh targetMesh;
[Tooltip("The material to use for the picked mesh")]
public Material pickedMaterial;
[Tooltip("The material to use for the target mesh")]
public Material targetMaterial;
[Tooltip("The maximum distance a rope can be picked from")]
public float maxPickDistance = 2.0f;
[Tooltip("The max allowable impulse strength to use. If zero, no limit is applied.")]
public float maxImpulseStrength = 3.0f;
[Tooltip("The mass multiplier to apply to the pulled rope particle. Increasing the mass multiplier for a particle increases its influence on neighboring particles. As this script pulls a single particle at a time only, it is beneficial to set the mass multiplier above 1 to improve the stability of the overall rope simulation.")]
public float leverage = 10.0f;
[Tooltip("The keyboard key to use to split a picked rope. May be set to None to disable this feature.")]
public KeyCode splitPickedRopeOnKey = KeyCode.Space;
[Tooltip("The list of ropes that may be picked")]
public List<Rope> ropes;
protected bool ready;
protected Rope rope;
protected int particle;
protected float distance;
protected float3 pickedPosition;
protected float3 targetPosition;
public void SplitPickedRope()
{
if (rope == null)
{
return;
}
ropes.Remove(rope);
var newRopes = new Rope[2];
rope.SplitAt(particle, newRopes);
if (newRopes[0] != null) ropes.Add(newRopes[0]);
if (newRopes[1] != null) ropes.Add(newRopes[1]);
rope = null;
}
protected Rope GetClosestRope(Ray ray, out int closestParticleIndex, out float closestDistanceAlongRay)
{
closestParticleIndex = -1;
closestDistanceAlongRay = 0.0f;
var closestRopeIndex = -1;
var closestDistance = 0.0f;
for (int i = 0; i < ropes.Count; i++)
{
ropes[i].GetClosestParticle(ray, out int particleIndex, out float distance, out float distanceAlongRay);
if (distance > maxPickDistance)
{
continue;
}
if (closestRopeIndex != -1 && distance > closestDistance)
{
continue;
}
closestRopeIndex = i;
closestParticleIndex = particleIndex;
closestDistance = distance;
closestDistanceAlongRay = distanceAlongRay;
}
return closestRopeIndex != -1 ? ropes[closestRopeIndex] : null;
}
public void FixedUpdate()
{
var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Input.GetMouseButton(0))
{
// Mouse down
if (ready && rope == null)
{
// Not pulling a rope, find the closest one to the mouse
var closestRope = GetClosestRope(ray, out int closestParticleIndex, out float closestDistanceAlongRay);
if (closestRope != null && closestParticleIndex != -1 && closestRope.GetMassMultiplierAt(closestParticleIndex) > 0.0f)
{
// Found a rope and particle on the rope, start pulling that particle!
rope = closestRope;
particle = closestParticleIndex;
distance = closestDistanceAlongRay;
ready = false;
}
}
}
else
{
// Mouse up
if (rope != null)
{
// Stop pulling the rope
rope.SetMassMultiplierAt(particle, 1.0f);
rope = null;
}
}
if (rope != null)
{
// We are pulling the rope
// Move the rope particle to the mouse position on the grab-plane
pickedPosition = rope.GetPositionAt(particle);
targetPosition = ray.GetPoint(distance);
if (maxImpulseStrength == 0.0f)
{
rope.SetMassMultiplierAt(particle, 0.0f);
}
else
{
rope.SetMassMultiplierAt(particle, leverage);
}
rope.SetPositionAt(particle, targetPosition, maxImpulseStrength);
// Split the rope on key if keybind is set
if (Input.GetKey(splitPickedRopeOnKey))
{
SplitPickedRope();
}
}
}
public void Update()
{
if (!Input.GetMouseButton(0))
{
ready = true;
}
if (rope != null)
{
if (pickedMesh != null && pickedMaterial != null)
{
Graphics.DrawMesh(pickedMesh, Matrix4x4.TRS(pickedPosition, Quaternion.identity, Vector3.one * 0.25f), pickedMaterial, 0);
}
if (targetMesh != null && targetMaterial != null)
{
Graphics.DrawMesh(targetMesh, Matrix4x4.TRS(targetPosition, Quaternion.identity, Vector3.one * 0.25f), targetMaterial, 0);
}
}
}
}
}