切割接入

This commit is contained in:
2025-05-20 19:28:58 +08:00
parent cfe8f8e5c1
commit 9fb81dcdd2
16 changed files with 2221 additions and 2955 deletions
@@ -5,6 +5,7 @@ using AibisDream.Framework;
using AibisDream.Kit;
using AibisDream.Utility;
using DG.Tweening;
using JetBrains.Annotations;
using Newtonsoft.Json;
using UnityEngine;
@@ -25,6 +26,9 @@ namespace AibisDream.FixSystem
private SpriteRenderer _targetSpriteRenderer; // 目标的 SpriteRenderer
private SpriteRenderer _cutSpriteRenderer;
private CutLine _cutLine;
#endregion
@@ -47,7 +51,10 @@ namespace AibisDream.FixSystem
_bodyModuleSystem = transform.parent.parent.GetComponent<BodyModuleSystem>();
_targetSpriteRenderer = transform.Find("Module Pic").GetComponent<SpriteRenderer>();
_originalMaterial = _targetSpriteRenderer.GetComponent<SpriteRenderer>().material;
_originalMaterial = _targetSpriteRenderer.GetComponent<SpriteRenderer>().material;
_cutSpriteRenderer = transform.Find("Cut Pic").GetComponent<SpriteRenderer>();
_highlightMaterial = Resources.Load<Material>("Materials/HighlightMaterial");
_alarmMaterial = Resources.Load<Material>("Materials/AlarmMaterial");
}
@@ -117,6 +124,19 @@ namespace AibisDream.FixSystem
return _targetSpriteRenderer;
}
public void OnCuttingDown()
{
_bodyModuleSystem.RemoveModule(this);
DialogController.Instance?.StartDialogNode($"{data.moduleName}CutDown");
EnumEventSystem.Global.Send(EventEnum.CutEnd);
Destroy(gameObject);
}
public SpriteRenderer GetCutSpriteRenderer()
{
return _cutSpriteRenderer;
}
// public void EnableCut()
// {
@@ -10,13 +10,13 @@ namespace AibisDream
private static BodyModuleSystem BodyModuleSystem => FixSystemCenter.SystemDic.Get<BodyModuleSystem>();
private static PunchTapeSystem PunchTapeSystem => FixSystemCenter.SystemDic.Get<PunchTapeSystem>();
// [YarnCommand("enable_cut")]
// public static void EnableCut(string moduleName)
// {
// Reset_Plug();
// var cutModule = BodyModuleSystem.FindBodyModuleByName(moduleName);
// cutModule.EnableCut();
// }
[YarnCommand("enable_cut")]
public static void EnableCut(string moduleName)
{
Reset_Plug();
var cutModule = BodyModuleSystem.FindBodyModuleByName(moduleName);
//cutModule.EnableCut();
}
[YarnCommand("Reset_Plug")]
public static void Reset_Plug()
{
@@ -0,0 +1,105 @@
using UnityEngine;
using AibisDream;
using AibisDream.FixSystem;
using Cinemachine;
using AibisDream.Framework;
using AibisDream.Kit;
using UnityEditor.Localization.Plugins.XLIFF.V12;
namespace AibisDream
{
public class CuttingManager : MonoBehaviour
{
[Header("切割组件")]
public GameObject gearFollowerPrefab;
private GearFollower gearFollower;
private bool isCuttingMode = false;
private BodyModule _targetModule;
private SpriteRenderer _targetSpriteRenderer;
private void Awake()
{
// 注册
FixSystemCenter.SystemDic.Register(this);
var virtualCam1 = transform.Find("Cut Emo Camera").GetComponent<ICinemachineCamera>();
var virtualCam2 = transform.Find("Cut Memory Camera").GetComponent<ICinemachineCamera>();
var virtualCam3 = transform.Find("Cut Logic Camera").GetComponent<ICinemachineCamera>();
var virtualCam4 = transform.Find("Cut Emo Deep Camera").GetComponent<ICinemachineCamera>();
var virtualCam5 = transform.Find("Cut Memory Deep Camera").GetComponent<ICinemachineCamera>();
var virtualCam6 = transform.Find("Cut Logic Deep Camera").GetComponent<ICinemachineCamera>();
CameraKit.Instance.RegisterCamera(CameraEnum.CutEmo, virtualCam1);
CameraKit.Instance.RegisterCamera(CameraEnum.CutMemory, virtualCam2);
CameraKit.Instance.RegisterCamera(CameraEnum.CutLogic, virtualCam3);
CameraKit.Instance.RegisterCamera(CameraEnum.CutEmoDeep, virtualCam4);
CameraKit.Instance.RegisterCamera(CameraEnum.CutMemoryDeep, virtualCam5);
CameraKit.Instance.RegisterCamera(CameraEnum.CutLogicDeep, virtualCam6);
}
private void Update()
{
if (isCuttingMode && gearFollower != null)
{
gearFollower.GearUpdate();
}
}
public void StartCutting(BodyModule targetModule)
{
// 检查参数
if (targetModule == null)
{
Debug.LogError("targetModule 为空");
return;
}
// 保存目标模块
_targetModule = targetModule;
// 获取目标精灵渲染器
_targetSpriteRenderer = targetModule.GetCutSpriteRenderer();
if (_targetSpriteRenderer == null)
{
Debug.LogError("targetSprite 为空");
return;
}
// 停止之前的切割
StopCutting();
// 设置切割模式
isCuttingMode = true;
// 创建GearFollower
Vector3 SpawnPosition = new Vector3(Screen.width / 2f, Screen.height / 4f, 0);
GameObject gearFollowerObj = Instantiate(gearFollowerPrefab, SpawnPosition, Quaternion.identity);
gearFollower = gearFollowerObj.GetComponent<GearFollower>();
gearFollower.Init(_targetSpriteRenderer);
}
public void OnCutComplete()
{
isCuttingMode = false;
if (gearFollower != null)
{
gearFollower.FinishCutting();
}
}
public void UpdateModule()
{
if (_targetModule != null)
{
_targetModule.OnCuttingDown();
}
}
public void StopCutting()
{
isCuttingMode = false;
if (gearFollower != null)
{
Destroy(gearFollower.gameObject);
gearFollower = null;
}
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fe673cb153d7fdf428d58d3261c48863
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -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()