多轮审查评估

This commit is contained in:
2026-05-13 09:19:54 +08:00
parent 458f344e83
commit 1b37297585
57 changed files with 3019 additions and 218 deletions

View File

@@ -1,6 +1,9 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using BaseGames.Core;
using BaseGames.Core.Events;
using BaseGames.Enemies;
@@ -25,7 +28,10 @@ namespace BaseGames.Challenge
private int _remainingEnemies;
private float _elapsedTime;
private bool _isRunning;
private bool _noHitViolated; // 架构 §12requireNoHit 挑战是否被破坏
private bool _noHitViolated;
// 预加载句柄(挑战开始前预热全部敌人资源,结束时释放)
private readonly List<AsyncOperationHandle<GameObject>> _preloadHandles = new();
private void OnEnable()
{
@@ -35,6 +41,7 @@ namespace BaseGames.Challenge
private void OnDisable()
{
if (_player != null) _player.OnDamaged -= OnPlayerDamaged;
ReleasePreloadedAssets();
}
private void OnPlayerDamaged() => _noHitViolated = true;
@@ -58,7 +65,51 @@ namespace BaseGames.Challenge
_currentEncounterIndex = 0;
_elapsedTime = 0f;
_noHitViolated = false;
SpawnWave(0);
// 预加载所有敌人资源,全部缓存就绪后再开始生成第一波
PreloadEnemyAssets(() => SpawnWave(0));
}
/// <summary>
/// 预加载本次挑战所有敌人的 Addressable 资源。
/// 确保所有资源均已内存驻留后才调用 <paramref name="onComplete"/>.
/// 无敌人配置时直接回调。
/// </summary>
private void PreloadEnemyAssets(Action onComplete)
{
var keys = new HashSet<string>();
if (_challengeData.encounters != null)
foreach (var enc in _challengeData.encounters)
if (enc.enemies != null)
foreach (var entry in enc.enemies)
if (!string.IsNullOrEmpty(entry.enemyAddressKey))
keys.Add(entry.enemyAddressKey);
if (keys.Count == 0)
{
onComplete?.Invoke();
return;
}
int remaining = keys.Count;
foreach (var key in keys)
{
var handle = Addressables.LoadAssetAsync<GameObject>(key);
_preloadHandles.Add(handle);
handle.Completed += _ =>
{
if (--remaining == 0)
onComplete?.Invoke();
};
}
}
/// <summary>释放预加载的所有资源句柄。</summary>
private void ReleasePreloadedAssets()
{
foreach (var h in _preloadHandles)
if (h.IsValid()) Addressables.Release(h);
_preloadHandles.Clear();
}
private void SpawnWave(int index)
@@ -77,7 +128,16 @@ namespace BaseGames.Challenge
for (int i = 0; i < entry.count; i++)
{
_remainingEnemies++;
Vector3 pos = entry.spawnPoint != null ? entry.spawnPoint.position : Vector3.zero;
Vector3 pos;
if (entry.spawnPoint != null)
{
pos = entry.spawnPoint.position;
}
else
{
Debug.LogWarning($"[ChallengeRoomManager] encounter[{index}] 中的 enemyAddressKey='{entry.enemyAddressKey}' 未配置 spawnPoint将在 Vector3.zero 生成。请在 ChallengeRoomSO 中补全配置。", this);
pos = Vector3.zero;
}
Addressables.InstantiateAsync(entry.enemyAddressKey, pos, Quaternion.identity)
.Completed += handle =>
{

View File

@@ -13,7 +13,7 @@ namespace BaseGames.Quest
[Header("标识")]
public string objectiveId;
[TextArea(1, 4)]
public string displayText; // 任务日志中显示的文本
public string displayTextKey; // 本地化 key通过 LocalizationManager.Get(displayTextKey, "Quest") 显示)
public bool IsOptional; // 可选目标(完成加奖励但不阻塞任务)
/// <summary>根据当前进度判断目标是否完成。</summary>