P0-02 补齐数据表:组件、敌人、波次、节点、事件、商店商品

- 组件:
    - 底座:Assets\GameMain\DataTables\BaseComp.txt
    - 轴承:Assets\GameMain\DataTables\BearingComp.txt
    - 枪口:Assets\GameMain\DataTables\MuzzleComp.txt
- 敌人:Assets\GameMain\DataTables\Enemy.txt
- 波次:
    - 关卡:Assets\GameMain\DataTables\Level.txt
    - 关卡阶段(波次):Assets\GameMain\DataTables\LevelPhase.txt
    - 波次条目(波次出怪规则):Assets\GameMain\DataTables\LevelSpawnEntry.txt
- 事件:Assets\GameMain\DataTables\Event.txt
- 商店:Assets\GameMain\DataTables\ShopPrice.txt
This commit is contained in:
SepComet 2026-02-26 21:36:29 +08:00
parent bb0a4edfb7
commit 11e4c1c1f2
115 changed files with 3218 additions and 135 deletions

1
.gitignore vendored
View File

@ -101,3 +101,4 @@ InitTestScene*.unity*
/数据表
/.vscode
AGENTS.md
/.dotnet-home

View File

@ -1,7 +1,6 @@
# 底座表
# Id EntityId Name AttackSpeed PropertyType Constraint PossibleTag
# Id 策划备注 EntityId Name AttackSpeed PropertyType Constraint PossibleTag
# int int string float[] AttackPropertyType string TagType[]
# 底座编号 策划备注 实体Id 底座名 攻击速度(秒/次) 攻击属性 属性约束 可能出现的Tag
# 底座编号 实体Id 底座名 攻击速度(秒/次) 攻击属性 属性约束 可能出现的Tag
1 301 元素底座 [2,1.5,1,0.8,0.7] Fire [Fire,BurnSpread,IgniteBurst,Inferno]
2 301 控制底座 [4,3.8,3.6,3.4,3.2] Ice [Ice,FreezeMask,Shatter,AbsoluteZero]
3 301 穿透底座 [1,0,8,0,6,0.4,0.2] Physics [Pierce,Crit,Overpenetrate,Execution]

View File

@ -1,7 +1,6 @@
# 轴承表
# Id EntityId Name RotateSpeed AttackRange Constraint PossibleTag
# Id 策划备注 EntityId Name RotateSpeed AttackRange Constraint PossibleTag
# int int string float[] float[] string TagType[]
# 轴承编号 策划备注 实体Id 轴承名 各品质旋转速度 各品质攻击范围 属性约束 可能出现的Tag
# 轴承编号 实体Id 轴承名 各品质旋转速度 各品质攻击范围 属性约束 可能出现的Tag
1 201 元素轴承 [10,12,13,14,15] [2,2,2,2,2] [Fire,BurnSpread,IgniteBurst,Inferno]
2 201 控制轴承 [20,25,30,32,35] [6,6.5,7,8,8] [Ice,FreezeMask,Shatter,AbsoluteZero]
3 201 穿透轴承 [60,70,80,90,100] [4,4.5,5,5.5,6] [Pierce,Crit,Overpenetrate,Execution]

View File

@ -0,0 +1,5 @@
# Id 策划备注 EntityId BaseHp BaseDamage Speed DropCoin
# int int int int float int
# 敌人Id 敌人实体Id 基础血量 基地伤害 移动速度 掉落硬币
1 1001 500 5 1 5
2 1002 5000 50 0.5 100

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: d2ccda2aca4a348428805b273ee2aaf2
guid: d860a5c1c09addf4ba7539e97c85c0bd
TextScriptImporter:
externalObjects: {}
userData:

View File

@ -1,7 +1,8 @@
# 实体表
# Id AssetName
# Id 策划备注 AssetName
# int string
# 实体编号 策划备注 资源名称
# 实体编号 资源名称
101 测试枪口 TestMuzzle
201 测试轴承 TestBearing
301 测试底座 TestBase
1001 测试普通敌人 TestEnemy
1002 测试Boss TestBoss

View File

@ -0,0 +1,6 @@
# Id 列1 Title Description Options
# int string string string
# 事件编号 策划备注 事件题目 事件描述 事件选项
1 赌马 一名商人邀请你下注。赢了就能赚一笔。 [{"optionText":"下注 100- 稳健70% 赢 150","requirements":[{"type":"GoldAtLeast","param":{"Count":100}}],"costEffects":[{"type":"AddGold","param":{"Count":-100}}],"rewardEffects":[{"type":"AddGold","param":{"Count":150}}],"probability":0.7},{"optionText":"下注 100- 激进30% 赢 250","requirements":[{"type":"GoldAtLeast","param":{"Count":100}}],"costEffects":[{"type":"AddGold","param":{"Count":-100}}],"rewardEffects":[{"type":"AddGold","param":{"Count":250}}],"probability":0.3}]
2 工匠的熔炉 工匠以金币交换防御塔组件。 [{"optionText":"交出 3 个白色组件,获得 50 金币","requirements":[{"type":"CompCountAtLeast","param":{"Count":3,"Rarity":"White"}}],"costEffects":[{"type":"RemoveRandomComps","param":{"Count":3,"Rarity":"White"}}],"rewardEffects":[{"type":"AddGold","param":{"Count":50}}]},{"optionText":"交出 2 个绿色组件,获得 70 金币","requirements":[{"type":"CompCountAtLeast","param":{"Count":2,"Rarity":"Green"}}],"costEffects":[{"type":"RemoveRandomComps","param":{"Count":2,"Rarity":"Green"}}],"rewardEffects":[{"type":"AddGold","param":{"Count":70}}]},{"optionText":"交出 1 个蓝色组件,获得 80 金币","requirements":[{"type":"CompCountAtLeast","param":{"Count":1,"Rarity":"Blue"}}],"costEffects":[{"type":"RemoveRandomComps","param":{"Count":1,"Rarity":"Blue"}}],"rewardEffects":[{"type":"AddGold","param":{"Count":80}}]},{"optionText":"拒绝","rewardEffects":[]}]
3 代价与回报 某种黑暗力量向你索取代价。 [{"optionText":"展示你的防御塔","requirements":[{"type":"TowerCountAtLeast","param":{"Count":2}}],"rewardEffects":[{"type":"AddGold","param":{"Count":50}}]},{"optionText":"离开","rewardEffects":[]}]

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: d64aa32f74f749c42847421244466515
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
# Id 列1 LevelThemeType BaseHp StartCoin VictoryType VictoryParam RewardGold
# int LevelThemeType int int VictoryType string int
# 关卡号 策划备注 关卡所属主题类型 基地初始生命 初始硬币 胜利条件 胜利参数 奖励金币
1 平原1 Plain 100 100 PhasesCleared 30
2 平原2 Plain 100 100 PhasesCleared 30
3 平原3 Plain 100 100 PhasesCleared 40
4 平原4 Plain 100 100 BossDead 100

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 05abbe814ec127b46a5e1a640a899e09
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,23 @@
# Id 列1 DurationSeconds EndType EndParam
# int int PhaseEndType string
# 关卡阶段号 策划备注 波次持续时间 波次结束条件 结束参数
1001 平原1.1 60 TimeElapsed 60
1002 平原1.2 60 TimeElapsed 60
1003 平原1.3 60 TimeElapsed 60
1004 平原1.4 60 EnemiesCleared 60
1005 平原1.* 0
2001 平原2.1 60 TimeElapsed 60
2002 平原2.2 60 TimeElapsed 60
2003 平原2.3 60 TimeElapsed 60
2004 平原2.4 60 EnemiesCleared 60
2005 平原2.* 0
3001 平原3.1 60 TimeElapsed 60
3002 平原3.2 60 TimeElapsed 60
3003 平原3.3 60 TimeElapsed 60
3004 平原3.4 60 EnemiesCleared 60
3005 平原3.* 0
4001 平原4.1 60 TimeElapsed 60
4002 平原4.2 60 TimeElapsed 60
4003 平原4.3 60 TimeElapsed 60
4004 平原4.4 60 TimeElapsed 60
4005 平原4.5 0 BossDead

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 392984cd87843f34989251453d4a455b
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,33 @@
# Id 列1 SpawnPointId StartTime EntryType EnemyId Count Interval Duration Gap
# int int int EntryType int int float int float
# 阶段条目号 策划备注 敌人出生口Id 相对时间 条目类型 敌人Id 单次出怪数量 出怪间隔 持续时间 单怪出生时间间隔
1001001 1 5 Stream 1 3 5 60 0
1001002 2 5 Burst 1 10 0 0 0.5
1002001 1 3 Stream 1 3 5 60 0
1002002 2 3 Burst 1 10 0 0 0.5
1003001 1 5 Stream 1 3 5 60 0
1003002 2 5 Burst 1 10 0 0 0.5
1004001 1 3 Stream 1 3 5 60 0
1004002 2 3 Burst 1 10 0 0 0.5
1005001 1 5 Stream 1 3 5 60 0
1005002 2 5 Burst 1 10 0 0 0.5
2001001 1 5 Stream 1 3 5 60 0
2002001 1 5 Burst 1 10 0 0 0.5
2003001 1 5 Stream 1 3 5 60 0
2004001 1 5 Burst 1 10 0 0 0.5
2005001 1 5 Stream 1 3 5 60 0
3001001 1 5 Stream 1 3 5 60 0
3001002 2 5 Burst 1 10 0 0 0.5
3002001 1 3 Stream 1 3 5 60 0
3002002 2 3 Burst 1 10 0 0 0.5
3003001 1 5 Stream 1 3 5 60 0
3003002 2 5 Burst 1 10 0 0 0.5
3004001 1 3 Stream 1 3 5 60 0
3004002 2 3 Burst 1 10 0 0 0.5
3005001 1 5 Stream 1 3 5 60 0
3005002 2 5 Burst 1 10 0 0 0.5
4001001 1 5 Stream 1 3 5 60 0
4002001 1 5 Burst 1 10 0 0 0.5
4003001 1 5 Stream 1 3 5 60 0
4004001 1 5 Burst 1 10 0 0 0.5
4005001 1 5 Boss 2 1 5 60 0

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 554836c1a57522a4e887ae48023708fc
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,7 +1,6 @@
# 枪口表
# Id EntityId Name AttackDamage DamageRandomRate Method Constraint PossibleTag
# int int string int[] float AttackMethodType string TagType[]
# 枪口编号 策划备注 实体Id 枪口名 各品质伤害 伤害浮动 攻击方式 属性约束 可能出现的Tag
# Id 策划备注 EntityId Name AttackDamage DamageRandomRate Method Constraint PossibleTag
# int int string int[] float AttackMethodType Constraint TagType[]
# 枪口编号 策划备注 实体Id 枪口名 各品质伤害 伤害浮动 攻击方式 Constraint 可能出现的Tag
1 101 元素枪口 [20,30,40,50,80] 0.05 NormalBullet [Fire,BurnSpread,IgniteBurst,Inferno]
2 101 控制枪口 [30,50,70,90,100] 0.01 NormalBullet [Ice,FreezeMask,Shatter,AbsoluteZero]
3 101 穿透枪口 [50,55,60,80,90] 0.02 NormalBullet [Pierce,Crit,Overpenetrate,Execution]

View File

@ -0,0 +1,8 @@
# Id 列1 Rarity MinPrice MaxPrice
# int RarityType int int
# 定价编号 策划备注 商品品质 最低价格 最高价格
1 White 10 30
2 Green 50 70
3 Blue 100 120
4 Purple 150 170
5 Red 200 220

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 55f4464fd7c6ad14584b9b10aabc18ba
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -6,3 +6,4 @@
100 主菜单 MenuForm Default False True
101 设置 SettingForm Default False True
102 关于 AboutForm Default False True
201 事件UI EventForm Default False True

View File

@ -1,5 +0,0 @@
# 武器表
# Id Attack AttackInterval BulletId BulletSpeed BulletSoundId
# int int float int float int
# 武器编号 策划备注 攻击力 攻击间隔 子弹编号 子弹速度 子弹声音编号
30000 玩家武器 100 0.2 50000 20 10000

View File

@ -19,10 +19,16 @@ public partial class GameEntry : MonoBehaviour
public static EnemyManagerComponent EnemyManager { get; private set; }
public static EventNodeComponent EventNode { get; private set; }
public static CombatNodeComponent CombatNode { get; private set; }
private static void InitCustomComponents()
{
BuiltinData = UnityGameFramework.Runtime.GameEntry.GetComponent<BuiltinDataComponent>();
HPBar = UnityGameFramework.Runtime.GameEntry.GetComponent<HPBarComponent>();
EnemyManager = UnityGameFramework.Runtime.GameEntry.GetComponent<EnemyManagerComponent>();
EventNode = UnityGameFramework.Runtime.GameEntry.GetComponent<EventNodeComponent>();
CombatNode = UnityGameFramework.Runtime.GameEntry.GetComponent<CombatNodeComponent>();
}
}
}

View File

@ -0,0 +1,145 @@
using System.Collections.Generic;
using GameFramework.DataTable;
using GeometryTD.DataTable;
using GeometryTD.Definition;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace GeometryTD.CustomComponent
{
/// <summary>
/// 战斗节点组件
/// </summary>
public class CombatNodeComponent : GameFrameworkComponent
{
// Level.Id => Level
private readonly Dictionary<int, DRLevel> _levelsById = new();
// LevelId => LevelPhases
private readonly Dictionary<int, List<DRLevelPhase>> _phasesByLevelId = new();
// LevelPhase.Id => LevelSpawnEntries
private readonly Dictionary<int, List<DRLevelSpawnEntry>> _spawnEntriesByPhaseId = new();
private readonly List<int> _levelIdBuffer = new();
public LevelThemeType CurrentThemeType { get; private set; }
public DRLevel CurrentLevel { get; private set; }
public void OnInit(LevelThemeType themeType)
{
CurrentThemeType = themeType;
CurrentLevel = null;
_levelsById.Clear();
_phasesByLevelId.Clear();
_spawnEntriesByPhaseId.Clear();
_levelIdBuffer.Clear();
IDataTable<DRLevel> dtLevel = GameEntry.DataTable.GetDataTable<DRLevel>();
IDataTable<DRLevelPhase> dtLevelPhase = GameEntry.DataTable.GetDataTable<DRLevelPhase>();
IDataTable<DRLevelSpawnEntry> dtSpawnEntry = GameEntry.DataTable.GetDataTable<DRLevelSpawnEntry>();
if (dtLevel == null || dtLevelPhase == null || dtSpawnEntry == null)
{
Log.Warning("CombatNodeComponent init failed. Missing data table(s).");
return;
}
DRLevel[] levels = dtLevel.GetAllDataRows();
foreach (var level in levels)
{
if (level.LevelThemeType != themeType)
{
continue;
}
_levelsById[level.Id] = level;
_phasesByLevelId[level.Id] = new List<DRLevelPhase>();
_levelIdBuffer.Add(level.Id);
}
DRLevelPhase[] levelPhases = dtLevelPhase.GetAllDataRows();
foreach (var phase in levelPhases)
{
int levelId = phase.Id / 1000;
if (!_levelsById.ContainsKey(levelId))
{
continue;
}
if (!_phasesByLevelId.TryGetValue(levelId, out List<DRLevelPhase> phases))
{
phases = new List<DRLevelPhase>();
_phasesByLevelId[levelId] = phases;
}
phases.Add(phase);
_spawnEntriesByPhaseId[phase.Id] = new List<DRLevelSpawnEntry>();
}
DRLevelSpawnEntry[] spawnEntries = dtSpawnEntry.GetAllDataRows();
for (int i = 0; i < spawnEntries.Length; i++)
{
DRLevelSpawnEntry spawnEntry = spawnEntries[i];
int phaseId = spawnEntry.Id / 1000;
int levelId = phaseId / 1000;
if (!_levelsById.ContainsKey(levelId))
{
continue;
}
if (!_spawnEntriesByPhaseId.TryGetValue(phaseId, out List<DRLevelSpawnEntry> entries))
{
entries = new List<DRLevelSpawnEntry>();
_spawnEntriesByPhaseId[phaseId] = entries;
}
entries.Add(spawnEntry);
}
Log.Info(
"CombatNodeComponent initialized. Theme={0}, Levels={1}, Phases={2}, Entries={3}",
themeType,
_levelsById.Count,
CountPhases(),
CountEntries());
}
public void StartCombat()
{
if (_levelIdBuffer.Count <= 0)
{
Log.Warning("CombatNodeComponent has no level cache. Call OnInit(levelThemeType) first.");
return;
}
int randomIndex = Random.Range(0, _levelIdBuffer.Count);
int randomLevelId = _levelIdBuffer[randomIndex];
CurrentLevel = _levelsById[randomLevelId];
// TODO: 在这里接入真实战斗节点玩法启动流程(场景进入、敌人生成、结算等)。
Log.Info("StartCombat selected level '{0}' (Theme={1}).", CurrentLevel.Id, CurrentThemeType);
}
private int CountPhases()
{
int count = 0;
foreach (List<DRLevelPhase> phases in _phasesByLevelId.Values)
{
count += phases.Count;
}
return count;
}
private int CountEntries()
{
int count = 0;
foreach (var list in _spawnEntriesByPhaseId.Values)
{
count += list.Count;
}
return count;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5e646500b9304d438746f2351c71a0f4
timeCreated: 1772103300

View File

@ -0,0 +1,172 @@
using System.Collections.Generic;
using GameFramework.DataTable;
using GeometryTD.DataTable;
using GeometryTD.Definition;
using Newtonsoft.Json.Linq;
using GeometryTD.UI;
using UnityEngine;
using UnityGameFramework.Runtime;
namespace GeometryTD.CustomComponent
{
public class EventNodeComponent : GameFrameworkComponent
{
private readonly List<EventItem> _eventItems = new List<EventItem>();
private EventFormUseCase _eventFormUseCase;
private EventFormController _eventFormController;
private bool _initialized;
public void OnInit()
{
_eventItems.Clear();
IDataTable<DREvent> dtEvent = GameEntry.DataTable.GetDataTable<DREvent>();
if (dtEvent == null)
{
Log.Warning("Event data table is not loaded.");
_initialized = true;
return;
}
DREvent[] rows = dtEvent.GetAllDataRows();
foreach (var drEvent in rows)
{
EventOption[] options = ParseOptions(drEvent.OptionsRaw);
_eventItems.Add(new EventItem(drEvent.Id, drEvent.Title, drEvent.Description, options));
}
if (_eventFormUseCase == null)
{
_eventFormUseCase = new EventFormUseCase();
}
if (_eventFormController == null)
{
_eventFormController = new EventFormController();
_eventFormController.BindUseCase(_eventFormUseCase);
}
_initialized = true;
Log.Info("EventNodeComponent initialized with {0} events.", _eventItems.Count);
}
public void StartEvent()
{
if (!_initialized)
{
OnInit();
}
if (_eventItems.Count <= 0)
{
Log.Warning("EventNodeComponent has no event data.");
return;
}
int index = Random.Range(0, _eventItems.Count);
EventItem randomEvent = _eventItems[index];
if (_eventFormUseCase == null || _eventFormController == null)
{
Log.Warning("EventNodeComponent StartEvent failed. Event form is not initialized.");
return;
}
_eventFormUseCase.SetCurrentEvent(randomEvent);
_eventFormController.OpenUI();
}
private static EventOption[] ParseOptions(string optionsRaw)
{
if (string.IsNullOrWhiteSpace(optionsRaw))
{
return System.Array.Empty<EventOption>();
}
try
{
JArray array = JArray.Parse(optionsRaw);
List<EventOption> options = new List<EventOption>(array.Count);
for (int i = 0; i < array.Count; i++)
{
if (!(array[i] is JObject optionObj))
{
continue;
}
string optionText = optionObj.Value<string>("optionText") ?? string.Empty;
float probability = optionObj.Value<float?>("probability") ?? 1f;
EventRequirementBase[] requirements = ParseRequirements(optionObj["requirements"] as JArray);
EventEffectBase[] costEffects = ParseEffects(optionObj["costEffects"] as JArray, probability);
EventEffectBase[] rewardEffects = ParseEffects(optionObj["rewardEffects"] as JArray, probability);
options.Add(new EventOption(optionText, requirements, costEffects, rewardEffects, probability));
}
return options.ToArray();
}
catch (System.Exception e)
{
Log.Warning("Failed to parse event options json. {0}", e.Message);
return System.Array.Empty<EventOption>();
}
}
private static EventRequirementBase[] ParseRequirements(JArray requirementsArray)
{
if (requirementsArray == null || requirementsArray.Count == 0)
{
return System.Array.Empty<EventRequirementBase>();
}
List<EventRequirementBase> requirements = new List<EventRequirementBase>(requirementsArray.Count);
for (int i = 0; i < requirementsArray.Count; i++)
{
if (!(requirementsArray[i] is JObject reqObj))
{
continue;
}
string type = reqObj.Value<string>("type");
JObject param = reqObj["param"] as JObject;
EventRequirementBase requirement = EventRequirementFactory.Create(type, param);
if (requirement != null)
{
requirements.Add(requirement);
}
}
return requirements.ToArray();
}
private static EventEffectBase[] ParseEffects(JArray effectsArray, float probability)
{
if (effectsArray == null || effectsArray.Count == 0)
{
return System.Array.Empty<EventEffectBase>();
}
List<EventEffectBase> effects = new List<EventEffectBase>(effectsArray.Count);
for (int i = 0; i < effectsArray.Count; i++)
{
if (!(effectsArray[i] is JObject effectObj))
{
continue;
}
string type = effectObj.Value<string>("type");
JObject param = effectObj["param"] as JObject;
EventEffectBase effect = EventEffectFactory.Create(type, param, probability);
if (effect != null)
{
effects.Add(effect);
}
}
return effects.ToArray();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0a0c1c547ca24c95819f5f62f0bd3ea3
timeCreated: 1772102402

View File

@ -0,0 +1,63 @@
using UnityGameFramework.Runtime;
namespace GeometryTD.DataTable
{
/// <summary>
/// 敌人配置表
/// </summary>
public class DREnemy : DataRowBase
{
private int m_Id = 0;
/// <summary>
/// 获取敌人编号
/// </summary>
public override int Id => m_Id;
/// <summary>
/// 获取敌人实体编号
/// </summary>
public int EntityId { get; private set; }
/// <summary>
/// 获取敌人基础血量
/// </summary>
public int BaseHp { get; private set; }
/// <summary>
/// 获取敌人基础基地伤害
/// </summary>
public int BaseDamage { get; private set; }
/// <summary>
/// 获取敌人移动速度
/// </summary>
public float Speed { get; private set; }
/// <summary>
/// 获取敌人掉落金币
/// </summary>
public int DropCoin { get; private set; }
public override bool ParseDataRow(string dataRowString, object userData)
{
string[] columnStrings = dataRowString.Split(DataTableExtension.DataSplitSeparators);
for (int i = 0; i < columnStrings.Length; i++)
{
columnStrings[i] = columnStrings[i].Trim(DataTableExtension.DataTrimSeparators);
}
int index = 0;
index++;
m_Id = int.Parse(columnStrings[index++]);
index++;
EntityId = int.Parse(columnStrings[index++]);
BaseHp = int.Parse(columnStrings[index++]);
BaseDamage = int.Parse(columnStrings[index++]);
Speed = float.Parse(columnStrings[index++]);
DropCoin = int.Parse(columnStrings[index++]);
return true;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0f9832b810954c4eb0f45ad735bb5a58
timeCreated: 1772101800

View File

@ -0,0 +1,52 @@
using UnityGameFramework.Runtime;
namespace GeometryTD.DataTable
{
/// <summary>
/// 事件配置表
/// </summary>
public class DREvent : DataRowBase
{
private int m_Id = 0;
/// <summary>
/// 获取事件编号
/// </summary>
public override int Id => m_Id;
/// <summary>
/// 获取事件题目
/// </summary>
public string Title { get; private set; }
/// <summary>
/// 获取事件描述
/// </summary>
public string Description { get; private set; }
/// <summary>
/// 获取事件选项
/// </summary>
/// <remarks>原始字符串(如 JSON 文本),不在此处做解析。</remarks>
public string OptionsRaw { get; private set; }
public override bool ParseDataRow(string dataRowString, object userData)
{
string[] columnStrings = dataRowString.Split(DataTableExtension.DataSplitSeparators);
for (int i = 0; i < columnStrings.Length; i++)
{
columnStrings[i] = columnStrings[i].Trim(DataTableExtension.DataTrimSeparators);
}
int index = 0;
index++;
m_Id = int.Parse(columnStrings[index++]);
index++;
Title = columnStrings[index++];
Description = columnStrings[index++];
OptionsRaw = columnStrings[index++];
return true;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 57e29dfa7f1044a1acfbf3abde81859f
timeCreated: 1772097514

View File

@ -0,0 +1,72 @@
using System;
using GeometryTD.Definition;
using GeometryTD.CustomUtility;
using UnityGameFramework.Runtime;
namespace GeometryTD.DataTable
{
/// <summary>
/// 关卡表
/// </summary>
public class DRLevel : DataRowBase
{
private int m_Id = 0;
/// <summary>
/// 获取关卡编号
/// </summary>
public override int Id => m_Id;
/// <summary>
/// 获取关卡所属主题类型
/// </summary>
public LevelThemeType LevelThemeType { get; private set; }
/// <summary>
/// 获取关卡初始基地生命
/// </summary>
public int BaseHp { get; private set; }
/// <summary>
/// 获取关卡初始硬币数量
/// </summary>
public int StartCoin { get; private set; }
/// <summary>
/// 获取关卡胜利条件
/// </summary>
public LevelVictoryType LevelVictoryType { get; private set; }
/// <summary>
/// 获取关卡胜利奖励金币
/// </summary>
public int RewardGold { get; private set; }
/// <summary>
/// 获取关卡胜利条件参数
/// </summary>
public string VictoryParams { get; private set; }
public override bool ParseDataRow(string dataRowString, object userData)
{
string[] columnStrings = dataRowString.Split(DataTableExtension.DataSplitSeparators);
for (int i = 0; i < columnStrings.Length; i++)
{
columnStrings[i] = columnStrings[i].Trim(DataTableExtension.DataTrimSeparators);
}
int index = 0;
index++;
m_Id = int.Parse(columnStrings[index++]);
index++;
LevelThemeType = EnumUtility<LevelThemeType>.Get(columnStrings[index++]);
BaseHp = int.Parse(columnStrings[index++]);
StartCoin = int.Parse(columnStrings[index++]);
LevelVictoryType = EnumUtility<LevelVictoryType>.Get(columnStrings[index++]);
VictoryParams = columnStrings[index++];
RewardGold = int.Parse(columnStrings[index++]);
return true;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e0eb47d184fe4204b38dc7c9e86da609
timeCreated: 1772089145

View File

@ -0,0 +1,64 @@
using System;
using GeometryTD.CustomUtility;
using GeometryTD.Definition;
using UnityGameFramework.Runtime;
namespace GeometryTD.DataTable
{
/// <summary>
/// 关卡阶段表
/// </summary>
public class DRLevelPhase : DataRowBase
{
private int m_Id = 0;
/// <summary>
/// 获取关卡阶段编号
/// </summary>
public override int Id => m_Id;
/// <summary>
/// 获取阶段持续时间(秒)
/// </summary>
public int DurationSeconds { get; private set; }
/// <summary>
/// 获取阶段结束条件类型
/// </summary>
public PhaseEndType EndType { get; private set; }
/// <summary>
/// 获取阶段结束参数
/// </summary>
public string EndParam { get; private set; }
public override bool ParseDataRow(string dataRowString, object userData)
{
string[] columnStrings = dataRowString.Split(DataTableExtension.DataSplitSeparators);
for (int i = 0; i < columnStrings.Length; i++)
{
columnStrings[i] = columnStrings[i].Trim(DataTableExtension.DataTrimSeparators);
}
int index = 0;
index++;
m_Id = int.Parse(columnStrings[index++]);
index++;
DurationSeconds = int.Parse(columnStrings[index++]);
EndType = ParsePhaseEndType(columnStrings[index++]);
EndParam = columnStrings[index++];
return true;
}
private PhaseEndType ParsePhaseEndType(string raw)
{
if (string.IsNullOrWhiteSpace(raw))
{
return PhaseEndType.None;
}
return EnumUtility<PhaseEndType>.Get(raw);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f1fd79e88eca4bfbb38f5bcb8091e2dd
timeCreated: 1772090000

View File

@ -0,0 +1,94 @@
using System;
using GeometryTD.CustomUtility;
using GeometryTD.Definition;
using UnityGameFramework.Runtime;
namespace GeometryTD.DataTable
{
/// <summary>
/// 关卡阶段出怪条目表
/// </summary>
public class DRLevelSpawnEntry : DataRowBase
{
private int m_Id = 0;
/// <summary>
/// 获取阶段条目编号
/// </summary>
public override int Id => m_Id;
/// <summary>
/// 获取敌人出生口编号
/// </summary>
public int SpawnPointId { get; private set; }
/// <summary>
/// 获取相对开始时间(秒)
/// </summary>
public int StartTime { get; private set; }
/// <summary>
/// 获取出怪条目类型
/// </summary>
public EntryType EntryType { get; private set; }
/// <summary>
/// 获取敌人编号
/// </summary>
public int EnemyId { get; private set; }
/// <summary>
/// 获取单次出怪数量
/// </summary>
public int Count { get; private set; }
/// <summary>
/// 获取出怪间隔(秒)
/// </summary>
public float Interval { get; private set; }
/// <summary>
/// 获取持续时间(秒)
/// </summary>
public int Duration { get; private set; }
/// <summary>
/// 获取单怪出生间隔(秒)
/// </summary>
public float Gap { get; private set; }
public override bool ParseDataRow(string dataRowString, object userData)
{
string[] columnStrings = dataRowString.Split(DataTableExtension.DataSplitSeparators);
for (int i = 0; i < columnStrings.Length; i++)
{
columnStrings[i] = columnStrings[i].Trim(DataTableExtension.DataTrimSeparators);
}
int index = 0;
index++;
m_Id = int.Parse(columnStrings[index++]);
index++;
SpawnPointId = int.Parse(columnStrings[index++]);
StartTime = int.Parse(columnStrings[index++]);
EntryType = ParseEntryType(columnStrings[index++]);
EnemyId = int.Parse(columnStrings[index++]);
Count = int.Parse(columnStrings[index++]);
Interval = float.Parse(columnStrings[index++]);
Duration = int.Parse(columnStrings[index++]);
Gap = float.Parse(columnStrings[index++]);
return true;
}
private EntryType ParseEntryType(string raw)
{
if (string.IsNullOrWhiteSpace(raw))
{
return EntryType.None;
}
return EnumUtility<EntryType>.Get(raw);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b06804b242d247bd8a937cdce930cee1
timeCreated: 1772090001

View File

@ -0,0 +1,38 @@
using GeometryTD.CustomUtility;
using GeometryTD.Definition;
using UnityGameFramework.Runtime;
namespace GeometryTD.DataTable
{
public class DRShopPrice : DataRowBase
{
private int m_Id = 0;
public override int Id => m_Id;
public RarityType Rarity { get; set; }
public int MinPrice { get; set; }
public int MaxPrice { get; set; }
public override bool ParseDataRow(string dataRowString, object userData)
{
string[] columnStrings = dataRowString.Split(DataTableExtension.DataSplitSeparators);
for (int i = 0; i < columnStrings.Length; i++)
{
columnStrings[i] = columnStrings[i].Trim(DataTableExtension.DataTrimSeparators);
}
int index = 0;
index++;
m_Id = int.Parse(columnStrings[index++]);
index++;
Rarity = EnumUtility<RarityType>.Get(columnStrings[index++]);
MinPrice = int.Parse(columnStrings[index++]);
MaxPrice = int.Parse(columnStrings[index++]);
return true;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7c47aaecd99446f2b8c9ec84c797005b
timeCreated: 1772105886

View File

@ -0,0 +1,18 @@
namespace GeometryTD.Definition
{
public class EventItem
{
public EventItem(int id, string title, string description, EventOption[] options)
{
Id = id;
Title = title;
Description = description;
Options = options ?? System.Array.Empty<EventOption>();
}
public int Id { get; private set; }
public string Title { get; private set; }
public string Description { get; private set; }
public EventOption[] Options { get; private set; }
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c2a6dce0183e4efdbada20c25be949c0
timeCreated: 1772097196

View File

@ -0,0 +1,25 @@
namespace GeometryTD.Definition
{
public class EventOption
{
public string OptionText { get; private set; }
public EventRequirementBase[] Requirements { get; private set; }
public EventEffectBase[] CostEffects { get; private set; }
public EventEffectBase[] RewardEffects { get; private set; }
public float Probability { get; private set; }
public EventOption(
string optionText,
EventRequirementBase[] requirements,
EventEffectBase[] costEffects,
EventEffectBase[] rewardEffects,
float probability = 1f)
{
OptionText = optionText;
Requirements = requirements ?? System.Array.Empty<EventRequirementBase>();
CostEffects = costEffects ?? System.Array.Empty<EventEffectBase>();
RewardEffects = rewardEffects ?? System.Array.Empty<EventEffectBase>();
Probability = probability;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bcb612057a454fcf97f41fdf5c6d9b22
timeCreated: 1772097742

View File

@ -3,7 +3,7 @@ namespace GeometryTD.Definition
public enum AttackPropertyType : byte
{
None = 0,
Physical = 1,
Physics = 1,
Fire = 2,
Water = 3,
Earth = 4,

View File

@ -0,0 +1,13 @@
namespace GeometryTD.Definition
{
/// <summary>
/// 出怪条目类型
/// </summary>
public enum EntryType : byte
{
None = 0,
Stream = 1,
Burst = 2,
Boss = 3
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 14433e1048844c5d942c885c2f50ffe0
timeCreated: 1772090003

View File

@ -0,0 +1,21 @@
namespace GeometryTD.Definition
{
public enum EventEffectType
{
None,
AddGold,
RemoveGold,
AddRandomComps,
RemoveRandomComps,
AddRandomCompsEndurance,
RemoveRandomCompsEndurance,
AddRandomTowersEndurance,
DamageRandomTowersEndurance,
TransformComponents,
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6f11ba35aa8f491f942964435b32cba6
timeCreated: 1772095333

View File

@ -0,0 +1,11 @@
namespace GeometryTD.Definition
{
public enum EventRequirementType
{
None,
GoldAtLeast,
CompCountAtLeast,
TowerCountAtLeast,
HasRelic,
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f9da1af87a4f4115b9a5da706b4e1092
timeCreated: 1772095290

View File

@ -0,0 +1,10 @@
namespace GeometryTD.Definition
{
public enum LevelThemeType
{
None,
Plain,
Volcano,
Mountain
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 06ec7c0ec8924c7988e521abdd97bffe
timeCreated: 1772089321

View File

@ -0,0 +1,10 @@
namespace GeometryTD.Definition
{
public enum LevelVictoryType
{
None,
PhasesCleared,
BossDead,
TimeElapsed
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ea9b7c078511464fa572923f66cc200e
timeCreated: 1772089447

View File

@ -0,0 +1,13 @@
namespace GeometryTD.Definition
{
/// <summary>
/// 关卡阶段结束类型
/// </summary>
public enum PhaseEndType : byte
{
None = 0,
TimeElapsed = 1,
EnemiesCleared = 2,
BossDead = 3
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: eed7685430c24cdaac639581331393f3
timeCreated: 1772090002

View File

@ -26,5 +26,10 @@
/// 关于。
/// </summary>
AboutForm = 102,
/// <summary>
/// 事件节点界面。
/// </summary>
EventForm = 200,
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8a291a17879242cc8c7cec678aa5aaf1
timeCreated: 1772101365

View File

@ -0,0 +1,25 @@
namespace GeometryTD.Definition
{
public class AddGoldEffect : EventEffectBase
{
public override EventEffectType EffectType => EventEffectType.AddGold;
public override EventEffectParam Param => _param;
private AddGoldParam _param;
public AddGoldEffect(AddGoldParam param, float? probability = null)
{
_param = param;
Probability = probability;
}
}
public class AddGoldParam : EventEffectParam
{
public int Count;
public AddGoldParam(int count)
{
Count = count;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 75cacc997d8f414ca73f381cad303b5b
timeCreated: 1772101474

View File

@ -0,0 +1,28 @@
namespace GeometryTD.Definition
{
public class AddRandomCompsEffect : EventEffectBase
{
public override EventEffectType EffectType => EventEffectType.AddRandomComps;
public override EventEffectParam Param => _param;
private AddRandomCompsParam _param;
public AddRandomCompsEffect(AddRandomCompsParam param, float? probability = null)
{
_param = param;
Probability = probability;
}
}
public class AddRandomCompsParam : EventEffectParam
{
public int Count;
public RarityType Rarity;
public AddRandomCompsParam(int count, RarityType rarity)
{
Count = count;
Rarity = rarity;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 35656d42c28448268d0547c19938b2d8
timeCreated: 1772101530

View File

@ -0,0 +1,34 @@
namespace GeometryTD.Definition
{
public class DamageRandomTowerEnduranceEffect : EventEffectBase
{
public override EventEffectType EffectType => EventEffectType.DamageRandomTowersEndurance;
public override EventEffectParam Param => _param;
private DamageRandomTowerEnduranceParam _param;
public DamageRandomTowerEnduranceEffect(DamageRandomTowerEnduranceParam param, float? probability = null)
{
_param = param;
Probability = probability;
}
}
public class DamageRandomTowerEnduranceParam : EventEffectParam
{
/// <summary>
/// 减少耐久的防御塔数量
/// </summary>
public int Count;
/// <summary>
/// 防御塔耐久减少的量
/// </summary>
public int Amount;
public DamageRandomTowerEnduranceParam(int count, int amount)
{
Count = count;
Amount = amount;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a1b06f274c054844ad68b1db02d3737a
timeCreated: 1772101563

View File

@ -0,0 +1,14 @@
namespace GeometryTD.Definition
{
public abstract class EventEffectBase
{
public abstract EventEffectType EffectType { get; }
public abstract EventEffectParam Param { get; }
public float? Probability;
}
public class EventEffectParam
{
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2be5a7ff782240f79bde2dd0310d11ea
timeCreated: 1772101392

View File

@ -0,0 +1,27 @@
namespace GeometryTD.Definition
{
public class RemoveRandomCompsEffect : EventEffectBase
{
public override EventEffectType EffectType => EventEffectType.RemoveRandomComps;
public override EventEffectParam Param => _param;
private RemoveRandomCompsParam _param;
public RemoveRandomCompsEffect(RemoveRandomCompsParam param, float? probability = null)
{
_param = param;
Probability = probability;
}
}
public class RemoveRandomCompsParam : EventEffectParam
{
public int Count;
public RarityType Rarity;
public RemoveRandomCompsParam(int Count, RarityType Rarity)
{
this.Count = Count;
this.Rarity = Rarity;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 77f8e0d1879b48108e6ad5faca07d7f7
timeCreated: 1772101548

View File

@ -0,0 +1,76 @@
using GeometryTD.CustomUtility;
using Newtonsoft.Json.Linq;
using UnityGameFramework.Runtime;
namespace GeometryTD.Definition
{
public static class EventEffectFactory
{
public static EventEffectBase Create(string rawType, JObject param, float? probability = null)
{
if (string.IsNullOrWhiteSpace(rawType))
{
return null;
}
EventEffectType type = EnumUtility<EventEffectType>.Get(rawType);
switch (type)
{
case EventEffectType.AddGold:
{
int count = GetInt(param, "Count");
return new AddGoldEffect(new AddGoldParam(count), probability);
}
case EventEffectType.RemoveRandomComps:
{
int count = GetInt(param, "Count");
RarityType rarity = EnumUtility<RarityType>.Get(GetString(param, "Rarity"));
return new RemoveRandomCompsEffect(new RemoveRandomCompsParam(count, rarity), probability);
}
case EventEffectType.AddRandomComps:
{
int count = GetInt(param, "Count");
RarityType rarity = EnumUtility<RarityType>.Get(GetString(param, "Rarity"));
return new AddRandomCompsEffect(new AddRandomCompsParam(count, rarity), probability);
}
case EventEffectType.DamageRandomTowersEndurance:
{
int count = GetInt(param, "Count");
int amount = GetInt(param, "Amount");
return new DamageRandomTowerEnduranceEffect(new DamageRandomTowerEnduranceParam(count, amount), probability);
}
default:
Log.Warning("Unsupported EventEffectType '{0}'.", rawType);
return null;
}
}
private static int GetInt(JObject param, params string[] keys)
{
if (param == null)
{
return 0;
}
foreach (string key in keys)
{
if (param.TryGetValue(key, out JToken token) && token.Type != JTokenType.Null)
{
return token.Value<int>();
}
}
return 0;
}
private static string GetString(JObject param, string key)
{
if (param == null || !param.TryGetValue(key, out JToken token) || token.Type == JTokenType.Null)
{
return string.Empty;
}
return token.Value<string>();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fae04d7a401d4c7fbe2de385c3f23580
timeCreated: 1772102401

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cee1f415e08743a9914efd2ecbc6273e
timeCreated: 1772100925

View File

@ -0,0 +1,26 @@
namespace GeometryTD.Definition
{
public class CompCountAtLeastRequirement : EventRequirementBase
{
public override EventRequirementType RequirementType => EventRequirementType.CompCountAtLeast;
public override EventRequirementParam Param => _param;
private CompCountAtLeastParam _param;
public CompCountAtLeastRequirement(CompCountAtLeastParam param)
{
_param = param;
}
}
public class CompCountAtLeastParam : EventRequirementParam
{
public int Count;
public RarityType Rarity;
public CompCountAtLeastParam(int count, RarityType rarity)
{
Count = count;
Rarity = rarity;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b845abef81934b75b266a738597bb890
timeCreated: 1772101103

View File

@ -0,0 +1,12 @@
namespace GeometryTD.Definition
{
public abstract class EventRequirementBase
{
public abstract EventRequirementType RequirementType { get; }
public abstract EventRequirementParam Param { get; }
}
public class EventRequirementParam
{
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: eaa757b9c4cd4bcca38d73a30ab06285
timeCreated: 1772100961

View File

@ -0,0 +1,24 @@
namespace GeometryTD.Definition
{
public class GoldAtLeastRequirement : EventRequirementBase
{
public override EventRequirementType RequirementType => EventRequirementType.GoldAtLeast;
public override EventRequirementParam Param => _param;
private GoldAtLeastParam _param;
public GoldAtLeastRequirement(GoldAtLeastParam param)
{
_param = param;
}
}
public class GoldAtLeastParam : EventRequirementParam
{
public int Gold;
public GoldAtLeastParam(int gold)
{
Gold = gold;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5a2de86ff2b442dd9f7d6af64f518bb8
timeCreated: 1772101058

View File

@ -0,0 +1,24 @@
namespace GeometryTD.Definition
{
public class HasRelicRequirement : EventRequirementBase
{
public override EventRequirementType RequirementType => EventRequirementType.HasRelic;
public override EventRequirementParam Param => _param;
private HasRelicParam _param;
public HasRelicRequirement(HasRelicParam param)
{
_param = param;
}
}
public class HasRelicParam : EventRequirementParam
{
public int RelicId;
public HasRelicParam(int relicId)
{
RelicId = relicId;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b06e03ee597d4345b95c524c7a6a27d4
timeCreated: 1772101234

View File

@ -0,0 +1,24 @@
namespace GeometryTD.Definition
{
public class TowerCountAtLeastRequirement : EventRequirementBase
{
public override EventRequirementType RequirementType => EventRequirementType.TowerCountAtLeast;
public override EventRequirementParam Param => _param;
private TowerCountAtLeastParam _param;
public TowerCountAtLeastRequirement(TowerCountAtLeastParam param)
{
_param = param;
}
}
public class TowerCountAtLeastParam : EventRequirementParam
{
public int Count;
public TowerCountAtLeastParam(int count)
{
Count = count;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 81a1102b3c0e4a53ae74ebb779ea7c19
timeCreated: 1772101156

View File

@ -0,0 +1,74 @@
using GeometryTD.CustomUtility;
using Newtonsoft.Json.Linq;
using UnityGameFramework.Runtime;
namespace GeometryTD.Definition
{
public static class EventRequirementFactory
{
public static EventRequirementBase Create(string rawType, JObject param)
{
if (string.IsNullOrWhiteSpace(rawType))
{
return null;
}
EventRequirementType type = EnumUtility<EventRequirementType>.Get(rawType);
switch (type)
{
case EventRequirementType.GoldAtLeast:
{
int count = GetInt(param, "Count", "Gold");
return new GoldAtLeastRequirement(new GoldAtLeastParam(count));
}
case EventRequirementType.CompCountAtLeast:
{
int count = GetInt(param, "Count");
RarityType rarity = EnumUtility<RarityType>.Get(GetString(param, "Rarity"));
return new CompCountAtLeastRequirement(new CompCountAtLeastParam(count, rarity));
}
case EventRequirementType.TowerCountAtLeast:
{
int count = GetInt(param, "Count");
return new TowerCountAtLeastRequirement(new TowerCountAtLeastParam(count));
}
case EventRequirementType.HasRelic:
{
int relicId = GetInt(param, "RelicId", "Id");
return new HasRelicRequirement(new HasRelicParam(relicId));
}
default:
Log.Warning("Unsupported EventRequirementType '{0}'.", rawType);
return null;
}
}
private static int GetInt(JObject param, params string[] keys)
{
if (param == null)
{
return 0;
}
foreach (string key in keys)
{
if (param.TryGetValue(key, out JToken token) && token.Type != JTokenType.Null)
{
return token.Value<int>();
}
}
return 0;
}
private static string GetString(JObject param, string key)
{
if (param == null || !param.TryGetValue(key, out JToken token) || token.Type == JTokenType.Null)
{
return string.Empty;
}
return token.Value<string>();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e3b92d366cac404394c9e6aa1aa4062b
timeCreated: 1772102400

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7e5a261a50044ebe841fc7ae36c96f16
timeCreated: 1772112201

View File

@ -0,0 +1,27 @@
using GameFramework;
using GameFramework.Event;
namespace GeometryTD.CustomEvent
{
public class EventOptionItemSelectedEventArgs : GameEventArgs
{
public static int EventId => typeof(EventOptionItemSelectedEventArgs).GetHashCode();
public override int Id => EventId;
public int SelectedItemId { get; private set; } = -1;
public static EventOptionItemSelectedEventArgs Create(int selectedItemId)
{
var args = ReferencePool.Acquire<EventOptionItemSelectedEventArgs>();
args.SelectedItemId = selectedItemId;
return args;
}
public override void Clear()
{
SelectedItemId = -1;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e6152ef428a64a08a9dd279b73f45520
timeCreated: 1772112224

View File

@ -46,7 +46,7 @@ namespace GeometryTD.Procedure
GameEntry.Base.ResetNormalGameSpeed();
_nextSceneId = procedureOwner.GetData<VarInt32>("NextSceneId");
IDataTable<DRScene> dtScene = GameEntry.DataTable.GetDataTable<DRScene>();
DRScene drScene = dtScene.GetDataRow(_nextSceneId);
if (drScene == null)
@ -55,7 +55,8 @@ namespace GeometryTD.Procedure
return;
}
GameEntry.Scene.LoadScene(AssetUtility.GetSceneAsset(drScene.AssetName), Constant.AssetPriority.SceneAsset, this);
GameEntry.Scene.LoadScene(AssetUtility.GetSceneAsset(drScene.AssetName), Constant.AssetPriority.SceneAsset,
this);
_backgroundMusicId = drScene.BackgroundMusicId;
}
@ -81,13 +82,15 @@ namespace GeometryTD.Procedure
SceneType sceneType = (SceneType)_nextSceneId;
switch (sceneType)
{
//TODO:场景切换
// case SceneId.StressTest:
// ChangeState<ProcedureStressTest>(procedureOwner);
// break;
// default:
// Log.Debug($"Scene {sceneId.ToString()} don't configure a procedure");
// break;
case SceneType.Menu:
ChangeState<ProcedureMenu>(procedureOwner);
break;
case SceneType.Main:
ChangeState<ProcedureTest>(procedureOwner);
break;
default:
Log.Debug($"Scene {sceneType.ToString()} don't configure a procedure");
break;
}
}
@ -139,7 +142,8 @@ namespace GeometryTD.Procedure
return;
}
Log.Info("Load scene '{0}' dependency asset '{1}', count '{2}/{3}'.", ne.SceneAssetName, ne.DependencyAssetName, ne.LoadedCount.ToString(), ne.TotalCount.ToString());
Log.Info("Load scene '{0}' dependency asset '{1}', count '{2}/{3}'.", ne.SceneAssetName,
ne.DependencyAssetName, ne.LoadedCount.ToString(), ne.TotalCount.ToString());
}
}
}
}

View File

@ -0,0 +1,49 @@
using GameFramework.Fsm;
using GameFramework.Procedure;
using GeometryTD.Definition;
using UnityGameFramework.Runtime;
namespace GeometryTD.Procedure
{
public class ProcedureMenu : ProcedureBase
{
public override bool UseNativeDialog => false;
public bool GameStart { get; set; }
#region FSM
protected override void OnInit(IFsm<IProcedureManager> procedureOwner)
{
base.OnInit(procedureOwner);
}
protected override void OnEnter(IFsm<IProcedureManager> procedureOwner)
{
base.OnEnter(procedureOwner);
GameStart = false;
GameEntry.EventNode.OnInit();
GameEntry.CombatNode.OnInit(LevelThemeType.Plain);
}
protected override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds,
float realElapseSeconds)
{
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
if (GameStart)
{
procedureOwner.SetData<VarInt32>("NextSceneId", (int)SceneType.Main);
ChangeState<ProcedureChangeScene>(procedureOwner);
}
}
protected override void OnLeave(IFsm<IProcedureManager> procedureOwner, bool isShutdown)
{
base.OnLeave(procedureOwner, isShutdown);
}
#endregion
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ac91f61cef224d7ab324491156d904bb
timeCreated: 1772105440

View File

@ -25,16 +25,22 @@ namespace GeometryTD.Procedure
{
public static readonly string[] DataTableNames = new string[]
{
"BaseComp",
"BearingComp",
"Enemy",
"Entity",
"Event",
"Level",
"LevelPhase",
"LevelSpawnEntry",
"Music",
"MuzzleComp",
"Scene",
"ShopPrice",
"Sound",
"Tag",
"UIForm",
"UISound",
"MuzzleComp",
"BearingComp",
"BaseComp",
"Tag",
};
private Dictionary<string, bool> _loadedFlag = new Dictionary<string, bool>();
@ -128,37 +134,39 @@ namespace GeometryTD.Procedure
private void LoadFont(string fontName)
{
_loadedFlag.Add(Utility.Text.Format("Font.{0}", fontName), false);
GameEntry.Resource.LoadAsset(AssetUtility.GetFontAsset(fontName), Constant.AssetPriority.FontAsset, new LoadAssetCallbacks(
(assetName, asset, duration, userData) =>
{
_loadedFlag[Utility.Text.Format("Font.{0}", fontName)] = true;
UGuiForm.SetMainFont((Font)asset);
Log.Info("Load font '{0}' OK.", fontName);
},
(assetName, status, errorMessage, userData) =>
{
Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", fontName, assetName, errorMessage);
}));
GameEntry.Resource.LoadAsset(AssetUtility.GetFontAsset(fontName), Constant.AssetPriority.FontAsset,
new LoadAssetCallbacks(
(assetName, asset, duration, userData) =>
{
_loadedFlag[Utility.Text.Format("Font.{0}", fontName)] = true;
UGuiForm.SetMainFont((Font)asset);
Log.Info("Load font '{0}' OK.", fontName);
},
(assetName, status, errorMessage, userData) =>
{
Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", fontName, assetName,
errorMessage);
}));
}
private void LoadTMPFont(string fontName)
{
_loadedFlag.Add(Utility.Text.Format("Font.{0}", fontName), false);
GameEntry.Resource.LoadAsset(AssetUtility.GetTMPFontAsset(fontName), Constant.AssetPriority.FontAsset, new LoadAssetCallbacks(
(assetName, asset, duration, userData) =>
{
_loadedFlag[Utility.Text.Format("Font.{0}", fontName)] = true;
UGuiForm.SetMainTMPFont((TMP_FontAsset)asset);
Log.Info("Load font '{0}' OK.", fontName);
},
(assetName, status, errorMessage, userData) =>
{
Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", fontName, assetName, errorMessage);
}));
GameEntry.Resource.LoadAsset(AssetUtility.GetTMPFontAsset(fontName), Constant.AssetPriority.FontAsset,
new LoadAssetCallbacks(
(assetName, asset, duration, userData) =>
{
_loadedFlag[Utility.Text.Format("Font.{0}", fontName)] = true;
UGuiForm.SetMainTMPFont((TMP_FontAsset)asset);
Log.Info("Load font '{0}' OK.", fontName);
},
(assetName, status, errorMessage, userData) =>
{
Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", fontName, assetName,
errorMessage);
}));
}
private void OnLoadConfigSuccess(object sender, GameEventArgs e)
{
LoadConfigSuccessEventArgs ne = (LoadConfigSuccessEventArgs)e;
@ -179,7 +187,8 @@ namespace GeometryTD.Procedure
return;
}
Log.Error("Can not load config '{0}' from '{1}' with error message '{2}'.", ne.ConfigAssetName, ne.ConfigAssetName, ne.ErrorMessage);
Log.Error("Can not load config '{0}' from '{1}' with error message '{2}'.", ne.ConfigAssetName,
ne.ConfigAssetName, ne.ErrorMessage);
}
private void OnLoadDataTableSuccess(object sender, GameEventArgs e)
@ -202,7 +211,8 @@ namespace GeometryTD.Procedure
return;
}
Log.Error("Can not load data table '{0}' from '{1}' with error message '{2}'.", ne.DataTableAssetName, ne.DataTableAssetName, ne.ErrorMessage);
Log.Error("Can not load data table '{0}' from '{1}' with error message '{2}'.", ne.DataTableAssetName,
ne.DataTableAssetName, ne.ErrorMessage);
}
private void OnLoadDictionarySuccess(object sender, GameEventArgs e)
@ -225,7 +235,8 @@ namespace GeometryTD.Procedure
return;
}
Log.Error("Can not load dictionary '{0}' from '{1}' with error message '{2}'.", ne.DictionaryAssetName, ne.DictionaryAssetName, ne.ErrorMessage);
Log.Error("Can not load dictionary '{0}' from '{1}' with error message '{2}'.", ne.DictionaryAssetName,
ne.DictionaryAssetName, ne.ErrorMessage);
}
}
}
}

View File

@ -0,0 +1,30 @@
using GameFramework.Fsm;
using GameFramework.Procedure;
namespace GeometryTD.Procedure
{
public class ProcedureTest : ProcedureBase
{
public override bool UseNativeDialog => false;
#region FSM
protected override void OnEnter(IFsm<IProcedureManager> procedureOwner)
{
base.OnEnter(procedureOwner);
}
protected override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds,
float realElapseSeconds)
{
base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
}
protected override void OnLeave(IFsm<IProcedureManager> procedureOwner, bool isShutdown)
{
base.OnLeave(procedureOwner, isShutdown);
}
#endregion
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5a5a3c55b2b34a159cbb1680728d87d3
timeCreated: 1772105466

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 3ecda907b9217e5499e31cb81a154ff4
guid: 34c97e1af6767d049b17b5c4ff75cb5a
folderAsset: yes
DefaultImporter:
externalObjects: {}

View File

@ -0,0 +1,12 @@
using GeometryTD.UI;
namespace GeometryTD.UI
{
public class EventFormContext : UIContext
{
public int EventId;
public string Title;
public string Description;
public EventOptionItemContext[] OptionItems;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 95f3e80a51954c66b14e41365622d63f
timeCreated: 1772104202

View File

@ -0,0 +1,8 @@
namespace GeometryTD.UI
{
public class EventOptionItemContext
{
public int OptionIndex;
public string OptionText;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f56befc364564ac8b499f81ca48a165b
timeCreated: 1772104201

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 043cb0d817552b549aeff457ac685a0b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,124 @@
using GeometryTD.Definition;
using GeometryTD.CustomEvent;
using GameFramework.Event;
using UnityGameFramework.Runtime;
namespace GeometryTD.UI
{
public class EventFormController : UIFormControllerCommonBase<EventFormContext, EventForm>
{
private EventFormUseCase m_UseCase;
protected override UIFormType UIFormTypeId => UIFormType.EventForm;
protected override void RefreshUI(EventForm form, EventFormContext context)
{
form.RefreshUI(context);
}
protected override void SubscribeCustomEvents()
{
GameEntry.Event.Subscribe(EventOptionItemSelectedEventArgs.EventId, OnEventOptionItemSelected);
}
protected override void UnsubscribeCustomEvents()
{
GameEntry.Event.Unsubscribe(EventOptionItemSelectedEventArgs.EventId, OnEventOptionItemSelected);
}
public override int? OpenUI(object userData = null)
{
if (userData is EventFormContext eventFormContext)
{
return OpenUIInternal(eventFormContext);
}
if (userData is EventFormRawData rawDataFromUserData)
{
return OpenUI(rawDataFromUserData);
}
if (userData != null)
{
Log.Warning("EventFormController.OpenUI() userData type is invalid.");
return null;
}
if (m_UseCase == null)
{
Log.Error("EventFormController.OpenUI() useCase is null.");
return null;
}
EventFormRawData rawData = m_UseCase.CreateInitialModel();
return OpenUI(rawData);
}
public int? OpenUI(EventFormRawData rawData)
{
EventFormContext context = BuildContext(rawData);
return OpenUIInternal(context);
}
public override void BindUseCase(IUIUseCase useCase)
{
if (!(useCase is EventFormUseCase eventFormUseCase))
{
Log.Error("EventFormController.BindUseCase() useCase is invalid.");
return;
}
m_UseCase = eventFormUseCase;
}
private static EventFormContext BuildContext(EventFormRawData rawData)
{
if (rawData?.EventItem == null)
{
return null;
}
EventOptionItemContext[] options = new EventOptionItemContext[4];
for (int i = 0; i < options.Length; i++)
{
string optionText = string.Empty;
if (rawData.EventItem.Options != null && i < rawData.EventItem.Options.Length &&
rawData.EventItem.Options[i] != null)
{
optionText = rawData.EventItem.Options[i].OptionText;
}
options[i] = new EventOptionItemContext
{
OptionIndex = i,
OptionText = optionText
};
}
return new EventFormContext
{
EventId = rawData.EventItem.Id,
Title = rawData.EventItem.Title,
Description = rawData.EventItem.Description,
OptionItems = options
};
}
private void OnEventOptionItemSelected(object sender, GameEventArgs e)
{
if (!(e is EventOptionItemSelectedEventArgs args))
{
return;
}
if (m_UseCase == null)
{
Log.Warning("EventFormController.OnOptionSelected() useCase is null.");
return;
}
m_UseCase.SelectOption(args.SelectedItemId);
CloseUI();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 916da3490ed14b01ae064cbb37880bba
timeCreated: 1772104204

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a0e002d6d3ee84d46859c7933b285513
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,9 @@
using GeometryTD.Definition;
namespace GeometryTD.UI
{
public class EventFormRawData
{
public EventItem EventItem;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 463e60ff83314069b83158ccf64cddef
timeCreated: 1772104200

Some files were not shown because too many files have changed in this diff Show More