ROPE
This commit is contained in:
2922
Assets/Scenes/FishingRopeTest.unity
Normal file
2922
Assets/Scenes/FishingRopeTest.unity
Normal file
File diff suppressed because it is too large
Load Diff
7
Assets/Scenes/FishingRopeTest.unity.meta
Normal file
7
Assets/Scenes/FishingRopeTest.unity.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9d0db7554866cd0429e8f7b5db5412ae
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -207,6 +207,63 @@ MonoBehaviour:
|
||||
m_MaximumFOV: 60
|
||||
m_MinimumOrthoSize: 1
|
||||
m_MaximumOrthoSize: 5000
|
||||
--- !u!1 &159075238
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 159075240}
|
||||
- component: {fileID: 159075239}
|
||||
- component: {fileID: 159075241}
|
||||
m_Layer: 0
|
||||
m_Name: FPS
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &159075239
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 159075238}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 117515d39da46664d994b9132854541c, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::FPSCounter
|
||||
--- !u!4 &159075240
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 159075238}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 24.72638, y: -17.23207, z: 87.19942}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &159075241
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 159075238}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: b189222c6db8433db1239d314f92cf9f, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier: Assembly-CSharp::DontDestroy
|
||||
--- !u!1 &174907465
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -1839,3 +1896,4 @@ SceneRoots:
|
||||
- {fileID: 1199298675}
|
||||
- {fileID: 1688884899048394910}
|
||||
- {fileID: 646846706}
|
||||
- {fileID: 159075240}
|
||||
|
||||
44
Assets/Scripts/Common/FPSShower.cs
Normal file
44
Assets/Scripts/Common/FPSShower.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
public class FPSShower : MonoBehaviour
|
||||
{
|
||||
|
||||
public TextMeshProUGUI TextFPS;
|
||||
|
||||
public float updateInterval = 0.2f; // 更新间隔(秒)
|
||||
|
||||
private float accum = 0;
|
||||
private int frames = 0;
|
||||
private float timeleft;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Application.targetFrameRate = 300; // 设为极高值
|
||||
}
|
||||
|
||||
|
||||
public int FPS;
|
||||
|
||||
void Update()
|
||||
{
|
||||
timeleft -= Time.deltaTime;
|
||||
accum += Time.timeScale / Time.deltaTime;
|
||||
frames++;
|
||||
|
||||
if (timeleft <= 0.0f)
|
||||
{
|
||||
FPS = (int)(accum / frames);
|
||||
|
||||
timeleft = updateInterval;
|
||||
accum = 0.0f;
|
||||
frames = 0;
|
||||
TextFPS.text = FPS.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Common/FPSShower.cs.meta
Normal file
3
Assets/Scripts/Common/FPSShower.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf0d58315f7747cd8e9139b6b7a0345b
|
||||
timeCreated: 1768745219
|
||||
215
Assets/Scripts/Common/FishingRope.cs
Normal file
215
Assets/Scripts/Common/FishingRope.cs
Normal file
@@ -0,0 +1,215 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace NBF
|
||||
{
|
||||
[RequireComponent(typeof(LineRenderer))]
|
||||
public class FishingRope : MonoBehaviour
|
||||
{
|
||||
[Header("Demo Parameters")] [SerializeField, Min(0)]
|
||||
float mouseOffset = 10f;
|
||||
|
||||
[Header("Verlet Parameters")] [SerializeField]
|
||||
float nodeDistance = 0.35f;
|
||||
|
||||
[SerializeField] float nodeColliderRadius = 0.2f;
|
||||
[SerializeField] float gravityStrength = 2;
|
||||
[SerializeField, Range(1, 500)] int totalNodes = 100;
|
||||
[SerializeField, Range(0, 1)] float velocityDampen = 0.95f;
|
||||
[SerializeField, Range(0, 0.99f)] float stiffness = 0.8f;
|
||||
[SerializeField, Range(1, 10)] int iterateCollisionsEvery = 1;
|
||||
[SerializeField, Range(1, 200)] int iterations = 10;
|
||||
[SerializeField] int colliderBufferSize = 1;
|
||||
|
||||
[Header("Line Renderer")] [SerializeField]
|
||||
float ropeWidth = 0.02f;
|
||||
|
||||
// 私有变量
|
||||
Camera cam;
|
||||
Vector3 gravity;
|
||||
Vector3 startLock;
|
||||
Vector3 endLock;
|
||||
bool isStartLocked = false;
|
||||
bool isEndLocked = false;
|
||||
|
||||
// 数组和缓存
|
||||
Vector3[] currentNodePositions;
|
||||
Vector3[] previousNodePositions;
|
||||
Collider[] colliderHitBuffer;
|
||||
LineRenderer lineRenderer;
|
||||
GameObject nodeTester;
|
||||
SphereCollider nodeCollider;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
// 初始化数组
|
||||
currentNodePositions = new Vector3[totalNodes];
|
||||
previousNodePositions = new Vector3[totalNodes];
|
||||
colliderHitBuffer = new Collider[colliderBufferSize];
|
||||
|
||||
// 获取组件引用
|
||||
lineRenderer = GetComponent<LineRenderer>();
|
||||
cam = Camera.main;
|
||||
gravity = new Vector3(0, -gravityStrength, 0);
|
||||
|
||||
// 初始化节点测试器
|
||||
nodeTester = new GameObject("Node Tester");
|
||||
nodeTester.layer = 8;
|
||||
nodeCollider = nodeTester.AddComponent<SphereCollider>();
|
||||
nodeCollider.radius = nodeColliderRadius;
|
||||
|
||||
// 初始化节点位置
|
||||
Vector3 startPos = transform.position;
|
||||
for (int i = 0; i < totalNodes; i++)
|
||||
{
|
||||
currentNodePositions[i] = startPos;
|
||||
previousNodePositions[i] = startPos;
|
||||
startPos.y -= nodeDistance;
|
||||
}
|
||||
|
||||
// 设置线渲染器
|
||||
lineRenderer.startWidth = ropeWidth;
|
||||
lineRenderer.endWidth = ropeWidth;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
// 处理鼠标输入
|
||||
if (Input.GetMouseButtonDown(0))
|
||||
{
|
||||
if (!isStartLocked)
|
||||
{
|
||||
isStartLocked = true;
|
||||
startLock = GetMouseWorldPosition();
|
||||
}
|
||||
else if (!isEndLocked)
|
||||
{
|
||||
isEndLocked = true;
|
||||
endLock = GetMouseWorldPosition();
|
||||
}
|
||||
}
|
||||
else if (!isStartLocked)
|
||||
{
|
||||
startLock = GetMouseWorldPosition();
|
||||
}
|
||||
else if (isStartLocked && !isEndLocked)
|
||||
{
|
||||
endLock = GetMouseWorldPosition();
|
||||
}
|
||||
|
||||
DrawRope();
|
||||
}
|
||||
|
||||
void FixedUpdate()
|
||||
{
|
||||
Simulate();
|
||||
|
||||
for (int i = 0; i < iterations; i++)
|
||||
{
|
||||
ApplyConstraint();
|
||||
|
||||
// 减少碰撞检测频率
|
||||
if (i % (iterateCollisionsEvery + 1) == 0)
|
||||
{
|
||||
AdjustCollisions();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Vector3 GetMouseWorldPosition()
|
||||
{
|
||||
return cam.ScreenToWorldPoint(Input.mousePosition + new Vector3(0, 0, mouseOffset));
|
||||
}
|
||||
|
||||
void Simulate()
|
||||
{
|
||||
float fixedDt = Time.fixedDeltaTime;
|
||||
for (int i = 0; i < totalNodes; i++)
|
||||
{
|
||||
// 计算并应用速度
|
||||
Vector3 velocity = (currentNodePositions[i] - previousNodePositions[i]) * velocityDampen;
|
||||
previousNodePositions[i] = currentNodePositions[i];
|
||||
currentNodePositions[i] += velocity + gravity * fixedDt;
|
||||
}
|
||||
}
|
||||
|
||||
void ApplyConstraint()
|
||||
{
|
||||
// 锁定端点
|
||||
currentNodePositions[0] = startLock;
|
||||
if (isStartLocked && isEndLocked)
|
||||
{
|
||||
currentNodePositions[totalNodes - 1] = endLock;
|
||||
}
|
||||
|
||||
// 预计算所有常用值
|
||||
float halfStiffness = 0.5f * stiffness;
|
||||
float sqrNodeDistance = nodeDistance * nodeDistance;
|
||||
int nodeCountMinusOne = totalNodes - 1;
|
||||
|
||||
for (int i = 0; i < nodeCountMinusOne; i++)
|
||||
{
|
||||
Vector3 node1 = currentNodePositions[i];
|
||||
Vector3 node2 = currentNodePositions[i + 1];
|
||||
Vector3 diff = node1 - node2;
|
||||
|
||||
float sqrDistance = diff.x * diff.x + diff.y * diff.y + diff.z * diff.z;
|
||||
|
||||
// 只有当距离差异超过一定阈值时才调整
|
||||
if (Mathf.Abs(sqrDistance - sqrNodeDistance) > 0.001f)
|
||||
{
|
||||
float distance = Mathf.Sqrt(sqrDistance);
|
||||
float difference = nodeDistance - distance;
|
||||
Vector3 direction = diff / distance; // 比 normalized 更快
|
||||
|
||||
Vector3 adjustment = direction * (difference * halfStiffness);
|
||||
|
||||
currentNodePositions[i] += adjustment;
|
||||
currentNodePositions[i + 1] -= adjustment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void AdjustCollisions()
|
||||
{
|
||||
for (int i = 1; i < totalNodes; i += 2) // 跳过更多节点减少计算
|
||||
{
|
||||
int hits = Physics.OverlapSphereNonAlloc(
|
||||
currentNodePositions[i],
|
||||
nodeColliderRadius,
|
||||
colliderHitBuffer,
|
||||
~(1 << 8)); // 忽略特定层
|
||||
|
||||
for (int n = 0; n < hits; n++)
|
||||
{
|
||||
if (Physics.ComputePenetration(
|
||||
nodeCollider,
|
||||
currentNodePositions[i],
|
||||
Quaternion.identity,
|
||||
colliderHitBuffer[n],
|
||||
colliderHitBuffer[n].transform.position,
|
||||
colliderHitBuffer[n].transform.rotation,
|
||||
out Vector3 direction,
|
||||
out float distance))
|
||||
{
|
||||
currentNodePositions[i] += direction * distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawRope()
|
||||
{
|
||||
// 直接使用currentNodePositions数组避免额外拷贝
|
||||
lineRenderer.positionCount = totalNodes;
|
||||
lineRenderer.SetPositions(currentNodePositions);
|
||||
}
|
||||
|
||||
void OnDestroy()
|
||||
{
|
||||
if (nodeTester != null)
|
||||
{
|
||||
Destroy(nodeTester);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Scripts/Common/FishingRope.cs.meta
Normal file
3
Assets/Scripts/Common/FishingRope.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c499dd9219664cd3a407bd4df1825ca7
|
||||
timeCreated: 1768743058
|
||||
Reference in New Issue
Block a user