173 lines
5.8 KiB
C#
173 lines
5.8 KiB
C#
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);
|
||
}
|
||
}
|
||
}
|
||
}
|