This commit is contained in:
2026-01-18 22:27:22 +08:00
parent 331ec8c8bf
commit 120b8cda26
9 changed files with 3269 additions and 14 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9d0db7554866cd0429e8f7b5db5412ae
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -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}

View 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();
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bf0d58315f7747cd8e9139b6b7a0345b
timeCreated: 1768745219

View 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);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c499dd9219664cd3a407bd4df1825ca7
timeCreated: 1768743058

View File

@@ -8,6 +8,9 @@ EditorBuildSettings:
- enabled: 1
path: Assets/Scenes/StartUp.unity
guid: 64599d3325ec9504aa804534e2feeab6
- enabled: 1
path: Assets/Scenes/FishingRopeTest.unity
guid: 9d0db7554866cd0429e8f7b5db5412ae
- enabled: 1
path: Assets/ResRaw/Maps/Map1/Map1.unity
guid: 087123319930fec42beb5f420fdf983b

View File

@@ -9,31 +9,31 @@ EditorUserSettings:
value: 18134705175a055722080a3115371d4a0d55006876786860616b0471b8b3666cacb72ba5a52a362c3c0ee63201181433fe3e101bf3250b06144ca74c24f1190708e016c213c61a52f91c12cac80fd8edd298e1e4d1fde2cacddeacbcc1fee7eef0e3b6faa69af9ceaeaaec81a6d2c2c8c8c4b2e5dfd5ccd3f8cf
flags: 0
RecentlyUsedSceneGuid-0:
value: 5303020755510a0f5e085c2744775a40454e1a2f282b72632f284d61e1e5673d
flags: 0
RecentlyUsedSceneGuid-1:
value: 565700055d51590c0f56557545710744124f492b2a2976662828456ae6b03269
flags: 0
RecentlyUsedSceneGuid-2:
value: 0254070454505a0d55595d2113250844404f48297b7927342e281b6ab7b2676d
flags: 0
RecentlyUsedSceneGuid-3:
value: 5301015756025c0a095d082148750c444f154e79752e2569787e4966b7b53561
flags: 0
RecentlyUsedSceneGuid-4:
RecentlyUsedSceneGuid-1:
value: 5307565150535b0b0c5a552711700644474e19297a29206379704b37e7b86368
flags: 0
RecentlyUsedSceneGuid-5:
RecentlyUsedSceneGuid-2:
value: 5b520400060d5a5a5b5b557641770b43424f1c28787d25612b2d196ab0b66068
flags: 0
RecentlyUsedSceneGuid-6:
RecentlyUsedSceneGuid-3:
value: 52530c5601535f020f565a2043770d1612154d2f747975692c7b4e66b5e3303b
flags: 0
RecentlyUsedSceneGuid-4:
value: 00050c5150005f5f54560f2640270d4410161c28282b72357e7c4835e4b63760
flags: 0
RecentlyUsedSceneGuid-5:
value: 0707505403515a0b555b557012715d444215197b747e206779281e67e0b6646d
flags: 0
RecentlyUsedSceneGuid-6:
value: 07060c5454040c0a545b547240700a441216417e7f2e7268752c4966b4b0663d
flags: 0
RecentlyUsedSceneGuid-7:
value: 5309035757065a0a54575f7216265c4444151d28792e72627d2f1935bbb8673a
value: 5a55040207025c0e59565a7413270f44444e1d722a7f2465292b4867b3b2353d
flags: 0
RecentlyUsedSceneGuid-8:
value: 00050c5150005f5f54560f2640270d4410161c28282b72357e7c4835e4b63760
value: 5309035757065a0a54575f7216265c4444151d28792e72627d2f1935bbb8673a
flags: 0
RecentlyUsedSceneGuid-9:
value: 5505015f5c515a085f5b092149760f441716407a787d7564287b1b36e7e1366e