根据提供的code differences信息,由于没有具体的代码变更内容,我将生成一个通用的commit message模板:
``` docs(readme): 更新文档说明 - 添加项目使用指南 - 完善API接口说明 - 修正错误的配置示例 ``` 注意:由于您提供的code differences部分为空,以上是一个示例模板。当您有具体的代码变更时,请提供详细的变更内容以便生成更准确的commit message。
This commit is contained in:
1 parent
8d58c2223c
commit
11f1af357d
191 files changed
+2315
-1539
No files matched your search
@@ -0,0 +1,257 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class DefenseWaveLevelController : MonoBehaviour
|
||||
{
|
||||
[System.Serializable]
|
||||
private class LevelWaveFile
|
||||
{
|
||||
public string levelId;
|
||||
public string levelName;
|
||||
public WaveEntry[] waves;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
private class WaveEntry
|
||||
{
|
||||
public int waveIndex;
|
||||
public float restBeforeWave = 2f;
|
||||
public float spawnInterval = 1f;
|
||||
public string[] enemyIds;
|
||||
public int[] counts;
|
||||
public float[] spawnX;
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class EnemyPrefabEntry
|
||||
{
|
||||
public string id;
|
||||
public GameObject prefab;
|
||||
}
|
||||
|
||||
[Header("关卡 JSON")]
|
||||
public TextAsset levelJson;
|
||||
|
||||
[Header("JSON enemyId 对应 Prefab")]
|
||||
public EnemyPrefabEntry[] enemyPrefabs;
|
||||
|
||||
[Header("自动模拟")]
|
||||
public bool autoStart = true;
|
||||
public float spawnZ = 20f; // 敌人生成的Z位置
|
||||
public float spawnY = 0.16f;
|
||||
public float waveCompleteDelay = 3f;
|
||||
|
||||
private LevelWaveFile level;
|
||||
private readonly List<GameObject> activeEnemies = new List<GameObject>();
|
||||
private Slider progressSlider;
|
||||
private Text progressText;
|
||||
private int currentWaveIndex = -1;
|
||||
private int totalEnemies;
|
||||
private int defeatedEnemies;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
if (!LoadLevel()) return;
|
||||
CreateProgressBar();
|
||||
if (autoStart) StartCoroutine(RunLevel());
|
||||
}
|
||||
|
||||
private bool LoadLevel()
|
||||
{
|
||||
if (levelJson == null)
|
||||
{
|
||||
Debug.LogError("DefenseWaveLevelController: 未配置关卡 JSON。");
|
||||
return false;
|
||||
}
|
||||
|
||||
level = JsonUtility.FromJson<LevelWaveFile>(levelJson.text);
|
||||
if (level == null || level.waves == null || level.waves.Length == 0)
|
||||
{
|
||||
Debug.LogError("DefenseWaveLevelController: JSON 没有有效波次。");
|
||||
return false;
|
||||
}
|
||||
|
||||
totalEnemies = level.waves.Sum(w => TotalCount(w));
|
||||
defeatedEnemies = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
private IEnumerator RunLevel()
|
||||
{
|
||||
for (int i = 0; i < level.waves.Length; i++)
|
||||
{
|
||||
currentWaveIndex = i;
|
||||
var wave = level.waves[i];
|
||||
yield return new WaitForSeconds(Mathf.Max(0f, wave.restBeforeWave));
|
||||
yield return SpawnWave(wave);
|
||||
yield return WaitForWaveCleared();
|
||||
yield return new WaitForSeconds(Mathf.Max(0f, waveCompleteDelay));
|
||||
}
|
||||
|
||||
UpdateProgress(level.waves.Length, level.waves.Length, "通关");
|
||||
Debug.Log("DefenseWaveLevelController: 第一关波次全部完成。");
|
||||
}
|
||||
|
||||
private IEnumerator SpawnWave(WaveEntry wave)
|
||||
{
|
||||
int total = TotalCount(wave);
|
||||
int spawned = 0;
|
||||
UpdateProgress(wave.waveIndex, level.waves.Length, $"第 {wave.waveIndex} 波 0/{total}");
|
||||
|
||||
for (int typeIndex = 0; typeIndex < wave.enemyIds.Length; typeIndex++)
|
||||
{
|
||||
var prefab = FindPrefab(wave.enemyIds[typeIndex]);
|
||||
if (prefab == null) continue;
|
||||
|
||||
int count = wave.counts != null && typeIndex < wave.counts.Length ? wave.counts[typeIndex] : 0;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
float x = wave.spawnX != null && wave.spawnX.Length > 0
|
||||
? wave.spawnX[(spawned) % wave.spawnX.Length]
|
||||
: (spawned % 2 == 0 ? -3f : 3f);
|
||||
var enemy = Instantiate(prefab, new Vector3(x, spawnY, spawnZ), Quaternion.identity);
|
||||
enemy.tag = "Enemy";
|
||||
|
||||
// 设置敌方阵营(teamId=1),否则会被当成友军
|
||||
UnitTeam enemyTeam = enemy.GetComponent<UnitTeam>();
|
||||
if (enemyTeam == null) enemyTeam = enemy.AddComponent<UnitTeam>();
|
||||
enemyTeam.teamId = 1;
|
||||
|
||||
// 增大敌人的寻敌距离
|
||||
UnitBase unitBase = enemy.GetComponent<UnitBase>();
|
||||
if (unitBase != null)
|
||||
{
|
||||
unitBase.detectionRange = 100f; // 从默认30增加到100
|
||||
}
|
||||
|
||||
ApplyCharacterData(enemy, wave.enemyIds[typeIndex]);
|
||||
activeEnemies.Add(enemy);
|
||||
spawned++;
|
||||
UpdateProgress(wave.waveIndex, level.waves.Length, $"第 {wave.waveIndex} 波 {spawned}/{total}");
|
||||
yield return new WaitForSeconds(Mathf.Max(0.1f, wave.spawnInterval));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator WaitForWaveCleared()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
for (int i = activeEnemies.Count - 1; i >= 0; i--)
|
||||
{
|
||||
var enemy = activeEnemies[i];
|
||||
if (enemy == null || !enemy.activeInHierarchy)
|
||||
{
|
||||
activeEnemies.RemoveAt(i);
|
||||
defeatedEnemies++;
|
||||
}
|
||||
}
|
||||
|
||||
if (activeEnemies.Count == 0) yield break;
|
||||
yield return new WaitForSeconds(0.25f);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyCharacterData(GameObject enemy, string characterId)
|
||||
{
|
||||
// 从所有 CharacterData 中按 characterId 字段查找,而不是按文件名
|
||||
var allData = Resources.LoadAll<CharacterData>("Data");
|
||||
CharacterData data = null;
|
||||
foreach (var d in allData)
|
||||
{
|
||||
if (d != null && d.characterId == characterId)
|
||||
{
|
||||
data = d;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var unit = enemy.GetComponent<UnitBase>();
|
||||
if (data == null)
|
||||
{
|
||||
Debug.LogWarning($"ApplyCharacterData: 找不到 characterId={characterId} 的 CharacterData");
|
||||
return;
|
||||
}
|
||||
if (unit == null) return;
|
||||
|
||||
unit.InitializeFromPlayerData(data.GetMaxHealth(1), data.GetAttackPower(1), data.GetMoveSpeed(1));
|
||||
}
|
||||
|
||||
private int TotalCount(WaveEntry wave)
|
||||
{
|
||||
if (wave == null || wave.counts == null) return 0;
|
||||
return wave.counts.Sum(c => Mathf.Max(0, c));
|
||||
}
|
||||
|
||||
private GameObject FindPrefab(string id)
|
||||
{
|
||||
if (enemyPrefabs == null) return null;
|
||||
var entry = enemyPrefabs.FirstOrDefault(e => e != null && e.id == id);
|
||||
if (entry == null || entry.prefab == null)
|
||||
{
|
||||
Debug.LogError("DefenseWaveLevelController: 找不到小怪 Prefab: " + id);
|
||||
return null;
|
||||
}
|
||||
return entry.prefab;
|
||||
}
|
||||
|
||||
private void CreateProgressBar()
|
||||
{
|
||||
var canvasObject = new GameObject("WaveProgressHUD", typeof(Canvas), typeof(CanvasScaler), typeof(GraphicRaycaster));
|
||||
var canvas = canvasObject.GetComponent<Canvas>();
|
||||
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
|
||||
canvas.sortingOrder = 500;
|
||||
|
||||
var root = canvasObject.GetComponent<RectTransform>();
|
||||
var panel = new GameObject("WaveProgressPanel", typeof(RectTransform), typeof(Image));
|
||||
panel.transform.SetParent(root, false);
|
||||
var panelRect = panel.GetComponent<RectTransform>();
|
||||
panelRect.anchorMin = new Vector2(0.5f, 1f);
|
||||
panelRect.anchorMax = new Vector2(0.5f, 1f);
|
||||
panelRect.pivot = new Vector2(0.5f, 1f);
|
||||
panelRect.anchoredPosition = new Vector2(0f, -20f);
|
||||
panelRect.sizeDelta = new Vector2(420f, 64f);
|
||||
panel.GetComponent<Image>().color = new Color(0f, 0f, 0f, 0.45f);
|
||||
|
||||
var sliderObject = new GameObject("WaveProgress", typeof(RectTransform), typeof(Slider));
|
||||
sliderObject.transform.SetParent(panel.transform, false);
|
||||
var sliderRect = sliderObject.GetComponent<RectTransform>();
|
||||
sliderRect.anchorMin = new Vector2(0.5f, 0f);
|
||||
sliderRect.anchorMax = new Vector2(0.5f, 0f);
|
||||
sliderRect.pivot = new Vector2(0.5f, 0f);
|
||||
sliderRect.anchoredPosition = new Vector2(0f, 10f);
|
||||
sliderRect.sizeDelta = new Vector2(360f, 16f);
|
||||
progressSlider = sliderObject.GetComponent<Slider>();
|
||||
progressSlider.minValue = 0f;
|
||||
progressSlider.maxValue = 1f;
|
||||
progressSlider.value = 0f;
|
||||
progressSlider.interactable = false;
|
||||
|
||||
var textObject = new GameObject("WaveProgressText", typeof(RectTransform), typeof(Text));
|
||||
textObject.transform.SetParent(panel.transform, false);
|
||||
var textRect = textObject.GetComponent<RectTransform>();
|
||||
textRect.anchorMin = new Vector2(0.5f, 1f);
|
||||
textRect.anchorMax = new Vector2(0.5f, 1f);
|
||||
textRect.pivot = new Vector2(0.5f, 1f);
|
||||
textRect.anchoredPosition = new Vector2(0f, -8f);
|
||||
textRect.sizeDelta = new Vector2(390f, 28f);
|
||||
progressText = textObject.GetComponent<Text>();
|
||||
progressText.alignment = TextAnchor.MiddleCenter;
|
||||
progressText.font = Resources.GetBuiltinResource<Font>("LegacyRuntime.ttf");
|
||||
progressText.fontSize = 18;
|
||||
progressText.color = Color.white;
|
||||
}
|
||||
|
||||
private void UpdateProgress(int waveNumber, int waveCount, string text)
|
||||
{
|
||||
if (progressSlider != null)
|
||||
{
|
||||
float defeatedRatio = totalEnemies > 0 ? (float)defeatedEnemies / totalEnemies : 0f;
|
||||
progressSlider.value = Mathf.Clamp01((waveNumber - 1 + defeatedRatio) / Mathf.Max(1, waveCount));
|
||||
}
|
||||
if (progressText != null) progressText.text = text;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user