Merge branch 'develop' into feature/新对话框

This commit is contained in:
2025-06-05 22:24:43 +08:00
151 changed files with 40838 additions and 3375 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
// 模块基本数据
@@ -52,7 +60,11 @@ namespace AibisDream.FixSystem
_targetSpriteRenderer = transform.Find("Module Pic").GetComponent<SpriteRenderer>();
_originalMaterial = _targetSpriteRenderer.GetComponent<SpriteRenderer>().material;
_cutSpriteRenderer = transform.Find("Cut Pic").GetComponent<SpriteRenderer>();
_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");
@@ -126,6 +138,16 @@ namespace AibisDream.FixSystem
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()
@@ -133,6 +155,114 @@ 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
// ShowCutLine();
// _cutLine.OnCuttingDown += OnCuttingDown;
// _cutting = true;
// EnumEventSystem.Global.Send(EventEnum.CutStart);
// }
// private void OnCut()
// {
// Vector2 mousePos = CommonUtil.GetMouseWorldPos(Input.mousePosition);
// _cutLine.DetectLineClick(mousePos, clickRadius);
// }
// private void OnCuttingDown()
// {
// _cutLine.OnCuttingDown -= OnCuttingDown;
// _cutting = false;
// // 模块脱落
// _cutLine.HideLine();
// _bodyModuleSystem.RemoveModule(this);
// ActionKit.Sequence()
// .Delay(0.8f)
// .DOTween(() => transform.DOMoveY(ConstRef.TweenEndY,
// (transform.position.y - ConstRef.TweenEndY) / (ConstRef.FallSpeed * 0.6f))
// .SetEase(Ease.InQuad))
// .Callback(() => DialogController.Instance?.StartDialogNode($"{data.moduleName}CutDown"))
// .Callback(() => EnumEventSystem.Global.Send(EventEnum.CutEnd))
// .Start(this, () => Destroy(gameObject));
// }
// private void ShowCutLine()
// {
// // 切割线不存在,就新建一个
// if (!_cutLine)
// {
// var prefab = ResourceKit.LoadAssetSync<GameObject>(ConstRef.CutLinePrefabName);
// var cutLineObj = Instantiate(prefab, transform);
// _cutLine = cutLineObj.GetComponent<CutLine>();
// }
// // 对切割线进行初始化
// var shapePoints = new List<Vector2>();
// _targetSpriteRenderer.sprite.GetPhysicsShape(0, shapePoints);
// if (shapePoints.Count <= 0)
// {
// Debug.LogWarning($"{name} has no shape");
// return;
// }
// // 本地坐标转世界坐标
// var shapePointsV3 = shapePoints
// .Select(item => _targetSpriteRenderer.transform.TransformPoint(item))
// .ToList();
// _cutLine.Init(shapePointsV3, clickRadius);
// }
#endregion
}
@@ -62,11 +62,24 @@ namespace AibisDream.FixSystem
heatMapController = transform.Find("HeatMapController").GetComponent<HeatMapController>();
}
// 初始化 BodyModules 列表
BodyModules = new List<BodyModule>();
if (_bodyModuleGroup != null)
{
BodyModules.AddRange(_bodyModuleGroup.GetComponentsInChildren<BodyModule>());
}
if (_headModuleGroup != null)
{
BodyModules.AddRange(_headModuleGroup.GetComponentsInChildren<BodyModule>());
}
FixSystemCenter.SystemDic.Register(this);
// 注册Camera
var virtualCam = transform.GetComponentInChildren<ICinemachineCamera>();
CameraKit.Instance.RegisterCamera(CameraEnum.BodyModule, virtualCam);
var virtualCam2 = transform.Find("Body Module Camera Center").GetComponent<ICinemachineCamera>();
CameraKit.Instance.RegisterCamera(CameraEnum.BodyModuleCenter, virtualCam2);
}
private void OnDestroy()
@@ -2,6 +2,7 @@ using System.Collections;
using AibisDream.FixSystem;
using AibisDream.Framework;
using Yarn.Unity;
using UnityEngine;
namespace AibisDream
{
@@ -111,7 +112,14 @@ namespace AibisDream
public static void ModuleHightLight(string moduleName, bool enable)
{
var targetModule = BodyModuleSystem.FindBodyModuleByName(moduleName);
targetModule.Highlight(enable);
if (targetModule != null)
{
targetModule.Highlight(enable);
}
else
{
Debug.LogWarning($"Module {moduleName} not found!");
}
}
[YarnCommand("ModuleAlarm")]
@@ -126,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();
}
}
}
+66 -12
View File
@@ -12,6 +12,7 @@ namespace AibisDream.FixSystem
private Transform _end;
private LineRenderer _lineRenderer;
private LineRenderer _stiffLineRenderer; // 用于渲染刚性部分
private Vector3[] _points;
private CableSystem _cableSystem;
@@ -19,6 +20,17 @@ namespace AibisDream.FixSystem
[SerializeField]
private CableConfig config = CableConfig.GeneDefaultConfig();
public void ShowCable()
{
_lineRenderer.enabled = true;
_stiffLineRenderer.enabled = true;
}
public void HideCable()
{
_lineRenderer.enabled = false;
_stiffLineRenderer.enabled = false;
}
private void Start()
{
InitComponentRefs();
@@ -30,7 +42,22 @@ namespace AibisDream.FixSystem
_cableSystem = transform.parent.GetComponent<CableSystem>();
_lineRenderer = GetComponent<LineRenderer>();
_lineRenderer.positionCount = config.resolution;
_lineRenderer.positionCount = config.resolution - config.stiffCount;
// 创建第二个LineRenderer用于刚性部分
GameObject stiffObj = new GameObject("StiffLineRenderer");
stiffObj.transform.SetParent(transform);
_stiffLineRenderer = stiffObj.AddComponent<LineRenderer>();
_stiffLineRenderer.positionCount = config.stiffCount;
// 复制第一个LineRenderer的属性到第二个
_stiffLineRenderer.startWidth = _lineRenderer.startWidth;
_stiffLineRenderer.endWidth = _lineRenderer.startWidth;
_stiffLineRenderer.material = _lineRenderer.material;
_stiffLineRenderer.startColor = _lineRenderer.startColor;
_stiffLineRenderer.endColor = _lineRenderer.startColor;
_stiffLineRenderer.sortingLayerName = _cableSystem.CableReelRef.GetComponent<SpriteRenderer>().sortingLayerName;
_stiffLineRenderer.sortingOrder = _cableSystem.CableReelRef.GetComponent<SpriteRenderer>().sortingOrder - 1;
// 连线起止点
_start = _cableSystem.CableRootPos;
@@ -55,31 +82,54 @@ namespace AibisDream.FixSystem
void DrawLine()
{
var points = UpdateRope();
for (int i = 0; i < config.resolution; i++)
// 渲染刚性部分
for (int i = 0; i < config.stiffCount; i++)
{
_lineRenderer.SetPosition(i, points[i] + Vector3.forward * -.3f);
_stiffLineRenderer.SetPosition(i, points[i] + Vector3.forward * -.3f);
}
// 渲染非刚性部分
for (int i = 0; i < config.resolution - config.stiffCount; i++)
{
_lineRenderer.SetPosition(i, points[i + config.stiffCount] + Vector3.forward * -.3f);
}
}
Vector3[] UpdateRope()
{
float t = Mathf.InverseLerp(config.dstMin, config.dstMax, (_start.position - _end.position).magnitude);
float F = Mathf.Lerp(config.forceMin, config.forceMax, t);
_points[0] = _start.position;
_points[^1] = _end.position;
for (int ik = 0; ik < config.k; ik++)
// 计算出线方向(从转盘出线口到起始点)
Vector3 dir = (_start.position - _cableSystem.CableReelRef.transform.position).normalized;
// 设置刚性部分
for (int i = 0; i < config.stiffCount; i++)
{
for (int i = 1; i < _points.Length - 1; i++)
float t_stiff = (float)i / (config.stiffCount - 1);
_points[i] = _start.position + dir * (config.stiffLength * t_stiff);
}
// 设置末端点
_points[^1] = _end.position;
// 只对非刚性部分进行物理模拟
for (int ik = 0; ik < config.k; ik++)
{
// 确保非刚性部分的第一个点与刚性部分的最后一个点重合
_points[config.stiffCount] = _points[config.stiffCount - 1];
for (int i = config.stiffCount + 1; i < _points.Length - 1; i++)
{
Vector3 offsetPrev = _points[i - 1] - _points[i];
Vector3 offsetNext = _points[i + 1] - _points[i];
Vector3 velocity = offsetPrev.normalized * (offsetPrev.magnitude * F) +
offsetNext.normalized * (offsetNext.magnitude * F);
_points[i] += velocity * Time.deltaTime / config.k;
}
}
for (int i = 1; i < _points.Length - 1; i++)
for (int i = config.stiffCount + 1; i < _points.Length - 1; i++)
{
_points[i] += Vector3.down * (9.8f * Time.deltaTime) / config.k;
}
@@ -98,7 +148,7 @@ namespace AibisDream.FixSystem
}
public Vector3 GetDirection()
{
return _points[^1]-_points[_points.Length-1];
return _points[^1] - _points[^2];
}
}
@@ -111,6 +161,8 @@ namespace AibisDream.FixSystem
public float forceMin;
public float forceMax;
public int k;
public int stiffCount; // 刚性部分点数
public float stiffLength; // 刚性部分长度
public static CableConfig GeneDefaultConfig()
{
@@ -121,7 +173,9 @@ namespace AibisDream.FixSystem
dstMax = 1.0f,
forceMin = 0.1f,
forceMax = 150f,
k = 10
k = 10,
stiffCount = 3,
stiffLength = 0.1f
};
}
}
@@ -0,0 +1,88 @@
using UnityEngine;
namespace AibisDream.FixSystem
{
public class CableReel : MonoBehaviour
{
[Header("转盘设置")]
[SerializeField] private float torqueStrength = 200f; // 扭矩强度
[SerializeField] private float angularDamping = 5f; // 角速度阻尼
private CableSystem cableSystem;
private float angularVelocity; // 角速度
private float currentAngle; // 当前角度
public Vector3 outletPos { get; private set; } // 出线口位置
private SpriteRenderer spriteRenderer;
private float reelRadius; // 转盘半径
private void Start()
{
// 获取CableSystem引用
cableSystem = transform.parent.GetComponent<CableSystem>();
currentAngle = transform.eulerAngles.z;
// 获取SpriteRenderer并计算半径
spriteRenderer = GetComponent<SpriteRenderer>();
if (spriteRenderer != null)
{
// 使用sprite的bounds来计算半径
reelRadius = spriteRenderer.bounds.extents.y; // 使用y方向的半高作为半径
}
else
{
Debug.LogWarning("CableReel没有SpriteRenderer组件!");
reelRadius = 0.5f; // 默认值
}
// 初始化出线口位置
UpdateOutletPosition();
}
private void UpdateOutletPosition()
{
// 更新出线口位置(圆形本地坐标 (0, -radius) 转成世界坐标)
outletPos = transform.TransformPoint(new Vector3(0, -reelRadius, 0));
}
public void ResetRotation()
{
// 重置角度和角速度
currentAngle = 0;
angularVelocity = 0;
transform.rotation = Quaternion.identity;
UpdateOutletPosition();
}
public void UpdateRotation()
{
// 如果PhysicCable激活,不进行旋转
if (cableSystem == null || cableSystem.PlugRef == null ||
cableSystem.PhysicCableRef.GetComponent<LineRenderer>().enabled) return;
Vector2 center = transform.position;
// 使用当前出线口位置
Vector2 outlet = outletPos;
// 力向量(线缆拉力方向)
Vector2 force = (Vector2)cableSystem.PlugRef.transform.position - outlet;
// 杆臂向量(力作用点相对于圆心的位置)
Vector2 r = outlet - center;
// 计算 2D 扭矩:r × F
float torque = (r.x * force.y - r.y * force.x);
// 应用扭矩 + 阻尼
angularVelocity += torque * torqueStrength * Time.deltaTime;
angularVelocity *= Mathf.Exp(-angularDamping * Time.deltaTime); // 简易阻尼
// 应用旋转
currentAngle += angularVelocity * Time.deltaTime;
transform.rotation = Quaternion.Euler(0, 0, currentAngle);
// 更新出线口位置
UpdateOutletPosition();
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 81da72a4f38d7f94784a80abb68a0ddd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -1,4 +1,6 @@
using UnityEngine;
using DG.Tweening;
using System;
namespace AibisDream.FixSystem
{
@@ -11,21 +13,28 @@ namespace AibisDream.FixSystem
public PhysicCable PhysicCableRef { get; private set; }
public Transform CableRootPos { get; private set; }
public CableReel CableReelRef { get; private set; }
public BodyModuleSystem BodyModuleSystem { get; private set; }
#endregion
#region
public bool isInDialog;
public bool isActive = true;
public bool isCableRetracted = true; // 线缆是否收起
[SerializeField] private Transform retractedPos; // 收起位置
[SerializeField] private float dropDownDuration = 0.5f; // 放下动画时长
[SerializeField] private float swingDuration = 0.3f; // 摆动动画时长
[SerializeField] private float swingAngle = 15f; // 摆动角度
[HideInInspector] public ISocket curSocket;
[HideInInspector] public BodyModule curBodyModule;
#endregion
private void Awake()
{
InitComponentRefs();
@@ -48,11 +57,13 @@ namespace AibisDream.FixSystem
DialogController.OnDialogueComplete -= HandleDialogueComplete;
}
private void InitComponentRefs()
{
PlugRef = transform.Find("Plug").GetComponent<Plug>();
CableRef = transform.Find("Cable").GetComponent<Cable>();
CableRootPos = transform.Find("Cable Root Pos").transform;
CableReelRef = transform.Find("CableReel").GetComponent<CableReel>();
CableRootPos = CableReelRef.transform.Find("Cable Root Pos").transform;
PhysicCableRef = transform.Find("PhysicCable").GetComponent<PhysicCable>();
BodyModuleSystem = transform.parent.GetComponent<BodyModuleSystem>();
@@ -60,12 +71,39 @@ namespace AibisDream.FixSystem
private void InitSystem()
{
// 初始状态Plug垂下
PlugRef.InitPlug();
if (isCableRetracted)
{
SetRetractCable();
}
else
{
PlugRef.ReturnToStartPosition();
}
}
private void Update()
{
// 获取线缆方向并更新转盘旋转
if (CableRef != null && CableReelRef != null)
{
CableReelRef.UpdateRotation();
}
if (Input.GetKeyDown(KeyCode.Space))
{
if (isCableRetracted)
{
DropDownCable();
}
else
{
PullUpCable();
}
}
}
public void ResetPlug()
{
Debug.Log("ResetPlug");
// 不在初始插孔里,就从当前插孔拔出来,插回初始插孔
PlugRef.PullUpSocket();
PlugRef.ReturnToStartPosition();
@@ -93,7 +131,7 @@ namespace AibisDream.FixSystem
{
isInDialog = false;
}
public void Disable_plugInput()
{
isActive = false;
@@ -114,5 +152,46 @@ namespace AibisDream.FixSystem
}
#endregion
public void PullUpCable()
{
if (isCableRetracted) return;
//禁用plug交互
Disable_plugInput();
ResetPlug();
PlugRef.SetPhysicCableActive(false);
PlugRef.GetComponent<SpriteRenderer>().sortingLayerName = CableReelRef.GetComponent<SpriteRenderer>().sortingLayerName;
PlugRef.GetComponent<SpriteRenderer>().sortingOrder = 41;
PlugRef.transform.DOMove(retractedPos.position, 0.1f).OnComplete(() =>
{
PhysicCableRef.GetComponent<LineRenderer>().enabled = false;
isCableRetracted = true;
});
}
public void DropDownCable()
{
if (!isCableRetracted) return;
PlugRef.PullUpSocket();
CableReelRef.ResetRotation();
PlugRef.transform.DOMove(PlugRef.GetStartPos(), 0.1f).OnComplete(() =>
{
PlugRef.SwitchToPhysicCableState();
isCableRetracted = false;
});
// 只有在非收起状态时才切换到物理线缆状态
}
public void SetRetractCable()
{
// 禁用物理线缆和普通线缆
PhysicCableRef.GetComponent<LineRenderer>().enabled = false;
CableRef.HideCable();
// 设置Plug位置和层级
PlugRef.transform.position = retractedPos.position;
PlugRef.transform.rotation = retractedPos.rotation;
PlugRef.GetComponent<SpriteRenderer>().sortingLayerName = CableReelRef.GetComponent<SpriteRenderer>().sortingLayerName;
PlugRef.GetComponent<SpriteRenderer>().sortingOrder = 41;
}
}
}
@@ -2,6 +2,10 @@ using UnityEngine;
using AibisDream.FixSystem;
using Cinemachine;
using AibisDream.Framework;
using AibisDream.Kit;
using UnityEditor.Localization.Plugins.XLIFF.V12;
using DG.Tweening;
using System.Collections;
namespace AibisDream
{
@@ -9,10 +13,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()
{
@@ -30,23 +44,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;
}
// 保存目标模块
@@ -57,7 +111,7 @@ namespace AibisDream
if (_targetSpriteRenderer == null)
{
Debug.LogError("targetSprite 为空");
return;
yield break;
}
// 停止之前的切割
@@ -65,21 +119,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()
{
@@ -88,11 +215,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()
+32 -22
View File
@@ -16,9 +16,10 @@ namespace AibisDream.FixSystem
#region
private Vector3 _startPos;
private Vector3 _RetractedPos;
private readonly Vector3 _pickupOffset = new(0, 0, 0);
private readonly Quaternion _pickupRotationOffset = Quaternion.Euler(0, 0, 30);
private readonly Quaternion _initRotation = Quaternion.Euler(0, 0, 180);
#endregion
@@ -38,8 +39,9 @@ namespace AibisDream.FixSystem
private void Awake()
{
InitComponentRef();
EventRegister();
_startPos = transform.position; // 初始化时记录初始位置
EventRegister();
_RetractedPos = transform.position;
_startPos = new Vector3(transform.position.x+0.3f, transform.position.y - 2f, transform.position.z); // 初始化时记录初始位置
}
private void InitComponentRef()
@@ -60,10 +62,6 @@ namespace AibisDream.FixSystem
_trigger.Register(EventTriggerType.PointerUp, OnPointerUp);
}
public void InitPlug()
{
ReturnToStartPosition();
}
/// <summary>
/// 插入某个socket
@@ -127,20 +125,17 @@ namespace AibisDream.FixSystem
private void OnPointerDown(BaseEventData eventData)
{
GetComponent<SpriteRenderer>().sortingLayerName = "Tools";
GetComponent<SpriteRenderer>().sortingOrder = 48;
// 系统被锁定就返回
if (!_cableSystem.IsPlugAvailable()) return;
// 首次拖拽后关闭高亮
if (GlobalVariableKit.IsPlugHighLight)
{
GlobalVariableKit.IsPlugHighLight = false;
_sprite.material.SetFloat(ShineFade, 0);
// 拖拽后还要高亮其他组件
// var bodyModuleSystem = FixSystemCenter.SystemDic.Get<BodyModuleSystem>();
// foreach (var module in bodyModuleSystem.BodyModules)
// {
// module.Highlight(true);
// }
DialogController.Instance.StartDialogNode("拿起插头");
}
@@ -156,7 +151,7 @@ namespace AibisDream.FixSystem
// 关闭 PhysicCable 的更新,并显示 Cable 的 LineRenderer
_cableSystem.PhysicCableRef.GetComponent<LineRenderer>().enabled = false;
_isPhysicCableActive = false;
_cableSystem.CableRef.GetComponent<LineRenderer>().enabled = true;
_cableSystem.CableRef.ShowCable();
}
private void OnPointerUp(BaseEventData eventData)
@@ -179,7 +174,11 @@ namespace AibisDream.FixSystem
public void ReturnToStartPosition()
{
transform.DOMove(_startPos, 0.1f).OnComplete(SwitchToPhysicCableState);
PlugPosBack();
transform.DOMove(_startPos, 0.1f).OnComplete(() => {
_cableSystem.CableReelRef.ResetRotation();
SwitchToPhysicCableState();
});
}
private void AdjustPlugPos()
@@ -194,20 +193,22 @@ namespace AibisDream.FixSystem
transform.rotation = _initRotation;
}
private void SwitchToPhysicCableState()
public void SwitchToPhysicCableState()
{
// 隐藏 Cable 的 LineRenderer
PlugPosBack();
_cableSystem.PhysicCableRef.Init(transform.position);
_cableSystem.CableRef.GetComponent<LineRenderer>().enabled = false;
// 激活 PhysicCable
_cableSystem.CableRef.HideCable();
_cableSystem.PhysicCableRef.GetComponent<LineRenderer>().enabled = true;
_isPhysicCableActive = true;
}
public void SetPhysicCableActive(bool active)
{
_isPhysicCableActive = active;
}
private void Update()
{
if (_isPhysicCableActive)
if (_isPhysicCableActive && !_cableSystem.isCableRetracted)
{
_cableSystem.PhysicCableRef.physicLine.UpdatePlug(this.transform);
}
@@ -221,11 +222,20 @@ namespace AibisDream.FixSystem
public bool IsActive => true;
public bool IsAvailable => _cableSystem.BodyModuleSystem.isAvailable;
public bool IsAvailable => _cableSystem.BodyModuleSystem.isAvailable && !_cableSystem.isCableRetracted;
public GameObject GetGameObject()
{
return gameObject;
}
public void SetStartPos(Vector3 pos)
{
_startPos = pos;
}
public Vector3 GetStartPos()
{
return _startPos;
}
}
}