仓库组件 + 防御塔升级
- `PlayerInventoryComponent`:玩家库存组件,收集金币/组件/防御塔等道具 - 补全防御塔的升级逻辑,最高 5 级
This commit is contained in:
@@ -245,6 +245,7 @@ namespace GeometryTD.CustomComponent
|
||||
{
|
||||
int defeatedEnemyCount = _enemyManager.DefeatedEnemyCount;
|
||||
BackpackInventoryData rewardInventory = _combatResourceManager.GetRewardInventorySnapshot();
|
||||
GameEntry.PlayerInventory?.MergeInventory(rewardInventory);
|
||||
|
||||
// Step 1: stop runtime and clear enemy entities only.
|
||||
_enemyManager.EndPhase();
|
||||
|
||||
@@ -0,0 +1,408 @@
|
||||
using System;
|
||||
using GeometryTD.Definition;
|
||||
using GeometryTD.UI;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.CustomComponent
|
||||
{
|
||||
public class PlayerInventoryComponent : GameFrameworkComponent
|
||||
{
|
||||
private BackpackInventoryData _inventory = new BackpackInventoryData();
|
||||
private long _nextInstanceId = 1;
|
||||
private bool _initialized;
|
||||
|
||||
public int Gold
|
||||
{
|
||||
get
|
||||
{
|
||||
EnsureInitialized();
|
||||
return _inventory.Gold;
|
||||
}
|
||||
}
|
||||
|
||||
public void OnInit()
|
||||
{
|
||||
_inventory = CloneInventory(RepoFormUseCase.SampleInventory());
|
||||
RebuildNextInstanceId();
|
||||
_initialized = true;
|
||||
Log.Info(
|
||||
"PlayerInventory initialized. Gold={0}, Tower={1}, Muzzle={2}, Bearing={3}, Base={4}.",
|
||||
_inventory.Gold,
|
||||
_inventory.Towers.Count,
|
||||
_inventory.MuzzleComponents.Count,
|
||||
_inventory.BearingComponents.Count,
|
||||
_inventory.BaseComponents.Count);
|
||||
}
|
||||
|
||||
public BackpackInventoryData GetInventorySnapshot()
|
||||
{
|
||||
EnsureInitialized();
|
||||
return CloneInventory(_inventory);
|
||||
}
|
||||
|
||||
public void MergeInventory(BackpackInventoryData gainedInventory)
|
||||
{
|
||||
EnsureInitialized();
|
||||
if (gainedInventory == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int gainedGold = Mathf.Max(0, gainedInventory.Gold);
|
||||
int gainedMuzzleCount = 0;
|
||||
int gainedBearingCount = 0;
|
||||
int gainedBaseCount = 0;
|
||||
int gainedTowerCount = 0;
|
||||
|
||||
if (gainedGold > 0)
|
||||
{
|
||||
_inventory.Gold += gainedGold;
|
||||
}
|
||||
|
||||
if (gainedInventory.MuzzleComponents != null)
|
||||
{
|
||||
for (int i = 0; i < gainedInventory.MuzzleComponents.Count; i++)
|
||||
{
|
||||
MuzzleCompItemData source = gainedInventory.MuzzleComponents[i];
|
||||
if (source == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
MuzzleCompItemData cloned = CloneMuzzleComp(source);
|
||||
cloned.InstanceId = AllocateInstanceId();
|
||||
_inventory.MuzzleComponents.Add(cloned);
|
||||
gainedMuzzleCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (gainedInventory.BearingComponents != null)
|
||||
{
|
||||
for (int i = 0; i < gainedInventory.BearingComponents.Count; i++)
|
||||
{
|
||||
BearingCompItemData source = gainedInventory.BearingComponents[i];
|
||||
if (source == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BearingCompItemData cloned = CloneBearingComp(source);
|
||||
cloned.InstanceId = AllocateInstanceId();
|
||||
_inventory.BearingComponents.Add(cloned);
|
||||
gainedBearingCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (gainedInventory.BaseComponents != null)
|
||||
{
|
||||
for (int i = 0; i < gainedInventory.BaseComponents.Count; i++)
|
||||
{
|
||||
BaseCompItemData source = gainedInventory.BaseComponents[i];
|
||||
if (source == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BaseCompItemData cloned = CloneBaseComp(source);
|
||||
cloned.InstanceId = AllocateInstanceId();
|
||||
_inventory.BaseComponents.Add(cloned);
|
||||
gainedBaseCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (gainedInventory.Towers != null)
|
||||
{
|
||||
for (int i = 0; i < gainedInventory.Towers.Count; i++)
|
||||
{
|
||||
DefenseTowerItemData source = gainedInventory.Towers[i];
|
||||
if (source == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
DefenseTowerItemData cloned = CloneTower(source);
|
||||
cloned.InstanceId = AllocateInstanceId();
|
||||
_inventory.Towers.Add(cloned);
|
||||
gainedTowerCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (gainedGold > 0 || gainedMuzzleCount > 0 || gainedBearingCount > 0 || gainedBaseCount > 0 ||
|
||||
gainedTowerCount > 0)
|
||||
{
|
||||
Log.Info(
|
||||
"PlayerInventory merged reward. Gold+{0}, Tower+{1}, Muzzle+{2}, Bearing+{3}, Base+{4}.",
|
||||
gainedGold,
|
||||
gainedTowerCount,
|
||||
gainedMuzzleCount,
|
||||
gainedBearingCount,
|
||||
gainedBaseCount);
|
||||
}
|
||||
}
|
||||
|
||||
public bool TryConsumeGold(int costGold)
|
||||
{
|
||||
EnsureInitialized();
|
||||
int resolvedCost = Mathf.Max(0, costGold);
|
||||
if (resolvedCost <= 0)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
if (_inventory.Gold < resolvedCost)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_inventory.Gold -= resolvedCost;
|
||||
return true;
|
||||
}
|
||||
|
||||
public void AddGold(int gainGold)
|
||||
{
|
||||
EnsureInitialized();
|
||||
int resolvedGain = Mathf.Max(0, gainGold);
|
||||
if (resolvedGain <= 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_inventory.Gold += resolvedGain;
|
||||
}
|
||||
|
||||
private void EnsureInitialized()
|
||||
{
|
||||
if (_initialized)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
OnInit();
|
||||
}
|
||||
|
||||
private long AllocateInstanceId()
|
||||
{
|
||||
if (_nextInstanceId < 1)
|
||||
{
|
||||
_nextInstanceId = 1;
|
||||
}
|
||||
|
||||
return _nextInstanceId++;
|
||||
}
|
||||
|
||||
private void RebuildNextInstanceId()
|
||||
{
|
||||
long maxInstanceId = 0;
|
||||
if (_inventory.Towers != null)
|
||||
{
|
||||
for (int i = 0; i < _inventory.Towers.Count; i++)
|
||||
{
|
||||
DefenseTowerItemData item = _inventory.Towers[i];
|
||||
if (item != null)
|
||||
{
|
||||
maxInstanceId = Math.Max(maxInstanceId, item.InstanceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_inventory.MuzzleComponents != null)
|
||||
{
|
||||
for (int i = 0; i < _inventory.MuzzleComponents.Count; i++)
|
||||
{
|
||||
MuzzleCompItemData item = _inventory.MuzzleComponents[i];
|
||||
if (item != null)
|
||||
{
|
||||
maxInstanceId = Math.Max(maxInstanceId, item.InstanceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_inventory.BearingComponents != null)
|
||||
{
|
||||
for (int i = 0; i < _inventory.BearingComponents.Count; i++)
|
||||
{
|
||||
BearingCompItemData item = _inventory.BearingComponents[i];
|
||||
if (item != null)
|
||||
{
|
||||
maxInstanceId = Math.Max(maxInstanceId, item.InstanceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_inventory.BaseComponents != null)
|
||||
{
|
||||
for (int i = 0; i < _inventory.BaseComponents.Count; i++)
|
||||
{
|
||||
BaseCompItemData item = _inventory.BaseComponents[i];
|
||||
if (item != null)
|
||||
{
|
||||
maxInstanceId = Math.Max(maxInstanceId, item.InstanceId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_nextInstanceId = Math.Max(1, maxInstanceId + 1);
|
||||
}
|
||||
|
||||
private static BackpackInventoryData CloneInventory(BackpackInventoryData source)
|
||||
{
|
||||
BackpackInventoryData cloned = new BackpackInventoryData();
|
||||
if (source == null)
|
||||
{
|
||||
return cloned;
|
||||
}
|
||||
|
||||
cloned.Gold = Mathf.Max(0, source.Gold);
|
||||
|
||||
if (source.MuzzleComponents != null)
|
||||
{
|
||||
for (int i = 0; i < source.MuzzleComponents.Count; i++)
|
||||
{
|
||||
MuzzleCompItemData item = source.MuzzleComponents[i];
|
||||
if (item != null)
|
||||
{
|
||||
cloned.MuzzleComponents.Add(CloneMuzzleComp(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (source.BearingComponents != null)
|
||||
{
|
||||
for (int i = 0; i < source.BearingComponents.Count; i++)
|
||||
{
|
||||
BearingCompItemData item = source.BearingComponents[i];
|
||||
if (item != null)
|
||||
{
|
||||
cloned.BearingComponents.Add(CloneBearingComp(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (source.BaseComponents != null)
|
||||
{
|
||||
for (int i = 0; i < source.BaseComponents.Count; i++)
|
||||
{
|
||||
BaseCompItemData item = source.BaseComponents[i];
|
||||
if (item != null)
|
||||
{
|
||||
cloned.BaseComponents.Add(CloneBaseComp(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (source.Towers != null)
|
||||
{
|
||||
for (int i = 0; i < source.Towers.Count; i++)
|
||||
{
|
||||
DefenseTowerItemData item = source.Towers[i];
|
||||
if (item != null)
|
||||
{
|
||||
cloned.Towers.Add(CloneTower(item));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return cloned;
|
||||
}
|
||||
|
||||
private static MuzzleCompItemData CloneMuzzleComp(MuzzleCompItemData source)
|
||||
{
|
||||
return new MuzzleCompItemData
|
||||
{
|
||||
InstanceId = source.InstanceId,
|
||||
ConfigId = source.ConfigId,
|
||||
Name = source.Name,
|
||||
Rarity = source.Rarity,
|
||||
Endurance = source.Endurance,
|
||||
Constraint = source.Constraint,
|
||||
Tags = CloneTags(source.Tags),
|
||||
AttackDamage = CloneIntArray(source.AttackDamage),
|
||||
DamageRandomRate = source.DamageRandomRate,
|
||||
AttackMethodType = source.AttackMethodType
|
||||
};
|
||||
}
|
||||
|
||||
private static BearingCompItemData CloneBearingComp(BearingCompItemData source)
|
||||
{
|
||||
return new BearingCompItemData
|
||||
{
|
||||
InstanceId = source.InstanceId,
|
||||
ConfigId = source.ConfigId,
|
||||
Name = source.Name,
|
||||
Rarity = source.Rarity,
|
||||
Endurance = source.Endurance,
|
||||
Constraint = source.Constraint,
|
||||
Tags = CloneTags(source.Tags),
|
||||
RotateSpeed = CloneFloatArray(source.RotateSpeed),
|
||||
AttackRange = CloneFloatArray(source.AttackRange)
|
||||
};
|
||||
}
|
||||
|
||||
private static BaseCompItemData CloneBaseComp(BaseCompItemData source)
|
||||
{
|
||||
return new BaseCompItemData
|
||||
{
|
||||
InstanceId = source.InstanceId,
|
||||
ConfigId = source.ConfigId,
|
||||
Name = source.Name,
|
||||
Rarity = source.Rarity,
|
||||
Endurance = source.Endurance,
|
||||
Constraint = source.Constraint,
|
||||
Tags = CloneTags(source.Tags),
|
||||
AttackSpeed = CloneFloatArray(source.AttackSpeed),
|
||||
AttackPropertyType = source.AttackPropertyType
|
||||
};
|
||||
}
|
||||
|
||||
private static DefenseTowerItemData CloneTower(DefenseTowerItemData source)
|
||||
{
|
||||
return new DefenseTowerItemData
|
||||
{
|
||||
InstanceId = source.InstanceId,
|
||||
Name = source.Name,
|
||||
Rarity = source.Rarity,
|
||||
Endurance = source.Endurance,
|
||||
MuzzleComponentInstanceId = source.MuzzleComponentInstanceId,
|
||||
BearingComponentInstanceId = source.BearingComponentInstanceId,
|
||||
BaseComponentInstanceId = source.BaseComponentInstanceId,
|
||||
Stats = CloneTowerStats(source.Stats)
|
||||
};
|
||||
}
|
||||
|
||||
private static DefenseTowerStatsData CloneTowerStats(DefenseTowerStatsData source)
|
||||
{
|
||||
if (source == null)
|
||||
{
|
||||
return new DefenseTowerStatsData();
|
||||
}
|
||||
|
||||
return new DefenseTowerStatsData
|
||||
{
|
||||
AttackDamage = source.AttackDamage,
|
||||
DamageRandomRate = source.DamageRandomRate,
|
||||
RotateSpeed = source.RotateSpeed,
|
||||
AttackRange = source.AttackRange,
|
||||
AttackSpeed = source.AttackSpeed,
|
||||
AttackMethodType = source.AttackMethodType,
|
||||
AttackPropertyType = source.AttackPropertyType,
|
||||
Tags = CloneTags(source.Tags)
|
||||
};
|
||||
}
|
||||
|
||||
private static int[] CloneIntArray(int[] source)
|
||||
{
|
||||
return source != null ? (int[])source.Clone() : Array.Empty<int>();
|
||||
}
|
||||
|
||||
private static float[] CloneFloatArray(float[] source)
|
||||
{
|
||||
return source != null ? (float[])source.Clone() : Array.Empty<float>();
|
||||
}
|
||||
|
||||
private static TagType[] CloneTags(TagType[] source)
|
||||
{
|
||||
return source != null ? (TagType[])source.Clone() : Array.Empty<TagType>();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5db8d7bb243947fdbb9fe75a9d234d10
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user