fix:調整石像事件,修复石像无法完成的问题

This commit is contained in:
bzx
2026-02-26 18:48:48 +08:00
parent 7067993457
commit 2b26cf1dbd
6 changed files with 139 additions and 327 deletions

View File

@@ -1 +1 @@
Build from ZTT at 2026/2/26 16:44:10
Build from CHINAMI-UKDLSK3 at 2026/2/26 18:48:03

View File

@@ -17511,7 +17511,7 @@ MonoBehaviour:
- {fileID: 5026362574979566377}
- {fileID: 6259881349340267268}
statueShowOffset: {x: 0, y: 0, z: 5}
debugMode: 0
debugMode: 1
--- !u!1 &2025442969
GameObject:
m_ObjectHideFlags: 0

View File

@@ -561,8 +561,8 @@ public class GameManager : MonoBehaviour
if (Input.GetKeyDown(KeyCode.Space))
{
//GameInit.Ins.self.AddCoin(5000);
GameInit.Ins.self.AddScore(10000);
WinEndGame();
//GameInit.Ins.self.AddScore(10000);
//WinEndGame();
//StartFishTideEvent();
//StartDriftBottleEvent();
}

View File

@@ -28,20 +28,18 @@ public class DriftBottle : MonoBehaviour
[Header("移动配置")]
public float moveSpeed = 1.5f;
public float swimAmplitude = 0.1f; // 游动幅度
public float swimFrequency = 2f; // 游动频率
public float swimAmplitude = 0.1f;
public float swimFrequency = 2f;
// 私有变量
private SplineController controller;
private DriftBottleState state = DriftBottleState.Alive;
private int fragmentIndex; // 碎片序号0-29
private int statueIndex; // 所属雕像0-2
private bool unregisterCalled = false;
private Vector3 baseScale;
private float swimOffset;
// 事件
public event Action<DriftBottle, int, int> OnBottleCaptured; // 参数:瓶子,碎片序号,雕像序号
public event Action<DriftBottle> OnBottleCaptured;
private void Awake()
{
@@ -52,35 +50,10 @@ public class DriftBottle : MonoBehaviour
}
/// <summary>
/// 设置控制器 - 参考 Fish.cs 的 SetCollider 方法
/// 初始化漂流瓶 - 不绑定特定碎片,击中时由管理器决定
/// </summary>
public void SetController(CurvySpline spline)
public void Init(CurvySpline spline)
{
controller = GetComponent<SplineController>();
if(controller == null)
return;
// 确保控制器已启用(从对象池取出时可能被禁用)
controller.enabled = true;
controller.Spline = GameInit.Ins.GetFishPath();
controller.Speed = moveSpeed;
controller.Position = 0;
controller.Play();
controller.OnEndReached.AddListener((c) =>
{
OnSplineEnd();
});
}
/// <summary>
/// 初始化漂流瓶
/// </summary>
public void Init(CurvySpline spline, int fragIndex, int statIdx)
{
fragmentIndex = fragIndex;
statueIndex = statIdx;
state = DriftBottleState.Alive;
if (spline == null)
@@ -89,8 +62,20 @@ public class DriftBottle : MonoBehaviour
return;
}
// 使用和 Fish.cs 相同的模式
SetController(spline);
// 设置控制器
controller = GetComponent<SplineController>();
if (controller == null)
{
controller = gameObject.AddComponent<SplineController>();
}
controller.enabled = true;
controller.Spline = spline;
controller.Speed = moveSpeed;
controller.Position = 0;
controller.Play();
controller.OnEndReached.AddListener((c) => OnSplineEnd());
// 注册到管理器
DriftBottleManager.Instance?.RegisterBottle(this);
@@ -105,30 +90,26 @@ public class DriftBottle : MonoBehaviour
modelRoot.localScale = baseScale * (1f + swimAnim);
// 轻微上下浮动
if (modelRoot != null)
{
Vector3 pos = modelRoot.localPosition;
pos.y = Mathf.Sin(Time.time * swimFrequency * 0.5f + swimOffset) * 0.05f;
modelRoot.localPosition = pos;
}
Vector3 pos = modelRoot.localPosition;
pos.y = Mathf.Sin(Time.time * swimFrequency * 0.5f + swimOffset) * 0.05f;
modelRoot.localPosition = pos;
}
/// <summary>
/// 被击中
/// 被击中 - 通知管理器处理碎片分配
/// </summary>
public void OnHit(float gunLevel)
{
if (state != DriftBottleState.Alive)
return;
// 漂流瓶命中率计算(比鱼更容易击中)
float actualHitRate = gunLevel * 0.8f; // 80%的基础命中率
float hitProbability = actualHitRate * 100f + 30f; // 额外+30%基础概率
// 漂流瓶命中率计算
float actualHitRate = gunLevel * 0.8f;
float hitProbability = actualHitRate * 100f + 30f;
float randomValue = Random.Range(0f, 100f);
if (randomValue > hitProbability)
{
Debug.Log("漂流瓶未命中!");
return;
}
@@ -144,15 +125,11 @@ public class DriftBottle : MonoBehaviour
// 注销
SafeUnregister();
CoroutineTaskManager.Instance.WaitSecondTodo(() =>
{
DriftBottleManager.Instance?.OnBottleCaptured(this, fragmentIndex, statueIndex);
}, 2f);
// 触发捕获事件
//OnBottleCaptured?.Invoke(this, fragmentIndex, statueIndex);
// 播放特效
PlayCaptureEffects();
// 通知管理器处理碎片分配(立即处理,不等飞行结束)
DriftBottleManager.Instance?.OnBottleCaptured(this);
}
/// <summary>
@@ -160,11 +137,13 @@ public class DriftBottle : MonoBehaviour
/// </summary>
private void PlayCaptureEffects()
{
fragmentEffect.gameObject.SetActive(false);
// 碎片特效
var x = modelRoot.GetComponent<Animator>();
if(x != null)
x.SetBool("isDie",true);
if (fragmentEffect != null)
fragmentEffect.gameObject.SetActive(false);
var animator = modelRoot.GetComponent<Animator>();
if(animator != null)
animator.SetBool("isDie", true);
// 播放音效
GameManager.Ins?.PlaySound3D("漂流瓶击碎", transform);
@@ -210,16 +189,6 @@ public class DriftBottle : MonoBehaviour
unregisterCalled = true;
DriftBottleManager.Instance?.UnregisterBottle(this);
}
/// <summary>
/// 获取碎片序号
/// </summary>
public int GetFragmentIndex() => fragmentIndex;
/// <summary>
/// 获取雕像序号
/// </summary>
public int GetStatueIndex() => statueIndex;
/// <summary>
/// 获取当前状态

View File

@@ -11,51 +11,33 @@ using Random = UnityEngine.Random;
[Serializable]
public class StatueData
{
public int statueIndex; // 雕像序号0-2
public string statueName; // 雕像名称
public int[] requiredFragments; // 所需碎片序号数组
public bool isCompleted; // 是否已完成
public StatueAssembler assembler; // 石像拼凑器引用
public int statueIndex;
public string statueName;
public int[] requiredFragments;
public bool isCompleted;
public StatueAssembler assembler;
public int collectedCount; // 已收集的碎片数量
}
/// <summary>
/// 漂流瓶管理器 - 管理海底雕像事件
/// 每60秒生成3个漂流瓶玩家收集碎片集齐3个雕像
/// 漂流瓶管理器
/// 每60秒生成3个漂流瓶击中后判断给哪个雕像加碎片
/// </summary>
public class DriftBottleManager : MonoBehaviour
{
public static DriftBottleManager Instance { get; private set; }
[Header("生成配置")]
[Tooltip("生成间隔(秒)")]
public float spawnInterval = 60f;
[Tooltip("每次生成数量")]
public int spawnCountPerWave = 3;
[Tooltip("漂流瓶预制体")]
public GameObject driftBottlePrefab;
[Header("碎片飞行效果")]
[Tooltip("碎片飞行特效预制体")]
public GameObject fragmentFlyPrefab;
[Header("雕像配置")]
[Tooltip("雕像总数")]
public int totalStatues = 3;
[Tooltip("每个雕像所需碎片数")]
public int fragmentsPerStatue = 10;
[Tooltip("雕像名称列表")]
public string[] statueNames = { "龙王雕像", "美人鱼雕像", "三叉戟雕像" };
[Header("石像位置")]
[Tooltip("3个石像的位置Transform")]
public StatueAssembler[] statueTransforms;
[Tooltip("石像显示位置偏移")]
public Vector3 statueShowOffset = new Vector3(0, 0, 5f);
[Header("调试")]
@@ -64,22 +46,16 @@ public class DriftBottleManager : MonoBehaviour
// 私有变量
private float spawnTimer = 0f;
private bool isEventActive = false;
private int currentFragmentIndex = 0; // 当前碎片序号0-29
private HashSet<int> collectedFragments = new HashSet<int>(); // 已收集的碎片
private List<StatueData> statues = new List<StatueData>(); // 雕像数据列表
private HashSet<DriftBottle> activeBottles = new HashSet<DriftBottle>(); // 活跃漂流瓶
private List<StatueData> statues = new List<StatueData>();
private HashSet<DriftBottle> activeBottles = new HashSet<DriftBottle>();
private bool allStatuesCompleted = false;
// 事件
public event Action<int, int> OnFragmentCollected; // 参数:碎片序号,雕像序号
public event Action<int> OnStatueCompleted; // 参数:雕像序号
public event Action OnAllStatuesCompleted; // 所有雕像完成
public event Action<int, int, int> OnSpawnWave; // 参数:当前波次,总波次,生成数量
public event Action<int, int> OnFragmentCollected;
public event Action<int> OnStatueCompleted;
public event Action OnAllStatuesCompleted;
private void Awake()
{
Instance = this;
}
private void Awake() { Instance = this; }
private void Start()
{
@@ -88,8 +64,7 @@ public class DriftBottleManager : MonoBehaviour
private void Update()
{
if(GameManager.Ins.isGameEnd)
return;
if (GameManager.Ins.isGameEnd) return;
if (!isEventActive || allStatuesCompleted) return;
spawnTimer += Time.deltaTime;
@@ -100,21 +75,15 @@ public class DriftBottleManager : MonoBehaviour
TrySpawnBottles();
}
// 调试快捷键
if (debugMode && Input.GetKeyDown(KeyCode.B))
{
TrySpawnBottles();
}
}
/// <summary>
/// 初始化雕像数据
/// </summary>
private void InitializeStatues()
{
statues.Clear();
int totalFragments = totalStatues * fragmentsPerStatue;
for (int i = 0; i < totalStatues; i++)
{
StatueData statue = new StatueData
@@ -122,10 +91,10 @@ public class DriftBottleManager : MonoBehaviour
statueIndex = i,
statueName = statueNames.Length > i ? statueNames[i] : $"雕像{i + 1}",
requiredFragments = new int[fragmentsPerStatue],
isCompleted = false
isCompleted = false,
collectedCount = 0
};
// 填充所需碎片序号
for (int j = 0; j < fragmentsPerStatue; j++)
{
statue.requiredFragments[j] = i * fragmentsPerStatue + j;
@@ -134,7 +103,6 @@ public class DriftBottleManager : MonoBehaviour
statues.Add(statue);
}
// 注册石像拼凑器
if (statueTransforms != null)
{
foreach (StatueAssembler assembler in statueTransforms)
@@ -146,199 +114,160 @@ public class DriftBottleManager : MonoBehaviour
}
}
Debug.Log($"[DriftBottleManager] 初始化完成,共{totalStatues}个雕像{totalFragments}个碎片");
Debug.Log($"[DriftBottleManager] 初始化完成,共{totalStatues}个雕像");
}
/// <summary>
/// 设置石像拼凑器
/// </summary>
public void SetStatueAssembler(int statueIndex, StatueAssembler assembler)
{
if (statueIndex >= 0 && statueIndex < statues.Count)
{
statues[statueIndex].assembler = assembler;
// 注册完成事件
assembler.OnStatueCompleted += OnStatueAssembleCompleted;
}
}
/// <summary>
/// 启动雕像事件
/// </summary>
public void StartStatueEvent()
{
if (allStatuesCompleted)
{
Debug.Log("[DriftBottleManager] 所有雕像已集齐,事件不再启动");
Debug.Log("[DriftBottleManager] 所有雕像已集齐");
return;
}
isEventActive = true;
spawnTimer = 0f;
Debug.Log("[DriftBottleManager] 海底雕像事件已启动!");
// 立即生成第一波
//TrySpawnBottles();
}
/// <summary>
/// 停止雕像事件
/// </summary>
public void StopStatueEvent()
{
isEventActive = false;
Debug.Log("[DriftBottleManager] 海底雕像事件已停止");
}
/// <summary>
/// 尝试生成漂流瓶
/// 尝试生成漂流瓶 - 每波固定3个不绑定碎片
/// </summary>
private void TrySpawnBottles()
{
if (driftBottlePrefab == null)
if (driftBottlePrefab == null) return;
// 检查是否还有未完成的雕像
if (GetCurrentTargetStatueIndex() < 0)
{
Debug.LogError("[DriftBottleManager] 漂流瓶预制体未设置!");
allStatuesCompleted = true;
isEventActive = false;
Debug.Log("[DriftBottleManager] 所有雕像已完成,停止生成漂流瓶");
return;
}
// 计算还需要生成多少碎片
int totalFragments = totalStatues * fragmentsPerStatue;
int remainingFragments = totalFragments - currentFragmentIndex;
if (remainingFragments <= 0)
{
Debug.Log("[DriftBottleManager] 所有碎片已生成完毕");
return;
}
// 计算本次生成数量
int spawnCount = Mathf.Min(spawnCountPerWave, remainingFragments);
// 获取路径
CurvySpline[] availablePaths = GameInit.Ins.GetIndexPath(3);
if (availablePaths.Length == 0)
// 获取3条不同的路径
CurvySpline[] availablePaths = GameInit.Ins.GetIndexPath(spawnCountPerWave);
if (availablePaths == null || availablePaths.Length == 0)
{
Debug.LogError("[DriftBottleManager] 没有可用的路径!");
return;
}
// 生成漂流瓶,分散在不同路径
for (int i = 0; i < spawnCount; i++)
// 生成3个漂流瓶不绑定碎片
for (int i = 0; i < spawnCountPerWave; i++)
{
int fragIndex = currentFragmentIndex++;
int statueIdx = fragIndex / fragmentsPerStatue;
// 选择路径(分散在不同路径)
CurvySpline path = availablePaths[i % availablePaths.Length];
SpawnBottle(path, fragIndex, statueIdx);
SpawnBottle(path);
}
// 触发事件
int currentWave = (currentFragmentIndex - 1) / spawnCountPerWave + 1;
int totalWaves = Mathf.CeilToInt((float)totalFragments / spawnCountPerWave);
OnSpawnWave?.Invoke(currentWave, totalWaves, spawnCount);
Debug.Log($"[DriftBottleManager] 生成{spawnCountPerWave}个漂流瓶");
}
/// <summary>
/// 生成单个漂流瓶
/// </summary>
private void SpawnBottle(CurvySpline path, int fragIndex, int statueIdx)
private void SpawnBottle(CurvySpline path)
{
if (driftBottlePrefab == null) return;
if (driftBottlePrefab == null || path == null) return;
if (path == null)
{
Debug.LogError("[DriftBottleManager] SpawnBottle 失败path 为 null");
return;
}
// 使用路径对象的位置作为生成点(路径生成器已将路径对象设置在正确位置)
Vector3 spawnPos = path.transform.position;
// 在路径起点生成漂流瓶
GameObject bottleGO = Instantiate(driftBottlePrefab, spawnPos, Quaternion.identity);
DriftBottle bottle = bottleGO.GetComponent<DriftBottle>();
if (bottle != null)
{
bottle.Init(path, fragIndex, statueIdx);
bottle.Init(path);
}
}
/// <summary>
/// 获取可用路径列表 - 每次生成都是全新的随机路径
/// 漂流瓶被击中 - 数据立即+1动画等碎片飞到后再播放
/// </summary>
/// <summary>
/// 漂流瓶被捕获 - 创建飞行碎片效果
/// </summary>
public void OnBottleCaptured(DriftBottle bottle, int fragIndex, int statueIdx)
public void OnBottleCaptured(DriftBottle bottle)
{
if (collectedFragments.Contains(fragIndex))
// 找到当前未完成的雕像
int targetStatueIndex = GetCurrentTargetStatueIndex();
if (targetStatueIndex < 0)
{
Debug.Log("[DriftBottleManager] 所有雕像已完成,不产生碎片");
return;
}
// 记录收集
collectedFragments.Add(fragIndex);
StatueData statue = statues[targetStatueIndex];
// 获取漂流瓶位置
// 计算该雕像的碎片序号
int fragmentIndex = statue.statueIndex * fragmentsPerStatue + statue.collectedCount;
// 立即增加计数(数据立即更新)
statue.collectedCount++;
// 检查雕像是否完成(数据层面)
if (statue.collectedCount >= fragmentsPerStatue)
{
statue.isCompleted = true;
}
// 创建飞行特效(动画等飞到后再播放)
Vector3 bottlePosition = bottle != null ? bottle.transform.position : Vector3.zero;
// 创建碎片飞行效果
CreateFragmentFlyEffect(bottlePosition, fragIndex, statueIdx);
CreateFragmentFlyEffect(bottlePosition, fragmentIndex, targetStatueIndex);
// 触发事件
OnFragmentCollected?.Invoke(fragIndex, statueIdx);
OnFragmentCollected?.Invoke(fragmentIndex, targetStatueIndex);
Debug.Log($"[DriftBottleManager] 碎片{fragmentIndex}分配给雕像{targetStatueIndex},当前进度{statue.collectedCount}/{fragmentsPerStatue}(数据已更新,动画稍后播放)");
}
/// <summary>
/// 创建碎片飞行效果
/// </summary>
private void CreateFragmentFlyEffect(Vector3 startPos, int fragIndex, int statueIdx)
{
if (fragmentFlyPrefab == null)
{
// 如果没有飞行特效预制体,直接添加到石像
AddFragmentToStatue(fragIndex, statueIdx);
return;
}
// 获取目标石像
Transform targetStatue = GetStatueTransform(statueIdx);
if (targetStatue == null)
{
// 没有飞行特效,直接播放动画
AddFragmentToStatue(fragIndex, statueIdx);
CheckAllStatuesCompleted();
return;
}
// 实例化飞行碎片
GameObject flyObj = Instantiate(fragmentFlyPrefab, startPos, Quaternion.identity);
FragmentFlyEffect flyEffect = flyObj.GetComponent<FragmentFlyEffect>();
if (flyEffect != null)
if (fragmentFlyPrefab != null)
{
flyEffect.Initialize(startPos, targetStatue, fragIndex, statueIdx, OnFragmentArrived);
GameObject flyObj = Instantiate(fragmentFlyPrefab, startPos, Quaternion.identity);
FragmentFlyEffect flyEffect = flyObj.GetComponent<FragmentFlyEffect>();
if (flyEffect != null)
{
// 传递回调:等碎片飞到后再播放动画
flyEffect.Initialize(startPos, targetStatue, fragIndex, statueIdx,
(fIdx, sIdx) =>
{
AddFragmentToStatue(fIdx, sIdx);
CheckAllStatuesCompleted();
});
}
else
{
Destroy(flyObj);
AddFragmentToStatue(fragIndex, statueIdx);
CheckAllStatuesCompleted();
}
}
else
{
// 如果没有FragmentFlyEffect组件直接添加
// 没有飞行特效预制体,直接播放动画
AddFragmentToStatue(fragIndex, statueIdx);
Destroy(flyObj);
CheckAllStatuesCompleted();
}
}
/// <summary>
/// 碎片到达回调
/// </summary>
private void OnFragmentArrived(int fragIndex, int statueIdx)
{
AddFragmentToStatue(fragIndex, statueIdx);
}
/// <summary>
/// 添加碎片到石像
/// </summary>
private void AddFragmentToStatue(int fragIndex, int statueIdx)
{
if (statueIdx >= statues.Count) return;
@@ -348,15 +277,8 @@ public class DriftBottleManager : MonoBehaviour
{
statue.assembler.AddFragment(fragIndex);
}
else
{
Debug.LogWarning($"[DriftBottleManager] 石像{statueIdx}的拼凑器未设置!");
}
}
/// <summary>
/// 获取石像位置
/// </summary>
private Transform GetStatueTransform(int statueIdx)
{
if (statueTransforms != null && statueIdx < statueTransforms.Length && statueTransforms[statueIdx] != null)
@@ -364,14 +286,11 @@ public class DriftBottleManager : MonoBehaviour
return statueTransforms[statueIdx].transform;
}
// 如果没有设置,使用默认位置
if (GameInit.Ins?.playerCam != null)
{
Vector3 playerPos = GameInit.Ins.playerCam.transform.position;
Vector3 playerForward = GameInit.Ins.playerCam.transform.forward;
// 在玩家前方显示石像
float offsetX = (statueIdx - 1) * 5f; // 三个石像水平分布
float offsetX = (statueIdx - 1) * 5f;
Vector3 statuePos = playerPos + playerForward * statueShowOffset.z + Vector3.right * offsetX;
statuePos.y += statueShowOffset.y;
@@ -383,26 +302,15 @@ public class DriftBottleManager : MonoBehaviour
return null;
}
/// <summary>
/// 石像拼凑完成回调
/// </summary>
private void OnStatueAssembleCompleted(int statueIdx)
{
if (statueIdx >= statues.Count) return;
statues[statueIdx].isCompleted = true;
Debug.Log($"[DriftBottleManager] {statues[statueIdx].statueName} 拼凑完成!");
// 触发事件
OnStatueCompleted?.Invoke(statueIdx);
// 检查是否所有雕像都完成了
CheckAllStatuesCompleted();
}
/// <summary>
/// 检查是否所有雕像都完成
/// </summary>
private void CheckAllStatuesCompleted()
{
foreach (var statue in statues)
@@ -411,19 +319,23 @@ public class DriftBottleManager : MonoBehaviour
return;
}
// 所有雕像完成
allStatuesCompleted = true;
isEventActive = false;
Debug.Log("[DriftBottleManager] 所有雕像已集齐!海底雕像事件结束!");
Debug.Log("[DriftBottleManager] 所有雕像已集齐!事件结束!");
OnAllStatuesCompleted?.Invoke();
// 播放完成音效
GameManager.Ins?.PlaySound2D("雕像事件完成");
}
#region
public int GetCurrentTargetStatueIndex()
{
for (int i = 0; i < statues.Count; i++)
{
if (!statues[i].isCompleted)
return i;
}
return -1;
}
public void RegisterBottle(DriftBottle bottle)
{
@@ -437,80 +349,13 @@ public class DriftBottleManager : MonoBehaviour
activeBottles.Remove(bottle);
}
#endregion
#region
/// <summary>
/// 获取已收集碎片数量
/// </summary>
public int GetCollectedFragmentCount()
{
return collectedFragments.Count;
}
/// <summary>
/// 获取指定雕像的收集进度
/// </summary>
public int GetStatueProgress(int statueIdx)
{
if (statueIdx >= statues.Count) return 0;
if (statues[statueIdx].assembler != null)
{
return statues[statueIdx].assembler.GetProgress();
}
return 0;
}
/// <summary>
/// 获取指定雕像是否完成
/// </summary>
public bool IsStatueCompleted(int statueIdx)
{
if (statueIdx >= statues.Count) return false;
return statues[statueIdx].isCompleted;
}
/// <summary>
/// 获取当前目标雕像序号
/// </summary>
public int GetCurrentTargetStatueIndex()
{
for (int i = 0; i < statues.Count; i++)
{
if (!statues[i].isCompleted)
return i;
}
return -1; // 全部完成
}
/// <summary>
/// 获取雕像数据列表
/// </summary>
public List<StatueData> GetStatues() => statues;
/// <summary>
/// 是否所有雕像都完成
/// </summary>
public bool IsAllStatuesCompleted() => allStatuesCompleted;
/// <summary>
/// 获取下一次生成倒计时
/// </summary>
public float GetNextSpawnCountdown()
{
if (!isEventActive || allStatuesCompleted) return -1;
return Mathf.Max(0, spawnInterval - spawnTimer);
}
public void ClearAllStatuesCompleted()
{
foreach (var item in activeBottles)
{
if(item==null)
continue;
if(item == null) continue;
if (item.gameObject != null)
{
item.gameObject.SetActive(false);
@@ -519,6 +364,4 @@ public class DriftBottleManager : MonoBehaviour
}
activeBottles.Clear();
}
#endregion
}

View File

@@ -119,7 +119,7 @@ public class FragmentFlyEffect : MonoBehaviour
});
// 播放到达音效
GameManager.Ins?.PlaySound3D("碎片到达", transform);
//GameManager.Ins?.PlaySound3D("碎片到达", transform);
}
private void OnDestroy()