补全防御塔组装与介绍描述功能
- RepoForm.CombineArea:防御塔组装,直接继承所有组件的属性 - ItemDescUtility:根据属性构建不同的 ItemDescForm 的文本
This commit is contained in:
parent
e12d2e73b2
commit
1e5803f4c5
|
|
@ -105,3 +105,4 @@ AGENTS.md
|
|||
/[Aa]ssets/RawResources
|
||||
/[Aa]ssets/RawResources.meta
|
||||
/docs/TODO.md
|
||||
/.dotnet
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ using UnityEngine;
|
|||
namespace Components
|
||||
{
|
||||
[DisallowMultipleComponent]
|
||||
public class DefenseTowerController : MonoBehaviour
|
||||
public class TowerController : MonoBehaviour
|
||||
{
|
||||
private const string AttackRangeIndicatorObjectName = "AttackRangeIndicator";
|
||||
private const int MinTowerLevel = 0;
|
||||
|
|
@ -35,12 +35,12 @@ namespace Components
|
|||
ResolveComponents();
|
||||
}
|
||||
|
||||
public void OnInit(DefenseTowerStatsData stats)
|
||||
public void OnInit(TowerStatsData stats)
|
||||
{
|
||||
OnInit(stats, MinTowerLevel);
|
||||
}
|
||||
|
||||
public void OnInit(DefenseTowerStatsData stats, int towerLevel)
|
||||
public void OnInit(TowerStatsData stats, int towerLevel)
|
||||
{
|
||||
ResolveComponents();
|
||||
if (stats == null)
|
||||
|
|
@ -54,7 +54,7 @@ namespace GeometryTD.CustomComponent
|
|||
MuzzleComponents = new List<MuzzleCompItemData>(_rewardInventory.MuzzleComponents),
|
||||
BearingComponents = new List<BearingCompItemData>(_rewardInventory.BearingComponents),
|
||||
BaseComponents = new List<BaseCompItemData>(_rewardInventory.BaseComponents),
|
||||
Towers = new List<DefenseTowerItemData>(_rewardInventory.Towers)
|
||||
Towers = new List<TowerItemData>(_rewardInventory.Towers)
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using GameFramework.DataTable;
|
||||
using GeometryTD.DataTable;
|
||||
using GeometryTD.Definition;
|
||||
using GeometryTD.UI;
|
||||
using UnityEngine;
|
||||
|
|
@ -8,9 +11,13 @@ namespace GeometryTD.CustomComponent
|
|||
{
|
||||
public class PlayerInventoryComponent : GameFrameworkComponent
|
||||
{
|
||||
private const int TowerLevelCount = 5;
|
||||
private BackpackInventoryData _inventory = new BackpackInventoryData();
|
||||
private long _nextInstanceId = 1;
|
||||
private bool _initialized;
|
||||
private IDataTable<DRMuzzleComp> _drMuzzleComp;
|
||||
private IDataTable<DRBearingComp> _drBearingComp;
|
||||
private IDataTable<DRBaseComp> _drBaseComp;
|
||||
|
||||
public int Gold
|
||||
{
|
||||
|
|
@ -115,13 +122,13 @@ namespace GeometryTD.CustomComponent
|
|||
{
|
||||
for (int i = 0; i < gainedInventory.Towers.Count; i++)
|
||||
{
|
||||
DefenseTowerItemData source = gainedInventory.Towers[i];
|
||||
TowerItemData source = gainedInventory.Towers[i];
|
||||
if (source == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
DefenseTowerItemData cloned = CloneTower(source);
|
||||
TowerItemData cloned = CloneTower(source);
|
||||
cloned.InstanceId = AllocateInstanceId();
|
||||
_inventory.Towers.Add(cloned);
|
||||
gainedTowerCount++;
|
||||
|
|
@ -171,6 +178,58 @@ namespace GeometryTD.CustomComponent
|
|||
_inventory.Gold += resolvedGain;
|
||||
}
|
||||
|
||||
public bool TryAssembleTower(
|
||||
long muzzleInstanceId,
|
||||
long bearingInstanceId,
|
||||
long baseInstanceId,
|
||||
out TowerItemData assembledTower)
|
||||
{
|
||||
EnsureInitialized();
|
||||
assembledTower = null;
|
||||
if (muzzleInstanceId <= 0 || bearingInstanceId <= 0 || baseInstanceId <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TryGetComponentById(_inventory.MuzzleComponents, muzzleInstanceId,
|
||||
out MuzzleCompItemData muzzleComp) ||
|
||||
!TryGetComponentById(_inventory.BearingComponents, bearingInstanceId,
|
||||
out BearingCompItemData bearingComp) ||
|
||||
!TryGetComponentById(_inventory.BaseComponents, baseInstanceId, out BaseCompItemData baseComp))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (muzzleComp.IsAssembledIntoTower || bearingComp.IsAssembledIntoTower || baseComp.IsAssembledIntoTower)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TryBuildTowerStats(muzzleComp, bearingComp, baseComp, out TowerStatsData stats))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
long towerInstanceId = AllocateInstanceId();
|
||||
TowerItemData tower = new TowerItemData
|
||||
{
|
||||
InstanceId = towerInstanceId,
|
||||
Name = $"组装防御塔-{towerInstanceId}",
|
||||
Rarity = ResolveAverageRarity(muzzleComp.Rarity, bearingComp.Rarity, baseComp.Rarity),
|
||||
MuzzleComponentInstanceId = muzzleComp.InstanceId,
|
||||
BearingComponentInstanceId = bearingComp.InstanceId,
|
||||
BaseComponentInstanceId = baseComp.InstanceId,
|
||||
Stats = stats
|
||||
};
|
||||
|
||||
muzzleComp.IsAssembledIntoTower = true;
|
||||
bearingComp.IsAssembledIntoTower = true;
|
||||
baseComp.IsAssembledIntoTower = true;
|
||||
_inventory.Towers.Add(tower);
|
||||
assembledTower = CloneTower(tower);
|
||||
return true;
|
||||
}
|
||||
|
||||
public int ReduceAllTowerEndurance(float enduranceLoss)
|
||||
{
|
||||
EnsureInitialized();
|
||||
|
|
@ -180,27 +239,250 @@ namespace GeometryTD.CustomComponent
|
|||
return 0;
|
||||
}
|
||||
|
||||
Dictionary<long, MuzzleCompItemData> muzzleMap = BuildComponentMap(_inventory.MuzzleComponents);
|
||||
Dictionary<long, BearingCompItemData> bearingMap = BuildComponentMap(_inventory.BearingComponents);
|
||||
Dictionary<long, BaseCompItemData> baseMap = BuildComponentMap(_inventory.BaseComponents);
|
||||
|
||||
int affectedCount = 0;
|
||||
for (int i = 0; i < _inventory.Towers.Count; i++)
|
||||
foreach (var tower in _inventory.Towers)
|
||||
{
|
||||
DefenseTowerItemData tower = _inventory.Towers[i];
|
||||
if (tower == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float originalEndurance = tower.Endurance;
|
||||
float nextEndurance = Mathf.Clamp(originalEndurance - resolvedLoss, 0f, 100f);
|
||||
bool towerAffected = false;
|
||||
if (muzzleMap.TryGetValue(tower.MuzzleComponentInstanceId, out MuzzleCompItemData muzzleComp))
|
||||
{
|
||||
towerAffected |= TryReduceComponentEndurance(muzzleComp, resolvedLoss);
|
||||
}
|
||||
|
||||
if (bearingMap.TryGetValue(tower.BearingComponentInstanceId, out BearingCompItemData bearingComp))
|
||||
{
|
||||
towerAffected |= TryReduceComponentEndurance(bearingComp, resolvedLoss);
|
||||
}
|
||||
|
||||
if (baseMap.TryGetValue(tower.BaseComponentInstanceId, out BaseCompItemData baseComp))
|
||||
{
|
||||
towerAffected |= TryReduceComponentEndurance(baseComp, resolvedLoss);
|
||||
}
|
||||
|
||||
if (towerAffected)
|
||||
{
|
||||
affectedCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return affectedCount;
|
||||
}
|
||||
|
||||
private static bool TryReduceComponentEndurance(TowerCompItemData component, float enduranceLoss)
|
||||
{
|
||||
if (component == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float originalEndurance = component.Endurance;
|
||||
float nextEndurance = Mathf.Clamp(originalEndurance - Mathf.Max(0f, enduranceLoss), 0f, 100f);
|
||||
if (nextEndurance >= originalEndurance)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
component.Endurance = nextEndurance;
|
||||
return true;
|
||||
}
|
||||
|
||||
private static Dictionary<long, TComp> BuildComponentMap<TComp>(List<TComp> components)
|
||||
where TComp : TowerCompItemData
|
||||
{
|
||||
Dictionary<long, TComp> map = new Dictionary<long, TComp>();
|
||||
if (components == null || components.Count <= 0)
|
||||
{
|
||||
return map;
|
||||
}
|
||||
|
||||
foreach (var component in components)
|
||||
{
|
||||
if (component == null || component.InstanceId <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
tower.Endurance = nextEndurance;
|
||||
affectedCount++;
|
||||
map[component.InstanceId] = component;
|
||||
}
|
||||
|
||||
return affectedCount;
|
||||
return map;
|
||||
}
|
||||
|
||||
private static bool TryGetComponentById<TComp>(List<TComp> components, long instanceId, out TComp result)
|
||||
where TComp : TowerCompItemData
|
||||
{
|
||||
result = null;
|
||||
if (components == null || instanceId <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (TComp component in components)
|
||||
{
|
||||
if (component != null && component.InstanceId == instanceId)
|
||||
{
|
||||
result = component;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool TryBuildTowerStats(
|
||||
MuzzleCompItemData muzzleComp,
|
||||
BearingCompItemData bearingComp,
|
||||
BaseCompItemData baseComp,
|
||||
out TowerStatsData stats)
|
||||
{
|
||||
stats = null;
|
||||
if (muzzleComp == null || bearingComp == null || baseComp == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
DRMuzzleComp muzzleConfig = EnsureMuzzleTable()?.GetDataRow(muzzleComp.ConfigId);
|
||||
DRBearingComp bearingConfig = EnsureBearingTable()?.GetDataRow(bearingComp.ConfigId);
|
||||
DRBaseComp baseConfig = EnsureBaseTable()?.GetDataRow(baseComp.ConfigId);
|
||||
if (muzzleConfig == null || bearingConfig == null || baseConfig == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
stats = new TowerStatsData
|
||||
{
|
||||
AttackDamage = BuildLevelIntArray(muzzleComp.AttackDamage, muzzleComp.Rarity,
|
||||
muzzleConfig.AttackDamagePerLevel),
|
||||
DamageRandomRate = Mathf.Max(0f, muzzleComp.DamageRandomRate),
|
||||
RotateSpeed = BuildLevelFloatArray(bearingComp.RotateSpeed, bearingComp.Rarity,
|
||||
bearingConfig.RotateSpeedPerLevel),
|
||||
AttackRange = BuildLevelFloatArray(bearingComp.AttackRange, bearingComp.Rarity,
|
||||
bearingConfig.AttackRangePerLevel),
|
||||
AttackSpeed =
|
||||
BuildLevelFloatArray(baseComp.AttackSpeed, baseComp.Rarity, baseConfig.AttackSpeedPerLevel),
|
||||
AttackMethodType = muzzleComp.AttackMethodType,
|
||||
AttackPropertyType = baseComp.AttackPropertyType,
|
||||
Tags = MergeTags(muzzleComp.Tags, bearingComp.Tags, baseComp.Tags)
|
||||
};
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static int[] BuildLevelIntArray(int[] rarityBaseArray, RarityType rarity, int perLevel)
|
||||
{
|
||||
int baseValue = ResolveRarityBaseValue(rarityBaseArray, rarity);
|
||||
int[] values = new int[TowerLevelCount];
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
{
|
||||
values[i] = baseValue + perLevel * i;
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
private static float[] BuildLevelFloatArray(float[] rarityBaseArray, RarityType rarity, float perLevel)
|
||||
{
|
||||
float baseValue = ResolveRarityBaseValue(rarityBaseArray, rarity);
|
||||
float[] values = new float[TowerLevelCount];
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
{
|
||||
values[i] = baseValue + perLevel * i;
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
private static float[] BuildConstantLevelFloatArray(float value)
|
||||
{
|
||||
float[] values = new float[TowerLevelCount];
|
||||
for (int i = 0; i < values.Length; i++)
|
||||
{
|
||||
values[i] = value;
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
private static int ResolveRarityBaseValue(int[] rarityBaseArray, RarityType rarity)
|
||||
{
|
||||
if (rarityBaseArray == null || rarityBaseArray.Length <= 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rarityIndex = Mathf.Clamp((int)rarity - 1, 0, rarityBaseArray.Length - 1);
|
||||
return rarityBaseArray[rarityIndex];
|
||||
}
|
||||
|
||||
private static float ResolveRarityBaseValue(float[] rarityBaseArray, RarityType rarity)
|
||||
{
|
||||
if (rarityBaseArray == null || rarityBaseArray.Length <= 0)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
int rarityIndex = Mathf.Clamp((int)rarity - 1, 0, rarityBaseArray.Length - 1);
|
||||
return rarityBaseArray[rarityIndex];
|
||||
}
|
||||
|
||||
private static TagType[] MergeTags(params TagType[][] sources)
|
||||
{
|
||||
HashSet<TagType> uniqueTags = new HashSet<TagType>();
|
||||
if (sources != null)
|
||||
{
|
||||
for (int i = 0; i < sources.Length; i++)
|
||||
{
|
||||
TagType[] tags = sources[i];
|
||||
if (tags == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int j = 0; j < tags.Length; j++)
|
||||
{
|
||||
uniqueTags.Add(tags[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TagType[] mergedTags = new TagType[uniqueTags.Count];
|
||||
uniqueTags.CopyTo(mergedTags);
|
||||
return mergedTags;
|
||||
}
|
||||
|
||||
private static RarityType ResolveAverageRarity(RarityType muzzleRarity, RarityType bearingRarity,
|
||||
RarityType baseRarity)
|
||||
{
|
||||
float avg = ((int)muzzleRarity + (int)bearingRarity + (int)baseRarity) / 3f;
|
||||
int rounded = Mathf.RoundToInt(avg);
|
||||
int clamped = Mathf.Clamp(rounded, (int)RarityType.White, (int)RarityType.Red);
|
||||
return (RarityType)clamped;
|
||||
}
|
||||
|
||||
private IDataTable<DRMuzzleComp> EnsureMuzzleTable()
|
||||
{
|
||||
_drMuzzleComp ??= GameEntry.DataTable.GetDataTable<DRMuzzleComp>();
|
||||
return _drMuzzleComp;
|
||||
}
|
||||
|
||||
private IDataTable<DRBearingComp> EnsureBearingTable()
|
||||
{
|
||||
_drBearingComp ??= GameEntry.DataTable.GetDataTable<DRBearingComp>();
|
||||
return _drBearingComp;
|
||||
}
|
||||
|
||||
private IDataTable<DRBaseComp> EnsureBaseTable()
|
||||
{
|
||||
_drBaseComp ??= GameEntry.DataTable.GetDataTable<DRBaseComp>();
|
||||
return _drBaseComp;
|
||||
}
|
||||
|
||||
private void EnsureInitialized()
|
||||
|
|
@ -228,9 +510,8 @@ namespace GeometryTD.CustomComponent
|
|||
long maxInstanceId = 0;
|
||||
if (_inventory.Towers != null)
|
||||
{
|
||||
for (int i = 0; i < _inventory.Towers.Count; i++)
|
||||
foreach (var item in _inventory.Towers)
|
||||
{
|
||||
DefenseTowerItemData item = _inventory.Towers[i];
|
||||
if (item != null)
|
||||
{
|
||||
maxInstanceId = Math.Max(maxInstanceId, item.InstanceId);
|
||||
|
|
@ -240,9 +521,8 @@ namespace GeometryTD.CustomComponent
|
|||
|
||||
if (_inventory.MuzzleComponents != null)
|
||||
{
|
||||
for (int i = 0; i < _inventory.MuzzleComponents.Count; i++)
|
||||
foreach (var item in _inventory.MuzzleComponents)
|
||||
{
|
||||
MuzzleCompItemData item = _inventory.MuzzleComponents[i];
|
||||
if (item != null)
|
||||
{
|
||||
maxInstanceId = Math.Max(maxInstanceId, item.InstanceId);
|
||||
|
|
@ -252,9 +532,8 @@ namespace GeometryTD.CustomComponent
|
|||
|
||||
if (_inventory.BearingComponents != null)
|
||||
{
|
||||
for (int i = 0; i < _inventory.BearingComponents.Count; i++)
|
||||
foreach (var item in _inventory.BearingComponents)
|
||||
{
|
||||
BearingCompItemData item = _inventory.BearingComponents[i];
|
||||
if (item != null)
|
||||
{
|
||||
maxInstanceId = Math.Max(maxInstanceId, item.InstanceId);
|
||||
|
|
@ -264,9 +543,8 @@ namespace GeometryTD.CustomComponent
|
|||
|
||||
if (_inventory.BaseComponents != null)
|
||||
{
|
||||
for (int i = 0; i < _inventory.BaseComponents.Count; i++)
|
||||
foreach (var item in _inventory.BaseComponents)
|
||||
{
|
||||
BaseCompItemData item = _inventory.BaseComponents[i];
|
||||
if (item != null)
|
||||
{
|
||||
maxInstanceId = Math.Max(maxInstanceId, item.InstanceId);
|
||||
|
|
@ -327,7 +605,7 @@ namespace GeometryTD.CustomComponent
|
|||
{
|
||||
for (int i = 0; i < source.Towers.Count; i++)
|
||||
{
|
||||
DefenseTowerItemData item = source.Towers[i];
|
||||
TowerItemData item = source.Towers[i];
|
||||
if (item != null)
|
||||
{
|
||||
cloned.Towers.Add(CloneTower(item));
|
||||
|
|
@ -347,6 +625,7 @@ namespace GeometryTD.CustomComponent
|
|||
Name = source.Name,
|
||||
Rarity = source.Rarity,
|
||||
Endurance = source.Endurance,
|
||||
IsAssembledIntoTower = source.IsAssembledIntoTower,
|
||||
Constraint = source.Constraint,
|
||||
Tags = CloneTags(source.Tags),
|
||||
AttackDamage = CloneIntArray(source.AttackDamage),
|
||||
|
|
@ -364,6 +643,7 @@ namespace GeometryTD.CustomComponent
|
|||
Name = source.Name,
|
||||
Rarity = source.Rarity,
|
||||
Endurance = source.Endurance,
|
||||
IsAssembledIntoTower = source.IsAssembledIntoTower,
|
||||
Constraint = source.Constraint,
|
||||
Tags = CloneTags(source.Tags),
|
||||
RotateSpeed = CloneFloatArray(source.RotateSpeed),
|
||||
|
|
@ -380,6 +660,7 @@ namespace GeometryTD.CustomComponent
|
|||
Name = source.Name,
|
||||
Rarity = source.Rarity,
|
||||
Endurance = source.Endurance,
|
||||
IsAssembledIntoTower = source.IsAssembledIntoTower,
|
||||
Constraint = source.Constraint,
|
||||
Tags = CloneTags(source.Tags),
|
||||
AttackSpeed = CloneFloatArray(source.AttackSpeed),
|
||||
|
|
@ -387,14 +668,13 @@ namespace GeometryTD.CustomComponent
|
|||
};
|
||||
}
|
||||
|
||||
private static DefenseTowerItemData CloneTower(DefenseTowerItemData source)
|
||||
private static TowerItemData CloneTower(TowerItemData source)
|
||||
{
|
||||
return new DefenseTowerItemData
|
||||
return new TowerItemData
|
||||
{
|
||||
InstanceId = source.InstanceId,
|
||||
Name = source.Name,
|
||||
Rarity = source.Rarity,
|
||||
Endurance = source.Endurance,
|
||||
MuzzleComponentInstanceId = source.MuzzleComponentInstanceId,
|
||||
BearingComponentInstanceId = source.BearingComponentInstanceId,
|
||||
BaseComponentInstanceId = source.BaseComponentInstanceId,
|
||||
|
|
@ -402,20 +682,20 @@ namespace GeometryTD.CustomComponent
|
|||
};
|
||||
}
|
||||
|
||||
private static DefenseTowerStatsData CloneTowerStats(DefenseTowerStatsData source)
|
||||
private static TowerStatsData CloneTowerStats(TowerStatsData source)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
return new DefenseTowerStatsData();
|
||||
return new TowerStatsData();
|
||||
}
|
||||
|
||||
return new DefenseTowerStatsData
|
||||
return new TowerStatsData
|
||||
{
|
||||
AttackDamage = source.AttackDamage,
|
||||
AttackDamage = CloneIntArray(source.AttackDamage),
|
||||
DamageRandomRate = source.DamageRandomRate,
|
||||
RotateSpeed = source.RotateSpeed,
|
||||
AttackRange = source.AttackRange,
|
||||
AttackSpeed = source.AttackSpeed,
|
||||
RotateSpeed = CloneFloatArray(source.RotateSpeed),
|
||||
AttackRange = CloneFloatArray(source.AttackRange),
|
||||
AttackSpeed = CloneFloatArray(source.AttackSpeed),
|
||||
AttackMethodType = source.AttackMethodType,
|
||||
AttackPropertyType = source.AttackPropertyType,
|
||||
Tags = CloneTags(source.Tags)
|
||||
|
|
|
|||
|
|
@ -32,6 +32,6 @@ namespace GeometryTD.Definition
|
|||
/// <summary>
|
||||
/// 背包中的防御塔实例。
|
||||
/// </summary>
|
||||
public List<DefenseTowerItemData> Towers { get; set; } = new List<DefenseTowerItemData>();
|
||||
public List<TowerItemData> Towers { get; set; } = new List<TowerItemData>();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,49 +5,20 @@ namespace GeometryTD.Definition
|
|||
[StructLayout(LayoutKind.Auto)]
|
||||
public struct ImpactData
|
||||
{
|
||||
private readonly CampType m_Camp;
|
||||
private readonly int m_HP;
|
||||
private readonly int m_Attack;
|
||||
private readonly int m_Defense;
|
||||
|
||||
public ImpactData(CampType camp, int hp, int attack, int defense)
|
||||
{
|
||||
m_Camp = camp;
|
||||
m_HP = hp;
|
||||
m_Attack = attack;
|
||||
m_Defense = defense;
|
||||
Camp = camp;
|
||||
HP = hp;
|
||||
Attack = attack;
|
||||
Defense = defense;
|
||||
}
|
||||
|
||||
public CampType Camp
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Camp;
|
||||
}
|
||||
}
|
||||
public CampType Camp { get; }
|
||||
|
||||
public int HP
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_HP;
|
||||
}
|
||||
}
|
||||
public int HP { get; }
|
||||
|
||||
public int Attack
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Attack;
|
||||
}
|
||||
}
|
||||
public int Attack { get; }
|
||||
|
||||
public int Defense
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_Defense;
|
||||
}
|
||||
}
|
||||
public int Defense { get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -37,6 +37,7 @@ namespace GeometryTD.Definition
|
|||
/// 组件当前耐久(0~100)。
|
||||
/// </summary>
|
||||
public float Endurance { get; set; } = 100f;
|
||||
public bool IsAssembledIntoTower { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 组件约束(先沿用 DataTable 原定义)。
|
||||
|
|
|
|||
|
|
@ -7,10 +7,10 @@ namespace GeometryTD.Definition
|
|||
/// 注意:这里是塔实例的独立值,不通过组件引用实时计算。
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed class DefenseTowerStatsData
|
||||
public sealed class TowerStatsData
|
||||
{
|
||||
public int[] AttackDamage { get; set; }
|
||||
public float[] DamageRandomRate { get; set; }
|
||||
public float DamageRandomRate { get; set; }
|
||||
public float[] RotateSpeed { get; set; }
|
||||
public float[] AttackRange { get; set; }
|
||||
public float[] AttackSpeed { get; set; }
|
||||
|
|
@ -23,7 +23,7 @@ namespace GeometryTD.Definition
|
|||
/// 背包内防御塔实例数据。
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed class DefenseTowerItemData
|
||||
public sealed class TowerItemData
|
||||
{
|
||||
/// <summary>
|
||||
/// 防御塔实例唯一 Id。
|
||||
|
|
@ -40,11 +40,6 @@ namespace GeometryTD.Definition
|
|||
/// </summary>
|
||||
public RarityType Rarity { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 当前耐久(0~100)。
|
||||
/// </summary>
|
||||
public float Endurance { get; set; } = 100f;
|
||||
|
||||
/// <summary>
|
||||
/// 构成该防御塔的枪口组件实例 Id。
|
||||
/// </summary>
|
||||
|
|
@ -63,6 +58,6 @@ namespace GeometryTD.Definition
|
|||
/// <summary>
|
||||
/// 防御塔独立属性,不依赖组件对象引用。
|
||||
/// </summary>
|
||||
public DefenseTowerStatsData Stats { get; set; } = new DefenseTowerStatsData();
|
||||
public TowerStatsData Stats { get; set; } = new TowerStatsData();
|
||||
}
|
||||
}
|
||||
|
|
@ -5,25 +5,25 @@ using UnityEngine;
|
|||
namespace GeometryTD.Entity.EntityData
|
||||
{
|
||||
[Serializable]
|
||||
public class DefenseTowerData : EntityDataBase
|
||||
public class TowerData : EntityDataBase
|
||||
{
|
||||
[SerializeField] private DefenseTowerStatsData _stats = new DefenseTowerStatsData();
|
||||
[SerializeField] private TowerStatsData _stats = new TowerStatsData();
|
||||
[SerializeField] private int _towerLevel = 0;
|
||||
|
||||
public DefenseTowerData(int entityId, int typeId, Vector3 position, Quaternion rotation,
|
||||
DefenseTowerStatsData stats, int towerLevel = 0)
|
||||
public TowerData(int entityId, int typeId, Vector3 position, Quaternion rotation,
|
||||
TowerStatsData stats, int towerLevel = 0)
|
||||
: base(entityId, typeId)
|
||||
{
|
||||
Position = position;
|
||||
Rotation = rotation;
|
||||
_stats = stats ?? new DefenseTowerStatsData();
|
||||
_stats = stats ?? new TowerStatsData();
|
||||
_towerLevel = Mathf.Max(0, towerLevel);
|
||||
}
|
||||
|
||||
public DefenseTowerStatsData Stats
|
||||
public TowerStatsData Stats
|
||||
{
|
||||
get => _stats;
|
||||
set => _stats = value ?? new DefenseTowerStatsData();
|
||||
set => _stats = value ?? new TowerStatsData();
|
||||
}
|
||||
|
||||
public int TowerLevel
|
||||
|
|
@ -46,9 +46,9 @@ namespace GeometryTD
|
|||
entityComponent.ShowEntity(typeof(EnemyEntity), "Enemy", Constant.AssetPriority.EnemyAsset, data);
|
||||
}
|
||||
|
||||
public static void ShowDefenseTower(this EntityComponent entityComponent, DefenseTowerData data)
|
||||
public static void ShowDefenseTower(this EntityComponent entityComponent, TowerData data)
|
||||
{
|
||||
entityComponent.ShowEntity(typeof(DefenseTowerEntity), "Tower", Constant.AssetPriority.EnemyAsset, data);
|
||||
entityComponent.ShowEntity(typeof(TowerEntity), "Tower", Constant.AssetPriority.EnemyAsset, data);
|
||||
}
|
||||
|
||||
public static void ShowBullet(this EntityComponent entityComponent, BulletData data)
|
||||
|
|
|
|||
|
|
@ -5,16 +5,16 @@ using UnityGameFramework.Runtime;
|
|||
|
||||
namespace GeometryTD.Entity
|
||||
{
|
||||
public class DefenseTowerEntity : EntityBase
|
||||
public class TowerEntity : EntityBase
|
||||
{
|
||||
private DefenseTowerController _towerController;
|
||||
private TowerController _towerController;
|
||||
|
||||
public void SetAttackRangeVisible(bool visible)
|
||||
{
|
||||
_towerController?.SetAttackRangeVisible(visible);
|
||||
}
|
||||
|
||||
public bool TryApplyStats(DefenseTowerStatsData stats, int towerLevel)
|
||||
public bool TryApplyStats(TowerStatsData stats, int towerLevel)
|
||||
{
|
||||
if (_towerController == null || stats == null)
|
||||
{
|
||||
|
|
@ -29,7 +29,7 @@ namespace GeometryTD.Entity
|
|||
{
|
||||
base.OnInit(userData);
|
||||
|
||||
_towerController = GetComponent<DefenseTowerController>();
|
||||
_towerController = GetComponent<TowerController>();
|
||||
if (_towerController == null)
|
||||
{
|
||||
Log.Error("DefenseTowerController is missing on tower entity '{0}'.", name);
|
||||
|
|
@ -45,7 +45,7 @@ namespace GeometryTD.Entity
|
|||
return;
|
||||
}
|
||||
|
||||
if (userData is not DefenseTowerData towerData)
|
||||
if (userData is not TowerData towerData)
|
||||
{
|
||||
Log.Warning("DefenseTowerData is invalid for tower entity '{0}'.", Id);
|
||||
_towerController.OnReset();
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
using GameFramework;
|
||||
using GameFramework.Event;
|
||||
|
||||
namespace GeometryTD.CustomEvent
|
||||
{
|
||||
public sealed class RepoCombineRequestedEventArgs : GameEventArgs
|
||||
{
|
||||
public static int EventId => typeof(RepoCombineRequestedEventArgs).GetHashCode();
|
||||
|
||||
public override int Id => EventId;
|
||||
|
||||
public long MuzzleItemId { get; private set; }
|
||||
public long BearingItemId { get; private set; }
|
||||
public long BaseItemId { get; private set; }
|
||||
|
||||
public static RepoCombineRequestedEventArgs Create(long muzzleItemId, long bearingItemId, long baseItemId)
|
||||
{
|
||||
RepoCombineRequestedEventArgs args = ReferencePool.Acquire<RepoCombineRequestedEventArgs>();
|
||||
args.MuzzleItemId = muzzleItemId;
|
||||
args.BearingItemId = bearingItemId;
|
||||
args.BaseItemId = baseItemId;
|
||||
return args;
|
||||
}
|
||||
|
||||
public override void Clear()
|
||||
{
|
||||
MuzzleItemId = 0;
|
||||
BearingItemId = 0;
|
||||
BaseItemId = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 93ff2618b5b54f6f9058ec17b9bf3329
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -16,7 +16,7 @@ namespace GeometryTD.Map
|
|||
|
||||
private readonly Dictionary<Vector3Int, int> _towerEntityIdByFoundationCell = new();
|
||||
private readonly Dictionary<int, Vector3Int> _foundationCellByTowerEntityId = new();
|
||||
private readonly Dictionary<int, DefenseTowerStatsData> _towerStatsByEntityId = new();
|
||||
private readonly Dictionary<int, TowerStatsData> _towerStatsByEntityId = new();
|
||||
private readonly Dictionary<int, int> _towerLevelByEntityId = new();
|
||||
private readonly List<int> _towerEntityIdBuffer = new();
|
||||
|
||||
|
|
@ -30,8 +30,8 @@ namespace GeometryTD.Map
|
|||
return false;
|
||||
}
|
||||
|
||||
DefenseTowerStatsData towerStats =
|
||||
_towerStatsByEntityId.TryGetValue(towerEntityId, out DefenseTowerStatsData cachedStats)
|
||||
TowerStatsData towerStats =
|
||||
_towerStatsByEntityId.TryGetValue(towerEntityId, out TowerStatsData cachedStats)
|
||||
? cachedStats
|
||||
: null;
|
||||
int currentLevel = GetTowerLevel(towerEntityId);
|
||||
|
|
@ -61,7 +61,7 @@ namespace GeometryTD.Map
|
|||
return false;
|
||||
}
|
||||
|
||||
DefenseTowerStatsData towerStats = BuildTowerStats(buildIndex);
|
||||
TowerStatsData towerStats = BuildTowerStats(buildIndex);
|
||||
if (!TryShowTowerEntity(foundationCell, towerStats, towerTypeId, tilemap, out int newTowerEntityId))
|
||||
{
|
||||
addCoin?.Invoke(buildCost);
|
||||
|
|
@ -87,8 +87,8 @@ namespace GeometryTD.Map
|
|||
return false;
|
||||
}
|
||||
|
||||
DefenseTowerStatsData towerStats =
|
||||
_towerStatsByEntityId.TryGetValue(towerEntityId, out DefenseTowerStatsData cachedStats)
|
||||
TowerStatsData towerStats =
|
||||
_towerStatsByEntityId.TryGetValue(towerEntityId, out TowerStatsData cachedStats)
|
||||
? CloneTowerStats(cachedStats)
|
||||
: BuildTowerStats(0);
|
||||
int currentTowerLevel = GetTowerLevel(towerEntityId);
|
||||
|
|
@ -177,7 +177,7 @@ namespace GeometryTD.Map
|
|||
return Mathf.Max(0, buildTowerCosts[buildIndex]);
|
||||
}
|
||||
|
||||
private static bool TryShowTowerEntity(Vector3Int foundationCell, DefenseTowerStatsData towerStats,
|
||||
private static bool TryShowTowerEntity(Vector3Int foundationCell, TowerStatsData towerStats,
|
||||
int towerTypeId,
|
||||
Tilemap tilemap, out int towerEntityId)
|
||||
{
|
||||
|
|
@ -191,7 +191,7 @@ namespace GeometryTD.Map
|
|||
int typeId = towerTypeId > 0 ? towerTypeId : DefaultTowerTypeId;
|
||||
Vector3 towerPosition = tilemap != null ? tilemap.GetCellCenterWorld(foundationCell) : foundationCell;
|
||||
towerPosition.z = 0f;
|
||||
var towerData = new DefenseTowerData(entityId, typeId, towerPosition, Quaternion.identity, towerStats,
|
||||
var towerData = new TowerData(entityId, typeId, towerPosition, Quaternion.identity, towerStats,
|
||||
MinTowerLevel);
|
||||
GameEntry.Entity.ShowDefenseTower(towerData);
|
||||
|
||||
|
|
@ -213,15 +213,15 @@ namespace GeometryTD.Map
|
|||
}
|
||||
}
|
||||
|
||||
private static DefenseTowerStatsData BuildTowerStats(int buildIndex)
|
||||
private static TowerStatsData BuildTowerStats(int buildIndex)
|
||||
{
|
||||
switch (buildIndex)
|
||||
{
|
||||
case 0:
|
||||
return new DefenseTowerStatsData
|
||||
return new TowerStatsData
|
||||
{
|
||||
AttackDamage = new[] { 200, 220, 240, 260, 300 },
|
||||
DamageRandomRate = new[] { 0f, 0f, 0f, 0f, 0f },
|
||||
DamageRandomRate = 0f,
|
||||
RotateSpeed = new[] { 200f, 210f, 220f, 230f, 240f },
|
||||
AttackRange = new[] { 4.5f, 4.7f, 4.9f, 5.1f, 5.3f },
|
||||
AttackSpeed = new[] { 1.5f, 1.2f, 1.1f, 1.0f, 0.8f },
|
||||
|
|
@ -230,10 +230,10 @@ namespace GeometryTD.Map
|
|||
Tags = Array.Empty<TagType>()
|
||||
};
|
||||
case 1:
|
||||
return new DefenseTowerStatsData
|
||||
return new TowerStatsData
|
||||
{
|
||||
AttackDamage = new[] { 200, 220, 240, 260, 300 },
|
||||
DamageRandomRate = new[] { 0f, 0f, 0f, 0f, 0f },
|
||||
DamageRandomRate = 0f,
|
||||
RotateSpeed = new[] { 200f, 210f, 220f, 230f, 240f },
|
||||
AttackRange = new[] { 4.5f, 4.7f, 4.9f, 5.1f, 5.3f },
|
||||
AttackSpeed = new[] { 1.5f, 1.2f, 1.1f, 1.0f, 0.8f },
|
||||
|
|
@ -242,10 +242,10 @@ namespace GeometryTD.Map
|
|||
Tags = Array.Empty<TagType>()
|
||||
};
|
||||
case 2:
|
||||
return new DefenseTowerStatsData
|
||||
return new TowerStatsData
|
||||
{
|
||||
AttackDamage = new[] { 200, 220, 240, 260, 300 },
|
||||
DamageRandomRate = new[] { 0f, 0f, 0f, 0f, 0f },
|
||||
DamageRandomRate = 0f,
|
||||
RotateSpeed = new[] { 200f, 210f, 220f, 230f, 240f },
|
||||
AttackRange = new[] { 4.5f, 4.7f, 4.9f, 5.1f, 5.3f },
|
||||
AttackSpeed = new[] { 1.5f, 1.2f, 1.1f, 1.0f, 0.8f },
|
||||
|
|
@ -254,10 +254,10 @@ namespace GeometryTD.Map
|
|||
Tags = Array.Empty<TagType>()
|
||||
};
|
||||
case 3:
|
||||
return new DefenseTowerStatsData
|
||||
return new TowerStatsData
|
||||
{
|
||||
AttackDamage = new[] { 200, 220, 240, 260, 300 },
|
||||
DamageRandomRate = new[] { 0f, 0f, 0f, 0f, 0f },
|
||||
DamageRandomRate = 0f,
|
||||
RotateSpeed = new[] { 200f, 210f, 220f, 230f, 240f },
|
||||
AttackRange = new[] { 4.5f, 4.7f, 4.9f, 5.1f, 5.3f },
|
||||
AttackSpeed = new[] { 1.5f, 1.2f, 1.1f, 1.0f, 0.8f },
|
||||
|
|
@ -266,10 +266,10 @@ namespace GeometryTD.Map
|
|||
Tags = Array.Empty<TagType>()
|
||||
};
|
||||
default:
|
||||
return new DefenseTowerStatsData
|
||||
return new TowerStatsData
|
||||
{
|
||||
AttackDamage = new[] { 200, 220, 240, 260, 300 },
|
||||
DamageRandomRate = new[] { 0f, 0f, 0f, 0f, 0f },
|
||||
DamageRandomRate = 0f,
|
||||
RotateSpeed = new[] { 200f, 210f, 220f, 230f, 240f },
|
||||
AttackRange = new[] { 4.5f, 4.7f, 4.9f, 5.1f, 5.3f },
|
||||
AttackSpeed = new[] { 1.5f, 1.2f, 1.1f, 1.0f, 0.8f },
|
||||
|
|
@ -280,7 +280,7 @@ namespace GeometryTD.Map
|
|||
}
|
||||
}
|
||||
|
||||
private static DefenseTowerStatsData CloneTowerStats(DefenseTowerStatsData source)
|
||||
private static TowerStatsData CloneTowerStats(TowerStatsData source)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
|
|
@ -288,12 +288,10 @@ namespace GeometryTD.Map
|
|||
}
|
||||
|
||||
TagType[] copiedTags = source.Tags != null ? (TagType[])source.Tags.Clone() : Array.Empty<TagType>();
|
||||
return new DefenseTowerStatsData
|
||||
return new TowerStatsData
|
||||
{
|
||||
AttackDamage = source.AttackDamage != null ? (int[])source.AttackDamage.Clone() : Array.Empty<int>(),
|
||||
DamageRandomRate = source.DamageRandomRate != null
|
||||
? (float[])source.DamageRandomRate.Clone()
|
||||
: Array.Empty<float>(),
|
||||
DamageRandomRate = source.DamageRandomRate,
|
||||
RotateSpeed = source.RotateSpeed != null ? (float[])source.RotateSpeed.Clone() : Array.Empty<float>(),
|
||||
AttackRange = source.AttackRange != null ? (float[])source.AttackRange.Clone() : Array.Empty<float>(),
|
||||
AttackSpeed = source.AttackSpeed != null ? (float[])source.AttackSpeed.Clone() : Array.Empty<float>(),
|
||||
|
|
@ -313,11 +311,10 @@ namespace GeometryTD.Map
|
|||
return Mathf.Clamp(towerLevel, MinTowerLevel, MaxTowerLevel);
|
||||
}
|
||||
|
||||
private static int ResolveMaxTowerLevel(DefenseTowerStatsData stats)
|
||||
private static int ResolveMaxTowerLevel(TowerStatsData stats)
|
||||
{
|
||||
int maxCount = Mathf.Max(
|
||||
GetLength(stats?.AttackDamage),
|
||||
GetLength(stats?.DamageRandomRate),
|
||||
GetLength(stats?.RotateSpeed),
|
||||
GetLength(stats?.AttackRange),
|
||||
GetLength(stats?.AttackSpeed));
|
||||
|
|
@ -329,14 +326,14 @@ namespace GeometryTD.Map
|
|||
return Mathf.Clamp(maxCount - 1, MinTowerLevel, MaxTowerLevel);
|
||||
}
|
||||
|
||||
private static bool TryApplyTowerStats(int towerEntityId, DefenseTowerStatsData towerStats, int towerLevel)
|
||||
private static bool TryApplyTowerStats(int towerEntityId, TowerStatsData towerStats, int towerLevel)
|
||||
{
|
||||
if (towerEntityId == 0 || towerStats == null || GameEntry.Entity == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GameEntry.Entity.GetGameEntity(towerEntityId) is not DefenseTowerEntity towerEntity)
|
||||
if (GameEntry.Entity.GetGameEntity(towerEntityId) is not TowerEntity towerEntity)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -120,7 +120,7 @@ namespace GeometryTD.Map
|
|||
}
|
||||
|
||||
EntityBase gameEntity = GameEntry.Entity.GetGameEntity(towerEntityId);
|
||||
if (gameEntity is not DefenseTowerEntity towerEntity)
|
||||
if (gameEntity is not TowerEntity towerEntity)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ namespace GeometryTD.UI
|
|||
{
|
||||
public string Title;
|
||||
public string TypeText;
|
||||
public string Description;
|
||||
public TagType[] Tags;
|
||||
}
|
||||
|
||||
|
|
@ -128,7 +129,11 @@ namespace GeometryTD.UI
|
|||
IconAreaContext = BuildIconAreaContext(tower)
|
||||
});
|
||||
|
||||
AddItemDescSeed(tower.InstanceId, tower.Name, "Tower",
|
||||
AddItemDescSeed(
|
||||
tower.InstanceId,
|
||||
tower.Name,
|
||||
"Tower",
|
||||
ItemDescUtility.BuildTowerDesc(tower.Stats) ?? string.Empty,
|
||||
tower.Stats != null ? tower.Stats.Tags : null);
|
||||
}
|
||||
}
|
||||
|
|
@ -151,7 +156,12 @@ namespace GeometryTD.UI
|
|||
IconAreaContext = BuildIconAreaContext(item)
|
||||
});
|
||||
|
||||
AddItemDescSeed(item.InstanceId, item.Name, BuildComponentTypeText(item.SlotType), item.Tags);
|
||||
AddItemDescSeed(
|
||||
item.InstanceId,
|
||||
item.Name,
|
||||
BuildComponentTypeText(item.SlotType),
|
||||
ItemDescUtility.BuildMuzzleDesc(item) ?? string.Empty,
|
||||
item.Tags);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -172,7 +182,12 @@ namespace GeometryTD.UI
|
|||
IconAreaContext = BuildIconAreaContext(item)
|
||||
});
|
||||
|
||||
AddItemDescSeed(item.InstanceId, item.Name, BuildComponentTypeText(item.SlotType), item.Tags);
|
||||
AddItemDescSeed(
|
||||
item.InstanceId,
|
||||
item.Name,
|
||||
BuildComponentTypeText(item.SlotType),
|
||||
ItemDescUtility.BuildBearingDesc(item) ?? string.Empty,
|
||||
item.Tags);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -194,14 +209,19 @@ namespace GeometryTD.UI
|
|||
IconAreaContext = BuildIconAreaContext(item)
|
||||
});
|
||||
|
||||
AddItemDescSeed(item.InstanceId, item.Name, BuildComponentTypeText(item.SlotType), item.Tags);
|
||||
AddItemDescSeed(
|
||||
item.InstanceId,
|
||||
item.Name,
|
||||
BuildComponentTypeText(item.SlotType),
|
||||
ItemDescUtility.BuildBaseDesc(item) ?? string.Empty,
|
||||
item.Tags);
|
||||
}
|
||||
}
|
||||
|
||||
return itemContexts.ToArray();
|
||||
}
|
||||
|
||||
private void AddItemDescSeed(long itemId, string title, string typeText, TagType[] tags)
|
||||
private void AddItemDescSeed(long itemId, string title, string typeText, string description, TagType[] tags)
|
||||
{
|
||||
if (itemId <= 0)
|
||||
{
|
||||
|
|
@ -212,6 +232,7 @@ namespace GeometryTD.UI
|
|||
{
|
||||
Title = string.IsNullOrWhiteSpace(title) ? $"Item {itemId}" : title,
|
||||
TypeText = typeText ?? string.Empty,
|
||||
Description = description ?? string.Empty,
|
||||
Tags = CloneTags(tags)
|
||||
};
|
||||
}
|
||||
|
|
@ -233,7 +254,7 @@ namespace GeometryTD.UI
|
|||
};
|
||||
}
|
||||
|
||||
private static IconAreaContext BuildIconAreaContext(DefenseTowerItemData tower)
|
||||
private static IconAreaContext BuildIconAreaContext(TowerItemData tower)
|
||||
{
|
||||
if (tower == null)
|
||||
{
|
||||
|
|
@ -308,7 +329,7 @@ namespace GeometryTD.UI
|
|||
{
|
||||
Title = seed.Title,
|
||||
TypeText = seed.TypeText,
|
||||
Description = string.Empty,
|
||||
Description = seed.Description ?? string.Empty,
|
||||
Price = 0,
|
||||
TargetPos = args.TargetPos,
|
||||
Tags = CloneTags(seed.Tags)
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ namespace GeometryTD.UI
|
|||
{
|
||||
public string Title;
|
||||
public string TypeText;
|
||||
public string Description;
|
||||
public TagType[] Tags;
|
||||
}
|
||||
|
||||
|
|
@ -34,6 +35,7 @@ namespace GeometryTD.UI
|
|||
GameEntry.Event.Subscribe(RepoItemDetailRequestedEventArgs.EventId, OnRepoItemDetailRequested);
|
||||
GameEntry.Event.Subscribe(RepoItemDragEndedEventArgs.EventId, OnRepoItemDragEnded);
|
||||
GameEntry.Event.Subscribe(CombineSlotClickedEventArgs.EventId, OnCombineSlotClicked);
|
||||
GameEntry.Event.Subscribe(RepoCombineRequestedEventArgs.EventId, OnRepoCombineRequested);
|
||||
GameEntry.Event.Subscribe(RepoFormReturnEventArgs.EventId, OnRepoFormReturn);
|
||||
}
|
||||
|
||||
|
|
@ -42,6 +44,7 @@ namespace GeometryTD.UI
|
|||
GameEntry.Event.Unsubscribe(RepoItemDetailRequestedEventArgs.EventId, OnRepoItemDetailRequested);
|
||||
GameEntry.Event.Unsubscribe(RepoItemDragEndedEventArgs.EventId, OnRepoItemDragEnded);
|
||||
GameEntry.Event.Unsubscribe(CombineSlotClickedEventArgs.EventId, OnCombineSlotClicked);
|
||||
GameEntry.Event.Unsubscribe(RepoCombineRequestedEventArgs.EventId, OnRepoCombineRequested);
|
||||
GameEntry.Event.Unsubscribe(RepoFormReturnEventArgs.EventId, OnRepoFormReturn);
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +106,7 @@ namespace GeometryTD.UI
|
|||
|
||||
if (rawData.Inventory.Towers != null)
|
||||
{
|
||||
foreach (DefenseTowerItemData tower in rawData.Inventory.Towers)
|
||||
foreach (TowerItemData tower in rawData.Inventory.Towers)
|
||||
{
|
||||
if (tower == null)
|
||||
{
|
||||
|
|
@ -117,7 +120,11 @@ namespace GeometryTD.UI
|
|||
ComponentSlotType = TowerCompSlotType.None,
|
||||
IconAreaContext = BuildIconAreaContext(tower)
|
||||
});
|
||||
AddItemDescSeed(tower.InstanceId, tower.Name, "Tower",
|
||||
AddItemDescSeed(
|
||||
tower.InstanceId,
|
||||
tower.Name,
|
||||
"Tower",
|
||||
ItemDescUtility.BuildTowerDesc(tower.Stats) ?? string.Empty,
|
||||
tower.Stats != null ? tower.Stats.Tags : null);
|
||||
}
|
||||
}
|
||||
|
|
@ -126,7 +133,7 @@ namespace GeometryTD.UI
|
|||
{
|
||||
foreach (MuzzleCompItemData item in rawData.Inventory.MuzzleComponents)
|
||||
{
|
||||
if (item == null)
|
||||
if (item == null || item.IsAssembledIntoTower)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -138,7 +145,12 @@ namespace GeometryTD.UI
|
|||
ComponentSlotType = TowerCompSlotType.Muzzle,
|
||||
IconAreaContext = BuildIconAreaContext(item)
|
||||
});
|
||||
AddItemDescSeed(item.InstanceId, item.Name, BuildComponentTypeText(item.SlotType), item.Tags);
|
||||
AddItemDescSeed(
|
||||
item.InstanceId,
|
||||
item.Name,
|
||||
BuildComponentTypeText(item.SlotType),
|
||||
ItemDescUtility.BuildMuzzleDesc(item) ?? string.Empty,
|
||||
item.Tags);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -146,7 +158,7 @@ namespace GeometryTD.UI
|
|||
{
|
||||
foreach (BearingCompItemData item in rawData.Inventory.BearingComponents)
|
||||
{
|
||||
if (item == null)
|
||||
if (item == null || item.IsAssembledIntoTower)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -158,7 +170,12 @@ namespace GeometryTD.UI
|
|||
ComponentSlotType = TowerCompSlotType.Bearing,
|
||||
IconAreaContext = BuildIconAreaContext(item)
|
||||
});
|
||||
AddItemDescSeed(item.InstanceId, item.Name, BuildComponentTypeText(item.SlotType), item.Tags);
|
||||
AddItemDescSeed(
|
||||
item.InstanceId,
|
||||
item.Name,
|
||||
BuildComponentTypeText(item.SlotType),
|
||||
ItemDescUtility.BuildBearingDesc(item) ?? string.Empty,
|
||||
item.Tags);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -166,7 +183,7 @@ namespace GeometryTD.UI
|
|||
{
|
||||
foreach (BaseCompItemData item in rawData.Inventory.BaseComponents)
|
||||
{
|
||||
if (item == null)
|
||||
if (item == null || item.IsAssembledIntoTower)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
@ -178,7 +195,12 @@ namespace GeometryTD.UI
|
|||
ComponentSlotType = TowerCompSlotType.Base,
|
||||
IconAreaContext = BuildIconAreaContext(item)
|
||||
});
|
||||
AddItemDescSeed(item.InstanceId, item.Name, BuildComponentTypeText(item.SlotType), item.Tags);
|
||||
AddItemDescSeed(
|
||||
item.InstanceId,
|
||||
item.Name,
|
||||
BuildComponentTypeText(item.SlotType),
|
||||
ItemDescUtility.BuildBaseDesc(item) ?? string.Empty,
|
||||
item.Tags);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -203,7 +225,7 @@ namespace GeometryTD.UI
|
|||
_itemContextMap[itemContext.InstanceId] = itemContext;
|
||||
}
|
||||
|
||||
private void AddItemDescSeed(long itemId, string title, string typeText, TagType[] tags)
|
||||
private void AddItemDescSeed(long itemId, string title, string typeText, string description, TagType[] tags)
|
||||
{
|
||||
if (itemId <= 0)
|
||||
{
|
||||
|
|
@ -214,6 +236,7 @@ namespace GeometryTD.UI
|
|||
{
|
||||
Title = string.IsNullOrWhiteSpace(title) ? $"Item {itemId}" : title,
|
||||
TypeText = typeText ?? string.Empty,
|
||||
Description = description ?? string.Empty,
|
||||
Tags = CloneTags(tags)
|
||||
};
|
||||
}
|
||||
|
|
@ -235,7 +258,7 @@ namespace GeometryTD.UI
|
|||
};
|
||||
}
|
||||
|
||||
private static IconAreaContext BuildIconAreaContext(DefenseTowerItemData tower)
|
||||
private static IconAreaContext BuildIconAreaContext(TowerItemData tower)
|
||||
{
|
||||
if (tower == null)
|
||||
{
|
||||
|
|
@ -302,7 +325,7 @@ namespace GeometryTD.UI
|
|||
{
|
||||
Title = seed.Title,
|
||||
TypeText = seed.TypeText,
|
||||
Description = string.Empty,
|
||||
Description = seed.Description ?? string.Empty,
|
||||
Price = 0,
|
||||
TargetPos = args.TargetPos,
|
||||
Tags = CloneTags(seed.Tags)
|
||||
|
|
@ -367,6 +390,36 @@ namespace GeometryTD.UI
|
|||
this.CloseUI();
|
||||
}
|
||||
|
||||
private void OnRepoCombineRequested(object sender, GameEventArgs e)
|
||||
{
|
||||
if (!IsEventFromCurrentForm(sender))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(e is RepoCombineRequestedEventArgs args))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (_useCase == null || Form == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_useCase.TryAssembleTower(args.MuzzleItemId, args.BearingItemId, args.BaseItemId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RepoFormRawData latestRawData = _useCase.CreateInitialModel();
|
||||
RepoFormContext latestContext = BuildContext(latestRawData);
|
||||
if (latestContext != null)
|
||||
{
|
||||
Form.RefreshUI(latestContext);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsEventFromCurrentForm(object sender)
|
||||
{
|
||||
if (Form == null)
|
||||
|
|
|
|||
|
|
@ -15,6 +15,20 @@ namespace GeometryTD.UI
|
|||
};
|
||||
}
|
||||
|
||||
public bool TryAssembleTower(long muzzleItemId, long bearingItemId, long baseItemId)
|
||||
{
|
||||
if (GameEntry.PlayerInventory == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return GameEntry.PlayerInventory.TryAssembleTower(
|
||||
muzzleItemId,
|
||||
bearingItemId,
|
||||
baseItemId,
|
||||
out _);
|
||||
}
|
||||
|
||||
public static BackpackInventoryData SampleInventory()
|
||||
{
|
||||
BackpackInventoryData inventory = new BackpackInventoryData
|
||||
|
|
@ -29,6 +43,7 @@ namespace GeometryTD.UI
|
|||
Name = "元素枪口",
|
||||
Rarity = RarityType.Green,
|
||||
Endurance = 90f,
|
||||
IsAssembledIntoTower = true,
|
||||
AttackDamage = new[] { 20, 30, 40, 50, 80 },
|
||||
DamageRandomRate = 0.05f,
|
||||
AttackMethodType = AttackMethodType.NormalBullet,
|
||||
|
|
@ -36,6 +51,34 @@ namespace GeometryTD.UI
|
|||
Tags = new[] { TagType.Fire }
|
||||
};
|
||||
inventory.MuzzleComponents.Add(muzzle);
|
||||
inventory.MuzzleComponents.Add(new MuzzleCompItemData
|
||||
{
|
||||
InstanceId = 10002,
|
||||
ConfigId = 2,
|
||||
Name = "控制枪口",
|
||||
Rarity = RarityType.Blue,
|
||||
Endurance = 100f,
|
||||
IsAssembledIntoTower = false,
|
||||
AttackDamage = new[] { 30, 50, 70, 90, 100 },
|
||||
DamageRandomRate = 0.01f,
|
||||
AttackMethodType = AttackMethodType.NormalBullet,
|
||||
Constraint = string.Empty,
|
||||
Tags = new[] { TagType.Ice, TagType.FreezeMask }
|
||||
});
|
||||
inventory.MuzzleComponents.Add(new MuzzleCompItemData
|
||||
{
|
||||
InstanceId = 10003,
|
||||
ConfigId = 3,
|
||||
Name = "穿透枪口",
|
||||
Rarity = RarityType.Purple,
|
||||
Endurance = 97f,
|
||||
IsAssembledIntoTower = false,
|
||||
AttackDamage = new[] { 50, 55, 60, 80, 90 },
|
||||
DamageRandomRate = 0.02f,
|
||||
AttackMethodType = AttackMethodType.NormalBullet,
|
||||
Constraint = string.Empty,
|
||||
Tags = new[] { TagType.Pierce, TagType.Crit }
|
||||
});
|
||||
|
||||
BearingCompItemData bearing = new BearingCompItemData
|
||||
{
|
||||
|
|
@ -44,12 +87,39 @@ namespace GeometryTD.UI
|
|||
Name = "元素轴承",
|
||||
Rarity = RarityType.Green,
|
||||
Endurance = 95f,
|
||||
IsAssembledIntoTower = true,
|
||||
RotateSpeed = new[] { 10f, 12f, 13f, 14f, 15f },
|
||||
AttackRange = new[] { 2f, 2f, 2f, 2f, 2f },
|
||||
Constraint = string.Empty,
|
||||
Tags = new[] { TagType.Fire }
|
||||
};
|
||||
inventory.BearingComponents.Add(bearing);
|
||||
inventory.BearingComponents.Add(new BearingCompItemData
|
||||
{
|
||||
InstanceId = 20002,
|
||||
ConfigId = 2,
|
||||
Name = "控制轴承",
|
||||
Rarity = RarityType.Blue,
|
||||
Endurance = 100f,
|
||||
IsAssembledIntoTower = false,
|
||||
RotateSpeed = new[] { 20f, 25f, 30f, 32f, 35f },
|
||||
AttackRange = new[] { 6f, 6.5f, 7f, 8f, 8f },
|
||||
Constraint = string.Empty,
|
||||
Tags = new[] { TagType.Ice, TagType.Shatter }
|
||||
});
|
||||
inventory.BearingComponents.Add(new BearingCompItemData
|
||||
{
|
||||
InstanceId = 20003,
|
||||
ConfigId = 3,
|
||||
Name = "穿透轴承",
|
||||
Rarity = RarityType.Purple,
|
||||
Endurance = 96f,
|
||||
IsAssembledIntoTower = false,
|
||||
RotateSpeed = new[] { 60f, 70f, 80f, 90f, 100f },
|
||||
AttackRange = new[] { 4f, 4.5f, 5f, 5.5f, 6f },
|
||||
Constraint = string.Empty,
|
||||
Tags = new[] { TagType.Pierce, TagType.Overpenetrate }
|
||||
});
|
||||
|
||||
BaseCompItemData baseComp = new BaseCompItemData
|
||||
{
|
||||
|
|
@ -58,26 +128,52 @@ namespace GeometryTD.UI
|
|||
Name = "元素底座",
|
||||
Rarity = RarityType.Green,
|
||||
Endurance = 88f,
|
||||
IsAssembledIntoTower = true,
|
||||
AttackSpeed = new[] { 2f, 1.5f, 1f, 0.8f, 0.7f },
|
||||
AttackPropertyType = AttackPropertyType.Fire,
|
||||
Constraint = string.Empty,
|
||||
Tags = new[] { TagType.Fire }
|
||||
};
|
||||
inventory.BaseComponents.Add(baseComp);
|
||||
inventory.BaseComponents.Add(new BaseCompItemData
|
||||
{
|
||||
InstanceId = 30002,
|
||||
ConfigId = 2,
|
||||
Name = "控制底座",
|
||||
Rarity = RarityType.Blue,
|
||||
Endurance = 100f,
|
||||
IsAssembledIntoTower = false,
|
||||
AttackSpeed = new[] { 4f, 4.2f, 4.4f, 4.6f, 4.8f },
|
||||
AttackPropertyType = AttackPropertyType.Ice,
|
||||
Constraint = string.Empty,
|
||||
Tags = new[] { TagType.Ice, TagType.AbsoluteZero }
|
||||
});
|
||||
inventory.BaseComponents.Add(new BaseCompItemData
|
||||
{
|
||||
InstanceId = 30003,
|
||||
ConfigId = 3,
|
||||
Name = "穿透底座",
|
||||
Rarity = RarityType.Purple,
|
||||
Endurance = 95f,
|
||||
IsAssembledIntoTower = false,
|
||||
AttackSpeed = new[] { 1f, 1f, 1f, 1f, 1f },
|
||||
AttackPropertyType = AttackPropertyType.Physics,
|
||||
Constraint = string.Empty,
|
||||
Tags = new[] { TagType.Pierce, TagType.Execution }
|
||||
});
|
||||
|
||||
DefenseTowerItemData tower = new DefenseTowerItemData
|
||||
TowerItemData tower = new TowerItemData
|
||||
{
|
||||
InstanceId = 90001,
|
||||
Name = "测试防御塔-A",
|
||||
Rarity = RarityType.Green,
|
||||
Endurance = 92f,
|
||||
MuzzleComponentInstanceId = muzzle.InstanceId,
|
||||
BearingComponentInstanceId = bearing.InstanceId,
|
||||
BaseComponentInstanceId = baseComp.InstanceId,
|
||||
Stats = new DefenseTowerStatsData
|
||||
Stats = new TowerStatsData
|
||||
{
|
||||
AttackDamage = new[] { 200, 220, 240, 260, 300 },
|
||||
DamageRandomRate = new[] { 0f, 0f, 0f, 0f, 0f },
|
||||
DamageRandomRate = 0f,
|
||||
RotateSpeed = new[] { 200f, 210f, 220f, 230f, 240f },
|
||||
AttackRange = new[] { 4.5f, 4.7f, 4.9f, 5.1f, 5.3f },
|
||||
AttackSpeed = new[] { 1.5f, 1.2f, 1.1f, 1.0f, 0.8f },
|
||||
|
|
@ -88,19 +184,18 @@ namespace GeometryTD.UI
|
|||
};
|
||||
inventory.Towers.Add(tower);
|
||||
|
||||
inventory.Towers.Add(new DefenseTowerItemData
|
||||
inventory.Towers.Add(new TowerItemData
|
||||
{
|
||||
InstanceId = 90002,
|
||||
Name = "测试防御塔-B",
|
||||
Rarity = RarityType.Blue,
|
||||
Endurance = 100f,
|
||||
MuzzleComponentInstanceId = 0,
|
||||
BearingComponentInstanceId = 0,
|
||||
BaseComponentInstanceId = 0,
|
||||
Stats = new DefenseTowerStatsData
|
||||
Stats = new TowerStatsData
|
||||
{
|
||||
AttackDamage = new[] { 200, 220, 240, 260, 300 },
|
||||
DamageRandomRate = new[] { 0f, 0f, 0f, 0f, 0f },
|
||||
DamageRandomRate = 0.1f,
|
||||
RotateSpeed = new[] { 200f, 210f, 220f, 230f, 240f },
|
||||
AttackRange = new[] { 4.5f, 4.7f, 4.9f, 5.1f, 5.3f },
|
||||
AttackSpeed = new[] { 1.5f, 1.2f, 1.1f, 1.0f, 0.8f },
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
using GeometryTD.Definition;
|
||||
using GeometryTD.CustomEvent;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
|
|
@ -42,7 +43,14 @@ namespace GeometryTD.UI
|
|||
|
||||
public void OnCombineClick()
|
||||
{
|
||||
// TODO: Combine logic.
|
||||
if (!TryGetBoundItemId(TowerCompSlotType.Muzzle, out long muzzleItemId) ||
|
||||
!TryGetBoundItemId(TowerCompSlotType.Bearing, out long bearingItemId) ||
|
||||
!TryGetBoundItemId(TowerCompSlotType.Base, out long baseItemId))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
GameEntry.Event.Fire(this, RepoCombineRequestedEventArgs.Create(muzzleItemId, bearingItemId, baseItemId));
|
||||
}
|
||||
|
||||
public bool TryAssignItem(RepoItemContext itemContext)
|
||||
|
|
@ -127,5 +135,18 @@ namespace GeometryTD.UI
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool TryGetBoundItemId(TowerCompSlotType slotType, out long boundItemId)
|
||||
{
|
||||
boundItemId = 0;
|
||||
CombineSlotItem slot = FindSlot(slotType);
|
||||
if (slot == null || !slot.HasItem || slot.BoundItemId <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
boundItemId = slot.BoundItemId;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,17 +61,17 @@ namespace GeometryTD.CustomUtility
|
|||
item.SlotType);
|
||||
}
|
||||
|
||||
public static Color GenerateForTower(DefenseTowerItemData tower)
|
||||
public static Color GenerateForTower(TowerItemData tower)
|
||||
{
|
||||
if (tower?.Stats == null)
|
||||
{
|
||||
return Color.white;
|
||||
}
|
||||
|
||||
DefenseTowerStatsData stats = tower.Stats;
|
||||
TowerStatsData stats = tower.Stats;
|
||||
return GenerateColor(
|
||||
ResolveArrayValue(stats.AttackDamage),
|
||||
ResolveArrayValue(stats.DamageRandomRate),
|
||||
stats.DamageRandomRate,
|
||||
ResolveArrayValue(stats.RotateSpeed),
|
||||
ResolveArrayValue(stats.AttackRange),
|
||||
ResolveArrayValue(stats.AttackSpeed),
|
||||
|
|
@ -127,14 +127,16 @@ namespace GeometryTD.CustomUtility
|
|||
return;
|
||||
}
|
||||
|
||||
if (!s_HasMuzzleRange && TryResolveMuzzleRange(out StatRange attackDamageRange, out StatRange damageRandomRateRange))
|
||||
if (!s_HasMuzzleRange &&
|
||||
TryResolveMuzzleRange(out StatRange attackDamageRange, out StatRange damageRandomRateRange))
|
||||
{
|
||||
_attackDamageRange = attackDamageRange;
|
||||
_damageRandomRateRange = damageRandomRateRange;
|
||||
s_HasMuzzleRange = true;
|
||||
}
|
||||
|
||||
if (!s_HasBearingRange && TryResolveBearingRange(out StatRange rotateSpeedRange, out StatRange attackRangeRange))
|
||||
if (!s_HasBearingRange &&
|
||||
TryResolveBearingRange(out StatRange rotateSpeedRange, out StatRange attackRangeRange))
|
||||
{
|
||||
_rotateSpeedRange = rotateSpeedRange;
|
||||
_attackRangeRange = attackRangeRange;
|
||||
|
|
@ -181,7 +183,8 @@ namespace GeometryTD.CustomUtility
|
|||
}
|
||||
|
||||
IncludeValues(row.AttackDamage, ref minAttackDamage, ref maxAttackDamage, ref hasAttackDamage);
|
||||
IncludeValue(Mathf.Max(0f, row.DamageRandomRate), ref minDamageRandomRate, ref maxDamageRandomRate, ref hasDamageRandomRate);
|
||||
IncludeValue(Mathf.Max(0f, row.DamageRandomRate), ref minDamageRandomRate, ref maxDamageRandomRate,
|
||||
ref hasDamageRandomRate);
|
||||
}
|
||||
|
||||
if (!hasAttackDamage || !hasDamageRandomRate)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,142 @@
|
|||
using System;
|
||||
using System.Text;
|
||||
using GeometryTD.Definition;
|
||||
|
||||
namespace GeometryTD.CustomUtility
|
||||
{
|
||||
public static class ItemDescUtility
|
||||
{
|
||||
public static string BuildTowerDesc(TowerStatsData towerData)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
// MuzzleComp
|
||||
sb.Append("攻击伤害:");
|
||||
for (int i = 0; i < towerData.AttackDamage.Length; i++)
|
||||
{
|
||||
if (i != 0) sb.Append("|");
|
||||
sb.Append(towerData.AttackDamage[i]);
|
||||
}
|
||||
sb.Append('\n');
|
||||
|
||||
sb.Append($"伤害浮动:{towerData.DamageRandomRate:P0}\n");
|
||||
|
||||
sb.Append($"攻击方式:{ConvertAttackMethod(towerData.AttackMethodType)}\n");
|
||||
|
||||
// BearingComp
|
||||
sb.Append("旋转速度:");
|
||||
for (int i = 0; i < towerData.RotateSpeed.Length; i++)
|
||||
{
|
||||
if (i != 0) sb.Append("|");
|
||||
sb.Append(towerData.RotateSpeed[i]);
|
||||
}
|
||||
sb.Append('\n');
|
||||
|
||||
sb.Append("攻击范围:");
|
||||
for (int i = 0; i < towerData.AttackRange.Length; i++)
|
||||
{
|
||||
if (i != 0) sb.Append("|");
|
||||
sb.Append(towerData.AttackRange[i]);
|
||||
}
|
||||
sb.Append('\n');
|
||||
|
||||
// BaseComp
|
||||
sb.Append("攻击速度:");
|
||||
for (int i = 0; i < towerData.AttackSpeed.Length; i++)
|
||||
{
|
||||
if (i != 0) sb.Append("|");
|
||||
sb.Append(towerData.AttackSpeed[i]);
|
||||
}
|
||||
sb.Append('\n');
|
||||
|
||||
sb.Append($"伤害属性:{ConvertAttackProperty(towerData.AttackPropertyType)}\n");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string BuildMuzzleDesc(MuzzleCompItemData muzzleData)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append("攻击伤害:");
|
||||
for (int i = 0; i < muzzleData.AttackDamage.Length; i++)
|
||||
{
|
||||
if (i != 0) sb.Append("|");
|
||||
sb.Append(muzzleData.AttackDamage[i]);
|
||||
}
|
||||
sb.Append('\n');
|
||||
|
||||
sb.Append($"伤害浮动:{muzzleData.DamageRandomRate:P0}\n");
|
||||
|
||||
sb.Append($"攻击方式:{ConvertAttackMethod(muzzleData.AttackMethodType)}\n");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string BuildBearingDesc(BearingCompItemData bearingData)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append("旋转速度:");
|
||||
for (int i = 0; i < bearingData.RotateSpeed.Length; i++)
|
||||
{
|
||||
if (i != 0) sb.Append("|");
|
||||
sb.Append(bearingData.RotateSpeed[i]);
|
||||
}
|
||||
sb.Append('\n');
|
||||
|
||||
sb.Append("攻击范围:");
|
||||
for (int i = 0; i < bearingData.AttackRange.Length; i++)
|
||||
{
|
||||
if (i != 0) sb.Append("|");
|
||||
sb.Append(bearingData.AttackRange[i]);
|
||||
}
|
||||
sb.Append('\n');
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string BuildBaseDesc(BaseCompItemData baseData)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append("攻击速度:");
|
||||
for (int i = 0; i < baseData.AttackSpeed.Length; i++)
|
||||
{
|
||||
if (i != 0) sb.Append("|");
|
||||
sb.Append(baseData.AttackSpeed[i]);
|
||||
}
|
||||
sb.Append('\n');
|
||||
|
||||
sb.Append($"伤害属性:{ConvertAttackProperty(baseData.AttackPropertyType)}\n");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public static string ConvertAttackMethod(AttackMethodType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
AttackMethodType.None => "无效",
|
||||
AttackMethodType.NormalBullet => "发射子弹",
|
||||
AttackMethodType.Range => "范围攻击",
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
|
||||
};
|
||||
}
|
||||
|
||||
public static string ConvertAttackProperty(AttackPropertyType type)
|
||||
{
|
||||
return type switch
|
||||
{
|
||||
AttackPropertyType.None => "无效",
|
||||
AttackPropertyType.Physics => "<color=#ffff00ff>物理</color>", //yellow
|
||||
AttackPropertyType.Fire => "<color=#ff0000ff>火</color>", //red
|
||||
AttackPropertyType.Water => "<color=#00ffffff>水</color>", //cyan
|
||||
AttackPropertyType.Earth => "<color=#00ff00ff>自然</color>", //lime
|
||||
AttackPropertyType.Poison => "<color=#008000ff>毒</color>", //green
|
||||
AttackPropertyType.Ice => "<color=#0000a0ff>冰</color>", //darkblue
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 855b508f90404cf38b99179d596426df
|
||||
timeCreated: 1772614668
|
||||
|
|
@ -65,6 +65,9 @@ MonoBehaviour:
|
|||
_screenEdgePadding: 0
|
||||
_sideGap: 16
|
||||
_anchorItemWidth: 0
|
||||
_blankAreaGraphic: {fileID: 0}
|
||||
_disableBlankAreaRaycast: 1
|
||||
_closeOnPointerDownOutsideContent: 1
|
||||
--- !u!1 &518771420464217804
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
@ -595,7 +598,7 @@ MonoBehaviour:
|
|||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
m_wordSpacing: 0
|
||||
m_lineSpacing: 0
|
||||
m_lineSpacing: 15
|
||||
m_lineSpacingMax: 0
|
||||
m_paragraphSpacing: 0
|
||||
m_charWidthMaxAdj: 0
|
||||
|
|
|
|||
|
|
@ -49,10 +49,10 @@ MonoBehaviour:
|
|||
m_Script: {fileID: 11500000, guid: f3b1aede0e52479995cf71ba52a69d63, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Content: {fileID: 1805918912036091081}
|
||||
m_ItemTemplate: {fileID: 8394974685918372820, guid: 2ead8e403e355dd4b9296a9d0a871a83,
|
||||
_content: {fileID: 1805918912036091081}
|
||||
_itemTemplate: {fileID: 8394974685918372820, guid: 2ead8e403e355dd4b9296a9d0a871a83,
|
||||
type: 3}
|
||||
m_InstancePoolCapacity: 64
|
||||
_instancePoolCapacity: 64
|
||||
--- !u!1 &2380285751925872027
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
@ -1736,6 +1736,41 @@ PrefabInstance:
|
|||
propertyPath: m_hasFontAssetChanged
|
||||
value: 0
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_Mode
|
||||
value: 1
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[0].m_Target
|
||||
value:
|
||||
objectReference: {fileID: 207314004719697847}
|
||||
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_Target
|
||||
value:
|
||||
objectReference: {fileID: 2687805356437946940}
|
||||
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: _onHover.m_PersistentCalls.m_Calls.Array.data[0].m_Target
|
||||
value:
|
||||
objectReference: {fileID: 207314004719697847}
|
||||
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_MethodName
|
||||
value: OnCombineClick
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_TargetAssemblyTypeName
|
||||
value: GeometryTD.UI.CombineArea, Assembly-CSharp
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4067353614215461310, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: _onClick.m_PersistentCalls.m_Calls.Array.data[1].m_Arguments.m_ObjectArgumentAssemblyTypeName
|
||||
value: UnityEngine.Object, UnityEngine
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 4491355866364659447, guid: 2307f223279813546a43b221ddd496cc,
|
||||
type: 3}
|
||||
propertyPath: m_Pivot.x
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@
|
|||
| [ ] | P0-05 | 实现 10 节点地图生成(最后节点固定 Boss) | `Assets/GameMain/Scripts/Scene/` | 每局都生成 10 节点且第 10 节点为 Boss |
|
||||
| [x] | P0-06 | 实现节点选择与跳转流程(战斗/事件/商店) | `Assets/GameMain/Scripts/Procedure/` | 节点完成后可返回地图并进入下个节点 |
|
||||
| [x] | P0-07 | 战斗节点基础玩法:放置塔、出怪、基地扣血、胜负判定 | `Assets/GameMain/Scripts/Entity/`<br>`Assets/GameMain/Scripts/Scene/` | 可完整打一场并得到胜利/失败结果 |
|
||||
| [ ] | P0-08 | 胜利波次与结算规则(100/80/50/<50) | `Assets/GameMain/Scripts/Procedure/` | 结算奖励与惩罚严格匹配设计文档 |
|
||||
| [ ] | P0-09 | 敌人掉落与关卡奖励(组件/配件/金币) | `Assets/GameMain/Scripts/Entity/` | 战斗结束能发放掉落并写入库存 |
|
||||
| [x] | P0-08 | 胜利波次与结算规则(100/80/50/<50) | `Assets/GameMain/Scripts/Procedure/` | 结算奖励与惩罚严格匹配设计文档 |
|
||||
| [x] | P0-09 | 敌人掉落与关卡奖励(组件/配件/金币) | `Assets/GameMain/Scripts/Entity/` | 战斗结束能发放掉落并写入库存 |
|
||||
| [ ] | P0-10 | 节点后组装:枪口/轴承/底座三组件约束 | `Assets/GameMain/Scripts/Entity/`<br>`Assets/GameMain/Scripts/UI/Templates/GameScene/` | 未满足三组件时禁止出战 |
|
||||
| [ ] | P0-11 | 品质/槽位/Tag 计算落地(白绿蓝紫红) | `Assets/GameMain/Scripts/Definition/`<br>`Assets/GameMain/Scripts/Entity/` | 计算结果可复现并与规则一致 |
|
||||
| [ ] | P0-12 | 组件/配件耐久生效与 0 耐久销毁 | `Assets/GameMain/Scripts/Entity/` | 耐久影响属性,归零后物品移除 |
|
||||
|
|
|
|||
Loading…
Reference in New Issue