Files
WulaFallenEmpireRW/Source/WulaFallenEmpire/Projectiles/Projectile_NorthArcTrail.cs
2025-12-02 11:15:13 +08:00

341 lines
13 KiB
C#
Raw Permalink 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 System.Collections.Generic;
using RimWorld;
using UnityEngine;
using Verse;
namespace WulaFallenEmpire
{
public class Projectile_NorthArcTrail : Projectile_Explosive
{
// --- 弹道部分变量 ---
public float northOffsetDistance = 0f;
private Vector3 exactPositionInt;
private float curveSteepness = 1f;
private Vector3 originPos;
private Vector3 destinationPos;
private Vector3 bezierControlPoint;
private int ticksFlying;
private int totalTicks;
private bool initialized = false;
// --- 尾迹部分变量 ---
private TrackingBulletDef trackingDefInt;
private int Fleck_MakeFleckTick;
private Vector3 lastTickPosition;
// 新增:绘制相关变量
private float currentArcHeight;
private const float DRAW_ALTITUDE_OFFSET = 0.5f; // 减少偏移量,避免裁剪问题
// 新增用于保存真实计算的位置仅XZ平面
private Vector3 horizontalPosition;
public TrackingBulletDef TrackingDef
{
get
{
if (trackingDefInt == null)
{
trackingDefInt = def.GetModExtension<TrackingBulletDef>();
if (trackingDefInt == null)
{
trackingDefInt = new TrackingBulletDef();
}
}
return trackingDefInt;
}
}
// 修改简化ExactPosition计算
public override Vector3 ExactPosition
{
get
{
if (!initialized)
return base.ExactPosition;
// 返回水平位置保持Y轴为定义的高度
// RimWorld使用Y轴作为高度层不应该随意改变
return new Vector3(horizontalPosition.x, def.Altitude, horizontalPosition.z);
}
}
// 修改重写ExactRotation以考虑高度变化
public override Quaternion ExactRotation => Quaternion.LookRotation(GetCurrentDirection());
// 新增:获取带高度的位置(用于特效绘制)
public Vector3 PositionWithHeight
{
get
{
if (!initialized)
return ExactPosition;
return new Vector3(
horizontalPosition.x,
def.Altitude + currentArcHeight * 0.3f, // 适当缩放高度
horizontalPosition.z
);
}
}
public override void ExposeData()
{
base.ExposeData();
Scribe_Values.Look(ref originPos, "originPos");
Scribe_Values.Look(ref destinationPos, "destinationPos");
Scribe_Values.Look(ref bezierControlPoint, "bezierControlPoint");
Scribe_Values.Look(ref ticksFlying, "ticksFlying", 0);
Scribe_Values.Look(ref totalTicks, "totalTicks", 0);
Scribe_Values.Look(ref initialized, "initialized", false);
Scribe_Values.Look(ref northOffsetDistance, "northOffsetDistance", 0f);
Scribe_Values.Look(ref exactPositionInt, "exactPositionInt", Vector3.zero);
Scribe_Values.Look(ref curveSteepness, "curveSteepness", 1f);
Scribe_Values.Look(ref currentArcHeight, "currentArcHeight", 0f);
Scribe_Values.Look(ref horizontalPosition, "horizontalPosition", Vector3.zero);
Scribe_Values.Look(ref Fleck_MakeFleckTick, "Fleck_MakeFleckTick", 0);
Scribe_Values.Look(ref lastTickPosition, "lastTickPosition", Vector3.zero);
}
public override void Launch(Thing launcher, Vector3 origin, LocalTargetInfo usedTarget, LocalTargetInfo intendedTarget, ProjectileHitFlags hitFlags, bool preventFriendlyFire = false, Thing equipment = null, ThingDef targetCoverDef = null)
{
base.Launch(launcher, origin, usedTarget, intendedTarget, hitFlags, preventFriendlyFire, equipment, targetCoverDef);
// 获取北向偏移配置
NorthArcModExtension arcExtension = def.GetModExtension<NorthArcModExtension>();
if (arcExtension != null)
{
northOffsetDistance = arcExtension.northOffsetDistance;
curveSteepness = arcExtension.curveSteepness;
}
else
{
northOffsetDistance = def.projectile.arcHeightFactor * 3;
}
// --- 初始化弹道 ---
originPos = origin;
destinationPos = usedTarget.CenterVector3;
float speed = def.projectile.speed;
if (speed <= 0) speed = 1f;
float distance = (originPos - destinationPos).MagnitudeHorizontal();
totalTicks = Mathf.CeilToInt(distance / speed * 100f);
if (totalTicks < 1) totalTicks = 1;
ticksFlying = 0;
// 贝塞尔曲线计算
Vector3 midPoint = (originPos + destinationPos) / 2f;
Vector3 apexPoint = midPoint + new Vector3(0, 0, northOffsetDistance);
bezierControlPoint = 2f * apexPoint - midPoint;
initialized = true;
horizontalPosition = origin;
exactPositionInt = origin;
lastTickPosition = origin;
currentArcHeight = 0f;
}
protected override void Tick()
{
base.Tick();
if (this.Destroyed)
{
return;
}
if (!initialized)
{
base.Tick();
return;
}
ticksFlying++;
// 1. 计算当前帧的新位置
float t = (float)ticksFlying / (float)totalTicks;
if (t > 1f) t = 1f;
float u = 1 - t;
// 水平位移 (贝塞尔)
Vector3 nextPos = (u * u * originPos) + (2 * u * t * bezierControlPoint) + (t * t * destinationPos);
// 垂直高度 (抛物线)
currentArcHeight = def.projectile.arcHeightFactor * GenMath.InverseParabola(t);
horizontalPosition = nextPos; // 保存水平位置
if (!nextPos.ToIntVec3().InBounds(base.Map))
{
this.Destroy();
return;
}
exactPositionInt = nextPos;
// 2. 处理拖尾特效
if (TrackingDef != null && TrackingDef.tailFleckDef != null)
{
Fleck_MakeFleckTick++;
if (Fleck_MakeFleckTick >= TrackingDef.fleckDelayTicks)
{
if (Fleck_MakeFleckTick >= (TrackingDef.fleckDelayTicks + TrackingDef.fleckMakeFleckTickMax))
{
Fleck_MakeFleckTick = TrackingDef.fleckDelayTicks;
}
Map map = base.Map;
if (map != null)
{
int count = TrackingDef.fleckMakeFleckNum.RandomInRange;
// 使用带高度的位置生成尾迹
Vector3 currentPosition = PositionWithHeight;
Vector3 previousPosition = lastTickPosition;
if ((currentPosition - previousPosition).MagnitudeHorizontalSquared() > 0.0001f)
{
float moveAngle = (currentPosition - previousPosition).AngleFlat();
for (int i = 0; i < count; i++)
{
float velocityAngle = TrackingDef.fleckAngle.RandomInRange + moveAngle;
FleckCreationData dataStatic = FleckMaker.GetDataStatic(currentPosition, map, TrackingDef.tailFleckDef, TrackingDef.fleckScale.RandomInRange);
dataStatic.rotation = moveAngle;
dataStatic.rotationRate = TrackingDef.fleckRotation.RandomInRange;
dataStatic.velocityAngle = velocityAngle;
dataStatic.velocitySpeed = TrackingDef.fleckSpeed.RandomInRange;
map.flecks.CreateFleck(dataStatic);
}
}
}
}
}
lastTickPosition = PositionWithHeight;
if (ticksFlying >= totalTicks)
{
Impact(null);
return;
}
}
// 修改:重写绘制方法
protected override void DrawAt(Vector3 drawLoc, bool flip = false)
{
if (!initialized)
{
base.DrawAt(drawLoc, flip);
return;
}
// 使用固定的绘制位置,但考虑高度偏移
Vector3 finalDrawPos = ExactPosition;
// 调整绘制位置以考虑抛物线高度
// 但保持Y轴在合理范围内避免被裁剪
float heightAdjustment = currentArcHeight * 0.2f; // 缩放高度影响
finalDrawPos.y += Mathf.Clamp(heightAdjustment, -0.5f, 2f);
// 绘制阴影
if (def.projectile.shadowSize > 0f)
{
DrawShadow(finalDrawPos);
}
Quaternion rotation = ExactRotation;
if (def.projectile.spinRate != 0f)
{
float spinAngle = 60f / def.projectile.spinRate;
rotation = Quaternion.AngleAxis((float)Find.TickManager.TicksGame % spinAngle / spinAngle * 360f, Vector3.up);
}
// 使用正确的绘制方法
if (def.projectile.useGraphicClass)
{
// 确保图形缩放合适
float scaleFactor = 1f + currentArcHeight * 0.1f; // 轻微缩放模拟远近
Matrix4x4 matrix = Matrix4x4.TRS(
finalDrawPos,
rotation,
new Vector3(scaleFactor, 1f, scaleFactor)
);
Graphics.DrawMesh(MeshPool.GridPlane(def.graphicData.drawSize), matrix, DrawMat, 0);
}
else
{
Graphics.DrawMesh(MeshPool.GridPlane(def.graphicData.drawSize), finalDrawPos, rotation, DrawMat, 0);
}
Comps_PostDraw();
}
// 修改:简化阴影绘制
private void DrawShadow(Vector3 drawLoc)
{
if (def.projectile.shadowSize <= 0f)
return;
Material shadowMat = MaterialPool.MatFrom("Things/Skyfaller/SkyfallerShadowCircle", ShaderDatabase.Transparent);
if (shadowMat == null) return;
// 根据当前高度调整阴影大小
float normalizedHeight = Mathf.Clamp01(currentArcHeight / (def.projectile.arcHeightFactor + 0.01f));
float shadowSize = def.projectile.shadowSize * Mathf.Lerp(1f, 0.4f, normalizedHeight);
Vector3 scale = new Vector3(shadowSize, 1f, shadowSize);
Vector3 shadowOffset = new Vector3(0f, -0.05f, 0f); // 稍微降低阴影位置
Matrix4x4 matrix = Matrix4x4.TRS(drawLoc + shadowOffset, Quaternion.identity, scale);
Graphics.DrawMesh(MeshPool.plane10, matrix, shadowMat, 0);
}
// 计算当前位置的切线方向(考虑高度变化)
private Vector3 GetCurrentDirection()
{
if (!initialized || totalTicks <= 0)
{
return (destinationPos - originPos).normalized;
}
float t = (float)ticksFlying / (float)totalTicks;
if (t > 1f) t = 1f;
float u = 1 - t;
Vector3 tangent = 2 * u * (bezierControlPoint - originPos) + 2 * t * (destinationPos - bezierControlPoint);
if (tangent.MagnitudeHorizontalSquared() < 0.0001f)
{
return (destinationPos - originPos).normalized;
}
// 添加轻微的上/下方向以模拟抛物线
float verticalComponent = GenMath.InverseParabola(t) * def.projectile.arcHeightFactor * 0.3f;
return (tangent.normalized + new Vector3(0, verticalComponent, 0)).normalized;
}
protected override void Impact(Thing hitThing, bool blockedByShield = false)
{
base.Impact(hitThing, blockedByShield);
}
// 新增:确保在保存时位置正确
public override void PostMapInit()
{
base.PostMapInit();
// 确保位置数据有效
if (initialized && horizontalPosition == Vector3.zero)
{
horizontalPosition = originPos;
}
}
}
}