diff --git a/Assets/Art/FengLei/Boss/1594/1594_PT.prefab.meta b/Assets/Art/FengLei/Boss/1594/1594_PT.prefab.meta
new file mode 100644
index 000000000..a411ecd4d
--- /dev/null
+++ b/Assets/Art/FengLei/Boss/1594/1594_PT.prefab.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 8c5a0a74fb5ddcd47abbdfe715e47e3f
+PrefabImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Assets/MyGame/Scripts/Items/Bullits/BullitMove.cs b/Assets/MyGame/Scripts/Items/Bullits/BullitMove.cs
index d3eb2d94c..59651fd38 100644
--- a/Assets/MyGame/Scripts/Items/Bullits/BullitMove.cs
+++ b/Assets/MyGame/Scripts/Items/Bullits/BullitMove.cs
@@ -27,6 +27,14 @@ public class BullitMove : MonoBehaviour
public float distanceForMaxTurn = 1f; // 在此距离内达到最大转向速度
float hitDistance = 2f; // 命中判定距离
+ // ⭐ 三合一抛物线(正常炮台散射+锁定时,上下两颗子弹的弧线飞行)
+ // 出膛偏移0 → 中段鼓出到 parabolaAmplitude(弧线最高点)→ 命中前归零(三发收敛到同一条鱼)
+ Vector2 parabolaAxis = Vector2.right; // 横向鼓出方向(垂直于炮口→目标连线)
+ float parabolaAmplitude = 0f; // 最高点横向鼓出幅度(<=0 关闭抛物线)
+ float parabolaInitialDistance = 1f; // 开火时到目标的距离(进度基准)
+ float parabolaPrevLateral = 0f; // 上一帧横向偏移(子弹是增量移动,偏移按帧差叠加)
+ float parabolaBaseSpeed = 0f; // 降速前的原始速度(清理时恢复,防池化复用残留慢速)
+
// ----------------------------------------------------------------
// ⭐ 渲染层级:sortingOrder 优先于 z 深度排序,
// 2D 鱼/飞机设置了 sortingOrder 后会把默认 0 的子弹压在下面,
@@ -84,6 +92,41 @@ public class BullitMove : MonoBehaviour
vector3_startPosition = transform.position;
vector3_startPosition.z = -400;
currShowTime = 0f;
+ // 解锁同时清除抛物线,防止直线飞行时残留横向偏移
+ ClearParabola();
+ }
+
+ ///
+ /// ⭐ 三合一抛物线:子弹在追踪目标的轨迹上叠加横向正弦偏移——
+ /// 出膛偏移0 → 中段鼓出到 amplitude(弧线最高点)→ 命中前归零(和另外两发收敛到同一条鱼)。
+ /// lateralAxis=横向鼓出方向(垂直于炮口→目标连线),totalDistance=开火时到目标的距离。
+ /// bulletSpeed>0 时给这发子弹降速:子弹默认速度太快(如100)时全程飞行仅零点几秒,弧线根本看不清。
+ ///
+ public void SetParabola(Vector2 lateralAxis, float amplitude, float totalDistance, float bulletSpeed = 0f)
+ {
+ parabolaAxis = lateralAxis.sqrMagnitude > 0.0001f ? lateralAxis.normalized : Vector2.right;
+ parabolaAmplitude = amplitude;
+ parabolaInitialDistance = Mathf.Max(0.01f, totalDistance);
+ parabolaPrevLateral = 0f;
+ // ⭐ 降速拉长飞行时间,弧线才看得清;记录原始速度,清理时恢复
+ if (bulletSpeed > 0f)
+ {
+ if (parabolaBaseSpeed <= 0f)
+ parabolaBaseSpeed = moveSpeed;
+ moveSpeed = bulletSpeed;
+ }
+ }
+
+ /// 清除抛物线状态(解锁/回池时调用):关偏移 + 恢复原速度
+ void ClearParabola()
+ {
+ parabolaAmplitude = 0f;
+ parabolaPrevLateral = 0f;
+ if (parabolaBaseSpeed > 0f)
+ {
+ moveSpeed = parabolaBaseSpeed;
+ parabolaBaseSpeed = 0f;
+ }
}
public void Init()
@@ -159,6 +202,19 @@ public class BullitMove : MonoBehaviour
// 沿当前方向移动
transform.position += transform.up * moveSpeed * Time.deltaTime;
+
+ // ⭐ 三合一抛物线:在追踪轨迹上叠加横向正弦偏移
+ // 进度按剩余距离算(dist=初始距离→0,dist=命中距离→1),命中前偏移正好归零,三发收敛到目标身上
+ if (parabolaAmplitude > 0f)
+ {
+ float range = parabolaInitialDistance - hitDistance;
+ float progress = range > 0.1f
+ ? Mathf.Clamp01(1f - (distance - hitDistance) / range)
+ : 1f;
+ float lateralNow = parabolaAmplitude * Mathf.Sin(progress * Mathf.PI);
+ transform.position += (Vector3)parabolaAxis * (lateralNow - parabolaPrevLateral);
+ parabolaPrevLateral = lateralNow;
+ }
}
else
{
diff --git a/Assets/MyGame/aa/UI/Game/FLZY/GameMainPanel_FLZY.prefab b/Assets/MyGame/aa/UI/Game/FLZY/GameMainPanel_FLZY.prefab
index 75f5e985b..1354cf5ed 100644
--- a/Assets/MyGame/aa/UI/Game/FLZY/GameMainPanel_FLZY.prefab
+++ b/Assets/MyGame/aa/UI/Game/FLZY/GameMainPanel_FLZY.prefab
@@ -3213,6 +3213,11 @@ MonoBehaviour:
JinDuTiao: {fileID: 6293566698206718061}
isFrenzy: 0
laserHitDelay: 0.2
+ sanSheNearDistance: 10
+ sanSheFarDistance: 35
+ sanSheMaxBulge: 6
+ sanSheMinBulge: 4
+ sanSheSideBulletSpeed: 50
sitBulletMaxCount: 100
--- !u!1 &5910028015393800118
GameObject:
diff --git a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs
index ee108ac9c..03c81b599 100644
--- a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs
+++ b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs
@@ -1934,9 +1934,21 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
}
/// 战神激光命中延迟(秒):不开实体子弹,开火后延迟此时间直接发 KillFish 给后端(模拟弹道飞行)
- [Tooltip("战神激光命中延迟(秒):不开实体子弹,开火后延迟此时间直接发 KillFish 给后端")]
+ [Tooltip("战神激光命中延迟(秒):不开实体子弹,开火后延迟此时间直接发 KillFish 给后端(模拟弹道飞行)")]
public float laserHitDelay = 0.2f;
+ [Header("三合一抛物线(正常炮台散射+锁定,上下两颗子弹的弧线)")]
+ [Tooltip("近距离阈值:目标距离小于此值时弧线鼓出封顶(防止目标太近子弹乱飘)")]
+ public float sanSheNearDistance = 10f;
+ [Tooltip("远距离阈值:目标距离大于此值时弧线鼓出保底(很远时仍有弧线感)")]
+ public float sanSheFarDistance = 35f;
+ [Tooltip("弧线最高点横向鼓出最大值(目标距离≤近距离阈值时,世界单位)")]
+ public float sanSheMaxBulge = 6f;
+ [Tooltip("弧线最高点横向鼓出最小值(目标距离≥远距离阈值时,世界单位)")]
+ public float sanSheMinBulge = 4f;
+ [Tooltip("三合一侧弹飞行速度(世界单位/秒,0=用子弹默认速度):子弹默认速度太快全程仅零点几秒,弧线看不清,降速拉长飞行时间")]
+ public float sanSheSideBulletSpeed = 50f;
+
private void FireBullet(SitPosData sit, float angle, bool isSanShe, bool isDouble, bool isLock, List bullitIDs,
List fireTargetMonsterIDs = null, List bulletGolds = null)
{
@@ -1972,18 +1984,60 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
// 必须保证三发子弹都创建,否则金币消耗和后端对不上
if (isSanShe && isLock)
{
- // 三发出膛角度:左 -20,中 0,右 +20(锁定子弹会追踪转向主锁目标)
+ // 三发出膛角度:右 -20,中 0,左 +20(锁定子弹会追踪转向主锁目标)
float[] defaultAngles = { angle - 20, angle, angle + 20 };
+ // ⭐ 三合一抛物线:主锁目标有效时,上下两颗子弹走弧线包抄
+ // 鼓出幅度随目标距离变化:近→大,远→小(最高点离中线越近),
+ // 用近距离/远距离两个阈值钳制:很近时封顶不乱飘,很远时保底仍有弧线感
+ bool hasLockTarget = sit.monCotl_Lock != null && sit.monCotl_Lock_Position != null
+ && sit.monCotl_Lock_Position.gameObject.activeInHierarchy;
+ Vector2 toTarget = Vector2.zero;
+ float targetDist = 0f;
+ if (hasLockTarget)
+ {
+ toTarget = (Vector2)sit.monCotl_Lock_Position.position - startPos;
+ targetDist = toTarget.magnitude;
+ hasLockTarget = targetDist > 0.01f;
+ }
+
+ // ⭐ 诊断日志(定位三合一抛物线不生效用,问题解决后删除)
+ if (sit.user == GameManager.Instance.user.id)
+ {
+ float tDiag = Mathf.InverseLerp(sanSheFarDistance, sanSheNearDistance, targetDist);
+ float bulgeDiag = Mathf.Lerp(sanSheMinBulge, sanSheMaxBulge, tDiag);
+ Debug.Log($"[三合一诊断] 进入三合一分支: 主锁目标={(sit.monCotl_Lock != null ? sit.monCotl_Lock.name : "无")} " +
+ $"锁定点={(sit.monCotl_Lock_Position != null ? "有" : "无")} hasLockTarget={hasLockTarget} " +
+ $"目标距离={targetDist:F2} 鼓出={bulgeDiag:F2} 侧弹速度={sanSheSideBulletSpeed} " +
+ $"阈值(近{sanSheNearDistance}/远{sanSheFarDistance}) 幅度(小{sanSheMinBulge}/大{sanSheMaxBulge})");
+ }
+
for (int i = 0; i < 3; i++)
{
// lockTarget 传 null:CreateBullet 内部兜底会 Lock(sit.monCotl_Lock, sit.monCotl_Lock_Position),
// 三发全部锁定同一条主锁目标;主锁目标为空时按普通子弹发射(不锁定)
- CreateBullet(sit, startPos, defaultAngles[i], isDouble, true, SafeBid(i), null, null, GetBulletGold(i));
+ var bullet = CreateBullet(sit, startPos, defaultAngles[i], isDouble, true, SafeBid(i), null, null, GetBulletGold(i));
+
+ // ⭐ 上下两颗(i=0/2)挂抛物线,中间(i=1)直线:
+ // 鼓出方向垂直于炮口→目标连线,两颗各往自己外侧鼓,形成弧线包抄汇聚
+ // 侧弹同时降速(子弹默认100太快,零点几秒飞完,弧线看不清)
+ if (bullet != null && hasLockTarget && i != 1)
+ {
+ // 近距离阈值内→最大鼓出,远距离阈值外→最小鼓出,中间线性过渡
+ float t = Mathf.InverseLerp(sanSheFarDistance, sanSheNearDistance, targetDist);
+ float bulge = Mathf.Lerp(sanSheMinBulge, sanSheMaxBulge, t);
+ Vector2 axisRight = new Vector2(toTarget.y, -toTarget.x).normalized;
+ bullet.SetParabola(i == 0 ? axisRight : -axisRight, bulge, targetDist, sanSheSideBulletSpeed);
+ }
}
}
else if (isSanShe)
{
+ // ⭐ 诊断日志(定位三合一抛物线不生效用,问题解决后删除)
+ if (sit.user == GameManager.Instance.user.id)
+ Debug.LogWarning($"[三合一诊断] 走了【散射不锁定】直飞分支: 锁定开关={isLock} → 三发直飞无终点无弧线。" +
+ $"三合一抛物线需要: 散射+锁定都开 且 锁定到一条鱼");
+
CreateBullet(sit, startPos, angle - 20, isDouble, isLock, SafeBid(0), null, null, GetBulletGold(0));
CreateBullet(sit, startPos, angle, isDouble, isLock, SafeBid(1), null, null, GetBulletGold(1));
CreateBullet(sit, startPos, angle + 20, isDouble, isLock, SafeBid(2), null, null, GetBulletGold(2));