切割接入
This commit is contained in:
@@ -4,12 +4,14 @@ using UnityEngine;
|
||||
using UnityEngine.Rendering.Universal;
|
||||
using UnityEngine.VFX;
|
||||
using DG.Tweening;
|
||||
using AibisDream.FixSystem;
|
||||
using AibisDream; // 添加OpenSystem的命名空间
|
||||
|
||||
public class GearFollower : MonoBehaviour
|
||||
{
|
||||
[Header("参数")]
|
||||
public SpriteRenderer targetSpriteRenderer;
|
||||
public float snapDistance = 0.3f;
|
||||
public float snapDistance = 1.0f;
|
||||
public float detachDistance = 1.0f;
|
||||
public float tractionSpeed = 2f;
|
||||
public float edgePointsScale = 1.2f; // 边缘点缩放倍率
|
||||
@@ -42,7 +44,7 @@ public class GearFollower : MonoBehaviour
|
||||
public float scaleUpDuration = 1f; // 放大动画持续时间
|
||||
public float fadeOutDelay = 1f; // 淡出前的延迟时间
|
||||
public AudioClip cutCompleteSound; // 切割完成音效
|
||||
|
||||
|
||||
private float totalEdgeLength = 0f; // 总边缘长度
|
||||
private float cutLength = 0f; // 已切割长度
|
||||
private bool isCutComplete = false;
|
||||
@@ -86,6 +88,16 @@ public class GearFollower : MonoBehaviour
|
||||
|
||||
void Start()
|
||||
{
|
||||
}
|
||||
public void Init(SpriteRenderer targetSpriteRenderer)
|
||||
{
|
||||
SpriteRenderer gearRenderer = GetComponent<SpriteRenderer>();
|
||||
if (gearRenderer != null)
|
||||
{
|
||||
gearRenderer.color = new Color(1, 1, 1, 1);
|
||||
}
|
||||
this.targetSpriteRenderer = null;
|
||||
this.targetSpriteRenderer = targetSpriteRenderer;
|
||||
mainCamera = Camera.main;
|
||||
LoadEdgePointsFromSprite();
|
||||
CalculateTotalEdgeLength();
|
||||
@@ -118,7 +130,24 @@ public class GearFollower : MonoBehaviour
|
||||
}
|
||||
void Update()
|
||||
{
|
||||
Vector2 mouseWorldPos = mainCamera.ScreenToWorldPoint(Input.mousePosition);
|
||||
|
||||
}
|
||||
public void GearUpdate()
|
||||
{
|
||||
// 获取鼠标在屏幕上的位置
|
||||
Vector3 mouseScreenPos = Input.mousePosition;
|
||||
// 将屏幕坐标转换为世界坐标
|
||||
Vector3 mouseWorldPos = mainCamera.ScreenToWorldPoint(new Vector3(mouseScreenPos.x, mouseScreenPos.y, -mainCamera.transform.position.z));
|
||||
mouseWorldPos.z = 0; // 确保z坐标为0
|
||||
|
||||
Debug.Log($"鼠标屏幕坐标: {mouseScreenPos}");
|
||||
Debug.Log($"鼠标世界坐标: {mouseWorldPos}");
|
||||
Debug.Log($"齿轮当前位置: {transform.position}");
|
||||
if (targetSpriteRenderer != null)
|
||||
{
|
||||
Debug.Log($"目标精灵位置: {targetSpriteRenderer.transform.position}");
|
||||
Debug.Log($"目标精灵边界: {targetSpriteRenderer.bounds}");
|
||||
}
|
||||
|
||||
if (Input.GetMouseButton(0))
|
||||
{
|
||||
@@ -181,7 +210,7 @@ public class GearFollower : MonoBehaviour
|
||||
{
|
||||
fadeOutTimer += Time.deltaTime;
|
||||
float alpha = 1f - (fadeOutTimer / fadeOutDuration);
|
||||
|
||||
|
||||
if (targetSpriteRenderer != null)
|
||||
{
|
||||
Color color = targetSpriteRenderer.color;
|
||||
@@ -220,6 +249,7 @@ public class GearFollower : MonoBehaviour
|
||||
Debug.LogError("targetSpriteRenderer 为空");
|
||||
return;
|
||||
}
|
||||
|
||||
List<Vector2> shapePoints = new List<Vector2>();
|
||||
targetSpriteRenderer.sprite.GetPhysicsShape(0, shapePoints);
|
||||
|
||||
@@ -228,33 +258,70 @@ public class GearFollower : MonoBehaviour
|
||||
Debug.LogError("目标Sprite没有物理形状点");
|
||||
return;
|
||||
}
|
||||
Debug.Log($"原始形状点数量: {shapePoints.Count}");
|
||||
float desiredSegmentLength = 0.1f;
|
||||
|
||||
edgePoints.Clear();
|
||||
originalEdgePoints.Clear();
|
||||
Vector2 center = Vector2.zero;
|
||||
foreach (Vector2 point in shapePoints)
|
||||
{
|
||||
center += point;
|
||||
}
|
||||
center /= shapePoints.Count;
|
||||
|
||||
// 获取精灵的世界坐标
|
||||
Vector3 spriteWorldPos = targetSpriteRenderer.transform.position;
|
||||
Debug.Log($"精灵世界坐标: {spriteWorldPos}");
|
||||
|
||||
// 计算精灵的局部边界
|
||||
Bounds localBounds = targetSpriteRenderer.bounds;
|
||||
Vector3 localCenter = localBounds.center;
|
||||
Vector3 localSize = localBounds.size;
|
||||
|
||||
// 计算缩放后的边界
|
||||
float maxScale = Mathf.Max(localSize.x, localSize.y) * edgePointsScale;
|
||||
float minScale = Mathf.Min(localSize.x, localSize.y) * edgePointsScale;
|
||||
|
||||
Debug.Log($"精灵局部边界: 中心={localCenter}, 大小={localSize}");
|
||||
Debug.Log($"缩放后边界: 最大={maxScale}, 最小={minScale}");
|
||||
|
||||
for (int i = 0; i < shapePoints.Count; i++)
|
||||
{
|
||||
Vector2 p1 = targetSpriteRenderer.transform.TransformPoint(shapePoints[i]);
|
||||
Vector2 p2 = targetSpriteRenderer.transform.TransformPoint(shapePoints[(i + 1) % shapePoints.Count]);
|
||||
// 将局部坐标转换为世界坐标
|
||||
Vector3 localPoint1 = shapePoints[i];
|
||||
Vector3 localPoint2 = shapePoints[(i + 1) % shapePoints.Count];
|
||||
|
||||
Vector2 scaledP1 = center + (p1 - center) * edgePointsScale;
|
||||
Vector2 scaledP2 = center + (p2 - center) * edgePointsScale;
|
||||
// 转换为世界坐标
|
||||
Vector3 worldPoint1 = targetSpriteRenderer.transform.TransformPoint(localPoint1);
|
||||
Vector3 worldPoint2 = targetSpriteRenderer.transform.TransformPoint(localPoint2);
|
||||
|
||||
float segmentLength = Vector2.Distance(scaledP1, scaledP2);
|
||||
// 确保坐标在合理范围内
|
||||
worldPoint1 = ClampPosition(worldPoint1, spriteWorldPos, maxScale);
|
||||
worldPoint2 = ClampPosition(worldPoint2, spriteWorldPos, maxScale);
|
||||
|
||||
Debug.Log($"点 {i} 局部坐标: {localPoint1} -> 世界坐标: {worldPoint1}");
|
||||
|
||||
// 计算相对于精灵中心点的缩放
|
||||
Vector3 scaledPoint1 = spriteWorldPos + (worldPoint1 - spriteWorldPos) * edgePointsScale;
|
||||
Vector3 scaledPoint2 = spriteWorldPos + (worldPoint2 - spriteWorldPos) * edgePointsScale;
|
||||
|
||||
// 确保缩放后的点也在合理范围内
|
||||
scaledPoint1 = ClampPosition(scaledPoint1, spriteWorldPos, maxScale);
|
||||
scaledPoint2 = ClampPosition(scaledPoint2, spriteWorldPos, maxScale);
|
||||
|
||||
Debug.Log($"点 {i} 缩放后世界坐标: {scaledPoint1}");
|
||||
|
||||
float segmentLength = Vector3.Distance(scaledPoint1, scaledPoint2);
|
||||
int steps = Mathf.Max(1, Mathf.CeilToInt(segmentLength / desiredSegmentLength));
|
||||
|
||||
for (int s = 0; s < steps; s++)
|
||||
{
|
||||
float t = (float)s / steps;
|
||||
Vector2 interpolated = Vector2.Lerp(scaledP1, scaledP2, t);
|
||||
Vector2 originalInterpolated = Vector2.Lerp(p1, p2, t);
|
||||
edgePoints.Add(interpolated);
|
||||
originalEdgePoints.Add(originalInterpolated);
|
||||
Vector3 interpolated = Vector3.Lerp(scaledPoint1, scaledPoint2, t);
|
||||
Vector3 originalInterpolated = Vector3.Lerp(worldPoint1, worldPoint2, t);
|
||||
|
||||
// 确保插值点也在合理范围内
|
||||
interpolated = ClampPosition(interpolated, spriteWorldPos, maxScale);
|
||||
originalInterpolated = ClampPosition(originalInterpolated, spriteWorldPos, maxScale);
|
||||
|
||||
// 存储为Vector2,但保持世界坐标
|
||||
edgePoints.Add(new Vector2(interpolated.x, interpolated.y));
|
||||
originalEdgePoints.Add(new Vector2(originalInterpolated.x, originalInterpolated.y));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,22 +330,48 @@ public class GearFollower : MonoBehaviour
|
||||
edgePoints.Add(edgePoints[0]);
|
||||
originalEdgePoints.Add(originalEdgePoints[0]);
|
||||
}
|
||||
|
||||
Debug.Log($"生成的边缘点数量: {edgePoints.Count}");
|
||||
Debug.Log($"第一个边缘点世界坐标: {edgePoints[0]}");
|
||||
Debug.Log($"最后一个边缘点世界坐标: {edgePoints[edgePoints.Count - 1]}");
|
||||
}
|
||||
|
||||
// 添加一个辅助方法来限制坐标范围
|
||||
private Vector3 ClampPosition(Vector3 position, Vector3 center, float maxDistance)
|
||||
{
|
||||
Vector3 offset = position - center;
|
||||
float distance = offset.magnitude;
|
||||
|
||||
if (distance > maxDistance)
|
||||
{
|
||||
offset = offset.normalized * maxDistance;
|
||||
position = center + offset;
|
||||
}
|
||||
|
||||
return position;
|
||||
}
|
||||
|
||||
private void UpdateFollowState(Vector2 mousePos)
|
||||
{
|
||||
transform.position = mousePos;
|
||||
isInTractionMode = false;
|
||||
|
||||
int nearestIndex = FindNearestEdgePointIndex(mousePos, out float dist);
|
||||
Debug.Log($"最近边缘点索引: {nearestIndex}, 距离: {dist}");
|
||||
Debug.Log($"最近边缘点位置: {edgePoints[nearestIndex]}");
|
||||
Debug.Log($"当前snapDistance: {snapDistance}");
|
||||
|
||||
if (dist < snapDistance)
|
||||
{
|
||||
currentEdgeIndex = nearestIndex;
|
||||
|
||||
Vector2 prev = edgePoints[WrapIndex(currentEdgeIndex - 1)];
|
||||
Vector2 next = edgePoints[WrapIndex(currentEdgeIndex + 1)];
|
||||
Debug.Log($"前一个点: {prev}, 后一个点: {next}");
|
||||
|
||||
float distToPrev = Vector2.Distance(mousePos, prev);
|
||||
float distToNext = Vector2.Distance(mousePos, next);
|
||||
Debug.Log($"到前一个点距离: {distToPrev}, 到后一个点距离: {distToNext}");
|
||||
|
||||
tractionDirection = (distToNext < distToPrev) ? 1 : -1;
|
||||
|
||||
@@ -454,12 +547,14 @@ public class GearFollower : MonoBehaviour
|
||||
sparkVFX.Stop();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
private int FindNearestEdgePointIndex(Vector2 pos, out float minDist)
|
||||
{
|
||||
int nearestIndex = 0;
|
||||
minDist = float.MaxValue;
|
||||
|
||||
// 使用世界坐标进行距离计算
|
||||
for (int i = 0; i < edgePoints.Count; i++)
|
||||
{
|
||||
float dist = Vector2.Distance(pos, edgePoints[i]);
|
||||
@@ -509,22 +604,29 @@ public class GearFollower : MonoBehaviour
|
||||
{
|
||||
totalEdgeLength += Vector2.Distance(edgePoints[i], edgePoints[i + 1]);
|
||||
}
|
||||
Debug.Log($"计算总边缘长度: {totalEdgeLength}");
|
||||
}
|
||||
|
||||
private void UpdateCutProgress(Vector2 from, Vector2 to)
|
||||
{
|
||||
cutLength += Vector2.Distance(from, to);
|
||||
float progress = cutLength / totalEdgeLength;
|
||||
|
||||
// 计算当前段的切割长度
|
||||
float segmentLength = Vector2.Distance(from, to);
|
||||
cutLength += segmentLength;
|
||||
|
||||
// 记录已切割的边缘点
|
||||
cutEdgeIndices.Add(currentEdgeIndex);
|
||||
|
||||
|
||||
// 计算切割进度
|
||||
float progress = cutLength / totalEdgeLength;
|
||||
Debug.Log($"当前切割长度: {cutLength}, 总长度: {totalEdgeLength}, 进度: {progress * 100}%");
|
||||
|
||||
// 检查是否满足切割完成条件
|
||||
if (!isCutComplete && progress >= cutCompletionThreshold && progress >= minCutLength)
|
||||
if (!isCutComplete && progress >= cutCompletionThreshold)
|
||||
{
|
||||
// 检查是否形成了连续的切割路径
|
||||
bool hasContinuousCut = CheckContinuousCut();
|
||||
|
||||
Debug.Log($"连续切割检查: {hasContinuousCut}, 已切割点数: {cutEdgeIndices.Count}, 总点数: {edgePoints.Count}");
|
||||
|
||||
if (hasContinuousCut)
|
||||
{
|
||||
isCutComplete = true;
|
||||
@@ -544,32 +646,64 @@ public class GearFollower : MonoBehaviour
|
||||
// 检查是否有连续的切割点
|
||||
int continuousCount = 1;
|
||||
int maxContinuousCount = 1;
|
||||
int totalPoints = edgePoints.Count;
|
||||
|
||||
for (int i = 1; i < sortedIndices.Count; i++)
|
||||
// 检查所有可能的连续段
|
||||
for (int startIndex = 0; startIndex < sortedIndices.Count; startIndex++)
|
||||
{
|
||||
if (sortedIndices[i] == sortedIndices[i - 1] + 1)
|
||||
continuousCount = 1;
|
||||
int currentIndex = sortedIndices[startIndex];
|
||||
|
||||
// 向前检查
|
||||
for (int i = 1; i < sortedIndices.Count; i++)
|
||||
{
|
||||
continuousCount++;
|
||||
maxContinuousCount = Mathf.Max(maxContinuousCount, continuousCount);
|
||||
int nextIndex = (currentIndex + i) % totalPoints;
|
||||
if (sortedIndices.Contains(nextIndex))
|
||||
{
|
||||
continuousCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
// 向后检查
|
||||
for (int i = 1; i < sortedIndices.Count; i++)
|
||||
{
|
||||
continuousCount = 1;
|
||||
int prevIndex = (currentIndex - i + totalPoints) % totalPoints;
|
||||
if (sortedIndices.Contains(prevIndex))
|
||||
{
|
||||
continuousCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
maxContinuousCount = Mathf.Max(maxContinuousCount, continuousCount);
|
||||
}
|
||||
|
||||
// 如果连续切割点的数量超过总点数的50%,认为形成了有效的切割路径
|
||||
return maxContinuousCount >= edgePoints.Count * 0.5f;
|
||||
// 计算连续切割点的比例
|
||||
float continuousRatio = (float)maxContinuousCount / totalPoints;
|
||||
Debug.Log($"最大连续切割点数: {maxContinuousCount}, 总点数: {totalPoints}, 比例: {continuousRatio * 100}%");
|
||||
|
||||
// 如果连续切割点的数量超过总点数的70%,认为形成了有效的切割路径
|
||||
return continuousRatio >= 0.7f;
|
||||
}
|
||||
|
||||
private void OnCutComplete()
|
||||
{
|
||||
// 停止切割状态
|
||||
isCutting = false;
|
||||
isInTractionMode = false;
|
||||
enabled = false;
|
||||
|
||||
// 清理特效
|
||||
var cuttingManager = FixSystemCenter.SystemDic.Get<CuttingManager>();
|
||||
if (cuttingManager != null)
|
||||
{
|
||||
cuttingManager.OnCutComplete();
|
||||
}
|
||||
}
|
||||
public void FinishCutting()
|
||||
{
|
||||
// 清理特效
|
||||
if (cutLight != null)
|
||||
{
|
||||
cutLight.enabled = false;
|
||||
@@ -582,47 +716,42 @@ public class GearFollower : MonoBehaviour
|
||||
{
|
||||
cutLineRenderer.positionCount = 0;
|
||||
}
|
||||
timedCutPoints.Clear();
|
||||
// 计算随机方向
|
||||
float randomAngle = Random.Range(-cutCompleteTiltAngle, cutCompleteTiltAngle);
|
||||
Vector2 randomOffset = Random.insideUnitCircle * cutCompleteOffset;
|
||||
|
||||
// 目标倾斜和位移
|
||||
if (targetSpriteRenderer != null)
|
||||
// 立即应用倾斜和位移
|
||||
targetSpriteRenderer.transform.rotation = Quaternion.Euler(0, 0, randomAngle);
|
||||
targetSpriteRenderer.transform.position = originalTargetPosition + (Vector3)randomOffset;
|
||||
|
||||
// 创建动画序列
|
||||
cutCompleteSequence = DOTween.Sequence();
|
||||
|
||||
// 等待一段时间后开始放大
|
||||
cutCompleteSequence.AppendInterval(cutCompleteDelay);
|
||||
cutCompleteSequence.Append(targetSpriteRenderer.transform.DOScale(originalTargetScale * cutCompleteScale, scaleUpDuration)
|
||||
.SetEase(Ease.OutQuad));
|
||||
|
||||
// 等待一段时间后开始淡出
|
||||
cutCompleteSequence.AppendInterval(fadeOutDelay);
|
||||
cutCompleteSequence.Append(targetSpriteRenderer.DOFade(0f, fadeOutDuration));
|
||||
|
||||
// 齿轮也同时淡出
|
||||
SpriteRenderer gearRenderer = GetComponent<SpriteRenderer>();
|
||||
if (gearRenderer != null)
|
||||
{
|
||||
// 计算随机方向
|
||||
float randomAngle = Random.Range(-cutCompleteTiltAngle, cutCompleteTiltAngle);
|
||||
Vector2 randomOffset = Random.insideUnitCircle * cutCompleteOffset;
|
||||
|
||||
// 立即应用倾斜和位移
|
||||
targetSpriteRenderer.transform.rotation = Quaternion.Euler(0, 0, randomAngle);
|
||||
targetSpriteRenderer.transform.position = originalTargetPosition + (Vector3)randomOffset;
|
||||
|
||||
// 创建动画序列
|
||||
cutCompleteSequence = DOTween.Sequence();
|
||||
|
||||
// 等待一段时间后开始放大
|
||||
cutCompleteSequence.AppendInterval(cutCompleteDelay);
|
||||
cutCompleteSequence.Append(targetSpriteRenderer.transform.DOScale(originalTargetScale * cutCompleteScale, scaleUpDuration)
|
||||
.SetEase(Ease.OutQuad));
|
||||
|
||||
// 等待一段时间后开始淡出
|
||||
cutCompleteSequence.AppendInterval(fadeOutDelay);
|
||||
cutCompleteSequence.Append(targetSpriteRenderer.DOFade(0f, fadeOutDuration));
|
||||
|
||||
// 齿轮也同时淡出
|
||||
SpriteRenderer gearRenderer = GetComponent<SpriteRenderer>();
|
||||
if (gearRenderer != null)
|
||||
cutCompleteSequence.Join(gearRenderer.DOFade(0f, fadeOutDuration));
|
||||
}
|
||||
cutCompleteSequence.OnComplete(() =>
|
||||
{
|
||||
cutCompleteSequence.Join(gearRenderer.DOFade(0f, fadeOutDuration));
|
||||
}
|
||||
|
||||
// 动画完成后销毁物体
|
||||
cutCompleteSequence.OnComplete(() => {
|
||||
Destroy(gameObject);
|
||||
if (targetSpriteRenderer != null)
|
||||
Destroy(this.gameObject);
|
||||
var cuttingManager = FixSystemCenter.SystemDic.Get<CuttingManager>();
|
||||
if (cuttingManager != null)
|
||||
{
|
||||
Destroy(targetSpriteRenderer.gameObject);
|
||||
cuttingManager.UpdateModule();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
|
||||
Reference in New Issue
Block a user