feat: 新增带通量控制、队列孵化和品质系统的督虫生成组件及相关UI。

This commit is contained in:
2025-12-23 17:20:06 +08:00
parent fd42bb9fe5
commit eab0afb1a0
10 changed files with 186 additions and 102 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -8,18 +8,22 @@ using Verse.AI;
namespace ArachnaeSwarm namespace ArachnaeSwarm
{ {
// 带状态和品质的物品订单(通量品质系统 // 带状态和品质的物品订单(与 Building_Ootheca 统一的累计进度模式
public class QueuedItemOrder : IExposable public class QueuedItemOrder : IExposable
{ {
public ProcessDef process; public ProcessDef process;
public string tempThingDefName; public string tempThingDefName;
public OrderStatus status = OrderStatus.WaitingForLarva; public OrderStatus status = OrderStatus.WaitingForLarva;
public int productionUntilTick = -1;
// 进度系统(累计模式,与 Building_Ootheca 统一)
public float incubationProgress = 0f;
public float incubationDuration = 0f;
// 通量品质系统 // 通量品质系统
public float qualityProgress = 0f; public float qualityProgress = 0f;
public float qualityTotal = 0f; public float qualityTotal = 0f;
public float ProgressPercent => incubationDuration > 0 ? incubationProgress / incubationDuration : 0f;
public float QualityPercent => qualityTotal > 0 ? qualityProgress / qualityTotal : 0f; public float QualityPercent => qualityTotal > 0 ? qualityProgress / qualityTotal : 0f;
public void ExposeData() public void ExposeData()
@@ -30,7 +34,8 @@ namespace ArachnaeSwarm
} }
Scribe_Values.Look(ref tempThingDefName, "thingDefName"); Scribe_Values.Look(ref tempThingDefName, "thingDefName");
Scribe_Values.Look(ref status, "status", OrderStatus.WaitingForLarva); Scribe_Values.Look(ref status, "status", OrderStatus.WaitingForLarva);
Scribe_Values.Look(ref productionUntilTick, "productionUntilTick", -1); Scribe_Values.Look(ref incubationProgress, "incubationProgress", 0f);
Scribe_Values.Look(ref incubationDuration, "incubationDuration", 0f);
Scribe_Values.Look(ref qualityProgress, "qualityProgress", 0f); Scribe_Values.Look(ref qualityProgress, "qualityProgress", 0f);
Scribe_Values.Look(ref qualityTotal, "qualityTotal", 0f); Scribe_Values.Look(ref qualityTotal, "qualityTotal", 0f);
} }
@@ -159,10 +164,8 @@ namespace ArachnaeSwarm
private float GetProgress(QueuedItemOrder order) private float GetProgress(QueuedItemOrder order)
{ {
if (order.status != OrderStatus.Incubating || order.process == null) return 0f; // 使用累计进度模式
int totalTicks = order.process.productionTicks; return order.ProgressPercent;
int elapsed = totalTicks - order.productionUntilTick;
return totalTicks > 0 ? Mathf.Clamp01((float)elapsed / totalTicks) : 0f;
} }
private QualityCategory GetQualityCategory(QueuedItemOrder order) private QualityCategory GetQualityCategory(QueuedItemOrder order)
@@ -253,8 +256,10 @@ namespace ArachnaeSwarm
if (waitingOrder != null) if (waitingOrder != null)
{ {
waitingOrder.status = OrderStatus.Incubating; waitingOrder.status = OrderStatus.Incubating;
waitingOrder.productionUntilTick = waitingOrder.process.productionTicks; // 使用累计进度模式(与 Building_Ootheca 统一)
waitingOrder.qualityTotal = waitingOrder.process.productionTicks; waitingOrder.incubationDuration = waitingOrder.process.productionTicks;
waitingOrder.incubationProgress = 0f;
waitingOrder.qualityTotal = waitingOrder.incubationDuration;
waitingOrder.qualityProgress = 0f; waitingOrder.qualityProgress = 0f;
} }
assignedLarvae.Remove(larva); assignedLarvae.Remove(larva);
@@ -286,50 +291,43 @@ namespace ArachnaeSwarm
CalculateAutoFlux(); CalculateAutoFlux();
} }
// 消耗燃料 // 消耗燃料(只有活性>0时
if (IsIncubating && FuelComp != null && neutronFlux > 0.01f) if (IsIncubating && FuelComp != null && neutronFlux > 0.01f)
{ {
float fuelPerTick = (80f * FluxEfficiency * IncubatingCount) / 60000f; float fuelPerTick = (80f * FluxEfficiency * IncubatingCount) / 60000f;
FuelComp.ConsumeFuel(fuelPerTick); FuelComp.ConsumeFuel(fuelPerTick);
} }
// 处理正在生产的订单 // 进度和品质处理(与 Building_Ootheca 统一)
if (hasFuel && !IsDormant) foreach (var order in orders.Where(o => o.status == OrderStatus.Incubating))
{ {
if (IsDormant)
{
// 休眠时:不推进进度,品质衰减
float qualityDecay = (order.qualityTotal * 0.1f) / 60000f;
order.qualityProgress = Mathf.Max(0f, order.qualityProgress - qualityDecay);
}
else
{
// 正常工作:推进进度和品质
float speedFactor = 1f + (FacilitiesComp?.GetStatOffset(StatDef.Named("ARA_IncubationSpeedFactor")) ?? 0f); float speedFactor = 1f + (FacilitiesComp?.GetStatOffset(StatDef.Named("ARA_IncubationSpeedFactor")) ?? 0f);
float fluxSpeed = speedFactor * FluxEfficiency * 5f; float fluxSpeed = speedFactor * FluxEfficiency * 5f;
foreach (var order in orders.Where(o => o.status == OrderStatus.Incubating && o.productionUntilTick > 0)) // 进度推进(累计模式)
{ order.incubationProgress += fluxSpeed;
// 进度推进
float extraProgress = fluxSpeed - 1f;
if (extraProgress > 0)
{
int extraTicks = Mathf.FloorToInt(extraProgress);
if (Rand.Value < (extraProgress - extraTicks)) extraTicks++;
order.productionUntilTick = Mathf.Max(0, order.productionUntilTick - extraTicks);
}
// 通量品质系统:低通量时品质增长快 // 品质增长 - 低活性时品质增长
float qualityBonus = 1f + (1f - neutronFlux) * 0.5f; float qualityBonus = 1f + (1f - neutronFlux) * 0.5f;
float qualityGain = speedFactor * qualityBonus; float qualityGain = speedFactor * qualityBonus;
order.qualityProgress = Mathf.Min(order.qualityProgress + qualityGain, order.qualityTotal); order.qualityProgress = Mathf.Min(order.qualityProgress + qualityGain, order.qualityTotal);
} }
} }
else if (IsDormant)
{
// 休眠时品质下降
foreach (var order in orders.Where(o => o.status == OrderStatus.Incubating))
{
float qualityDecay = (order.qualityTotal * 0.1f) / 60000f;
order.qualityProgress = Mathf.Max(0f, order.qualityProgress - qualityDecay);
}
}
// 完成订单 // 完成检查(进度达到持续时间时完成)
orders.RemoveAll(order => orders.RemoveAll(order =>
{ {
if (order.status == OrderStatus.Incubating && order.productionUntilTick == 0) if (order.status == OrderStatus.Incubating &&
order.incubationProgress >= order.incubationDuration)
{ {
FinishProduction(order); FinishProduction(order);
return true; return true;
@@ -447,17 +445,23 @@ namespace ArachnaeSwarm
var options = new List<FloatMenuOption>(); var options = new List<FloatMenuOption>();
foreach (var process in Processes) foreach (var process in Processes)
{ {
Texture2D icon = process.thingDef?.uiIcon;
string label = process.thingDef.LabelCap;
if (process.requiredResearch != null && !process.requiredResearch.IsFinished) if (process.requiredResearch != null && !process.requiredResearch.IsFinished)
{ {
options.Add(new FloatMenuOption(process.thingDef.LabelCap + " (需要研究: " + process.requiredResearch.LabelCap + ")", null)); label += $" (需要研究: {process.requiredResearch.LabelCap})";
options.Add(new FloatMenuOption(label, null, icon, Color.white));
} }
else else
{ {
var capturedProcess = process; var capturedProcess = process;
options.Add(new FloatMenuOption(process.thingDef.LabelCap, () => { float days = capturedProcess.productionTicks / 60000f;
label += $" ({days:F1}天)";
options.Add(new FloatMenuOption(label, () => {
AddOrder(capturedProcess); AddOrder(capturedProcess);
if (orders.Count < Props.productionQueueLimit) ShowOrderMenu(); if (orders.Count < Props.productionQueueLimit) ShowOrderMenu();
})); }, icon, Color.white));
} }
} }

View File

@@ -28,21 +28,26 @@ namespace ArachnaeSwarm
// 带状态和品质的督虫订单 // 带状态和品质的督虫订单
public class QueuedPawnOrder : IExposable public class QueuedPawnOrder : IExposable
{ {
public IncubationConfig config; // 使用 IncubationConfig 而不是 QueuedPawnSpawnEntry public IncubationConfig config;
public OrderStatus status = OrderStatus.WaitingForLarva; public OrderStatus status = OrderStatus.WaitingForLarva;
public int spawnUntilTick = -1;
// 进度系统(与 Building_Ootheca 统一)
public float incubationProgress = 0f;
public float incubationDuration = 0f;
// 品质系统 // 品质系统
public float qualityProgress = 0f; public float qualityProgress = 0f;
public float qualityTotal = 0f; public float qualityTotal = 0f;
public float ProgressPercent => incubationDuration > 0 ? incubationProgress / incubationDuration : 0f;
public float QualityPercent => qualityTotal > 0 ? qualityProgress / qualityTotal : 0f; public float QualityPercent => qualityTotal > 0 ? qualityProgress / qualityTotal : 0f;
public void ExposeData() public void ExposeData()
{ {
Scribe_Deep.Look(ref config, "config"); Scribe_Deep.Look(ref config, "config");
Scribe_Values.Look(ref status, "status", OrderStatus.WaitingForLarva); Scribe_Values.Look(ref status, "status", OrderStatus.WaitingForLarva);
Scribe_Values.Look(ref spawnUntilTick, "spawnUntilTick", -1); Scribe_Values.Look(ref incubationProgress, "incubationProgress", 0f);
Scribe_Values.Look(ref incubationDuration, "incubationDuration", 0f);
Scribe_Values.Look(ref qualityProgress, "qualityProgress", 0f); Scribe_Values.Look(ref qualityProgress, "qualityProgress", 0f);
Scribe_Values.Look(ref qualityTotal, "qualityTotal", 0f); Scribe_Values.Look(ref qualityTotal, "qualityTotal", 0f);
} }
@@ -154,8 +159,8 @@ namespace ArachnaeSwarm
status = order.status, status = order.status,
progress = prodProgress, progress = prodProgress,
qualityProgress = order.QualityPercent, qualityProgress = order.QualityPercent,
remainingTime = order.status == OrderStatus.Incubating && order.spawnUntilTick > 0 remainingTime = order.status == OrderStatus.Incubating
? (order.spawnUntilTick - Find.TickManager.TicksGame).ToStringTicksToPeriod() ? ((int)GetRemainingTicks(order)).ToStringTicksToPeriod()
: "等待中", : "等待中",
estimatedQuality = GetEstimatedQuality(order.QualityPercent) estimatedQuality = GetEstimatedQuality(order.QualityPercent)
}); });
@@ -165,11 +170,17 @@ namespace ArachnaeSwarm
private float GetProgress(QueuedPawnOrder order) private float GetProgress(QueuedPawnOrder order)
{ {
if (order.status != OrderStatus.Incubating || order.spawnUntilTick <= 0 || order.config == null) return 0f; // 使用累计进度模式
int totalTicks = Mathf.RoundToInt(order.config.daysRequired * 60000); return order.ProgressPercent;
int startTick = order.spawnUntilTick - totalTicks; }
int elapsed = Find.TickManager.TicksGame - startTick;
return totalTicks > 0 ? Mathf.Clamp01((float)elapsed / totalTicks) : 0f; private float GetRemainingTicks(QueuedPawnOrder order)
{
if (order.status != OrderStatus.Incubating || order.incubationDuration <= 0) return 0f;
float remaining = order.incubationDuration - order.incubationProgress;
float speedFactor = 1f + (FacilitiesComp?.GetStatOffset(StatDef.Named("ARA_IncubationSpeedFactor")) ?? 0f);
float fluxSpeed = speedFactor * FluxEfficiency * 5f;
return fluxSpeed > 0 ? remaining / fluxSpeed : remaining;
} }
private string GetEstimatedQuality(float qualityPercent) private string GetEstimatedQuality(float qualityPercent)
@@ -260,9 +271,10 @@ namespace ArachnaeSwarm
if (waitingOrder != null && waitingOrder.config != null) if (waitingOrder != null && waitingOrder.config != null)
{ {
waitingOrder.status = OrderStatus.Incubating; waitingOrder.status = OrderStatus.Incubating;
int totalTicks = Mathf.RoundToInt(waitingOrder.config.daysRequired * 60000); // 使用累计进度模式(与 Building_Ootheca 统一)
waitingOrder.spawnUntilTick = Find.TickManager.TicksGame + totalTicks; waitingOrder.incubationDuration = waitingOrder.config.daysRequired * 60000f;
waitingOrder.qualityTotal = totalTicks; waitingOrder.incubationProgress = 0f;
waitingOrder.qualityTotal = waitingOrder.incubationDuration;
waitingOrder.qualityProgress = 0f; waitingOrder.qualityProgress = 0f;
} }
assignedLarvae.Remove(larva); assignedLarvae.Remove(larva);
@@ -293,38 +305,43 @@ namespace ArachnaeSwarm
CalculateAutoFlux(); CalculateAutoFlux();
} }
// 消耗燃料(只有活性>0时
if (IsIncubating && FuelComp != null && neutronFlux > 0.01f) if (IsIncubating && FuelComp != null && neutronFlux > 0.01f)
{ {
float fuelPerTick = (50f * FluxEfficiency * IncubatingCount) / 60000f; float fuelPerTick = (50f * FluxEfficiency * IncubatingCount) / 60000f;
FuelComp.ConsumeFuel(fuelPerTick); FuelComp.ConsumeFuel(fuelPerTick);
} }
if (hasFuel && !IsDormant) // 进度和品质处理(与 Building_Ootheca 统一)
foreach (var order in orders.Where(o => o.status == OrderStatus.Incubating))
{ {
if (IsDormant)
{
// 休眠时:不推进进度,品质衰减
float qualityDecay = (order.qualityTotal * 0.1f) / 60000f;
order.qualityProgress = Mathf.Max(0f, order.qualityProgress - qualityDecay);
}
else
{
// 正常工作:推进进度和品质
float speedFactor = 1f + (FacilitiesComp?.GetStatOffset(StatDef.Named("ARA_IncubationSpeedFactor")) ?? 0f); float speedFactor = 1f + (FacilitiesComp?.GetStatOffset(StatDef.Named("ARA_IncubationSpeedFactor")) ?? 0f);
float fluxSpeed = speedFactor * FluxEfficiency * 5f; float fluxSpeed = speedFactor * FluxEfficiency * 5f;
foreach (var order in orders.Where(o => o.status == OrderStatus.Incubating)) // 进度推进(累计模式)
{ order.incubationProgress += fluxSpeed;
float extraProgress = fluxSpeed - 1f;
if (extraProgress > 0)
{
int extraTicks = Mathf.FloorToInt(extraProgress);
if (Rand.Value < (extraProgress - extraTicks)) extraTicks++;
order.spawnUntilTick -= extraTicks;
}
// 品质增长 - 低活性时品质增长更快
float qualityBonus = 1f + (1f - neutronFlux) * 0.5f; float qualityBonus = 1f + (1f - neutronFlux) * 0.5f;
float qualityGain = speedFactor * qualityBonus; float qualityGain = speedFactor * qualityBonus;
order.qualityProgress = Mathf.Min(order.qualityProgress + qualityGain, order.qualityTotal); order.qualityProgress = Mathf.Min(order.qualityProgress + qualityGain, order.qualityTotal);
} }
} }
// 完成检查(进度达到持续时间时完成)
orders.RemoveAll(order => orders.RemoveAll(order =>
{ {
if (order.status == OrderStatus.Incubating && if (order.status == OrderStatus.Incubating &&
order.spawnUntilTick > 0 && order.incubationProgress >= order.incubationDuration)
Find.TickManager.TicksGame >= order.spawnUntilTick)
{ {
CompleteOrder(order); CompleteOrder(order);
return true; return true;

View File

@@ -1,8 +1,9 @@
using RimWorld; using RimWorld;
using Verse; using Verse;
using Verse.Sound; // Ensure this is present using Verse.Sound;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text;
namespace ArachnaeSwarm namespace ArachnaeSwarm
{ {
@@ -73,5 +74,35 @@ namespace ArachnaeSwarm
!(gizmo is Designator_Build designator && designator.PlacingDef == ThingDefOf.Hopper) !(gizmo is Designator_Build designator && designator.PlacingDef == ThingDefOf.Hopper)
); );
} }
// 覆盖 GetInspectString 以隐藏电力和进料口相关的提示
public override string GetInspectString()
{
StringBuilder sb = new StringBuilder();
// 只显示燃料信息,不显示电力相关信息
if (nutritionComp != null && dispenserProps != null)
{
float fuel = nutritionComp.Fuel;
float cost = dispenserProps.nutritionCostPerDispense;
int mealsAvailable = (int)(fuel / cost);
sb.AppendLine($"可制作: {mealsAvailable} 份");
}
// 添加其他 Comp 的信息,但排除 CompPower 类型
foreach (var comp in AllComps)
{
// 跳过电力相关的组件
if (comp is CompPower) continue;
string compString = comp.CompInspectStringExtra();
if (!compString.NullOrEmpty())
{
sb.AppendLine(compString);
}
}
return sb.ToString().TrimEndNewlines();
}
} }
} }

View File

@@ -2,6 +2,7 @@
using RimWorld; using RimWorld;
using Verse; using Verse;
using System.Linq; using System.Linq;
using System.Collections.Generic;
namespace ArachnaeSwarm namespace ArachnaeSwarm
{ {
@@ -167,4 +168,20 @@ namespace ArachnaeSwarm
return bestDispenser; return bestDispenser;
} }
} }
/// <summary>
/// Patch to exclude our custom dispenser from the "needs hopper" alert.
/// The Alert checks all ThingsInGroup(ThingRequestGroup.FoodDispenser) and warns if they don't have adjacent hoppers.
/// We filter out our custom dispenser from the result.
/// </summary>
[HarmonyPatch(typeof(Alert_PasteDispenserNeedsHopper), "BadDispensers", MethodType.Getter)]
public static class Patch_AlertPasteDispenserNeedsHopper
{
[HarmonyPostfix]
public static void Postfix(ref List<Thing> __result)
{
// Remove all instances of our custom dispenser from the "bad" list
__result.RemoveAll(t => t is Building_ARANutrientDispenser);
}
}
} }

View File

@@ -60,7 +60,7 @@ namespace ArachnaeSwarm
else if (config != null) else if (config != null)
title = config.thingDef.LabelCap; title = config.thingDef.LabelCap;
else else
title = "选择孵化目标..."; title = "选择生产目标...";
// 标题按钮(只有非孵化状态可点击) // 标题按钮(只有非孵化状态可点击)
bool canSwitch = !isIncubating && !hasLarva && building.EquipmentIncubatorData?.IncubationConfigs?.Count > 0; bool canSwitch = !isIncubating && !hasLarva && building.EquipmentIncubatorData?.IncubationConfigs?.Count > 0;
@@ -225,12 +225,8 @@ namespace ArachnaeSwarm
else else
{ {
sb.AppendLine("【未选择目标】"); sb.AppendLine("【未选择目标】");
sb.AppendLine("点击上方标题选择孵化目标"); sb.AppendLine("点击上方标题选择生产目标");
} }
sb.AppendLine();
sb.AppendLine("当前速度加成: " + building.SpeedMultiplier.ToStringPercent());
sb.AppendLine("当前质量加成: " + building.QualityMultiplier.ToStringPercent());
} }
return sb.ToString().TrimEndNewlines(); return sb.ToString().TrimEndNewlines();

View File

@@ -94,15 +94,27 @@ namespace ArachnaeSwarm
// === 订单列表 === // === 订单列表 ===
if (orderCount > 0) if (orderCount > 0)
{ {
float listHeight = Mathf.Min(visibleCount, orderCount) * (BarHeight + Spacing + 14f); float itemHeight = BarHeight + Spacing + 14f;
Rect listRect = new Rect(innerRect.x, curY, innerRect.width, listHeight); float listHeight = Mathf.Min(visibleCount, orderCount) * itemHeight;
float totalContentHeight = orderCount * itemHeight;
bool needsScrollbar = orderCount > MaxVisibleOrders;
if (orderCount > MaxVisibleOrders && Mouse.IsOver(listRect)) float scrollbarWidth = needsScrollbar ? 12f : 0f;
Rect listRect = new Rect(innerRect.x, curY, innerRect.width - scrollbarWidth, listHeight);
// 滚动条
if (needsScrollbar)
{ {
float scrollMax = (orderCount - MaxVisibleOrders) * (BarHeight + Spacing + 14f); Rect scrollbarRect = new Rect(innerRect.xMax - scrollbarWidth, curY, scrollbarWidth, listHeight);
scrollPosition -= Event.current.delta.y * 0.5f; float scrollMax = totalContentHeight - listHeight;
scrollPosition = GUI.VerticalScrollbar(scrollbarRect, scrollPosition, listHeight, 0f, totalContentHeight);
if (Mouse.IsOver(listRect))
{
scrollPosition -= Event.current.delta.y * 1.5f;
scrollPosition = Mathf.Clamp(scrollPosition, 0f, scrollMax); scrollPosition = Mathf.Clamp(scrollPosition, 0f, scrollMax);
} }
}
GUI.BeginClip(listRect); GUI.BeginClip(listRect);
float drawY = -scrollPosition; float drawY = -scrollPosition;
@@ -110,14 +122,13 @@ namespace ArachnaeSwarm
for (int i = 0; i < orderCount; i++) for (int i = 0; i < orderCount; i++)
{ {
var order = orders[i]; var order = orders[i];
float itemHeight = BarHeight + 14f; Rect itemRect = new Rect(0, drawY, listRect.width, itemHeight - Spacing);
Rect itemRect = new Rect(0, drawY, listRect.width, itemHeight);
if (itemRect.yMax > 0 && itemRect.y < listRect.height) if (itemRect.yMax > 0 && itemRect.y < listRect.height)
{ {
DrawOrderItem(itemRect, order, i); DrawOrderItem(itemRect, order, i);
} }
drawY += itemHeight + Spacing; drawY += itemHeight;
} }
GUI.EndClip(); GUI.EndClip();

View File

@@ -224,10 +224,6 @@ namespace ArachnaeSwarm
sb.AppendLine("【未选择目标】"); sb.AppendLine("【未选择目标】");
sb.AppendLine("点击上方标题选择孵化目标"); sb.AppendLine("点击上方标题选择孵化目标");
} }
sb.AppendLine();
sb.AppendLine("当前速度加成: " + ootheca.SpeedMultiplier.ToStringPercent());
sb.AppendLine("当前质量加成: " + ootheca.QualityMultiplier.ToStringPercent());
} }
return sb.ToString().TrimEndNewlines(); return sb.ToString().TrimEndNewlines();

View File

@@ -97,16 +97,29 @@ namespace ArachnaeSwarm
// === 订单列表 === // === 订单列表 ===
if (orderCount > 0) if (orderCount > 0)
{ {
float listHeight = Mathf.Min(visibleCount, orderCount) * (BarHeight + Spacing + 14f); float itemHeight = BarHeight + Spacing + 14f;
Rect listRect = new Rect(innerRect.x, curY, innerRect.width, listHeight); float listHeight = Mathf.Min(visibleCount, orderCount) * itemHeight;
float totalContentHeight = orderCount * itemHeight;
bool needsScrollbar = orderCount > MaxVisibleOrders;
// 滚动支持 float scrollbarWidth = needsScrollbar ? 12f : 0f;
if (orderCount > MaxVisibleOrders && Mouse.IsOver(listRect)) Rect listRect = new Rect(innerRect.x, curY, innerRect.width - scrollbarWidth, listHeight);
Rect viewRect = new Rect(0, 0, listRect.width, totalContentHeight);
// 滚动条区域
if (needsScrollbar)
{ {
float scrollMax = (orderCount - MaxVisibleOrders) * (BarHeight + Spacing + 14f); Rect scrollbarRect = new Rect(innerRect.xMax - scrollbarWidth, curY, scrollbarWidth, listHeight);
scrollPosition -= Event.current.delta.y * 0.5f; float scrollMax = totalContentHeight - listHeight;
scrollPosition = GUI.VerticalScrollbar(scrollbarRect, scrollPosition, listHeight, 0f, totalContentHeight);
// 也支持滚轮
if (Mouse.IsOver(listRect))
{
scrollPosition -= Event.current.delta.y * 1.5f;
scrollPosition = Mathf.Clamp(scrollPosition, 0f, scrollMax); scrollPosition = Mathf.Clamp(scrollPosition, 0f, scrollMax);
} }
}
GUI.BeginClip(listRect); GUI.BeginClip(listRect);
float drawY = -scrollPosition; float drawY = -scrollPosition;
@@ -114,14 +127,13 @@ namespace ArachnaeSwarm
for (int i = 0; i < orderCount; i++) for (int i = 0; i < orderCount; i++)
{ {
var order = orders[i]; var order = orders[i];
float itemHeight = BarHeight + 14f; Rect itemRect = new Rect(0, drawY, listRect.width, itemHeight - Spacing);
Rect itemRect = new Rect(0, drawY, listRect.width, itemHeight);
if (itemRect.yMax > 0 && itemRect.y < listRect.height) if (itemRect.yMax > 0 && itemRect.y < listRect.height)
{ {
DrawOrderItem(itemRect, order, i); DrawOrderItem(itemRect, order, i);
} }
drawY += itemHeight + Spacing; drawY += itemHeight;
} }
GUI.EndClip(); GUI.EndClip();