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 /.vscode
AGENTS.md 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[] # 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] 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] 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] 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[] # 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] 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] 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] 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 fileFormatVersion: 2
guid: d2ccda2aca4a348428805b273ee2aaf2 guid: d860a5c1c09addf4ba7539e97c85c0bd
TextScriptImporter: TextScriptImporter:
externalObjects: {} externalObjects: {}
userData: userData:

View File

@ -1,7 +1,8 @@
# 实体表 # Id 策划备注 AssetName
# Id AssetName
# int string # int string
# 实体编号 策划备注 资源名称 # 实体编号 资源名称
101 测试枪口 TestMuzzle 101 测试枪口 TestMuzzle
201 测试轴承 TestBearing 201 测试轴承 TestBearing
301 测试底座 TestBase 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
# Id EntityId Name AttackDamage DamageRandomRate Method Constraint PossibleTag # int int string int[] float AttackMethodType Constraint TagType[]
# int int string int[] float AttackMethodType string TagType[] # 枪口编号 策划备注 实体Id 枪口名 各品质伤害 伤害浮动 攻击方式 Constraint 可能出现的Tag
# 枪口编号 策划备注 实体Id 枪口名 各品质伤害 伤害浮动 攻击方式 属性约束 可能出现的Tag
1 101 元素枪口 [20,30,40,50,80] 0.05 NormalBullet [Fire,BurnSpread,IgniteBurst,Inferno] 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] 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] 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 100 主菜单 MenuForm Default False True
101 设置 SettingForm Default False True 101 设置 SettingForm Default False True
102 关于 AboutForm 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 EnemyManagerComponent EnemyManager { get; private set; }
public static EventNodeComponent EventNode { get; private set; }
public static CombatNodeComponent CombatNode { get; private set; }
private static void InitCustomComponents() private static void InitCustomComponents()
{ {
BuiltinData = UnityGameFramework.Runtime.GameEntry.GetComponent<BuiltinDataComponent>(); BuiltinData = UnityGameFramework.Runtime.GameEntry.GetComponent<BuiltinDataComponent>();
HPBar = UnityGameFramework.Runtime.GameEntry.GetComponent<HPBarComponent>(); HPBar = UnityGameFramework.Runtime.GameEntry.GetComponent<HPBarComponent>();
EnemyManager = UnityGameFramework.Runtime.GameEntry.GetComponent<EnemyManagerComponent>(); 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 public enum AttackPropertyType : byte
{ {
None = 0, None = 0,
Physical = 1, Physics = 1,
Fire = 2, Fire = 2,
Water = 3, Water = 3,
Earth = 4, 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> /// </summary>
AboutForm = 102, 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(); GameEntry.Base.ResetNormalGameSpeed();
_nextSceneId = procedureOwner.GetData<VarInt32>("NextSceneId"); _nextSceneId = procedureOwner.GetData<VarInt32>("NextSceneId");
IDataTable<DRScene> dtScene = GameEntry.DataTable.GetDataTable<DRScene>(); IDataTable<DRScene> dtScene = GameEntry.DataTable.GetDataTable<DRScene>();
DRScene drScene = dtScene.GetDataRow(_nextSceneId); DRScene drScene = dtScene.GetDataRow(_nextSceneId);
if (drScene == null) if (drScene == null)
@ -55,7 +55,8 @@ namespace GeometryTD.Procedure
return; 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; _backgroundMusicId = drScene.BackgroundMusicId;
} }
@ -81,13 +82,15 @@ namespace GeometryTD.Procedure
SceneType sceneType = (SceneType)_nextSceneId; SceneType sceneType = (SceneType)_nextSceneId;
switch (sceneType) switch (sceneType)
{ {
//TODO:场景切换 case SceneType.Menu:
// case SceneId.StressTest: ChangeState<ProcedureMenu>(procedureOwner);
// ChangeState<ProcedureStressTest>(procedureOwner); break;
// break; case SceneType.Main:
// default: ChangeState<ProcedureTest>(procedureOwner);
// Log.Debug($"Scene {sceneId.ToString()} don't configure a procedure"); break;
// break; default:
Log.Debug($"Scene {sceneType.ToString()} don't configure a procedure");
break;
} }
} }
@ -139,7 +142,8 @@ namespace GeometryTD.Procedure
return; 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[] public static readonly string[] DataTableNames = new string[]
{ {
"BaseComp",
"BearingComp",
"Enemy",
"Entity", "Entity",
"Event",
"Level",
"LevelPhase",
"LevelSpawnEntry",
"Music", "Music",
"MuzzleComp",
"Scene", "Scene",
"ShopPrice",
"Sound", "Sound",
"Tag",
"UIForm", "UIForm",
"UISound", "UISound",
"MuzzleComp",
"BearingComp",
"BaseComp",
"Tag",
}; };
private Dictionary<string, bool> _loadedFlag = new Dictionary<string, bool>(); private Dictionary<string, bool> _loadedFlag = new Dictionary<string, bool>();
@ -128,37 +134,39 @@ namespace GeometryTD.Procedure
private void LoadFont(string fontName) private void LoadFont(string fontName)
{ {
_loadedFlag.Add(Utility.Text.Format("Font.{0}", fontName), false); _loadedFlag.Add(Utility.Text.Format("Font.{0}", fontName), false);
GameEntry.Resource.LoadAsset(AssetUtility.GetFontAsset(fontName), Constant.AssetPriority.FontAsset, new LoadAssetCallbacks( GameEntry.Resource.LoadAsset(AssetUtility.GetFontAsset(fontName), Constant.AssetPriority.FontAsset,
(assetName, asset, duration, userData) => new LoadAssetCallbacks(
{ (assetName, asset, duration, userData) =>
_loadedFlag[Utility.Text.Format("Font.{0}", fontName)] = true; {
UGuiForm.SetMainFont((Font)asset); _loadedFlag[Utility.Text.Format("Font.{0}", fontName)] = true;
Log.Info("Load font '{0}' OK.", fontName); UGuiForm.SetMainFont((Font)asset);
}, Log.Info("Load font '{0}' OK.", fontName);
},
(assetName, status, errorMessage, userData) => (assetName, status, errorMessage, userData) =>
{ {
Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", fontName, assetName, errorMessage); Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", fontName, assetName,
})); errorMessage);
}));
} }
private void LoadTMPFont(string fontName) private void LoadTMPFont(string fontName)
{ {
_loadedFlag.Add(Utility.Text.Format("Font.{0}", fontName), false); _loadedFlag.Add(Utility.Text.Format("Font.{0}", fontName), false);
GameEntry.Resource.LoadAsset(AssetUtility.GetTMPFontAsset(fontName), Constant.AssetPriority.FontAsset, new LoadAssetCallbacks( GameEntry.Resource.LoadAsset(AssetUtility.GetTMPFontAsset(fontName), Constant.AssetPriority.FontAsset,
(assetName, asset, duration, userData) => new LoadAssetCallbacks(
{ (assetName, asset, duration, userData) =>
_loadedFlag[Utility.Text.Format("Font.{0}", fontName)] = true; {
UGuiForm.SetMainTMPFont((TMP_FontAsset)asset); _loadedFlag[Utility.Text.Format("Font.{0}", fontName)] = true;
Log.Info("Load font '{0}' OK.", fontName); UGuiForm.SetMainTMPFont((TMP_FontAsset)asset);
}, Log.Info("Load font '{0}' OK.", fontName);
},
(assetName, status, errorMessage, userData) => (assetName, status, errorMessage, userData) =>
{ {
Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", fontName, assetName, errorMessage); Log.Error("Can not load font '{0}' from '{1}' with error message '{2}'.", fontName, assetName,
})); errorMessage);
}));
} }
private void OnLoadConfigSuccess(object sender, GameEventArgs e) private void OnLoadConfigSuccess(object sender, GameEventArgs e)
{ {
LoadConfigSuccessEventArgs ne = (LoadConfigSuccessEventArgs)e; LoadConfigSuccessEventArgs ne = (LoadConfigSuccessEventArgs)e;
@ -179,7 +187,8 @@ namespace GeometryTD.Procedure
return; 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) private void OnLoadDataTableSuccess(object sender, GameEventArgs e)
@ -202,7 +211,8 @@ namespace GeometryTD.Procedure
return; 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) private void OnLoadDictionarySuccess(object sender, GameEventArgs e)
@ -225,7 +235,8 @@ namespace GeometryTD.Procedure
return; 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 fileFormatVersion: 2
guid: 3ecda907b9217e5499e31cb81a154ff4 guid: 34c97e1af6767d049b17b5c4ff75cb5a
folderAsset: yes folderAsset: yes
DefaultImporter: DefaultImporter:
externalObjects: {} 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