调整 OutGameDropPool 表定义 + 添加部分组件定义
This commit is contained in:
@@ -19,9 +19,14 @@ namespace GeometryTD.CustomComponent
|
||||
_dropPoolTable = dropPoolTable;
|
||||
}
|
||||
|
||||
public bool TryRollRow(int displayPhaseIndex, LevelThemeType themeType, out DROutGameDropPool selectedRow)
|
||||
public bool TryRollRow(
|
||||
int displayPhaseIndex,
|
||||
LevelThemeType themeType,
|
||||
out DROutGameDropPool selectedRow,
|
||||
out RarityType selectedRarity)
|
||||
{
|
||||
selectedRow = null;
|
||||
selectedRarity = RarityType.None;
|
||||
|
||||
DROutGameDropPool[] allRows = _dropPoolTable.GetAllDataRows();
|
||||
if (allRows == null || allRows.Length <= 0)
|
||||
@@ -35,22 +40,30 @@ namespace GeometryTD.CustomComponent
|
||||
return false;
|
||||
}
|
||||
|
||||
RarityType selectedRarity = RollRarity(displayPhaseIndex);
|
||||
selectedRarity = RollRarity(displayPhaseIndex);
|
||||
if (selectedRarity == RarityType.None)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int totalWeight = 0;
|
||||
DROutGameDropPool fallbackRow = null;
|
||||
for (int i = 0; i < _eligibleRowBuffer.Count; i++)
|
||||
{
|
||||
DROutGameDropPool row = _eligibleRowBuffer[i];
|
||||
if (row.Rarity != selectedRarity)
|
||||
if (!IsEligibleAtPhase(row, selectedRarity, displayPhaseIndex))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
totalWeight += Mathf.Max(1, row.Weight);
|
||||
int rowWeight = row.GetWeight(selectedRarity);
|
||||
if (rowWeight <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
fallbackRow = row;
|
||||
totalWeight += rowWeight;
|
||||
}
|
||||
|
||||
if (totalWeight <= 0)
|
||||
@@ -62,12 +75,18 @@ namespace GeometryTD.CustomComponent
|
||||
int cumulativeWeight = 0;
|
||||
foreach (var row in _eligibleRowBuffer)
|
||||
{
|
||||
if (row.Rarity != selectedRarity)
|
||||
if (!IsEligibleAtPhase(row, selectedRarity, displayPhaseIndex))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
cumulativeWeight += Mathf.Max(1, row.Weight);
|
||||
int rowWeight = row.GetWeight(selectedRarity);
|
||||
if (rowWeight <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
cumulativeWeight += rowWeight;
|
||||
if (randomWeight <= cumulativeWeight)
|
||||
{
|
||||
selectedRow = row;
|
||||
@@ -75,7 +94,7 @@ namespace GeometryTD.CustomComponent
|
||||
}
|
||||
}
|
||||
|
||||
selectedRow = _eligibleRowBuffer[_eligibleRowBuffer.Count - 1];
|
||||
selectedRow = fallbackRow;
|
||||
return selectedRow != null;
|
||||
}
|
||||
|
||||
@@ -99,7 +118,7 @@ namespace GeometryTD.CustomComponent
|
||||
continue;
|
||||
}
|
||||
|
||||
if (displayPhaseIndex < row.MinPhase || displayPhaseIndex > row.MaxPhase)
|
||||
if (!IsEligibleAtPhase(row, displayPhaseIndex))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
@@ -116,20 +135,35 @@ namespace GeometryTD.CustomComponent
|
||||
for (int i = 0; i < _eligibleRowBuffer.Count; i++)
|
||||
{
|
||||
DROutGameDropPool row = _eligibleRowBuffer[i];
|
||||
float curveWeight = GetRarityCurveWeight(row.Rarity, phaseT);
|
||||
if (curveWeight <= 0f)
|
||||
for (int rarityIndex = (int)RarityType.White; rarityIndex <= (int)RarityType.Red; rarityIndex++)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
RarityType rarity = (RarityType)rarityIndex;
|
||||
if (!IsEligibleAtPhase(row, rarity, displayPhaseIndex))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float rowWeight = Mathf.Max(1, row.Weight) * curveWeight;
|
||||
if (_rarityWeightBuffer.TryGetValue(row.Rarity, out float existingWeight))
|
||||
{
|
||||
_rarityWeightBuffer[row.Rarity] = existingWeight + rowWeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
_rarityWeightBuffer[row.Rarity] = rowWeight;
|
||||
int rowWeight = row.GetWeight(rarity);
|
||||
if (rowWeight <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float curveWeight = GetRarityCurveWeight(rarity, phaseT);
|
||||
if (curveWeight <= 0f)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
float rarityWeight = rowWeight * curveWeight;
|
||||
if (_rarityWeightBuffer.TryGetValue(rarity, out float existingWeight))
|
||||
{
|
||||
_rarityWeightBuffer[rarity] = existingWeight + rarityWeight;
|
||||
}
|
||||
else
|
||||
{
|
||||
_rarityWeightBuffer[rarity] = rarityWeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -163,6 +197,32 @@ namespace GeometryTD.CustomComponent
|
||||
return RarityType.None;
|
||||
}
|
||||
|
||||
private static bool IsEligibleAtPhase(DROutGameDropPool row, int displayPhaseIndex)
|
||||
{
|
||||
for (int rarityIndex = (int)RarityType.White; rarityIndex <= (int)RarityType.Red; rarityIndex++)
|
||||
{
|
||||
RarityType rarity = (RarityType)rarityIndex;
|
||||
if (IsEligibleAtPhase(row, rarity, displayPhaseIndex))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static bool IsEligibleAtPhase(DROutGameDropPool row, RarityType rarity, int displayPhaseIndex)
|
||||
{
|
||||
if (row.GetWeight(rarity) <= 0)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
int minPhase = row.GetMinPhase(rarity);
|
||||
int maxPhase = row.GetMaxPhase(rarity);
|
||||
return displayPhaseIndex >= minPhase && displayPhaseIndex <= maxPhase;
|
||||
}
|
||||
|
||||
private static float GetRarityCurveWeight(RarityType rarityType, float phaseT)
|
||||
{
|
||||
float hump = Mathf.Exp(-Mathf.Pow((phaseT - 0.35f) / 0.28f, 2f));
|
||||
@@ -183,4 +243,4 @@ namespace GeometryTD.CustomComponent
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+22
-7
@@ -183,16 +183,26 @@ namespace GeometryTD.CustomComponent
|
||||
droppedItem = null;
|
||||
DropPoolRoller dropPoolRoller = EnsureDropPoolRoller();
|
||||
int phaseIndex = Mathf.Max(1, displayPhaseIndex);
|
||||
if (!dropPoolRoller.TryRollRow(phaseIndex, themeType, out DROutGameDropPool selectedRow) || selectedRow == null)
|
||||
if (!dropPoolRoller.TryRollRow(
|
||||
phaseIndex,
|
||||
themeType,
|
||||
out DROutGameDropPool selectedRow,
|
||||
out RarityType selectedRarity) || selectedRow == null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return TryBuildDropItem(selectedRow, InventoryTagSourceType.Drop, AllocateDropTagOrdinal(), out droppedItem);
|
||||
return TryBuildDropItem(
|
||||
selectedRow,
|
||||
selectedRarity,
|
||||
InventoryTagSourceType.Drop,
|
||||
AllocateDropTagOrdinal(),
|
||||
out droppedItem);
|
||||
}
|
||||
|
||||
private bool TryBuildDropItem(
|
||||
DROutGameDropPool row,
|
||||
RarityType rarity,
|
||||
InventoryTagSourceType sourceType,
|
||||
int localOrdinal,
|
||||
out TowerCompItemData droppedItem)
|
||||
@@ -215,7 +225,7 @@ namespace GeometryTD.CustomComponent
|
||||
droppedItem = ComponentItemFactory.CreateMuzzle(
|
||||
config,
|
||||
AllocateTempInstanceId(),
|
||||
row.Rarity,
|
||||
rarity,
|
||||
CreateRandomContext(sourceType, localOrdinal, config.Id));
|
||||
return true;
|
||||
}
|
||||
@@ -231,7 +241,7 @@ namespace GeometryTD.CustomComponent
|
||||
droppedItem = ComponentItemFactory.CreateBearing(
|
||||
config,
|
||||
AllocateTempInstanceId(),
|
||||
row.Rarity,
|
||||
rarity,
|
||||
CreateRandomContext(sourceType, localOrdinal, config.Id));
|
||||
return true;
|
||||
}
|
||||
@@ -247,7 +257,7 @@ namespace GeometryTD.CustomComponent
|
||||
droppedItem = ComponentItemFactory.CreateBase(
|
||||
config,
|
||||
AllocateTempInstanceId(),
|
||||
row.Rarity,
|
||||
rarity,
|
||||
CreateRandomContext(sourceType, localOrdinal, config.Id));
|
||||
return true;
|
||||
}
|
||||
@@ -265,9 +275,14 @@ namespace GeometryTD.CustomComponent
|
||||
return _nextRewardTagOrdinal++;
|
||||
}
|
||||
|
||||
private TowerCompItemData BuildRewardCandidateItem(DROutGameDropPool row)
|
||||
private TowerCompItemData BuildRewardCandidateItem(DROutGameDropPool row, RarityType rarity)
|
||||
{
|
||||
if (!TryBuildDropItem(row, InventoryTagSourceType.Reward, AllocateRewardTagOrdinal(), out TowerCompItemData droppedItem))
|
||||
if (!TryBuildDropItem(
|
||||
row,
|
||||
rarity,
|
||||
InventoryTagSourceType.Reward,
|
||||
AllocateRewardTagOrdinal(),
|
||||
out TowerCompItemData droppedItem))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
+20
-7
@@ -19,7 +19,7 @@ namespace GeometryTD.CustomComponent
|
||||
int displayPhaseIndex,
|
||||
LevelThemeType themeType,
|
||||
int candidateCount,
|
||||
Func<DROutGameDropPool, TowerCompItemData> buildRewardItem)
|
||||
Func<DROutGameDropPool, RarityType, TowerCompItemData> buildRewardItem)
|
||||
{
|
||||
int resolvedCount = Mathf.Max(0, candidateCount);
|
||||
if (resolvedCount <= 0)
|
||||
@@ -28,7 +28,7 @@ namespace GeometryTD.CustomComponent
|
||||
}
|
||||
|
||||
List<TowerCompItemData> candidates = new List<TowerCompItemData>(resolvedCount);
|
||||
HashSet<int> selectedPoolRowIds = new HashSet<int>();
|
||||
HashSet<long> selectedPoolEntryKeys = new HashSet<long>();
|
||||
int maxAttempts = Mathf.Max(resolvedCount * 6, resolvedCount);
|
||||
int phaseIndex = Mathf.Max(1, displayPhaseIndex);
|
||||
|
||||
@@ -36,17 +36,21 @@ namespace GeometryTD.CustomComponent
|
||||
while (candidates.Count < resolvedCount && attempts < maxAttempts)
|
||||
{
|
||||
attempts++;
|
||||
if (!_dropPoolRoller.TryRollRow(phaseIndex, themeType, out DROutGameDropPool selectedRow) || selectedRow == null)
|
||||
if (!_dropPoolRoller.TryRollRow(
|
||||
phaseIndex,
|
||||
themeType,
|
||||
out DROutGameDropPool selectedRow,
|
||||
out RarityType selectedRarity) || selectedRow == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if (!selectedPoolRowIds.Add(selectedRow.Id))
|
||||
if (!selectedPoolEntryKeys.Add(BuildSelectionKey(selectedRow.Id, selectedRarity)))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
TowerCompItemData candidate = buildRewardItem(selectedRow);
|
||||
TowerCompItemData candidate = buildRewardItem(selectedRow, selectedRarity);
|
||||
if (candidate == null)
|
||||
{
|
||||
continue;
|
||||
@@ -59,12 +63,16 @@ namespace GeometryTD.CustomComponent
|
||||
while (candidates.Count < resolvedCount && attempts < maxAttempts)
|
||||
{
|
||||
attempts++;
|
||||
if (!_dropPoolRoller.TryRollRow(phaseIndex, themeType, out DROutGameDropPool selectedRow) || selectedRow == null)
|
||||
if (!_dropPoolRoller.TryRollRow(
|
||||
phaseIndex,
|
||||
themeType,
|
||||
out DROutGameDropPool selectedRow,
|
||||
out RarityType selectedRarity) || selectedRow == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
TowerCompItemData candidate = buildRewardItem(selectedRow);
|
||||
TowerCompItemData candidate = buildRewardItem(selectedRow, selectedRarity);
|
||||
if (candidate == null)
|
||||
{
|
||||
continue;
|
||||
@@ -75,5 +83,10 @@ namespace GeometryTD.CustomComponent
|
||||
|
||||
return candidates;
|
||||
}
|
||||
|
||||
private static long BuildSelectionKey(int rowId, RarityType rarity)
|
||||
{
|
||||
return ((long)rowId << 32) | (uint)rarity;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
using System;
|
||||
using GeometryTD.CustomUtility;
|
||||
using GeometryTD.Definition;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Runtime;
|
||||
|
||||
namespace GeometryTD.DataTable
|
||||
@@ -14,12 +16,11 @@ namespace GeometryTD.DataTable
|
||||
public override int Id => m_Id;
|
||||
|
||||
public LevelThemeType LevelThemeType { get; private set; }
|
||||
public RarityType Rarity { get; private set; }
|
||||
public string ItemType { get; private set; }
|
||||
public int ItemId { get; private set; }
|
||||
public int Weight { get; private set; }
|
||||
public int MinPhase { get; private set; }
|
||||
public int MaxPhase { get; private set; }
|
||||
public int[] Weights { get; private set; }
|
||||
public int[] MinPhase { get; private set; }
|
||||
public int[] MaxPhase { get; private set; }
|
||||
|
||||
public override bool ParseDataRow(string dataRowString, object userData)
|
||||
{
|
||||
@@ -34,31 +35,110 @@ namespace GeometryTD.DataTable
|
||||
m_Id = int.Parse(columnStrings[index++]);
|
||||
index++;
|
||||
LevelThemeType = EnumUtility<LevelThemeType>.Get(columnStrings[index++]);
|
||||
Rarity = EnumUtility<RarityType>.Get(columnStrings[index++]);
|
||||
ItemType = columnStrings[index++];
|
||||
ItemId = ParseIntOrDefault(columnStrings[index++], 0);
|
||||
Weight = ParseIntOrDefault(columnStrings[index++], 1);
|
||||
MinPhase = ParseIntOrDefault(columnStrings[index++], 1);
|
||||
MaxPhase = ParseIntOrDefault(columnStrings[index++], int.MaxValue);
|
||||
|
||||
if (Weight <= 0)
|
||||
{
|
||||
Weight = 1;
|
||||
}
|
||||
|
||||
if (MinPhase <= 0)
|
||||
{
|
||||
MinPhase = 1;
|
||||
}
|
||||
|
||||
if (MaxPhase < MinPhase)
|
||||
{
|
||||
MaxPhase = MinPhase;
|
||||
}
|
||||
Weights = ParseWeights(columnStrings[index++]);
|
||||
MinPhase = ParsePhases(columnStrings[index++], 1);
|
||||
MaxPhase = ParsePhases(columnStrings[index++], int.MaxValue);
|
||||
NormalizePhaseRanges();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public int GetWeight(RarityType rarity)
|
||||
{
|
||||
int index = Mathf.Clamp((int)rarity - 1, 0, RarityCount - 1);
|
||||
return Weights[index];
|
||||
}
|
||||
|
||||
public int GetMinPhase(RarityType rarity)
|
||||
{
|
||||
int index = Mathf.Clamp((int)rarity - 1, 0, RarityCount - 1);
|
||||
return MinPhase[index];
|
||||
}
|
||||
|
||||
public int GetMaxPhase(RarityType rarity)
|
||||
{
|
||||
int index = Mathf.Clamp((int)rarity - 1, 0, RarityCount - 1);
|
||||
return MaxPhase[index];
|
||||
}
|
||||
|
||||
private static int[] ParseWeights(string raw)
|
||||
{
|
||||
if (!raw.StartsWith('[') || !raw.EndsWith(']'))
|
||||
{
|
||||
throw new ArgumentException("Weights must be enclosed in square brackets.");
|
||||
}
|
||||
|
||||
if (raw.Length == 2)
|
||||
{
|
||||
return new int[RarityCount];
|
||||
}
|
||||
|
||||
string[] raws = raw.Substring(1, raw.Length - 2).Split(",");
|
||||
if (raws.Length != RarityCount)
|
||||
{
|
||||
throw new ArgumentException($"Weights must contain exactly {RarityCount} values.");
|
||||
}
|
||||
|
||||
int[] weights = new int[RarityCount];
|
||||
for (int i = 0; i < raws.Length; i++)
|
||||
{
|
||||
weights[i] = Mathf.Max(0, int.Parse(raws[i]));
|
||||
}
|
||||
|
||||
return weights;
|
||||
}
|
||||
|
||||
private static int[] ParsePhases(string raw, int fallbackValue)
|
||||
{
|
||||
if (!raw.StartsWith('[') || !raw.EndsWith(']'))
|
||||
{
|
||||
throw new ArgumentException("Phase ranges must be enclosed in square brackets.");
|
||||
}
|
||||
|
||||
if (raw.Length == 2)
|
||||
{
|
||||
int[] fallbackValues = new int[RarityCount];
|
||||
for (int i = 0; i < fallbackValues.Length; i++)
|
||||
{
|
||||
fallbackValues[i] = fallbackValue;
|
||||
}
|
||||
|
||||
return fallbackValues;
|
||||
}
|
||||
|
||||
string[] raws = raw.Substring(1, raw.Length - 2).Split(",");
|
||||
if (raws.Length != RarityCount)
|
||||
{
|
||||
throw new ArgumentException($"Phase ranges must contain exactly {RarityCount} values.");
|
||||
}
|
||||
|
||||
int[] phases = new int[RarityCount];
|
||||
for (int i = 0; i < raws.Length; i++)
|
||||
{
|
||||
phases[i] = int.Parse(raws[i]);
|
||||
}
|
||||
|
||||
return phases;
|
||||
}
|
||||
|
||||
private void NormalizePhaseRanges()
|
||||
{
|
||||
for (int i = 0; i < RarityCount; i++)
|
||||
{
|
||||
if (MinPhase[i] <= 0)
|
||||
{
|
||||
MinPhase[i] = 1;
|
||||
}
|
||||
|
||||
if (MaxPhase[i] < MinPhase[i])
|
||||
{
|
||||
MaxPhase[i] = MinPhase[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static int ParseIntOrDefault(string raw, int fallbackValue)
|
||||
{
|
||||
if (int.TryParse(raw, out int parsed))
|
||||
@@ -68,5 +148,7 @@ namespace GeometryTD.DataTable
|
||||
|
||||
return fallbackValue;
|
||||
}
|
||||
|
||||
private const int RarityCount = (int)RarityType.Red;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -270,7 +270,7 @@ namespace GeometryTD.CustomUtility
|
||||
AttackPropertyType.None => "无效",
|
||||
AttackPropertyType.Physics => "<color=#ffff00ff>物理</color>", //yellow
|
||||
AttackPropertyType.Fire => "<color=#ff0000ff>火</color>", //red
|
||||
AttackPropertyType.Water => "<color=#00ffffff>水/color>", //cyan
|
||||
AttackPropertyType.Water => "<color=#00ffffff>水</color>", //cyan
|
||||
AttackPropertyType.Earth => "<color=#00ff00ff>自然</color>", //lime
|
||||
AttackPropertyType.Poison => "<color=#008000ff>毒</color>", //green
|
||||
AttackPropertyType.Ice => "<color=#0000a0ff>冰</color>", //darkblue
|
||||
|
||||
Reference in New Issue
Block a user