This commit is contained in:
2025-06-03 21:50:35 +08:00
parent 5bd103ceec
commit c8b0f8b375
46 changed files with 6296 additions and 1914 deletions
@@ -8,6 +8,7 @@ using DG.Tweening;
using JetBrains.Annotations;
using Newtonsoft.Json;
using UnityEngine;
using System.Collections;
namespace AibisDream.FixSystem
{
@@ -27,10 +28,17 @@ namespace AibisDream.FixSystem
private SpriteRenderer _targetSpriteRenderer; // 目标的 SpriteRenderer
private SpriteRenderer _cutSpriteRenderer;
private SpriteRenderer _cutTextRenderer; // 添加cutText的SpriteRenderer引用
private CutLine _cutLine;
[Header("CutText闪烁效果")]
private float cutTextFlickerThreshold = 0.7f; // 开始闪烁的阈值
private float cutTextFlickerInterval = 0.1f; // 闪烁间隔
private float cutTextFlickerTimer = 0f; // 闪烁计时器
private bool isCutTextFlickering = false; // 是否正在闪烁
private Coroutine flickerCoroutine; // 闪烁协程引用
#endregion
// 模块基本数据
@@ -54,6 +62,10 @@ namespace AibisDream.FixSystem
_originalMaterial = _targetSpriteRenderer.GetComponent<SpriteRenderer>().material;
_cutSpriteRenderer = transform.Find("Cut Pic")?.GetComponent<SpriteRenderer>();
if (_cutSpriteRenderer != null)
{
_cutTextRenderer = _cutSpriteRenderer.transform.Find("Cut Text")?.GetComponent<SpriteRenderer>(); // 初始化cutText的SpriteRenderer
}
_highlightMaterial = Resources.Load<Material>("Materials/HighlightMaterial");
_alarmMaterial = Resources.Load<Material>("Materials/AlarmMaterial");
@@ -128,9 +140,16 @@ namespace AibisDream.FixSystem
{
_bodyModuleSystem.RemoveModule(this);
DialogController.Instance?.StartDialogNode($"{data.moduleName}CutDown");
EnumEventSystem.Global.Send(EventEnum.CutEnd);
Destroy(gameObject);
DialogController.Instance?.StartDialogNode($"{data.moduleName}CutDown");
EnumEventSystem.Global.Send(EventEnum.CutEnd);
Destroy(gameObject);
}
public void SetCutTextVisible(bool visible)
{
if (_cutTextRenderer != null)
{
_cutTextRenderer.enabled = visible;
}
}
public SpriteRenderer GetCutSpriteRenderer()
@@ -138,6 +157,54 @@ namespace AibisDream.FixSystem
return _cutSpriteRenderer;
}
public void StartCutTextFlicker()
{
if (!isCutTextFlickering)
{
isCutTextFlickering = true;
if (flickerCoroutine != null)
{
StopCoroutine(flickerCoroutine);
}
flickerCoroutine = StartCoroutine(CutTextFlickerCoroutine());
}
}
public void StopCutTextFlicker()
{
isCutTextFlickering = false;
if (flickerCoroutine != null)
{
StopCoroutine(flickerCoroutine);
flickerCoroutine = null;
}
// 确保最终状态是可见的
SetCutTextVisible(true);
}
private IEnumerator CutTextFlickerCoroutine()
{
while (isCutTextFlickering)
{
// 随机决定是否显示
bool shouldShow = UnityEngine.Random.value > 0.5f;
SetCutTextVisible(shouldShow);
// 随机等待时间,模拟接触不良效果
float waitTime = UnityEngine.Random.Range(cutTextFlickerInterval * 0.5f, cutTextFlickerInterval * 1.5f);
yield return new WaitForSeconds(waitTime);
}
}
public void UpdateCutProgress(float progress)
{
// 检查是否达到闪烁阈值
if (!isCutTextFlickering && progress >= cutTextFlickerThreshold)
{
StartCutTextFlicker();
}
}
// public void EnableCut()
// {
// // 打开或获取CutLine
@@ -134,6 +134,15 @@ namespace AibisDream
{
yield return PunchTapeSystem.StartCoroutine(PunchTapeSystem.PrintPunchTapes(count));
}
[YarnCommand("DropCable")]
public static void DropCable()
{
BodyModuleSystem.CableSystem.DropDownCable();
}
[YarnCommand("RetractCable")]
public static void RetractCable()
{
BodyModuleSystem.CableSystem.PullUpCable();
}
}
}
@@ -5,6 +5,8 @@ using Cinemachine;
using AibisDream.Framework;
using AibisDream.Kit;
using UnityEditor.Localization.Plugins.XLIFF.V12;
using DG.Tweening;
using System.Collections;
namespace AibisDream
{
@@ -12,10 +14,20 @@ namespace AibisDream
{
[Header("切割组件")]
public GameObject gearFollowerPrefab;
public GameObject entrancePanelPrefab; // 入场面板预制体
public float entranceDuration = 1.5f; // 入场动画时长
public float exitDuration = 1.5f; // 退场动画时长
public float panelOffsetY = 2f; // 面板在相机视野下方的偏移量
private GearFollower gearFollower;
private bool isCuttingMode = false;
private bool isEntranceComplete = false; // 入场是否完成
private bool isGearActive = false; // 标记gear是否已激活
private BodyModule _targetModule;
private SpriteRenderer _targetSpriteRenderer;
private GameObject entrancePanel; // 入场面板实例
private Camera _mainCamera;
private CinemachineVirtualCamera _currentVirtualCamera;
private void Awake()
{
@@ -33,23 +45,63 @@ namespace AibisDream
CameraKit.Instance.RegisterCamera(CameraEnum.CutEmoDeep, virtualCam4);
CameraKit.Instance.RegisterCamera(CameraEnum.CutMemoryDeep, virtualCam5);
CameraKit.Instance.RegisterCamera(CameraEnum.CutLogicDeep, virtualCam6);
_mainCamera = Camera.main;
}
private void Update()
{
if (isCuttingMode && gearFollower != null)
if (isCuttingMode && !isGearActive && gearFollower != null)
{
// 检测点击
if (Input.GetMouseButtonDown(0))
{
Ray ray = _mainCamera.ScreenPointToRay(Input.mousePosition);
RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction);
if (hit.collider != null && hit.collider.gameObject.GetComponent<GearFollower>() != null)
{
gearFollower=hit.collider.gameObject.GetComponent<GearFollower>();
ActivateGear();
}
}
}
else if (isCuttingMode && isGearActive && gearFollower != null)
{
gearFollower.GearUpdate();
}
}
public void StartCutting(BodyModule targetModule)
private void ActivateGear()
{
isGearActive = true;
if (gearFollower != null)
{
// 解除父子关系
gearFollower.transform.SetParent(null);
gearFollower.Init(_targetSpriteRenderer);
}
// 面板退场
if (entrancePanel != null)
{
Vector3 startPosition = GetPanelSpawnPosition();
entrancePanel.transform.DOMove(startPosition, exitDuration)
.SetEase(Ease.InBack)
.OnComplete(() => {
Destroy(entrancePanel);
entrancePanel = null;
});
}
}
public IEnumerator StartCutting(BodyModule targetModule)
{
// 检查参数
if (targetModule == null)
{
Debug.LogError("targetModule 为空");
return;
yield break;
}
// 保存目标模块
@@ -60,7 +112,7 @@ namespace AibisDream
if (_targetSpriteRenderer == null)
{
Debug.LogError("targetSprite 为空");
return;
yield break;
}
// 停止之前的切割
@@ -68,21 +120,94 @@ namespace AibisDream
// 设置切割模式
isCuttingMode = true;
isEntranceComplete = false;
// 创建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);
// 创建入场面板
CreateEntrancePanel();
// 等待入场动画完成
yield return new WaitUntil(() => isEntranceComplete);
}
private Vector3 GetPanelSpawnPosition()
{
if (_mainCamera == null)
{
_mainCamera = Camera.main;
}
// 获取相机的位置和旋转
Vector3 cameraPosition = _mainCamera.transform.position;
Quaternion cameraRotation = _mainCamera.transform.rotation;
// 计算相机视野下方的位置
Vector3 forward = cameraRotation * Vector3.forward;
Vector3 right = cameraRotation * Vector3.right;
Vector3 up = cameraRotation * Vector3.up;
// 计算相机视野的底部中心点
float height = 2f * Mathf.Tan(_mainCamera.fieldOfView * 0.5f * Mathf.Deg2Rad) * _mainCamera.nearClipPlane;
float width = height * _mainCamera.aspect;
// 计算面板的起始位置(在相机视野下方)
Vector3 bottomCenter = cameraPosition + forward * _mainCamera.nearClipPlane - up * (height * 0.5f + panelOffsetY);
return bottomCenter;
}
private void CreateEntrancePanel()
{
// 获取基于当前相机位置的生成位置
Vector3 startPosition = GetPanelSpawnPosition();
if (startPosition == Vector3.zero)
{
Debug.LogError("无法获取面板生成位置");
return;
}
// 创建入场面板,保持原始旋转
entrancePanel = Instantiate(entrancePanelPrefab, startPosition, Quaternion.Euler(0,0,-90));
// 获取GearFollower组件(作为子物体)
gearFollower = entrancePanel.GetComponentInChildren<GearFollower>();
if (gearFollower == null)
{
Debug.LogError("入场面板预制体中没有找到GearFollower组件");
return;
}
// 计算相机视野高度
float height = 2f * Mathf.Tan(_mainCamera.fieldOfView * 0.5f * Mathf.Deg2Rad) * _mainCamera.nearClipPlane;
// 计算目标位置(相机视野中心偏下)
Vector3 targetPosition = startPosition + _mainCamera.transform.up * 3.5f;
// 执行入场动画
entrancePanel.transform.DOMove(targetPosition, entranceDuration)
.SetEase(Ease.OutBack)
.OnComplete(() => {
isEntranceComplete = true;
});
}
public void OnCutComplete()
{
isCuttingMode = false;
isEntranceComplete = false;
isGearActive = false;
if (gearFollower != null)
{
gearFollower.FinishCutting();
}
// 如果面板还存在,删除它
if (entrancePanel != null)
{
Destroy(entrancePanel);
entrancePanel = null;
}
}
public void UpdateModule()
{
@@ -91,11 +216,62 @@ namespace AibisDream
_targetModule.OnCuttingDown();
}
}
public void SetCutTextVisible(bool visible)
{
if (_targetModule != null)
{
_targetModule.SetCutTextVisible(visible);
}
}
public void UpdateCutProgress(float progress)
{
if (_targetModule != null)
{
_targetModule.UpdateCutProgress(progress);
}
}
public void StartCutTextFlicker()
{
if (_targetModule != null)
{
_targetModule.StartCutTextFlicker();
}
}
public void StopCutTextFlicker()
{
if (_targetModule != null)
{
_targetModule.StopCutTextFlicker();
}
}
public void StopCutting()
{
isCuttingMode = false;
if (gearFollower != null)
isEntranceComplete = false;
isGearActive = false;
if (_targetModule != null)
{
_targetModule.StopCutTextFlicker();
}
if (entrancePanel != null)
{
// 获取当前相机位置
Vector3 startPosition = GetPanelSpawnPosition();
// 执行退场动画
entrancePanel.transform.DOMove(startPosition, exitDuration)
.SetEase(Ease.InBack)
.OnComplete(() => {
Destroy(entrancePanel);
entrancePanel = null;
gearFollower = null;
});
}
else if (gearFollower != null)
{
Destroy(gearFollower.gameObject);
gearFollower = null;
@@ -6,6 +6,7 @@ using UnityEngine.VFX;
using DG.Tweening;
using AibisDream.FixSystem;
using AibisDream; // 添加OpenSystem的命名空间
using System.Collections;
public class GearFollower : MonoBehaviour
{
@@ -45,6 +46,12 @@ public class GearFollower : MonoBehaviour
public float fadeOutDelay = 1f; // 淡出前的延迟时间
public AudioClip cutCompleteSound; // 切割完成音效
[Header("CutText闪烁效果")]
private float cutTextFlickerThreshold = 0.7f; // 开始闪烁的阈值
private float cutTextFlickerInterval = 0.1f; // 闪烁间隔
private float cutTextFlickerTimer = 0f; // 闪烁计时器
private bool isCutTextFlickering = false; // 是否正在闪烁
private float totalEdgeLength = 0f; // 总边缘长度
private float cutLength = 0f; // 已切割长度
private bool isCutComplete = false;
@@ -127,6 +134,14 @@ public class GearFollower : MonoBehaviour
audioSource = gameObject.AddComponent<AudioSource>();
audioSource.playOnAwake = false;
audioSource.spatialBlend = 0f; // 2D音效
// 确保初始状态
isCutting = false;
isInTractionMode = false;
if (sparkVFX != null)
{
sparkVFX.Stop();
}
}
void Update()
{
@@ -379,6 +394,13 @@ public class GearFollower : MonoBehaviour
transform.position = targetPosition;
currentState = State.Traction;
isInTractionMode = true;
// 设置渲染顺序为5
SpriteRenderer gearRenderer = GetComponent<SpriteRenderer>();
if (gearRenderer != null)
{
gearRenderer.sortingOrder = 5;
}
}
}
private void UpdateTractionState(Vector2 mousePos)
@@ -547,7 +569,12 @@ public class GearFollower : MonoBehaviour
sparkVFX.Stop();
}
// 关闭切割光照
if (cutLight != null)
{
cutLight.enabled = false;
cutLight.intensity = 0f;
}
}
private int FindNearestEdgePointIndex(Vector2 pos, out float minDist)
{
@@ -620,6 +647,13 @@ public class GearFollower : MonoBehaviour
float progress = cutLength / totalEdgeLength;
Debug.Log($"当前切割长度: {cutLength}, 总长度: {totalEdgeLength}, 进度: {progress * 100}%");
// 更新切割进度
var cuttingManager = FixSystemCenter.SystemDic.Get<CuttingManager>();
if (cuttingManager != null)
{
cuttingManager.UpdateCutProgress(progress);
}
// 检查是否满足切割完成条件
if (!isCutComplete && progress >= cutCompletionThreshold)
{
@@ -703,7 +737,7 @@ public class GearFollower : MonoBehaviour
}
public void FinishCutting()
{
// 清理特效
// 清理特效
if (cutLight != null)
{
cutLight.enabled = false;
@@ -719,10 +753,19 @@ public class GearFollower : MonoBehaviour
// 计算随机方向
float randomAngle = Random.Range(-cutCompleteTiltAngle, cutCompleteTiltAngle);
Vector2 randomOffset = Random.insideUnitCircle * cutCompleteOffset;
var cuttingManager = FixSystemCenter.SystemDic.Get<CuttingManager>();
if (cuttingManager != null)
{
cuttingManager.StopCutTextFlicker();
cuttingManager.SetCutTextVisible(false);
}
// 立即应用倾斜和位移
targetSpriteRenderer.transform.rotation = Quaternion.Euler(0, 0, randomAngle);
targetSpriteRenderer.transform.position = originalTargetPosition + (Vector3)randomOffset;
// 创建动画序列
cutCompleteSequence = DOTween.Sequence();
@@ -751,7 +794,36 @@ public class GearFollower : MonoBehaviour
cuttingManager.UpdateModule();
}
});
}
private void StartCutTextFlicker()
{
var cuttingManager = FixSystemCenter.SystemDic.Get<CuttingManager>();
if (cuttingManager != null)
{
// 开始闪烁效果
StartCoroutine(CutTextFlickerCoroutine(cuttingManager));
}
}
private IEnumerator CutTextFlickerCoroutine(CuttingManager cuttingManager)
{
while (isCutTextFlickering && !isCutComplete)
{
// 随机决定是否显示
bool shouldShow = Random.value > 0.5f;
cuttingManager.SetCutTextVisible(shouldShow);
// 随机等待时间,模拟接触不良效果
float waitTime = Random.Range(cutTextFlickerInterval * 0.5f, cutTextFlickerInterval * 1.5f);
yield return new WaitForSeconds(waitTime);
}
// 确保最终状态是可见的
if (!isCutComplete)
{
cuttingManager.SetCutTextVisible(true);
}
}
private void OnDestroy()