Files
ArachnaeSwarm/Source/ArachnaeSwarm/Building_Comps/ARA_NutrientNetwork/CompLineDrawer.cs
Tourswen 221b62680a 我去
2025-10-04 12:20:26 +08:00

173 lines
5.8 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using RimWorld;
using Verse;
using UnityEngine;
using System.Collections.Generic;
using System.Linq;
namespace ArachnaeSwarm
{
public class CompProperties_LineDrawer : CompProperties
{
public List<ThingDef> linkableBuildings;
public float maxDistance = 999f;
public string lineTexturePath = "Things/Special/Power/Wire";
public CompProperties_LineDrawer()
{
compClass = typeof(CompLineDrawer);
}
}
public class CompLineDrawer : ThingComp
{
private CompProperties_LineDrawer Props => (CompProperties_LineDrawer)props;
private List<Thing> linkedBuildings = new List<Thing>();
private Material lineMat;
private Material LineMat
{
get
{
if (lineMat == null)
{
lineMat = MaterialPool.MatFrom(Props.lineTexturePath, ShaderDatabase.Transparent, Color.white);
}
return lineMat;
}
}
public override void PostSpawnSetup(bool respawningAfterLoad)
{
base.PostSpawnSetup(respawningAfterLoad);
FindAndLinkBuildings();
}
public override void CompTick()
{
base.CompTick();
if (parent.IsHashIntervalTick(120))
{
FindAndLinkBuildings();
}
}
private void FindAndLinkBuildings()
{
int previousCount = linkedBuildings.Count;
linkedBuildings.Clear();
if (Props.linkableBuildings.NullOrEmpty()) return;
var potentialTargets = parent.Map.listerBuildings.allBuildingsColonist.Where(b =>
b != parent &&
Props.linkableBuildings.Contains(b.def) &&
parent.Position.DistanceTo(b.Position) <= Props.maxDistance &&
HasLineOfSight(parent, b) // 新增:检查视线
);
linkedBuildings.AddRange(potentialTargets);
if (linkedBuildings.Count != previousCount)
{
parent.Map.mapDrawer.MapMeshDirty(parent.Position, MapMeshFlagDefOf.Things, true, false);
}
}
// 修复后的方法:检查两点之间是否有墙体遮挡
private bool HasLineOfSight(Thing from, Thing to)
{
IntVec3 fromPos = from.Position;
IntVec3 toPos = to.Position;
// 如果两个建筑在同一位置直接返回true
if (fromPos == toPos) return true;
// 使用更兼容的视线检查方法
if (!GenSight.LineOfSight(fromPos, toPos, parent.Map))
{
return false;
}
// 额外检查:确保路径上没有阻挡视线的建筑
foreach (IntVec3 cell in GetLineCells(fromPos, toPos))
{
// 跳过起点和终点
if (cell == fromPos || cell == toPos) continue;
// 检查该单元格是否有阻挡视线的建筑
List<Thing> things = parent.Map.thingGrid.ThingsListAt(cell);
foreach (Thing thing in things)
{
// 如果是建筑且阻挡视线
if (thing.def.passability == Traversability.Impassable &&
thing.def.category == ThingCategory.Building &&
!IsPassableBuilding(thing.def)) // 排除可通行的建筑类型
{
return false;
}
}
}
return true;
}
// 获取两点之间的直线上的所有单元格
private IEnumerable<IntVec3> GetLineCells(IntVec3 start, IntVec3 end)
{
// 使用简单的Bresenham直线算法
int x0 = start.x;
int y0 = start.z;
int x1 = end.x;
int y1 = end.z;
int dx = Mathf.Abs(x1 - x0);
int dy = Mathf.Abs(y1 - y0);
int sx = x0 < x1 ? 1 : -1;
int sy = y0 < y1 ? 1 : -1;
int err = dx - dy;
while (true)
{
yield return new IntVec3(x0, 0, y0);
if (x0 == x1 && y0 == y1) break;
int e2 = 2 * err;
if (e2 > -dy)
{
err -= dy;
x0 += sx;
}
if (e2 < dx)
{
err += dx;
y0 += sy;
}
}
}
// 检查建筑类型是否允许管线通过
private bool IsPassableBuilding(ThingDef def)
{
// 门、栅栏门等可通行的建筑不算阻挡
return def.IsDoor ||
def.passability == Traversability.PassThroughOnly ||
def.passability == Traversability.Standable;
}
public override void PostPrintOnto(SectionLayer layer)
{
base.PostPrintOnto(layer);
foreach (var building in linkedBuildings)
{
Vector3 center = (this.parent.TrueCenter() + this.parent.Graphic.DrawOffset(this.parent.Rotation) + building.TrueCenter() + building.Graphic.DrawOffset(building.Rotation)) / 2f;
center.y = AltitudeLayer.SmallWire.AltitudeFor();
Vector3 v = building.TrueCenter() - this.parent.TrueCenter();
Vector2 size = new Vector2(1f, v.MagnitudeHorizontal());
float rot = v.AngleFlat();
Printer_Plane.PrintPlane(layer, center, size, this.LineMat, rot);
}
}
}
}