伴飞系统,技能飞行物垂直入场
This commit is contained in:
Binary file not shown.
@@ -34,8 +34,9 @@
|
|||||||
<useHitPoints>false</useHitPoints>
|
<useHitPoints>false</useHitPoints>
|
||||||
<selectable>false</selectable>
|
<selectable>false</selectable>
|
||||||
<alwaysHaulable>false</alwaysHaulable>
|
<alwaysHaulable>false</alwaysHaulable>
|
||||||
<altitudeLayer>LightingOverlay</altitudeLayer>
|
<altitudeLayer>FogOfWar</altitudeLayer>
|
||||||
<comps>
|
<comps>
|
||||||
|
<!-- 入场信封信息 -->
|
||||||
<li Class="ArachnaeSwarm.CompProperties_SendLetterAfterTicks">
|
<li Class="ArachnaeSwarm.CompProperties_SendLetterAfterTicks">
|
||||||
<ticksDelay>60</ticksDelay> <!-- 2秒后发送 -->
|
<ticksDelay>60</ticksDelay> <!-- 2秒后发送 -->
|
||||||
<letterLabel>虫巢母舰</letterLabel>
|
<letterLabel>虫巢母舰</letterLabel>
|
||||||
@@ -45,6 +46,7 @@
|
|||||||
<requireOnMap>true</requireOnMap>
|
<requireOnMap>true</requireOnMap>
|
||||||
<destroyAfterSending>false</destroyAfterSending> <!-- 发送后销毁flyover -->
|
<destroyAfterSending>false</destroyAfterSending> <!-- 发送后销毁flyover -->
|
||||||
</li>
|
</li>
|
||||||
|
<!-- 空投 -->
|
||||||
<li Class="ArachnaeSwarm.CompProperties_FlyOverDropPods">
|
<li Class="ArachnaeSwarm.CompProperties_FlyOverDropPods">
|
||||||
<!-- <dropProgress>0.5</dropProgress> -->
|
<!-- <dropProgress>0.5</dropProgress> -->
|
||||||
<useCyclicDrops>true</useCyclicDrops>
|
<useCyclicDrops>true</useCyclicDrops>
|
||||||
@@ -102,13 +104,13 @@
|
|||||||
<joinPlayer>false</joinPlayer>
|
<joinPlayer>false</joinPlayer>
|
||||||
<makePrisoners>false</makePrisoners>
|
<makePrisoners>false</makePrisoners>
|
||||||
</li>
|
</li>
|
||||||
|
<!-- 炮击支援 -->
|
||||||
<li Class="ArachnaeSwarm.CompProperties_ShipArtillery">
|
<li Class="ArachnaeSwarm.CompProperties_ShipArtillery">
|
||||||
<ticksBetweenAttacks>600</ticksBetweenAttacks>
|
<ticksBetweenAttacks>600</ticksBetweenAttacks>
|
||||||
<attackDurationTicks>600</attackDurationTicks>
|
<attackDurationTicks>600</attackDurationTicks>
|
||||||
<warmupTicks>60</warmupTicks>
|
<warmupTicks>60</warmupTicks>
|
||||||
<attackRadius>60</attackRadius>
|
<attackRadius>60</attackRadius>
|
||||||
<shellsPerVolley>3</shellsPerVolley>
|
<shellsPerVolley>3</shellsPerVolley>
|
||||||
<scatterRadius>60</scatterRadius>
|
|
||||||
<ignoreProtectionChance>0.1</ignoreProtectionChance>
|
<ignoreProtectionChance>0.1</ignoreProtectionChance>
|
||||||
|
|
||||||
<skyfallerDef>ARA_HiveShip_Fire_Incoming</skyfallerDef>
|
<skyfallerDef>ARA_HiveShip_Fire_Incoming</skyfallerDef>
|
||||||
@@ -120,13 +122,78 @@
|
|||||||
<avoidPlayerAssets>true</avoidPlayerAssets>
|
<avoidPlayerAssets>true</avoidPlayerAssets>
|
||||||
<playerAssetAvoidanceRadius>10</playerAssetAvoidanceRadius>
|
<playerAssetAvoidanceRadius>10</playerAssetAvoidanceRadius>
|
||||||
|
|
||||||
<sendAttackLetter>true</sendAttackLetter>
|
<sendAttackLetter>false</sendAttackLetter>
|
||||||
<customLetterLabel>战舰炮击警告</customLetterLabel>
|
<customLetterLabel>战舰炮击警告</customLetterLabel>
|
||||||
<customLetterText>一艘敌方战舰正在对殖民地进行炮击!立即寻找掩护!</customLetterText>
|
<customLetterText>一艘敌方战舰正在对殖民地进行炮击!立即寻找掩护!</customLetterText>
|
||||||
<letterDef>ThreatBig</letterDef>
|
<letterDef>ThreatBig</letterDef>
|
||||||
</li>
|
</li>
|
||||||
|
<!-- 伴飞 -->
|
||||||
|
<li Class="ArachnaeSwarm.CompProperties_FlyOverEscort">
|
||||||
|
<escortFlyOverDef>ARA_HiveCorvette</escortFlyOverDef>
|
||||||
|
|
||||||
|
<!-- 生成配置 -->
|
||||||
|
<spawnIntervalTicks>250</spawnIntervalTicks> <!-- 5秒 -->
|
||||||
|
<maxEscorts>60</maxEscorts>
|
||||||
|
<spawnCount>1</spawnCount>
|
||||||
|
|
||||||
|
<!-- 位置配置 -->
|
||||||
|
<spawnDistance>15</spawnDistance>
|
||||||
|
<lateralOffset>200</lateralOffset>
|
||||||
|
<verticalOffset>5</verticalOffset>
|
||||||
|
<useRandomOffset>true</useRandomOffset>
|
||||||
|
|
||||||
|
<!-- 飞行配置 -->
|
||||||
|
<escortSpeedMultiplier>20</escortSpeedMultiplier> <!-- 比主舰稍快 -->
|
||||||
|
<escortAltitudeOffset>10</escortAltitudeOffset> <!-- 比主舰稍高 -->
|
||||||
|
<mirrorMovement>false</mirrorMovement>
|
||||||
|
|
||||||
|
<!-- 行为配置 -->
|
||||||
|
<spawnOnStart>true</spawnOnStart>
|
||||||
|
<destroyWithParent>false</destroyWithParent>
|
||||||
|
<continuousSpawning>true</continuousSpawning>
|
||||||
|
|
||||||
|
<!-- 外观配置 -->
|
||||||
|
<escortScale>0.6</escortScale>
|
||||||
|
<useParentRotation>true</useParentRotation>
|
||||||
|
</li>
|
||||||
</comps>
|
</comps>
|
||||||
</ThingDef>
|
</ThingDef>
|
||||||
|
<ThingDef Parent="EtherealThingBase">
|
||||||
|
<defName>ARA_HiveCorvette</defName>
|
||||||
|
<label>天巫虫巢舰</label>
|
||||||
|
<thingClass>ArachnaeSwarm.FlyOver</thingClass>
|
||||||
|
<tickerType>Normal</tickerType>
|
||||||
|
<drawerType>RealtimeOnly</drawerType>
|
||||||
|
<graphicData>
|
||||||
|
<!-- <texPath>ArachnaeSwarm/Weapon/ARA_Weapon_Empty</texPath> -->
|
||||||
|
<texPath>ArachnaeSwarm/FlyOverThing/ARA_HiveShip_Shadow</texPath>
|
||||||
|
<graphicClass>Graphic_Single</graphicClass>
|
||||||
|
<shaderType>TransparentPostLight</shaderType>
|
||||||
|
<drawSize>(20,30)</drawSize>
|
||||||
|
<color>(195,195,195,45)</color>
|
||||||
|
</graphicData>
|
||||||
|
<skyfaller>
|
||||||
|
<shadowSize>(0, 0)</shadowSize>
|
||||||
|
<motesPerCell>0</motesPerCell>
|
||||||
|
<floatingSound>FlyOver/Flying</floatingSound>
|
||||||
|
<impactSound>FlyOver/Landing</impactSound>
|
||||||
|
</skyfaller>
|
||||||
|
<modExtensions>
|
||||||
|
<li Class="ArachnaeSwarm.FlyOverShadowExtension">
|
||||||
|
<customShadowPath>ArachnaeSwarm/FlyOverThing/ARA_HiveShip_Shadow</customShadowPath>
|
||||||
|
<useCustomShadow>false</useCustomShadow>
|
||||||
|
<!-- <shadowIntensity>0.8</shadowIntensity>
|
||||||
|
<minShadowAlpha>0</minShadowAlpha>
|
||||||
|
<maxShadowAlpha>0</maxShadowAlpha>
|
||||||
|
<minShadowScale>15</minShadowScale>
|
||||||
|
<maxShadowScale>15</maxShadowScale> -->
|
||||||
|
</li>
|
||||||
|
</modExtensions>
|
||||||
|
<useHitPoints>false</useHitPoints>
|
||||||
|
<selectable>false</selectable>
|
||||||
|
<alwaysHaulable>false</alwaysHaulable>
|
||||||
|
<altitudeLayer>FogOfWar</altitudeLayer>
|
||||||
|
</ThingDef>
|
||||||
|
|
||||||
<ThingDef ParentName="SkyfallerBase">
|
<ThingDef ParentName="SkyfallerBase">
|
||||||
<defName>ARA_HiveShip_Fire_Incoming</defName>
|
<defName>ARA_HiveShip_Fire_Incoming</defName>
|
||||||
@@ -140,6 +207,12 @@
|
|||||||
<explosionDamage>ARA_AcidBurn</explosionDamage>
|
<explosionDamage>ARA_AcidBurn</explosionDamage>
|
||||||
<explosionDamageFactor>0.5</explosionDamageFactor>
|
<explosionDamageFactor>0.5</explosionDamageFactor>
|
||||||
<cameraShake>1</cameraShake>
|
<cameraShake>1</cameraShake>
|
||||||
|
<angleCurve>
|
||||||
|
<points>
|
||||||
|
<li>(0,0)</li>
|
||||||
|
<li>(1,-1)</li>
|
||||||
|
</points>
|
||||||
|
</angleCurve>
|
||||||
</skyfaller>
|
</skyfaller>
|
||||||
</ThingDef>
|
</ThingDef>
|
||||||
</Defs>
|
</Defs>
|
||||||
Binary file not shown.
@@ -1,7 +1,28 @@
|
|||||||
{
|
{
|
||||||
"Version": 1,
|
"Version": 1,
|
||||||
"WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\",
|
"WorkspaceRootPath": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\",
|
||||||
"Documents": [],
|
"Documents": [
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\flyover\\thingclassflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
|
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\thingclassflyover.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\flyover\\ara_flyoverescort\\compflyoverescort.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
|
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_flyoverescort\\compflyoverescort.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\flyover\\ara_flyoverescort\\compproperties_flyoverescort.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
|
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_flyoverescort\\compproperties_flyoverescort.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\flyover\\ara_shipartillery\\compshipartillery.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
|
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_shipartillery\\compshipartillery.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"AbsoluteMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|d:\\steamlibrary\\steamapps\\common\\rimworld\\mods\\arachnaeswarm\\source\\arachnaeswarm\\flyover\\ara_shipartillery\\compproperties_shipartillery.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}",
|
||||||
|
"RelativeMoniker": "D:0:0:{EAE0DB6B-E282-C812-7F5A-6D13E9D24581}|ArachnaeSwarm.csproj|solutionrelative:flyover\\ara_shipartillery\\compproperties_shipartillery.cs||{A6C744A8-0E4A-4FC6-886A-064283054674}"
|
||||||
|
}
|
||||||
|
],
|
||||||
"DocumentGroupContainers": [
|
"DocumentGroupContainers": [
|
||||||
{
|
{
|
||||||
"Orientation": 0,
|
"Orientation": 0,
|
||||||
@@ -9,11 +30,76 @@
|
|||||||
"DocumentGroups": [
|
"DocumentGroups": [
|
||||||
{
|
{
|
||||||
"DockedWidth": 200,
|
"DockedWidth": 200,
|
||||||
"SelectedChildIndex": -1,
|
"SelectedChildIndex": 1,
|
||||||
"Children": [
|
"Children": [
|
||||||
{
|
{
|
||||||
"$type": "Bookmark",
|
"$type": "Bookmark",
|
||||||
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
|
"Name": "ST:0:0:{1c4feeaa-4718-4aa9-859d-94ce25d182ba}"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 0,
|
||||||
|
"Title": "ThingclassFlyOver.cs",
|
||||||
|
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ThingclassFlyOver.cs",
|
||||||
|
"RelativeDocumentMoniker": "Flyover\\ThingclassFlyOver.cs",
|
||||||
|
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ThingclassFlyOver.cs",
|
||||||
|
"RelativeToolTip": "Flyover\\ThingclassFlyOver.cs",
|
||||||
|
"ViewState": "AgIAAAMCAAAAAAAAAAAAABcCAAAeAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
|
"WhenOpened": "2025-10-28T09:09:22.03Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 1,
|
||||||
|
"Title": "CompFlyOverEscort.cs",
|
||||||
|
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_FlyOverEscort\\CompFlyOverEscort.cs",
|
||||||
|
"RelativeDocumentMoniker": "Flyover\\ARA_FlyOverEscort\\CompFlyOverEscort.cs",
|
||||||
|
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_FlyOverEscort\\CompFlyOverEscort.cs",
|
||||||
|
"RelativeToolTip": "Flyover\\ARA_FlyOverEscort\\CompFlyOverEscort.cs",
|
||||||
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAAMAAAAMAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
|
"WhenOpened": "2025-10-28T07:30:55.268Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 2,
|
||||||
|
"Title": "CompProperties_FlyOverEscort.cs",
|
||||||
|
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_FlyOverEscort\\CompProperties_FlyOverEscort.cs",
|
||||||
|
"RelativeDocumentMoniker": "Flyover\\ARA_FlyOverEscort\\CompProperties_FlyOverEscort.cs",
|
||||||
|
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_FlyOverEscort\\CompProperties_FlyOverEscort.cs",
|
||||||
|
"RelativeToolTip": "Flyover\\ARA_FlyOverEscort\\CompProperties_FlyOverEscort.cs",
|
||||||
|
"ViewState": "AgIAAAMAAAAAAAAAAAAAABUAAAAjAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
|
"WhenOpened": "2025-10-28T07:30:47.27Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 4,
|
||||||
|
"Title": "CompProperties_ShipArtillery.cs",
|
||||||
|
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_ShipArtillery\\CompProperties_ShipArtillery.cs",
|
||||||
|
"RelativeDocumentMoniker": "Flyover\\ARA_ShipArtillery\\CompProperties_ShipArtillery.cs",
|
||||||
|
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_ShipArtillery\\CompProperties_ShipArtillery.cs",
|
||||||
|
"RelativeToolTip": "Flyover\\ARA_ShipArtillery\\CompProperties_ShipArtillery.cs",
|
||||||
|
"ViewState": "AgIAAAAAAAAAAAAAAAAAAA8AAAAhAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
|
"WhenOpened": "2025-10-28T06:21:06.271Z",
|
||||||
|
"EditorCaption": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$type": "Document",
|
||||||
|
"DocumentIndex": 3,
|
||||||
|
"Title": "CompShipArtillery.cs",
|
||||||
|
"DocumentMoniker": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_ShipArtillery\\CompShipArtillery.cs",
|
||||||
|
"RelativeDocumentMoniker": "Flyover\\ARA_ShipArtillery\\CompShipArtillery.cs",
|
||||||
|
"ToolTip": "D:\\SteamLibrary\\steamapps\\common\\RimWorld\\Mods\\ArachnaeSwarm\\Source\\ArachnaeSwarm\\Flyover\\ARA_ShipArtillery\\CompShipArtillery.cs",
|
||||||
|
"RelativeToolTip": "Flyover\\ARA_ShipArtillery\\CompShipArtillery.cs",
|
||||||
|
"ViewState": "AgIAALEAAAAAAAAAAAAywNEAAABcAAAAAAAAAA==",
|
||||||
|
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.000738|",
|
||||||
|
"WhenOpened": "2025-10-28T06:21:04.222Z",
|
||||||
|
"EditorCaption": ""
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -138,6 +138,8 @@
|
|||||||
<Compile Include="EventSystem\EventVariableManager.cs" />
|
<Compile Include="EventSystem\EventVariableManager.cs" />
|
||||||
<Compile Include="EventSystem\Letter_EventChoice.cs" />
|
<Compile Include="EventSystem\Letter_EventChoice.cs" />
|
||||||
<Compile Include="EventSystem\QuestNode_Root_EventLetter.cs" />
|
<Compile Include="EventSystem\QuestNode_Root_EventLetter.cs" />
|
||||||
|
<Compile Include="Flyover\ARA_FlyOverEscort\CompFlyOverEscort.cs" />
|
||||||
|
<Compile Include="Flyover\ARA_FlyOverEscort\CompProperties_FlyOverEscort.cs" />
|
||||||
<Compile Include="Flyover\ARA_SendLetterAfterTicks\CompProperties_SendLetterAfterTicks.cs" />
|
<Compile Include="Flyover\ARA_SendLetterAfterTicks\CompProperties_SendLetterAfterTicks.cs" />
|
||||||
<Compile Include="Flyover\ARA_SendLetterAfterTicks\CompSendLetterAfterTicks.cs" />
|
<Compile Include="Flyover\ARA_SendLetterAfterTicks\CompSendLetterAfterTicks.cs" />
|
||||||
<Compile Include="Flyover\ARA_ShipArtillery\CompProperties_ShipArtillery.cs" />
|
<Compile Include="Flyover\ARA_ShipArtillery\CompProperties_ShipArtillery.cs" />
|
||||||
|
|||||||
@@ -0,0 +1,338 @@
|
|||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace ArachnaeSwarm
|
||||||
|
{
|
||||||
|
public class CompFlyOverEscort : ThingComp
|
||||||
|
{
|
||||||
|
public CompProperties_FlyOverEscort Props => (CompProperties_FlyOverEscort)props;
|
||||||
|
|
||||||
|
// 状态变量
|
||||||
|
private float ticksUntilNextSpawn = 0f;
|
||||||
|
private List<FlyOver> activeEscorts = new List<FlyOver>();
|
||||||
|
private bool hasInitialized = false;
|
||||||
|
|
||||||
|
public override void Initialize(CompProperties props)
|
||||||
|
{
|
||||||
|
base.Initialize(props);
|
||||||
|
|
||||||
|
if (Props.spawnOnStart)
|
||||||
|
{
|
||||||
|
ticksUntilNextSpawn = 0f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ticksUntilNextSpawn = Props.spawnIntervalTicks;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Message($"FlyOver Escort initialized: {Props.spawnIntervalTicks} ticks interval, max {Props.maxEscorts} escorts");
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void CompTick()
|
||||||
|
{
|
||||||
|
base.CompTick();
|
||||||
|
|
||||||
|
if (parent is not FlyOver mainFlyOver || !mainFlyOver.Spawned || mainFlyOver.Map == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// 初始化检查
|
||||||
|
if (!hasInitialized && mainFlyOver.hasStarted)
|
||||||
|
{
|
||||||
|
hasInitialized = true;
|
||||||
|
Log.Message($"FlyOver Escort: Main FlyOver started at {mainFlyOver.startPosition}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 清理已销毁的伴飞
|
||||||
|
activeEscorts.RemoveAll(escort => escort == null || escort.Destroyed || !escort.Spawned);
|
||||||
|
|
||||||
|
// 检查是否应该生成新伴飞
|
||||||
|
if (ShouldSpawnEscort(mainFlyOver))
|
||||||
|
{
|
||||||
|
ticksUntilNextSpawn -= 1f;
|
||||||
|
|
||||||
|
if (ticksUntilNextSpawn <= 0f)
|
||||||
|
{
|
||||||
|
SpawnEscorts(mainFlyOver);
|
||||||
|
ticksUntilNextSpawn = Props.spawnIntervalTicks;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新现有伴飞的位置(如果需要)
|
||||||
|
UpdateEscortPositions(mainFlyOver);
|
||||||
|
}
|
||||||
|
|
||||||
|
private bool ShouldSpawnEscort(FlyOver mainFlyOver)
|
||||||
|
{
|
||||||
|
if (!mainFlyOver.hasStarted || mainFlyOver.hasCompleted)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (!Props.continuousSpawning && activeEscorts.Count >= Props.spawnCount)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (activeEscorts.Count >= Props.maxEscorts)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SpawnEscorts(FlyOver mainFlyOver)
|
||||||
|
{
|
||||||
|
int escortsToSpawn = Mathf.Min(Props.spawnCount, Props.maxEscorts - activeEscorts.Count);
|
||||||
|
|
||||||
|
for (int i = 0; i < escortsToSpawn; i++)
|
||||||
|
{
|
||||||
|
FlyOver escort = CreateEscort(mainFlyOver);
|
||||||
|
if (escort != null)
|
||||||
|
{
|
||||||
|
activeEscorts.Add(escort);
|
||||||
|
Log.Message($"Spawned escort #{i+1} for FlyOver at {mainFlyOver.DrawPos}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private FlyOver CreateEscort(FlyOver mainFlyOver)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 选择伴飞定义
|
||||||
|
ThingDef escortDef = SelectEscortDef();
|
||||||
|
if (escortDef == null)
|
||||||
|
{
|
||||||
|
Log.Error("FlyOver Escort: No valid escort def found");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算伴飞的起点和终点
|
||||||
|
IntVec3 escortStart = CalculateEscortStart(mainFlyOver);
|
||||||
|
IntVec3 escortEnd = CalculateEscortEnd(mainFlyOver, escortStart);
|
||||||
|
|
||||||
|
if (!escortStart.InBounds(mainFlyOver.Map) || !escortEnd.InBounds(mainFlyOver.Map))
|
||||||
|
{
|
||||||
|
Log.Warning("FlyOver Escort: Escort start or end position out of bounds");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算伴飞参数
|
||||||
|
float escortSpeed = mainFlyOver.flightSpeed * Props.escortSpeedMultiplier;
|
||||||
|
float escortAltitude = mainFlyOver.altitude + Props.escortAltitudeOffset;
|
||||||
|
|
||||||
|
// 创建伴飞
|
||||||
|
FlyOver escort = FlyOver.MakeFlyOver(
|
||||||
|
escortDef,
|
||||||
|
escortStart,
|
||||||
|
escortEnd,
|
||||||
|
mainFlyOver.Map,
|
||||||
|
escortSpeed,
|
||||||
|
escortAltitude,
|
||||||
|
null, // 没有内容物
|
||||||
|
mainFlyOver.fadeInDuration
|
||||||
|
);
|
||||||
|
|
||||||
|
// 设置伴飞属性
|
||||||
|
SetupEscortProperties(escort, mainFlyOver);
|
||||||
|
|
||||||
|
Log.Message($"Created escort: {escortStart} -> {escortEnd}, speed: {escortSpeed}, altitude: {escortAltitude}");
|
||||||
|
|
||||||
|
return escort;
|
||||||
|
}
|
||||||
|
catch (System.Exception ex)
|
||||||
|
{
|
||||||
|
Log.Error($"Error creating FlyOver escort: {ex}");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private ThingDef SelectEscortDef()
|
||||||
|
{
|
||||||
|
if (Props.escortFlyOverDefs != null && Props.escortFlyOverDefs.Count > 0)
|
||||||
|
{
|
||||||
|
return Props.escortFlyOverDefs.RandomElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
return Props.escortFlyOverDef;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntVec3 CalculateEscortStart(FlyOver mainFlyOver)
|
||||||
|
{
|
||||||
|
Vector3 mainDirection = mainFlyOver.MovementDirection;
|
||||||
|
Vector3 mainPosition = mainFlyOver.DrawPos;
|
||||||
|
|
||||||
|
// 计算横向偏移方向(垂直于飞行方向)
|
||||||
|
Vector3 lateralDirection = GetLateralOffsetDirection(mainDirection);
|
||||||
|
|
||||||
|
// 计算偏移量
|
||||||
|
float lateralOffset = Props.useRandomOffset ?
|
||||||
|
Rand.Range(-Props.lateralOffset, Props.lateralOffset) :
|
||||||
|
Props.lateralOffset;
|
||||||
|
|
||||||
|
float spawnDistance = Props.useRandomOffset ?
|
||||||
|
Rand.Range(Props.spawnDistance * 0.5f, Props.spawnDistance * 1.5f) :
|
||||||
|
Props.spawnDistance;
|
||||||
|
|
||||||
|
// 计算起点位置(从主FlyOver后方偏移)
|
||||||
|
Vector3 offset = (-mainDirection * spawnDistance) + (lateralDirection * lateralOffset);
|
||||||
|
Vector3 escortStartPos = mainPosition + offset;
|
||||||
|
|
||||||
|
// 确保位置在地图边界内
|
||||||
|
IntVec3 escortStart = escortStartPos.ToIntVec3();
|
||||||
|
if (!escortStart.InBounds(mainFlyOver.Map))
|
||||||
|
{
|
||||||
|
// 如果超出边界,调整到边界内
|
||||||
|
escortStart = ClampToMap(escortStart, mainFlyOver.Map);
|
||||||
|
}
|
||||||
|
|
||||||
|
return escortStart;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntVec3 CalculateEscortEnd(FlyOver mainFlyOver, IntVec3 escortStart)
|
||||||
|
{
|
||||||
|
Vector3 mainDirection = mainFlyOver.MovementDirection;
|
||||||
|
Vector3 mainEndPos = mainFlyOver.endPosition.ToVector3();
|
||||||
|
|
||||||
|
// 如果镜像移动,使用相反方向
|
||||||
|
if (Props.mirrorMovement)
|
||||||
|
{
|
||||||
|
mainDirection = -mainDirection;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算从起点沿飞行方向延伸的终点
|
||||||
|
float flightDistance = mainFlyOver.startPosition.DistanceTo(mainFlyOver.endPosition);
|
||||||
|
Vector3 escortEndPos = escortStart.ToVector3() + (mainDirection * flightDistance);
|
||||||
|
|
||||||
|
// 确保终点在地图边界内
|
||||||
|
IntVec3 escortEnd = escortEndPos.ToIntVec3();
|
||||||
|
if (!escortEnd.InBounds(mainFlyOver.Map))
|
||||||
|
{
|
||||||
|
escortEnd = ClampToMap(escortEnd, mainFlyOver.Map);
|
||||||
|
}
|
||||||
|
|
||||||
|
return escortEnd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Vector3 GetLateralOffsetDirection(Vector3 mainDirection)
|
||||||
|
{
|
||||||
|
// 获取垂直于飞行方向的向量(随机选择左侧或右侧)
|
||||||
|
Vector3 lateral = new Vector3(-mainDirection.z, 0f, mainDirection.x);
|
||||||
|
|
||||||
|
// 随机选择方向
|
||||||
|
if (Rand.Value > 0.5f)
|
||||||
|
{
|
||||||
|
lateral = -lateral;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lateral.normalized;
|
||||||
|
}
|
||||||
|
|
||||||
|
private IntVec3 ClampToMap(IntVec3 position, Map map)
|
||||||
|
{
|
||||||
|
CellRect mapRect = CellRect.WholeMap(map);
|
||||||
|
return new IntVec3(
|
||||||
|
Mathf.Clamp(position.x, mapRect.minX, mapRect.maxX),
|
||||||
|
0,
|
||||||
|
Mathf.Clamp(position.z, mapRect.minZ, mapRect.maxZ)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void SetupEscortProperties(FlyOver escort, FlyOver mainFlyOver)
|
||||||
|
{
|
||||||
|
// 设置缩放
|
||||||
|
if (Props.escortScale != 1f)
|
||||||
|
{
|
||||||
|
// 这里可能需要通过ModExtension或其他方式设置缩放
|
||||||
|
}
|
||||||
|
|
||||||
|
// 禁用阴影(如果需要)
|
||||||
|
if (!mainFlyOver.createShadow)
|
||||||
|
{
|
||||||
|
escort.createShadow = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 禁用音效(如果需要)
|
||||||
|
if (!mainFlyOver.playFlyOverSound)
|
||||||
|
{
|
||||||
|
escort.playFlyOverSound = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateEscortPositions(FlyOver mainFlyOver)
|
||||||
|
{
|
||||||
|
// 如果需要实时更新伴飞位置,可以在这里实现
|
||||||
|
// 目前伴飞会按照自己的路径飞行
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PostDestroy(DestroyMode mode, Map previousMap)
|
||||||
|
{
|
||||||
|
base.PostDestroy(mode, previousMap);
|
||||||
|
|
||||||
|
// 销毁所有伴飞
|
||||||
|
if (Props.destroyWithParent)
|
||||||
|
{
|
||||||
|
foreach (FlyOver escort in activeEscorts)
|
||||||
|
{
|
||||||
|
if (escort != null && escort.Spawned)
|
||||||
|
{
|
||||||
|
escort.Destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
activeEscorts.Clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PostExposeData()
|
||||||
|
{
|
||||||
|
base.PostExposeData();
|
||||||
|
Scribe_Values.Look(ref ticksUntilNextSpawn, "ticksUntilNextSpawn", 0f);
|
||||||
|
Scribe_Collections.Look(ref activeEscorts, "activeEscorts", LookMode.Reference);
|
||||||
|
Scribe_Values.Look(ref hasInitialized, "hasInitialized", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override IEnumerable<Gizmo> CompGetGizmosExtra()
|
||||||
|
{
|
||||||
|
if (DebugSettings.ShowDevGizmos && parent is FlyOver)
|
||||||
|
{
|
||||||
|
yield return new Command_Action
|
||||||
|
{
|
||||||
|
defaultLabel = "Dev: Spawn Escort",
|
||||||
|
action = () => SpawnEscorts(parent as FlyOver)
|
||||||
|
};
|
||||||
|
|
||||||
|
yield return new Command_Action
|
||||||
|
{
|
||||||
|
defaultLabel = $"Dev: Escort Status - Active: {activeEscorts.Count}/{Props.maxEscorts}",
|
||||||
|
action = () => {}
|
||||||
|
};
|
||||||
|
|
||||||
|
yield return new Command_Action
|
||||||
|
{
|
||||||
|
defaultLabel = "Dev: Clear All Escorts",
|
||||||
|
action = () =>
|
||||||
|
{
|
||||||
|
foreach (var escort in activeEscorts)
|
||||||
|
{
|
||||||
|
if (escort != null && escort.Spawned)
|
||||||
|
escort.Destroy();
|
||||||
|
}
|
||||||
|
activeEscorts.Clear();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公共方法:强制生成伴飞
|
||||||
|
public void SpawnEscortNow()
|
||||||
|
{
|
||||||
|
if (parent is FlyOver flyOver)
|
||||||
|
{
|
||||||
|
SpawnEscorts(flyOver);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 公共方法:获取活跃伴飞数量
|
||||||
|
public int GetActiveEscortCount()
|
||||||
|
{
|
||||||
|
return activeEscorts.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
using RimWorld;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Verse;
|
||||||
|
|
||||||
|
namespace ArachnaeSwarm
|
||||||
|
{
|
||||||
|
public class CompProperties_FlyOverEscort : CompProperties
|
||||||
|
{
|
||||||
|
// 伴飞配置
|
||||||
|
public ThingDef escortFlyOverDef; // 伴飞FlyOver定义
|
||||||
|
public List<ThingDef> escortFlyOverDefs; // 多个伴飞定义(随机选择)
|
||||||
|
|
||||||
|
// 生成配置
|
||||||
|
public float spawnIntervalTicks = 600f; // 生成间隔(tick)
|
||||||
|
public int maxEscorts = 3; // 最大伴飞数量
|
||||||
|
public int spawnCount = 1; // 每次生成的伴飞数量
|
||||||
|
|
||||||
|
// 位置配置
|
||||||
|
public float spawnDistance = 10f; // 生成距离(从主FlyOver)
|
||||||
|
public float lateralOffset = 5f; // 横向偏移量
|
||||||
|
public float verticalOffset = 2f; // 垂直偏移量(高度差)
|
||||||
|
public bool useRandomOffset = true; // 是否使用随机偏移
|
||||||
|
|
||||||
|
// 飞行配置
|
||||||
|
public float escortSpeedMultiplier = 1f; // 速度乘数(相对于主FlyOver)
|
||||||
|
public float escortAltitudeOffset = 0f; // 高度偏移
|
||||||
|
public bool mirrorMovement = false; // 是否镜像移动(相反方向)
|
||||||
|
|
||||||
|
// 行为配置
|
||||||
|
public bool spawnOnStart = true; // 开始时立即生成
|
||||||
|
public bool continuousSpawning = true; // 是否持续生成
|
||||||
|
public bool destroyWithParent = true; // 是否随父级销毁
|
||||||
|
|
||||||
|
// 外观配置
|
||||||
|
public float escortScale = 1f; // 缩放比例
|
||||||
|
public bool useParentRotation = true; // 使用父级旋转
|
||||||
|
|
||||||
|
public CompProperties_FlyOverEscort()
|
||||||
|
{
|
||||||
|
compClass = typeof(CompFlyOverEscort);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -26,7 +26,6 @@ namespace ArachnaeSwarm
|
|||||||
public ThingDef skyfallerDef; // 使用的 Skyfaller 定义
|
public ThingDef skyfallerDef; // 使用的 Skyfaller 定义
|
||||||
public List<ThingDef> skyfallerDefs; // 多个 Skyfaller 定义(随机选择)
|
public List<ThingDef> skyfallerDefs; // 多个 Skyfaller 定义(随机选择)
|
||||||
public int shellsPerVolley = 1; // 每轮齐射的炮弹数量
|
public int shellsPerVolley = 1; // 每轮齐射的炮弹数量
|
||||||
public float scatterRadius = 3f; // 散布半径
|
|
||||||
public bool useDifferentShells = false; // 是否使用不同类型的炮弹
|
public bool useDifferentShells = false; // 是否使用不同类型的炮弹
|
||||||
|
|
||||||
// 音效配置
|
// 音效配置
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using Verse;
|
using Verse;
|
||||||
|
using Verse.Sound;
|
||||||
|
|
||||||
namespace ArachnaeSwarm
|
namespace ArachnaeSwarm
|
||||||
{
|
{
|
||||||
@@ -29,7 +30,7 @@ namespace ArachnaeSwarm
|
|||||||
|
|
||||||
ticksUntilNextAttack = Props.ticksBetweenAttacks;
|
ticksUntilNextAttack = Props.ticksBetweenAttacks;
|
||||||
|
|
||||||
Log.Message($"Ship Artillery initialized: {Props.ticksBetweenAttacks} ticks between attacks, {Props.attackRadius} radius, Scatter: {Props.scatterRadius}");
|
Log.Message($"Ship Artillery initialized: {Props.ticksBetweenAttacks} ticks between attacks, {Props.attackRadius} radius");
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void CompTick()
|
public override void CompTick()
|
||||||
@@ -132,7 +133,7 @@ namespace ArachnaeSwarm
|
|||||||
attackEffecter = Props.attackEffect.Spawn();
|
attackEffecter = Props.attackEffect.Spawn();
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.Message($"Ship Artillery started firing at area {currentTarget} (scatter radius: {Props.scatterRadius})");
|
Log.Message($"Ship Artillery started firing at area {currentTarget}");
|
||||||
|
|
||||||
// 发送攻击通知
|
// 发送攻击通知
|
||||||
if (Props.sendAttackLetter)
|
if (Props.sendAttackLetter)
|
||||||
@@ -194,17 +195,20 @@ namespace ArachnaeSwarm
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算散布位置 - 使用新的散射逻辑
|
// 直接选择随机目标
|
||||||
IntVec3 shellTarget = GetScatteredTarget(flyOver);
|
IntVec3 shellTarget = SelectRandomTarget(flyOver);
|
||||||
|
|
||||||
// 创建 Skyfaller
|
// 关键修复:使用 SkyfallerMaker 创建并立即生成 Skyfaller
|
||||||
Skyfaller shell = (Skyfaller)ThingMaker.MakeThing(shellDef);
|
SkyfallerMaker.SpawnSkyfaller(shellDef, shellTarget, flyOver.Map);
|
||||||
|
|
||||||
// 生成炮弹
|
|
||||||
GenSpawn.Spawn(shell, GetLaunchPosition(flyOver), flyOver.Map);
|
|
||||||
|
|
||||||
float distanceFromCenter = shellTarget.DistanceTo(currentTarget);
|
float distanceFromCenter = shellTarget.DistanceTo(currentTarget);
|
||||||
Log.Message($"Ship Artillery fired shell at {shellTarget} (distance from center: {distanceFromCenter:F1}, scatter radius: {Props.scatterRadius})");
|
Log.Message($"Ship Artillery fired shell at {shellTarget} (distance from center: {distanceFromCenter:F1})");
|
||||||
|
|
||||||
|
// 播放音效
|
||||||
|
if (Props.attackSound != null)
|
||||||
|
{
|
||||||
|
Props.attackSound.PlayOneShot(new TargetInfo(shellTarget, flyOver.Map));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (System.Exception ex)
|
catch (System.Exception ex)
|
||||||
{
|
{
|
||||||
@@ -243,45 +247,11 @@ namespace ArachnaeSwarm
|
|||||||
return launchPos;
|
return launchPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新的散射逻辑 - 基于 FlyOverDropPods 的实现方式
|
// 简化的目标选择 - 每次直接随机选择目标
|
||||||
private IntVec3 GetScatteredTarget(FlyOver flyOver)
|
private IntVec3 SelectRandomTarget(FlyOver flyOver)
|
||||||
{
|
{
|
||||||
// 基础目标(攻击区域中心)
|
IntVec3 center = GetFlyOverPosition(flyOver) + Props.targetOffset;
|
||||||
IntVec3 baseTarget = currentTarget;
|
return FindRandomTargetInRadius(center, flyOver.Map, Props.attackRadius);
|
||||||
|
|
||||||
// 如果散射半径为0,直接返回基础目标
|
|
||||||
if (Props.scatterRadius <= 0)
|
|
||||||
return baseTarget;
|
|
||||||
|
|
||||||
// 使用类似 FlyOverDropPods 的散射逻辑
|
|
||||||
for (int i = 0; i < 20; i++) // 尝试20次找到有效位置
|
|
||||||
{
|
|
||||||
// 在散射半径内随机选择位置
|
|
||||||
IntVec3 scatteredPos = baseTarget;
|
|
||||||
|
|
||||||
// 使用圆形散射而不是方形
|
|
||||||
float angle = Rand.Range(0f, 360f);
|
|
||||||
float distance = Rand.Range(0f, Props.scatterRadius);
|
|
||||||
|
|
||||||
scatteredPos.x += Mathf.RoundToInt(Mathf.Cos(angle * Mathf.Deg2Rad) * distance);
|
|
||||||
scatteredPos.z += Mathf.RoundToInt(Mathf.Sin(angle * Mathf.Deg2Rad) * distance);
|
|
||||||
|
|
||||||
// 检查是否无视保护机制
|
|
||||||
bool ignoreProtectionThisShot = Rand.Value < Props.ignoreProtectionChance;
|
|
||||||
|
|
||||||
if (scatteredPos.InBounds(flyOver.Map) && IsValidTarget(scatteredPos, flyOver.Map, ignoreProtectionThisShot))
|
|
||||||
{
|
|
||||||
if (ignoreProtectionThisShot)
|
|
||||||
{
|
|
||||||
Log.Warning($"Ship Artillery: Protection ignored! Shell may hit player assets at {scatteredPos}");
|
|
||||||
}
|
|
||||||
return scatteredPos;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果找不到有效位置,使用基础目标
|
|
||||||
Log.Warning($"Ship Artillery: Could not find valid scattered target after 20 attempts, using base target");
|
|
||||||
return baseTarget;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntVec3 SelectTarget(FlyOver flyOver)
|
private IntVec3 SelectTarget(FlyOver flyOver)
|
||||||
@@ -316,7 +286,7 @@ namespace ArachnaeSwarm
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新的目标查找逻辑 - 基于攻击半径
|
// 目标查找逻辑 - 基于攻击半径
|
||||||
private IntVec3 FindRandomTargetInRadius(IntVec3 center, Map map, float radius)
|
private IntVec3 FindRandomTargetInRadius(IntVec3 center, Map map, float radius)
|
||||||
{
|
{
|
||||||
Log.Message($"Finding target around {center} with radius {radius}");
|
Log.Message($"Finding target around {center} with radius {radius}");
|
||||||
|
|||||||
@@ -22,8 +22,18 @@ namespace ArachnaeSwarm
|
|||||||
Log.Message($"Target cell: {target.Cell}, Dest: {dest.Cell}");
|
Log.Message($"Target cell: {target.Cell}, Dest: {dest.Cell}");
|
||||||
|
|
||||||
// 计算起始和结束位置
|
// 计算起始和结束位置
|
||||||
IntVec3 startPos = CalculateStartPosition(target);
|
IntVec3 startPos, endPos;
|
||||||
IntVec3 endPos = CalculateEndPosition(target, startPos);
|
|
||||||
|
// 根据进场类型选择不同的计算方法
|
||||||
|
if (Props.approachType == ApproachType.Perpendicular)
|
||||||
|
{
|
||||||
|
CalculatePerpendicularPath(target, out startPos, out endPos);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
startPos = CalculateStartPosition(target);
|
||||||
|
endPos = CalculateEndPosition(target, startPos);
|
||||||
|
}
|
||||||
|
|
||||||
Log.Message($"Final positions - Start: {startPos}, End: {endPos}");
|
Log.Message($"Final positions - Start: {startPos}, End: {endPos}");
|
||||||
|
|
||||||
@@ -40,6 +50,18 @@ namespace ArachnaeSwarm
|
|||||||
endPos = parent.pawn.Map.Center;
|
endPos = parent.pawn.Map.Center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 确保起点和终点不同
|
||||||
|
if (startPos == endPos)
|
||||||
|
{
|
||||||
|
Log.Warning($"FlyOver start and end positions are the same: {startPos}. Adjusting end position.");
|
||||||
|
IntVec3 randomOffset = new IntVec3(Rand.Range(-10, 11), 0, Rand.Range(-10, 11));
|
||||||
|
endPos += randomOffset;
|
||||||
|
if (!endPos.InBounds(parent.pawn.Map))
|
||||||
|
{
|
||||||
|
endPos = parent.pawn.Map.Center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 根据类型创建不同的飞越物体
|
// 根据类型创建不同的飞越物体
|
||||||
switch (Props.flyOverType)
|
switch (Props.flyOverType)
|
||||||
{
|
{
|
||||||
@@ -58,6 +80,78 @@ namespace ArachnaeSwarm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增:计算垂直线进场路径
|
||||||
|
private void CalculatePerpendicularPath(LocalTargetInfo target, out IntVec3 startPos, out IntVec3 endPos)
|
||||||
|
{
|
||||||
|
Map map = parent.pawn.Map;
|
||||||
|
IntVec3 casterPos = parent.pawn.Position;
|
||||||
|
IntVec3 targetPos = target.Cell;
|
||||||
|
|
||||||
|
Log.Message($"Calculating perpendicular path: Caster={casterPos}, Target={targetPos}");
|
||||||
|
|
||||||
|
// 计算施法者到目标的方向向量
|
||||||
|
Vector3 directionToTarget = (targetPos.ToVector3() - casterPos.ToVector3()).normalized;
|
||||||
|
|
||||||
|
// 如果方向为零向量,使用随机方向
|
||||||
|
if (directionToTarget == Vector3.zero)
|
||||||
|
{
|
||||||
|
directionToTarget = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
|
||||||
|
Log.Message($"Using random direction: {directionToTarget}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 计算垂直于施法者-目标连线的方向(旋转90度)
|
||||||
|
Vector3 perpendicularDirection = new Vector3(-directionToTarget.z, 0, directionToTarget.x).normalized;
|
||||||
|
|
||||||
|
Log.Message($"Perpendicular direction: {perpendicularDirection}");
|
||||||
|
|
||||||
|
// 从目标点出发,向垂直方向的两侧延伸找到地图边缘
|
||||||
|
IntVec3 edge1 = FindMapEdgeInDirection(map, targetPos, perpendicularDirection);
|
||||||
|
IntVec3 edge2 = FindMapEdgeInDirection(map, targetPos, -perpendicularDirection);
|
||||||
|
|
||||||
|
// 随机选择起点和终点(确保目标点在路径上)
|
||||||
|
if (Rand.Value < 0.5f)
|
||||||
|
{
|
||||||
|
startPos = edge1;
|
||||||
|
endPos = edge2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
startPos = edge2;
|
||||||
|
endPos = edge1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Log.Message($"Perpendicular path: {startPos} -> {targetPos} -> {endPos}");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增:在指定方向上找到地图边缘
|
||||||
|
private IntVec3 FindMapEdgeInDirection(Map map, IntVec3 fromPos, Vector3 direction)
|
||||||
|
{
|
||||||
|
// 计算最大搜索距离(地图对角线的一半)
|
||||||
|
float maxDistance = Mathf.Sqrt(map.Size.x * map.Size.x + map.Size.z * map.Size.z) * 0.6f;
|
||||||
|
|
||||||
|
// 沿着方向逐步搜索,直到找到地图边界
|
||||||
|
for (float distance = 10f; distance <= maxDistance; distance += 5f)
|
||||||
|
{
|
||||||
|
IntVec3 testPos = fromPos + new IntVec3(
|
||||||
|
Mathf.RoundToInt(direction.x * distance),
|
||||||
|
0,
|
||||||
|
Mathf.RoundToInt(direction.z * distance));
|
||||||
|
|
||||||
|
if (!testPos.InBounds(map))
|
||||||
|
{
|
||||||
|
// 找到边界,返回最近的有效位置
|
||||||
|
IntVec3 edgePos = FindClosestValidPosition(testPos, map);
|
||||||
|
Log.Message($"Found map edge at {edgePos} (direction: {direction}, distance: {distance})");
|
||||||
|
return edgePos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 如果没找到边界,使用随机边缘位置
|
||||||
|
Log.Warning($"Could not find map edge in direction {direction}, using random edge");
|
||||||
|
return GetRandomMapEdgePosition(map);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 原有的位置计算方法
|
||||||
private IntVec3 CalculateStartPosition(LocalTargetInfo target)
|
private IntVec3 CalculateStartPosition(LocalTargetInfo target)
|
||||||
{
|
{
|
||||||
Map map = parent.pawn.Map;
|
Map map = parent.pawn.Map;
|
||||||
@@ -114,60 +208,33 @@ namespace ArachnaeSwarm
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关键修复:确保起点和终点不同
|
|
||||||
if (startPos == endPos)
|
|
||||||
{
|
|
||||||
Log.Warning($"FlyOver start and end positions are the same: {startPos}. Adjusting end position.");
|
|
||||||
|
|
||||||
// 如果相同,将终点向随机方向移动
|
|
||||||
IntVec3 randomOffset = new IntVec3(Rand.Range(-10, 11), 0, Rand.Range(-10, 11));
|
|
||||||
endPos += randomOffset;
|
|
||||||
|
|
||||||
// 确保新位置在地图内
|
|
||||||
if (!endPos.InBounds(map))
|
|
||||||
{
|
|
||||||
endPos = map.Center;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.Message($"Calculated positions - Start: {startPos}, End: {endPos}, Distance: {startPos.DistanceTo(endPos)}");
|
|
||||||
return endPos;
|
return endPos;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 修复的 OppositeMapEdge 逻辑:确保穿过地图中心
|
// 原有的辅助方法保持不变
|
||||||
private IntVec3 GetOppositeMapEdgeThroughCenter(Map map, IntVec3 startPos)
|
private IntVec3 GetOppositeMapEdgeThroughCenter(Map map, IntVec3 startPos)
|
||||||
{
|
{
|
||||||
IntVec3 center = map.Center;
|
IntVec3 center = map.Center;
|
||||||
|
|
||||||
// 计算从起点到中心的方向
|
|
||||||
Vector3 toCenter = (center.ToVector3() - startPos.ToVector3()).normalized;
|
Vector3 toCenter = (center.ToVector3() - startPos.ToVector3()).normalized;
|
||||||
|
|
||||||
// 如果方向为零向量,使用随机方向
|
|
||||||
if (toCenter == Vector3.zero)
|
if (toCenter == Vector3.zero)
|
||||||
{
|
{
|
||||||
toCenter = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
|
toCenter = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
|
||||||
Log.Message($"Using random direction to center: {toCenter}");
|
Log.Message($"Using random direction to center: {toCenter}");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 计算从中心到对面边缘的方向(与起点到中心的方向相同)
|
|
||||||
Vector3 fromCenter = toCenter;
|
Vector3 fromCenter = toCenter;
|
||||||
|
|
||||||
Log.Message($"Calculating opposite edge: Start={startPos}, Center={center}, Direction={fromCenter}");
|
|
||||||
|
|
||||||
// 从中心出发,沿着相同方向找到对面的地图边缘
|
|
||||||
IntVec3 oppositeEdge = GetMapEdgePositionFromCenter(map, fromCenter);
|
IntVec3 oppositeEdge = GetMapEdgePositionFromCenter(map, fromCenter);
|
||||||
|
|
||||||
Log.Message($"Found opposite edge through center: {oppositeEdge}");
|
Log.Message($"Found opposite edge through center: {oppositeEdge}");
|
||||||
return oppositeEdge;
|
return oppositeEdge;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从地图中心出发找到指定方向的地图边缘
|
|
||||||
private IntVec3 GetMapEdgePositionFromCenter(Map map, Vector3 direction)
|
private IntVec3 GetMapEdgePositionFromCenter(Map map, Vector3 direction)
|
||||||
{
|
{
|
||||||
IntVec3 center = map.Center;
|
IntVec3 center = map.Center;
|
||||||
float maxDist = Mathf.Max(map.Size.x, map.Size.z) * 0.6f;
|
float maxDist = Mathf.Max(map.Size.x, map.Size.z) * 0.6f;
|
||||||
|
|
||||||
// 从中心向指定方向延伸
|
|
||||||
for (int i = 1; i <= maxDist; i++)
|
for (int i = 1; i <= maxDist; i++)
|
||||||
{
|
{
|
||||||
IntVec3 testPos = center + new IntVec3(
|
IntVec3 testPos = center + new IntVec3(
|
||||||
@@ -177,14 +244,12 @@ namespace ArachnaeSwarm
|
|||||||
|
|
||||||
if (!testPos.InBounds(map))
|
if (!testPos.InBounds(map))
|
||||||
{
|
{
|
||||||
// 找到边界位置
|
|
||||||
IntVec3 edgePos = FindClosestValidPosition(testPos, map);
|
IntVec3 edgePos = FindClosestValidPosition(testPos, map);
|
||||||
Log.Message($"Found map edge from center: {edgePos} (direction: {direction}, distance: {i})");
|
Log.Message($"Found map edge from center: {edgePos} (direction: {direction}, distance: {i})");
|
||||||
return edgePos;
|
return edgePos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果没找到边界,使用随机边缘位置
|
|
||||||
Log.Warning("Could not find map edge from center, using random edge");
|
Log.Warning("Could not find map edge from center, using random edge");
|
||||||
return GetRandomMapEdgePosition(map);
|
return GetRandomMapEdgePosition(map);
|
||||||
}
|
}
|
||||||
@@ -200,7 +265,6 @@ namespace ArachnaeSwarm
|
|||||||
IntVec3 center = map.Center;
|
IntVec3 center = map.Center;
|
||||||
float maxDist = Mathf.Max(map.Size.x, map.Size.z) * 0.6f;
|
float maxDist = Mathf.Max(map.Size.x, map.Size.z) * 0.6f;
|
||||||
|
|
||||||
// 从中心向指定方向延伸
|
|
||||||
for (int i = 1; i <= maxDist; i++)
|
for (int i = 1; i <= maxDist; i++)
|
||||||
{
|
{
|
||||||
IntVec3 testPos = center + new IntVec3(
|
IntVec3 testPos = center + new IntVec3(
|
||||||
@@ -210,21 +274,18 @@ namespace ArachnaeSwarm
|
|||||||
|
|
||||||
if (!testPos.InBounds(map))
|
if (!testPos.InBounds(map))
|
||||||
{
|
{
|
||||||
// 找到边界位置
|
|
||||||
IntVec3 edgePos = FindClosestValidPosition(testPos, map);
|
IntVec3 edgePos = FindClosestValidPosition(testPos, map);
|
||||||
Log.Message($"Found map edge position: {edgePos} (direction: {direction}, distance: {i})");
|
Log.Message($"Found map edge position: {edgePos} (direction: {direction}, distance: {i})");
|
||||||
return edgePos;
|
return edgePos;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果没找到边界,使用随机边缘位置
|
|
||||||
Log.Warning("Could not find map edge in direction, using random edge");
|
Log.Warning("Could not find map edge in direction, using random edge");
|
||||||
return GetRandomMapEdgePosition(map);
|
return GetRandomMapEdgePosition(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
private IntVec3 FindClosestValidPosition(IntVec3 invalidPos, Map map)
|
private IntVec3 FindClosestValidPosition(IntVec3 invalidPos, Map map)
|
||||||
{
|
{
|
||||||
// 在无效位置周围寻找有效的边界位置
|
|
||||||
for (int radius = 1; radius <= 5; radius++)
|
for (int radius = 1; radius <= 5; radius++)
|
||||||
{
|
{
|
||||||
foreach (IntVec3 pos in GenRadial.RadialPatternInRadius(radius))
|
foreach (IntVec3 pos in GenRadial.RadialPatternInRadius(radius))
|
||||||
@@ -240,26 +301,8 @@ namespace ArachnaeSwarm
|
|||||||
return map.Center;
|
return map.Center;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 旧的 OppositeMapEdge 逻辑(保留作为参考)
|
|
||||||
private IntVec3 GetOppositeMapEdgePosition(Map map, IntVec3 startPos)
|
|
||||||
{
|
|
||||||
// 计算从起点指向地图中心的方向,然后取反
|
|
||||||
Vector3 toCenter = (map.Center.ToVector3() - startPos.ToVector3()).normalized;
|
|
||||||
Vector3 oppositeDirection = -toCenter;
|
|
||||||
|
|
||||||
// 如果方向为零向量,使用随机方向
|
|
||||||
if (oppositeDirection == Vector3.zero)
|
|
||||||
{
|
|
||||||
oppositeDirection = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
|
|
||||||
}
|
|
||||||
|
|
||||||
Log.Message($"Opposite direction from {startPos}: {oppositeDirection}");
|
|
||||||
return GetMapEdgePosition(map, oppositeDirection);
|
|
||||||
}
|
|
||||||
|
|
||||||
private IntVec3 GetRandomMapEdgePosition(Map map)
|
private IntVec3 GetRandomMapEdgePosition(Map map)
|
||||||
{
|
{
|
||||||
// 随机选择一个地图边缘位置
|
|
||||||
int edge = Rand.Range(0, 4);
|
int edge = Rand.Range(0, 4);
|
||||||
int x, z;
|
int x, z;
|
||||||
|
|
||||||
@@ -305,7 +348,6 @@ namespace ArachnaeSwarm
|
|||||||
{
|
{
|
||||||
Vector3 direction = (target.Cell.ToVector3() - parent.pawn.Position.ToVector3()).normalized;
|
Vector3 direction = (target.Cell.ToVector3() - parent.pawn.Position.ToVector3()).normalized;
|
||||||
|
|
||||||
// 如果方向为零向量,使用随机方向
|
|
||||||
if (direction == Vector3.zero)
|
if (direction == Vector3.zero)
|
||||||
{
|
{
|
||||||
direction = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
|
direction = new Vector3(Rand.Range(-1f, 1f), 0, Rand.Range(-1f, 1f)).normalized;
|
||||||
@@ -317,7 +359,6 @@ namespace ArachnaeSwarm
|
|||||||
|
|
||||||
private void CreateStandardFlyOver(IntVec3 startPos, IntVec3 endPos)
|
private void CreateStandardFlyOver(IntVec3 startPos, IntVec3 endPos)
|
||||||
{
|
{
|
||||||
// 确保有默认的飞越定义
|
|
||||||
ThingDef flyOverDef = Props.flyOverDef ?? DefDatabase<ThingDef>.GetNamedSilentFail("ARA_HiveShip");
|
ThingDef flyOverDef = Props.flyOverDef ?? DefDatabase<ThingDef>.GetNamedSilentFail("ARA_HiveShip");
|
||||||
if (flyOverDef == null)
|
if (flyOverDef == null)
|
||||||
{
|
{
|
||||||
@@ -334,14 +375,12 @@ namespace ArachnaeSwarm
|
|||||||
Props.altitude
|
Props.altitude
|
||||||
);
|
);
|
||||||
|
|
||||||
// 设置属性
|
|
||||||
flyOver.spawnContentsOnImpact = Props.dropContentsOnImpact;
|
flyOver.spawnContentsOnImpact = Props.dropContentsOnImpact;
|
||||||
flyOver.playFlyOverSound = Props.playFlyOverSound;
|
flyOver.playFlyOverSound = Props.playFlyOverSound;
|
||||||
|
|
||||||
// 应用自定义音效
|
|
||||||
if (Props.customSound != null)
|
if (Props.customSound != null)
|
||||||
{
|
{
|
||||||
// 这里需要更复杂的逻辑来替换音效
|
// 自定义音效逻辑
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.Message($"Standard FlyOver created: {flyOver} from {startPos} to {endPos}");
|
Log.Message($"Standard FlyOver created: {flyOver} from {startPos} to {endPos}");
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ namespace ArachnaeSwarm
|
|||||||
{
|
{
|
||||||
public ThingDef flyOverDef; // 飞越物体的 ThingDef
|
public ThingDef flyOverDef; // 飞越物体的 ThingDef
|
||||||
public FlyOverType flyOverType = FlyOverType.Standard; // 飞越类型
|
public FlyOverType flyOverType = FlyOverType.Standard; // 飞越类型
|
||||||
|
public ApproachType approachType = ApproachType.Standard; // 进场类型
|
||||||
public float flightSpeed = 1f; // 飞行速度
|
public float flightSpeed = 1f; // 飞行速度
|
||||||
public float altitude = 15f; // 飞行高度
|
public float altitude = 15f; // 飞行高度
|
||||||
public bool spawnContents = false; // 是否生成内容物
|
public bool spawnContents = false; // 是否生成内容物
|
||||||
@@ -16,11 +17,11 @@ namespace ArachnaeSwarm
|
|||||||
public SoundDef customSound; // 自定义音效
|
public SoundDef customSound; // 自定义音效
|
||||||
public bool playFlyOverSound = true; // 是否播放飞越音效
|
public bool playFlyOverSound = true; // 是否播放飞越音效
|
||||||
|
|
||||||
// 起始位置选项
|
// 起始位置选项(当approachType为Standard时使用)
|
||||||
public StartPosition startPosition = StartPosition.Caster;
|
public StartPosition startPosition = StartPosition.Caster;
|
||||||
public IntVec3 customStartOffset = IntVec3.Zero;
|
public IntVec3 customStartOffset = IntVec3.Zero;
|
||||||
|
|
||||||
// 终点位置选项
|
// 终点位置选项(当approachType为Standard时使用)
|
||||||
public EndPosition endPosition = EndPosition.TargetCell;
|
public EndPosition endPosition = EndPosition.TargetCell;
|
||||||
public IntVec3 customEndOffset = IntVec3.Zero;
|
public IntVec3 customEndOffset = IntVec3.Zero;
|
||||||
public int flyOverDistance = 30; // 飞越距离(当终点为自定义时)
|
public int flyOverDistance = 30; // 飞越距离(当终点为自定义时)
|
||||||
@@ -41,6 +42,13 @@ namespace ArachnaeSwarm
|
|||||||
Reconnaissance // 侦察飞越
|
Reconnaissance // 侦察飞越
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增:进场类型枚举
|
||||||
|
public enum ApproachType
|
||||||
|
{
|
||||||
|
Standard, // 标准进场(使用原有的位置计算)
|
||||||
|
Perpendicular // 垂直线进场(垂直于施法者-目标连线)
|
||||||
|
}
|
||||||
|
|
||||||
// 起始位置枚举
|
// 起始位置枚举
|
||||||
public enum StartPosition
|
public enum StartPosition
|
||||||
{
|
{
|
||||||
@@ -56,7 +64,7 @@ namespace ArachnaeSwarm
|
|||||||
TargetCell, // 目标单元格
|
TargetCell, // 目标单元格
|
||||||
OppositeMapEdge, // 对面地图边缘
|
OppositeMapEdge, // 对面地图边缘
|
||||||
CustomOffset, // 自定义偏移
|
CustomOffset, // 自定义偏移
|
||||||
FixedDistance, // 固定距离
|
FixedDistance, // 固定距离
|
||||||
RandomMapEdge
|
RandomMapEdge
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,14 @@ namespace ArachnaeSwarm
|
|||||||
public float currentFadeInTime = 0f; // 当前淡入时间
|
public float currentFadeInTime = 0f; // 当前淡入时间
|
||||||
public bool fadeInCompleted = false; // 淡入是否完成
|
public bool fadeInCompleted = false; // 淡入是否完成
|
||||||
|
|
||||||
|
// 淡出效果相关
|
||||||
|
public float fadeOutDuration = 0f; // 动态计算的淡出持续时间
|
||||||
|
public float currentFadeOutTime = 0f; // 当前淡出时间
|
||||||
|
public bool fadeOutStarted = false; // 淡出是否开始
|
||||||
|
public bool fadeOutCompleted = false; // 淡出是否完成
|
||||||
|
public float fadeOutStartProgress = 0.7f; // 开始淡出的进度阈值(0-1)
|
||||||
|
public float defaultFadeOutDuration = 1.5f; // 默认淡出持续时间(仅用于销毁)
|
||||||
|
|
||||||
// 状态标志
|
// 状态标志
|
||||||
public bool hasStarted = false;
|
public bool hasStarted = false;
|
||||||
public bool hasCompleted = false;
|
public bool hasCompleted = false;
|
||||||
@@ -110,6 +118,55 @@ namespace ArachnaeSwarm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 淡出透明度(0-1)
|
||||||
|
public float FadeOutAlpha
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!fadeOutStarted) return 1f;
|
||||||
|
if (fadeOutCompleted) return 0f;
|
||||||
|
return Mathf.Clamp01(1f - (currentFadeOutTime / fadeOutDuration));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 总体透明度(淡入 * 淡出)
|
||||||
|
public float OverallAlpha
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return FadeInAlpha * FadeOutAlpha;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增:计算剩余飞行时间(秒)
|
||||||
|
public float RemainingFlightTime
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
float remainingProgress = 1f - currentProgress;
|
||||||
|
return remainingProgress / (flightSpeed * 0.001f) * (1f / 60f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 新增:计算基于剩余距离的淡出持续时间
|
||||||
|
private float CalculateDynamicFadeOutDuration()
|
||||||
|
{
|
||||||
|
// 获取 ModExtension 配置
|
||||||
|
var shadowExtension = def.GetModExtension<FlyOverShadowExtension>();
|
||||||
|
float minFadeOutDuration = shadowExtension?.minFadeOutDuration ?? 0.5f;
|
||||||
|
float maxFadeOutDuration = shadowExtension?.maxFadeOutDuration ?? 3f;
|
||||||
|
float fadeOutDistanceFactor = shadowExtension?.fadeOutDistanceFactor ?? 0.3f;
|
||||||
|
|
||||||
|
// 计算剩余飞行时间
|
||||||
|
float remainingTime = RemainingFlightTime;
|
||||||
|
|
||||||
|
// 使用剩余时间的一部分作为淡出持续时间
|
||||||
|
float dynamicDuration = remainingTime * fadeOutDistanceFactor;
|
||||||
|
|
||||||
|
// 限制在最小和最大范围内
|
||||||
|
return Mathf.Clamp(dynamicDuration, minFadeOutDuration, maxFadeOutDuration);
|
||||||
|
}
|
||||||
|
|
||||||
public FlyOver()
|
public FlyOver()
|
||||||
{
|
{
|
||||||
innerContainer = new ThingOwner<Thing>(this);
|
innerContainer = new ThingOwner<Thing>(this);
|
||||||
@@ -130,6 +187,14 @@ namespace ArachnaeSwarm
|
|||||||
Scribe_Values.Look(ref fadeInDuration, "fadeInDuration", 1.5f);
|
Scribe_Values.Look(ref fadeInDuration, "fadeInDuration", 1.5f);
|
||||||
Scribe_Values.Look(ref currentFadeInTime, "currentFadeInTime", 0f);
|
Scribe_Values.Look(ref currentFadeInTime, "currentFadeInTime", 0f);
|
||||||
Scribe_Values.Look(ref fadeInCompleted, "fadeInCompleted", false);
|
Scribe_Values.Look(ref fadeInCompleted, "fadeInCompleted", false);
|
||||||
|
|
||||||
|
// 淡出效果数据保存
|
||||||
|
Scribe_Values.Look(ref fadeOutDuration, "fadeOutDuration", 0f);
|
||||||
|
Scribe_Values.Look(ref currentFadeOutTime, "currentFadeOutTime", 0f);
|
||||||
|
Scribe_Values.Look(ref fadeOutStarted, "fadeOutStarted", false);
|
||||||
|
Scribe_Values.Look(ref fadeOutCompleted, "fadeOutCompleted", false);
|
||||||
|
Scribe_Values.Look(ref fadeOutStartProgress, "fadeOutStartProgress", 0.7f);
|
||||||
|
Scribe_Values.Look(ref defaultFadeOutDuration, "defaultFadeOutDuration", 1.5f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void SpawnSetup(Map map, bool respawningAfterLoad)
|
public override void SpawnSetup(Map map, bool respawningAfterLoad)
|
||||||
@@ -149,6 +214,12 @@ namespace ArachnaeSwarm
|
|||||||
currentFadeInTime = 0f;
|
currentFadeInTime = 0f;
|
||||||
fadeInCompleted = false;
|
fadeInCompleted = false;
|
||||||
|
|
||||||
|
// 重置淡出状态
|
||||||
|
currentFadeOutTime = 0f;
|
||||||
|
fadeOutStarted = false;
|
||||||
|
fadeOutCompleted = false;
|
||||||
|
fadeOutDuration = 0f;
|
||||||
|
|
||||||
// 开始飞行音效
|
// 开始飞行音效
|
||||||
if (playFlyOverSound && def.skyfaller?.floatingSound != null)
|
if (playFlyOverSound && def.skyfaller?.floatingSound != null)
|
||||||
{
|
{
|
||||||
@@ -169,7 +240,7 @@ namespace ArachnaeSwarm
|
|||||||
// 更新淡入效果
|
// 更新淡入效果
|
||||||
if (!fadeInCompleted)
|
if (!fadeInCompleted)
|
||||||
{
|
{
|
||||||
currentFadeInTime += 1f / 60f; // 假设 60 FPS
|
currentFadeInTime += 1f / 60f;
|
||||||
if (currentFadeInTime >= fadeInDuration)
|
if (currentFadeInTime >= fadeInDuration)
|
||||||
{
|
{
|
||||||
fadeInCompleted = true;
|
fadeInCompleted = true;
|
||||||
@@ -180,11 +251,29 @@ namespace ArachnaeSwarm
|
|||||||
// 更新飞行进度
|
// 更新飞行进度
|
||||||
currentProgress += flightSpeed * 0.001f;
|
currentProgress += flightSpeed * 0.001f;
|
||||||
|
|
||||||
// 更新当前位置(用于碰撞检测等)
|
// 检查是否应该开始淡出(基于剩余距离动态计算)
|
||||||
|
if (!fadeOutStarted && currentProgress >= fadeOutStartProgress)
|
||||||
|
{
|
||||||
|
StartFadeOut();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新淡出效果
|
||||||
|
if (fadeOutStarted && !fadeOutCompleted)
|
||||||
|
{
|
||||||
|
currentFadeOutTime += 1f / 60f;
|
||||||
|
if (currentFadeOutTime >= fadeOutDuration)
|
||||||
|
{
|
||||||
|
fadeOutCompleted = true;
|
||||||
|
currentFadeOutTime = fadeOutDuration;
|
||||||
|
Log.Message("FlyOver fade out completed");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新当前位置
|
||||||
UpdatePosition();
|
UpdatePosition();
|
||||||
|
|
||||||
// 维持飞行音效
|
// 维持飞行音效(在淡出时逐渐降低音量)
|
||||||
flightSoundPlaying?.Maintain();
|
UpdateFlightSound();
|
||||||
|
|
||||||
// 检查是否到达终点
|
// 检查是否到达终点
|
||||||
if (currentProgress >= 1f)
|
if (currentProgress >= 1f)
|
||||||
@@ -192,16 +281,23 @@ namespace ArachnaeSwarm
|
|||||||
CompleteFlyOver();
|
CompleteFlyOver();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 可选:生成飞行轨迹特效
|
// 生成飞行轨迹特效(在淡出时减少特效)
|
||||||
if (Rand.MTBEventOccurs(0.5f, 1f, 1f) && def.skyfaller?.motesPerCell > 0)
|
CreateFlightEffects();
|
||||||
{
|
}
|
||||||
CreateFlightEffects();
|
|
||||||
}
|
// 新增:开始淡出效果
|
||||||
|
private void StartFadeOut()
|
||||||
|
{
|
||||||
|
fadeOutStarted = true;
|
||||||
|
|
||||||
|
// 基于剩余距离动态计算淡出持续时间
|
||||||
|
fadeOutDuration = CalculateDynamicFadeOutDuration();
|
||||||
|
|
||||||
|
Log.Message($"FlyOver started fade out at progress {currentProgress:F2}, duration: {fadeOutDuration:F2}s, remaining time: {RemainingFlightTime:F2}s");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdatePosition()
|
private void UpdatePosition()
|
||||||
{
|
{
|
||||||
// 更新物体的网格位置(用于碰撞检测等)
|
|
||||||
Vector3 currentWorldPos = Vector3.Lerp(startPosition.ToVector3(), endPosition.ToVector3(), currentProgress);
|
Vector3 currentWorldPos = Vector3.Lerp(startPosition.ToVector3(), endPosition.ToVector3(), currentProgress);
|
||||||
IntVec3 newPos = currentWorldPos.ToIntVec3();
|
IntVec3 newPos = currentWorldPos.ToIntVec3();
|
||||||
|
|
||||||
@@ -211,6 +307,19 @@ namespace ArachnaeSwarm
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void UpdateFlightSound()
|
||||||
|
{
|
||||||
|
if (flightSoundPlaying != null)
|
||||||
|
{
|
||||||
|
if (fadeOutStarted)
|
||||||
|
{
|
||||||
|
// 淡出时逐渐降低音效音量
|
||||||
|
flightSoundPlaying.externalParams["VolumeFactor"] = FadeOutAlpha;
|
||||||
|
}
|
||||||
|
flightSoundPlaying?.Maintain();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void CompleteFlyOver()
|
private void CompleteFlyOver()
|
||||||
{
|
{
|
||||||
hasCompleted = true;
|
hasCompleted = true;
|
||||||
@@ -235,6 +344,21 @@ namespace ArachnaeSwarm
|
|||||||
Destroy();
|
Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 新增:紧急销毁方法(使用默认淡出时间)
|
||||||
|
public void EmergencyDestroy()
|
||||||
|
{
|
||||||
|
if (!fadeOutStarted)
|
||||||
|
{
|
||||||
|
// 如果还没有开始淡出,使用默认淡出时间
|
||||||
|
fadeOutStarted = true;
|
||||||
|
fadeOutDuration = defaultFadeOutDuration;
|
||||||
|
Log.Message($"FlyOver emergency destroy with default fade out: {defaultFadeOutDuration}s");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 设置标记,下一帧会处理淡出
|
||||||
|
hasCompleted = true;
|
||||||
|
}
|
||||||
|
|
||||||
private void SpawnContents()
|
private void SpawnContents()
|
||||||
{
|
{
|
||||||
foreach (Thing thing in innerContainer)
|
foreach (Thing thing in innerContainer)
|
||||||
@@ -250,33 +374,36 @@ namespace ArachnaeSwarm
|
|||||||
private void CreateFlightEffects()
|
private void CreateFlightEffects()
|
||||||
{
|
{
|
||||||
// 在飞行轨迹上生成粒子效果
|
// 在飞行轨迹上生成粒子效果
|
||||||
Vector3 effectPos = DrawPos;
|
if (Rand.MTBEventOccurs(0.5f, 1f, 1f) && def.skyfaller?.motesPerCell > 0 && !fadeOutCompleted)
|
||||||
effectPos.y = AltitudeLayer.MoteOverhead.AltitudeFor();
|
|
||||||
FleckMaker.ThrowSmoke(effectPos, base.Map, 1f);
|
|
||||||
|
|
||||||
// 可选:根据速度生成更多效果
|
|
||||||
if (flightSpeed > 2f)
|
|
||||||
{
|
{
|
||||||
FleckMaker.ThrowAirPuffUp(effectPos, base.Map);
|
Vector3 effectPos = DrawPos;
|
||||||
|
effectPos.y = AltitudeLayer.MoteOverhead.AltitudeFor();
|
||||||
|
|
||||||
|
// 淡出时减少粒子效果强度
|
||||||
|
float effectIntensity = fadeOutStarted ? FadeOutAlpha : 1f;
|
||||||
|
FleckMaker.ThrowSmoke(effectPos, base.Map, 1f * effectIntensity);
|
||||||
|
|
||||||
|
// 可选:根据速度生成更多效果
|
||||||
|
if (flightSpeed > 2f && !fadeOutStarted)
|
||||||
|
{
|
||||||
|
FleckMaker.ThrowAirPuffUp(effectPos, base.Map);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 关键修改:添加淡入效果的绘制方法
|
// 绘制方法保持不变,使用OverallAlpha
|
||||||
protected override void DrawAt(Vector3 drawLoc, bool flip = false)
|
protected override void DrawAt(Vector3 drawLoc, bool flip = false)
|
||||||
{
|
{
|
||||||
Vector3 finalDrawPos = drawLoc;
|
Vector3 finalDrawPos = drawLoc;
|
||||||
|
|
||||||
// 绘制阴影
|
|
||||||
if (createShadow)
|
if (createShadow)
|
||||||
{
|
{
|
||||||
DrawFlightShadow();
|
DrawFlightShadow();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 绘制主体 - 使用带淡入效果的绘制方法
|
|
||||||
DrawFlyOverWithFade(finalDrawPos);
|
DrawFlyOverWithFade(finalDrawPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 带淡入效果的主体绘制方法
|
|
||||||
protected virtual void DrawFlyOverWithFade(Vector3 drawPos)
|
protected virtual void DrawFlyOverWithFade(Vector3 drawPos)
|
||||||
{
|
{
|
||||||
Thing thingForGraphic = GetThingForGraphic();
|
Thing thingForGraphic = GetThingForGraphic();
|
||||||
@@ -285,41 +412,41 @@ namespace ArachnaeSwarm
|
|||||||
if (graphic == null)
|
if (graphic == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// 获取原始材质
|
|
||||||
Material material = graphic.MatSingle;
|
Material material = graphic.MatSingle;
|
||||||
if (material == null)
|
if (material == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// 计算淡入透明度
|
float alpha = OverallAlpha;
|
||||||
float alpha = FadeInAlpha;
|
|
||||||
|
|
||||||
// 如果已经完全淡入,使用原版绘制方法以获得最佳性能
|
if (alpha <= 0.001f)
|
||||||
if (alpha >= 0.999f)
|
return;
|
||||||
|
|
||||||
|
if (fadeInCompleted && !fadeOutStarted && alpha >= 0.999f)
|
||||||
{
|
{
|
||||||
graphic.Draw(drawPos, Rot4.North, thingForGraphic, ExactRotation.eulerAngles.y);
|
Vector3 highAltitudePos = drawPos;
|
||||||
|
highAltitudePos.y = AltitudeLayer.MetaOverlays.AltitudeFor();
|
||||||
|
graphic.Draw(highAltitudePos, Rot4.North, thingForGraphic, ExactRotation.eulerAngles.y);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 创建带透明度的材质属性块
|
|
||||||
fadePropertyBlock.SetColor(ShaderPropertyIDs.Color,
|
fadePropertyBlock.SetColor(ShaderPropertyIDs.Color,
|
||||||
new Color(graphic.Color.r, graphic.Color.g, graphic.Color.b, graphic.Color.a * alpha));
|
new Color(graphic.Color.r, graphic.Color.g, graphic.Color.b, graphic.Color.a * alpha));
|
||||||
|
|
||||||
// 计算缩放
|
|
||||||
Vector3 scale = Vector3.one;
|
Vector3 scale = Vector3.one;
|
||||||
if (def.graphicData != null)
|
if (def.graphicData != null)
|
||||||
{
|
{
|
||||||
scale = new Vector3(def.graphicData.drawSize.x, 1f, def.graphicData.drawSize.y);
|
scale = new Vector3(def.graphicData.drawSize.x, 1f, def.graphicData.drawSize.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用自定义绘制实现淡入效果
|
Vector3 highPos = drawPos;
|
||||||
Matrix4x4 matrix = Matrix4x4.TRS(drawPos, ExactRotation, scale);
|
highPos.y = AltitudeLayer.MetaOverlays.AltitudeFor();
|
||||||
|
|
||||||
|
Matrix4x4 matrix = Matrix4x4.TRS(highPos, ExactRotation, scale);
|
||||||
Graphics.DrawMesh(MeshPool.plane10, matrix, material, 0, null, 0, fadePropertyBlock);
|
Graphics.DrawMesh(MeshPool.plane10, matrix, material, 0, null, 0, fadePropertyBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 简化的阴影绘制方法 - 完全移除旋转(模仿原版)
|
|
||||||
protected virtual void DrawFlightShadow()
|
protected virtual void DrawFlightShadow()
|
||||||
{
|
{
|
||||||
// 检查是否有 ModExtension
|
|
||||||
var shadowExtension = def.GetModExtension<FlyOverShadowExtension>();
|
var shadowExtension = def.GetModExtension<FlyOverShadowExtension>();
|
||||||
|
|
||||||
Material shadowMaterial;
|
Material shadowMaterial;
|
||||||
@@ -338,7 +465,6 @@ namespace ArachnaeSwarm
|
|||||||
Vector3 shadowPos = DrawPos;
|
Vector3 shadowPos = DrawPos;
|
||||||
shadowPos.y = AltitudeLayer.Shadows.AltitudeFor();
|
shadowPos.y = AltitudeLayer.Shadows.AltitudeFor();
|
||||||
|
|
||||||
// 使用 ModExtension 参数或默认值
|
|
||||||
float shadowIntensity = shadowExtension?.shadowIntensity ?? 1f;
|
float shadowIntensity = shadowExtension?.shadowIntensity ?? 1f;
|
||||||
float minAlpha = shadowExtension?.minShadowAlpha ?? 0.3f;
|
float minAlpha = shadowExtension?.minShadowAlpha ?? 0.3f;
|
||||||
float maxAlpha = shadowExtension?.maxShadowAlpha ?? 1f;
|
float maxAlpha = shadowExtension?.maxShadowAlpha ?? 1f;
|
||||||
@@ -348,10 +474,11 @@ namespace ArachnaeSwarm
|
|||||||
float shadowAlpha = Mathf.Lerp(minAlpha, maxAlpha, currentProgress) * shadowIntensity;
|
float shadowAlpha = Mathf.Lerp(minAlpha, maxAlpha, currentProgress) * shadowIntensity;
|
||||||
float shadowScale = Mathf.Lerp(minScale, maxScale, currentProgress);
|
float shadowScale = Mathf.Lerp(minScale, maxScale, currentProgress);
|
||||||
|
|
||||||
// 阴影也应用淡入效果
|
shadowAlpha *= OverallAlpha;
|
||||||
shadowAlpha *= FadeInAlpha;
|
|
||||||
|
if (shadowAlpha <= 0.001f)
|
||||||
|
return;
|
||||||
|
|
||||||
// 完全移除阴影旋转 - 始终使用默认朝向(模仿原版 Projectile)
|
|
||||||
Vector3 s = new Vector3(shadowScale, 1f, shadowScale);
|
Vector3 s = new Vector3(shadowScale, 1f, shadowScale);
|
||||||
Vector3 vector = new Vector3(0f, -0.01f, 0f);
|
Vector3 vector = new Vector3(0f, -0.01f, 0f);
|
||||||
Matrix4x4 matrix = Matrix4x4.TRS(shadowPos + vector, Quaternion.identity, s);
|
Matrix4x4 matrix = Matrix4x4.TRS(shadowPos + vector, Quaternion.identity, s);
|
||||||
@@ -359,7 +486,7 @@ namespace ArachnaeSwarm
|
|||||||
Graphics.DrawMesh(MeshPool.plane10, matrix, shadowMaterial, 0);
|
Graphics.DrawMesh(MeshPool.plane10, matrix, shadowMaterial, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// IThingHolder 接口实现
|
// IThingHolder 接口实现和其他方法保持不变
|
||||||
public ThingOwner GetDirectlyHeldThings()
|
public ThingOwner GetDirectlyHeldThings()
|
||||||
{
|
{
|
||||||
return innerContainer;
|
return innerContainer;
|
||||||
@@ -381,7 +508,8 @@ namespace ArachnaeSwarm
|
|||||||
|
|
||||||
// 工具方法:创建飞越物体
|
// 工具方法:创建飞越物体
|
||||||
public static FlyOver MakeFlyOver(ThingDef flyOverDef, IntVec3 start, IntVec3 end, Map map,
|
public static FlyOver MakeFlyOver(ThingDef flyOverDef, IntVec3 start, IntVec3 end, Map map,
|
||||||
float speed = 1f, float height = 10f, ThingOwner contents = null, float fadeInDuration = 1.5f)
|
float speed = 1f, float height = 10f, ThingOwner contents = null,
|
||||||
|
float fadeInDuration = 1.5f, float defaultFadeOutDuration = 1.5f)
|
||||||
{
|
{
|
||||||
FlyOver flyOver = (FlyOver)ThingMaker.MakeThing(flyOverDef);
|
FlyOver flyOver = (FlyOver)ThingMaker.MakeThing(flyOverDef);
|
||||||
flyOver.startPosition = start;
|
flyOver.startPosition = start;
|
||||||
@@ -389,6 +517,7 @@ namespace ArachnaeSwarm
|
|||||||
flyOver.flightSpeed = speed;
|
flyOver.flightSpeed = speed;
|
||||||
flyOver.altitude = height;
|
flyOver.altitude = height;
|
||||||
flyOver.fadeInDuration = fadeInDuration;
|
flyOver.fadeInDuration = fadeInDuration;
|
||||||
|
flyOver.defaultFadeOutDuration = defaultFadeOutDuration;
|
||||||
|
|
||||||
if (contents != null)
|
if (contents != null)
|
||||||
{
|
{
|
||||||
@@ -397,51 +526,32 @@ namespace ArachnaeSwarm
|
|||||||
|
|
||||||
GenSpawn.Spawn(flyOver, start, map);
|
GenSpawn.Spawn(flyOver, start, map);
|
||||||
|
|
||||||
Log.Message($"FlyOver created: {flyOver} from {start} to {end} at altitude {height} with {fadeInDuration}s fade-in");
|
Log.Message($"FlyOver created: {flyOver} from {start} to {end} at altitude {height}");
|
||||||
return flyOver;
|
return flyOver;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 高空版本的工具方法
|
// 其他工具方法...
|
||||||
public static FlyOver MakeHighAltitudeFlyOver(ThingDef flyOverDef, IntVec3 start, IntVec3 end, Map map,
|
|
||||||
float speed = 2f, float height = 50f, ThingOwner contents = null, float fadeInDuration = 1.5f)
|
|
||||||
{
|
|
||||||
FlyOver flyOver = MakeFlyOver(flyOverDef, start, end, map, speed, height, contents, fadeInDuration);
|
|
||||||
|
|
||||||
// 高空特有的设置
|
|
||||||
flyOver.playFlyOverSound = false;
|
|
||||||
flyOver.createShadow = true;
|
|
||||||
flyOver.spawnContentsOnImpact = false;
|
|
||||||
|
|
||||||
Log.Message($"HighAltitude FlyOver created: {flyOver} from {start} to {end} at altitude {height}");
|
|
||||||
return flyOver;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 快速淡入版本的工具方法
|
|
||||||
public static FlyOver MakeQuickFlyOver(ThingDef flyOverDef, IntVec3 start, IntVec3 end, Map map,
|
|
||||||
float speed = 1f, float height = 10f, ThingOwner contents = null)
|
|
||||||
{
|
|
||||||
return MakeFlyOver(flyOverDef, start, end, map, speed, height, contents, 0.5f);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 慢速淡入版本的工具方法(适合非常大的模型)
|
|
||||||
public static FlyOver MakeSlowFlyOver(ThingDef flyOverDef, IntVec3 start, IntVec3 end, Map map,
|
|
||||||
float speed = 1f, float height = 10f, ThingOwner contents = null)
|
|
||||||
{
|
|
||||||
return MakeFlyOver(flyOverDef, start, end, map, speed, height, contents, 3f);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新的 ModExtension,添加淡入配置
|
// 更新的 ModExtension,添加淡出配置
|
||||||
public class FlyOverShadowExtension : DefModExtension
|
public class FlyOverShadowExtension : DefModExtension
|
||||||
{
|
{
|
||||||
public string customShadowPath; // 自定义阴影材质路径
|
public string customShadowPath;
|
||||||
public float shadowIntensity = 0.6f; // 阴影强度
|
public float shadowIntensity = 0.6f;
|
||||||
public bool useCustomShadow = false; // 是否使用自定义阴影
|
public bool useCustomShadow = false;
|
||||||
public float minShadowAlpha = 0.05f; // 最小阴影透明度
|
public float minShadowAlpha = 0.05f;
|
||||||
public float maxShadowAlpha = 0.2f; // 最大阴影透明度
|
public float maxShadowAlpha = 0.2f;
|
||||||
public float minShadowScale = 0.5f; // 最小阴影大小
|
public float minShadowScale = 0.5f;
|
||||||
public float maxShadowScale = 1.0f; // 最大阴影大小
|
public float maxShadowScale = 1.0f;
|
||||||
public float defaultFadeInDuration = 1.5f; // 默认淡入持续时间
|
public float defaultFadeInDuration = 1.5f;
|
||||||
public float ActuallyHeight = 150f; // 实际高度
|
public float defaultFadeOutDuration = 1.5f; // 默认淡出持续时间(用于紧急销毁)
|
||||||
|
public float fadeOutStartProgress = 0.98f;
|
||||||
|
|
||||||
|
// 新增:动态淡出配置
|
||||||
|
public float minFadeOutDuration = 0.5f; // 最小淡出持续时间
|
||||||
|
public float maxFadeOutDuration = 3f; // 最大淡出持续时间
|
||||||
|
public float fadeOutDistanceFactor = 0.3f; // 淡出距离因子(剩余时间的百分比)
|
||||||
|
|
||||||
|
public float ActuallyHeight = 150f;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user