线缆的物理表现

This commit is contained in:
2024-08-28 17:04:13 +08:00
parent a82b020c48
commit 5831a7cf84
17 changed files with 864 additions and 108 deletions
@@ -31,6 +31,11 @@ public class CustomCursor : MonoBehaviour
// 当禁用自定义光标时,显示默认的鼠标光标
Cursor.visible = true;
}
public void Shake(float intensity, float speed)
{
float shakeAmount = Mathf.Sin(Time.time * speed) * intensity;
transform.rotation = Quaternion.Euler(rotationCorrection + new Vector3(0, 0, shakeAmount));
}
}
@@ -36,12 +36,27 @@ public class InteractiveLineSegment : VisualLineSegment
{
_isCuttable = value;
// Change the color of the line segment based on its cuttability
GetComponent<LineRenderer>().material.color = value ? Color.white : Color.black;
//GetComponent<LineRenderer>().material.color = value ? Color.white : Color.black;
}
}
private bool _isCuttable=false;
public void OnHover()
{
if (IsCuttable)
{
TurnGreen();
}
else
{
TurnRed();
}
}
public void OnHoverExit()
{
TurnGrey();
}
protected override void Awake()
{
base.Awake();
@@ -52,11 +67,26 @@ public class InteractiveLineSegment : VisualLineSegment
Initialize();
}
public void TurnGreen()
{
lineRenderer.material.color = Color.green; // 改变 LineRenderer 的颜色
}
public void TurnGrey()
{
lineRenderer.material.color = Color.grey; // 改变 LineRenderer 的颜色
}
public void TurnRed()
{
lineRenderer.material.color = Color.red; // 改变 LineRenderer 的颜色
}
public void Initialize()
{
TurnGrey();
if (StartTransform == null || EndTransform == null)
{
Debug.LogError("StartTransform or EndTransform is not set.");
@@ -84,5 +114,7 @@ public class InteractiveLineSegment : VisualLineSegment
// Set the position of the BoxCollider2D to the start point
boxCollider.transform.position = StartPoint;
}
}
+128 -69
View File
@@ -5,11 +5,12 @@ using System.Collections.Generic;
using System.Collections;
using AibisDream;
using System.Linq;
using DG.Tweening;
public class LineManager : MonoBehaviour
{
//public GameObject interactiveLineSegmentPrefab;
public GameObject visualLineSegmentPrefab;
public GameObject physicLineSegmentPrefab;
public CustomCursor customCursor; // 自定义光标,你可以在 Inspector 中设置
@@ -41,6 +42,131 @@ public class LineManager : MonoBehaviour
{
return lineSegmentDictionary.Keys;
}
private InteractiveLineSegment currentLineSegment; // 当前要被剪断的线段
private const float LONG_PRESS_THRESHOLD = 3.0f; // 长按阈值,可以根据需要调整
private float longPressTime = 0.0f; // 长按时间
private float detectionRadius=0.4f;
public void CutLine(InteractiveLineSegment originalLineSegment, Vector3 splitPoint)
{
// 如果线段不可剪断,就直接返回,不进行剪断操作
if (!originalLineSegment.IsCuttable)
{
return;
}
// Create the first new line segment
GameObject firstLineSegmentObject = Instantiate(physicLineSegmentPrefab, transform);
PhysicLineSegment firstLineSegment = firstLineSegmentObject.GetComponent<PhysicLineSegment>();
firstLineSegment.Initialize(originalLineSegment.StartTransform.position, splitPoint);
// Create the second new line segment
GameObject secondLineSegmentObject = Instantiate(physicLineSegmentPrefab, transform);
PhysicLineSegment secondLineSegment = secondLineSegmentObject.GetComponent<PhysicLineSegment>();
secondLineSegment.Initialize(originalLineSegment.EndTransform.position,splitPoint);
// Immediately destroy the original line segment
Destroy(originalLineSegment.gameObject);
}
private void AddPhysicsComponents(GameObject lineSegmentObject)
{
// Add Rigidbody2D
Rigidbody2D rb = lineSegmentObject.AddComponent<Rigidbody2D>();
rb.gravityScale = 1; // Enable gravity
// Add HingeJoint2D
HingeJoint2D hinge = lineSegmentObject.AddComponent<HingeJoint2D>();
hinge.anchor = Vector2.zero; // Set the anchor at one end of the line segment
}
public void BindOptionToLineSegment(string lineSegmentName, YarnOption option)
{
InteractiveLineSegment lineSegment = GetLineSegmentByName(lineSegmentName);
if (lineSegment != null)
{
lineSegment.Option = option;
}
}
private void EnterLineSegment(InteractiveLineSegment lineSegment)
{
if (currentLineSegment != null)
{
lineSegment.OnHoverExit();
}
lineSegment.OnHover();
currentLineSegment = lineSegment;
}
private void LongPressLineSegment(InteractiveLineSegment lineSegment)
{
longPressTime += Time.deltaTime;
Vector3 midpoint = (lineSegment.StartPoint + lineSegment.EndPoint) / 2;
// Make the scissors shake and the line segment turn red
if (longPressTime < LONG_PRESS_THRESHOLD)
{
customCursor.Shake(longPressTime * 5.0f, 10.0f); // 抖动强度随时间增加
//lineSegment.TurnRed(longPressTime / LONG_PRESS_THRESHOLD); // 线段变红的程度随时间增加
// Calculate the midpoint of the line segment
// Move the scissors towards the midpoint
//customCursor.transform.DOMove(midpoint, 0.1f);
}
else
{
// Cut the line segment
CutLine(lineSegment,midpoint);
}
}
private void ExitLineSegment()
{
if (currentLineSegment != null)
{
currentLineSegment.TurnGrey();
}
currentLineSegment = null;
}
private void Update()
{
if (isScissorsMode)
{
// Get the position of the mouse in world coordinates
Vector3 mousePosition = Camera.main.ScreenToWorldPoint(Input.mousePosition);
// Check if there is a line segment in the scissors' detection range
Collider2D hitCollider = Physics2D.OverlapCircle(mousePosition, detectionRadius);
InteractiveLineSegment hitLineSegment = hitCollider != null ? hitCollider.GetComponent<InteractiveLineSegment>() : null;
if (hitLineSegment != null)
{
EnterLineSegment(hitLineSegment);
if (Input.GetMouseButtonDown(0))
{
longPressTime = 0.0f;
}
else if (Input.GetMouseButton(0))
{
LongPressLineSegment(hitLineSegment);
}
else if (Input.GetMouseButtonUp(0))
{
longPressTime = 0.0f;
//customCursor.ResetRotation(); // 假设你有一个方法来重置剪刀的旋转
//currentLineSegment.ResetColor(); // 假设你有一个方法来重置线段的颜色
}
}
else
{
ExitLineSegment();
}
}
}
private void SetScissorsCursor()
{
@@ -126,74 +252,7 @@ public class LineManager : MonoBehaviour
IsScissorsMode = isEnabled;
}
public void CutLine(InteractiveLineSegment originalLineSegment, Vector3 splitPoint)
{
// 如果线段不可剪断,就直接返回,不进行剪断操作
if (!originalLineSegment.IsCuttable)
{
return;
}
// Create the first new line segment
GameObject firstLineSegmentObject = Instantiate(visualLineSegmentPrefab, transform);
VisualLineSegment firstLineSegment = firstLineSegmentObject.GetComponent<VisualLineSegment>();
firstLineSegment.Initialize(originalLineSegment.StartPoint, splitPoint);
// Create the second new line segment
GameObject secondLineSegmentObject = Instantiate(visualLineSegmentPrefab, transform);
VisualLineSegment secondLineSegment = secondLineSegmentObject.GetComponent<VisualLineSegment>();
secondLineSegment.Initialize(originalLineSegment.EndPoint, splitPoint);
// Immediately destroy the original line segment
Destroy(originalLineSegment.gameObject);
// Shrink and disappear the new line segments
firstLineSegment.ShrinkAndDisappear();
secondLineSegment.ShrinkAndDisappear();
}
public void BindOptionToLineSegment(string lineSegmentName, YarnOption option)
{
InteractiveLineSegment lineSegment = GetLineSegmentByName(lineSegmentName);
if (lineSegment != null)
{
lineSegment.Option = option;
}
}
private void Update()
{
if (Input.GetMouseButtonDown(0) && isScissorsMode)
{
// Convert the mouse position to a 2D ray
Vector2 ray = Camera.main.ScreenToWorldPoint(Input.mousePosition);
// Check if the ray hits a line segment
RaycastHit2D hit = Physics2D.Raycast(ray, Vector2.zero);
if (hit.collider != null)
{
Debug.Log("Raycast hit: " + hit.transform.name);
InteractiveLineSegment originalLineSegment = hit.transform.GetComponent<InteractiveLineSegment>();
if (originalLineSegment != null)
{
Debug.Log("Line segment hit: " + originalLineSegment.name);
CutLine(originalLineSegment,hit.point);
// Check if Option is not null before selecting it
if (originalLineSegment.Option != null)
{
originalLineSegment.Option.SelectOption();
}
}
else
{
//Debug.Log("Hit object is not a line segment");
}
}
}
}
@@ -0,0 +1,83 @@
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(LineRenderer))]
public class PhysicLineSegment : MonoBehaviour
{
public float segmentSpacing = 0.1f;
public int k = 30;
public Vector3 start;
public Vector3 end;
private List<VerletParticle> particles = new List<VerletParticle>();
private List<VerletStick> sticks = new List<VerletStick>();
private LineRenderer lineRenderer;
private int segmentCount;
public float gravity = -9.8f;
public void Initialize(Vector3 start, Vector3 end)
{
this.start = start;
this.end = end;
//originalLength = Vector3.Distance(start, end);
// Calculate the number of segments and the spacing between them
segmentCount = Mathf.RoundToInt(Vector3.Distance(start, end) / segmentSpacing);
lineRenderer = GetComponent<LineRenderer>();
// Initialize particles
for (int i = 0; i < segmentCount; i++)
{
// Calculate the position of the segment
var particle = new VerletParticle(Vector3.Lerp(start, end, i / (float)segmentCount));
particles.Add(particle);
}
// Initialize sticks
for (int i = 0; i < segmentCount - 1; i++)
{
sticks.Add(new VerletStick(particles[i], particles[i + 1], segmentSpacing));
}
// Lock the first particle
particles[0].isLocked = true;
lineRenderer.positionCount = segmentCount;
}
void FixedUpdate()
{
UpdateLine();
for (int i = 0; i < segmentCount; i++)
{
lineRenderer.SetPosition(i, particles[i].position);
}
}
void UpdateLine()
{
// Apply gravity to particles
for (int i = 1; i < particles.Count; i++)
{
particles[i].ApplyForce(Vector3.up * gravity * Time.deltaTime);
particles[i].UpdatePosition(Time.deltaTime);
}
// Update sticks
for (int ik = 0; ik < k; ik++)
{
foreach (var stick in sticks)
{
stick.UpdateStick();
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1198bee0150e12d4aa20514b2c8f3362
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,31 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class VerletParticle
{
public Vector3 position;
public Vector3 previousPosition;
public bool isLocked;
public VerletParticle(Vector3 position)
{
this.position = position;
this.previousPosition = position;
this.isLocked = false;
}
public void ApplyForce(Vector3 force)
{
Vector3 temp = position;
position += position - previousPosition + force;
previousPosition = temp;
}
public void UpdatePosition(float deltaTime)
{
Vector3 temp = position;
position += (position - previousPosition) * deltaTime;
previousPosition = temp;
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cdb6feb01313af04f8abf13c63227196
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,35 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class VerletStick
{
private VerletParticle particleA;
private VerletParticle particleB;
private float length;
public float stiffness = 0.8f; // Add this line
public VerletStick(VerletParticle particleA, VerletParticle particleB, float length)
{
this.particleA = particleA;
this.particleB = particleB;
this.length = length;
}
public void UpdateStick()
{
float currentLength = Vector3.Distance(particleA.position, particleB.position);
float difference = length - currentLength;
Vector3 direction = (particleB.position - particleA.position).normalized;
if (!particleA.isLocked)
{
particleA.position -= direction * difference * stiffness; // Change this line
}
if (!particleB.isLocked)
{
particleB.position += direction * difference * stiffness; // Change this line
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4f52ebcdf1c225c48ad6413459d49309
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -23,14 +23,14 @@ public class VisualLineSegment : MonoBehaviour
lineRenderer.SetPosition(1, EndPoint);
}
public void ShrinkAndDisappear()
{
// Shrink the line segment from the end to the start
DOTween.To(() => EndPoint, x => EndPoint = x, StartPoint, 1f)
.OnUpdate(() => {
lineRenderer.SetPosition(0, StartPoint);
lineRenderer.SetPosition(1, EndPoint);
})
.OnComplete(() => Destroy(gameObject));
}
// public void ShrinkAndDisappear()
// {
// // Shrink the line segment from the end to the start
// DOTween.To(() => EndPoint, x => EndPoint = x, StartPoint, 1f)
// .OnUpdate(() => {
// lineRenderer.SetPosition(0, StartPoint);
// lineRenderer.SetPosition(1, EndPoint);
// })
// .OnComplete(() => Destroy(gameObject));
// }
}