This commit is contained in:
2026-10-01 22:26:56 +08:00
parent c14b6e69b4
commit 3c758438b0
3 changed files with 125 additions and 45 deletions
+2 -1
View File
@@ -4280,7 +4280,7 @@ MonoBehaviour:
spawnList: []
isCreateFish: 0
isFrozen: 0
debugSpawnFishNumber: 11023
debugSpawnFishNumber: 12034
isleft: 0
debugSpawnAllLines: 0
fishList_All: []
@@ -4290,6 +4290,7 @@ MonoBehaviour:
fishList_TS: []
fishList_TS_Boss: []
isResources: 0
lineConflictCooldown: 1
--- !u!114 &2075409202
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -1239,10 +1239,17 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
if (MonsterMoveLine.dic_BezierCurveDatas.TryGetValue("鱼阵" + pathId, out var bd700))
baseAngle = bd700.start.y > 0f ? 90f : -90f;
for (int i = 1; i <= 17; i++)
// ⭐ 扇形:17 条(单数)以基准角为中心左右对称展开,总张角 150°;
// 顺序从中间往两边:第1条在正中间(0°),之后依次 +step、-step 交替(保证左右对称)
const int fanFishCount = 17;
const float fanTotalAngle = 150f;
float fanStep = fanTotalAngle / (fanFishCount - 1); // 150 / 16 = 9.375°
for (int i = 1; i <= fanFishCount; i++)
{
// 交替正负角度,形成扇形分布(从基准角向两侧±5°~±85°展开)
float angle = i * 5f * (i % 2 == 0 ? -1f : 1f);
// i=1→0°, 2→+9.375°, 3→-9.375°, 4→+18.75°, 5→-18.75° … 16→+75°, 17→-75°
float mag = (i / 2) * fanStep;
float angle = i <= 1 ? 0f : (i % 2 == 0 ? mag : -mag);
// ⭐ 方向判断与原始flipY700一致:路线起点start.y<0的阵绕鱼头轴翻面180°
// (鱼头方向不变,肚背朝向翻转);原始写法为 transform.Rotate(Z,180,Space.Self)
float flipZ = (bd700 != null && bd700.start.y < 0f) ? 180f : 0f;
@@ -1272,7 +1279,7 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
mc.Init(pathId.ToString(), cfg.times, true, yz.arrayNumber);
// ⭐ 鱼阵调试日志:输出每条子鱼生成后的旋转与缩放(排查"有的正有的反")
Debug.Log($"[鱼阵调试] 阵={yz.arrayNumber}(扇形700) pathId={pathId} 第{i}/{16}条 guid={mc.guid} " +
Debug.Log($"[鱼阵调试] 阵={yz.arrayNumber}(扇形700) pathId={pathId} 第{i}/{fanFishCount}条 guid={mc.guid} " +
$"rotation={fish.transform.eulerAngles.ToString("F1")} localScale={fish.transform.localScale.ToString("F3")}");
}
}
+112 -40
View File
@@ -1,53 +1,125 @@
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
/// <summary>
/// 纵向循环滚动背景(所有直接子物体按顺序当作背景图,第一个在最上面)。
///
/// 适配不同机型的做法:背景大小仍由子物体上的 BgFit 按屏幕铺满,这里不自己算缩放,
/// 而是在“第一帧”(BgFit 缩放完成后)读出背景的真实世界高度,用它来定间距:
/// 间距 = 真实图高 - 2像素
/// 间距和图高永远同一个来源,所以不管什么分辨率/宽高比,接缝都不会张开露黑。
/// 另外位置按整像素对齐、底部留余量并跟随相机,运行中不会出现黑线。
/// </summary>
public class BGManager : MonoBehaviour
{
//private float height;
public Vector3 upV3;
public Vector3 centerV3;
public Vector3 downV3;
private float currHeight;
public float speed;
public float height;
// Start is called before the first frame update
[Header("滚动")]
[Tooltip("背景向下滚动的速度(世界单位/秒)")]
public float speed = 3f;
[Header("拼接(消除黑线)")]
[Tooltip("相邻两张背景的重叠像素:留一点重叠,接缝就不会因取整/采样露黑")]
public float overlapPixels = 2f;
[Tooltip("背景底部相对屏幕下边缘多留的比例,避免镜头抖动时露黑")]
public float bottomMargin = 0.05f;
[Tooltip("位置按整像素对齐:接缝只会落在像素边界上,画面更稳(参考工程的背景也是这样)")]
public bool snapToPixel = true;
// —— 运行时数据 ——
public float height; // 单张背景缩放后的真实世界高度
private float spacing; // 相邻背景间距(整像素对齐)= 图高 - 重叠
private float unitsPerPixel; // 1 个屏幕像素等于多少世界单位
private float marginWorld; // 底部余量(世界单位,整像素对齐)
private float offset; // 累计滚动距离
private bool layoutReady;
private readonly List<Transform> tiles = new List<Transform>();
private readonly List<float> pivotToBottom = new List<float>(); // pivot 到底边的世界距离
private readonly List<float> pivotToLeft = new List<float>(); // pivot 到左边的世界距离
void Start()
{
//设置背景布局
//height = Screen.height*3;
upV3 = Vector3.up * Screen.height*2;
centerV3 = Vector3.up * Screen.height;
downV3 = Vector3.zero;
upV3 = CoordinateTransformation.ScreenToCamera(upV3);
centerV3 = CoordinateTransformation.ScreenToCamera(centerV3);
downV3 = CoordinateTransformation.ScreenToCamera(downV3);
transform.GetChild(0).position = upV3;
transform.GetChild(1).position = centerV3;
transform.GetChild(2).position = downV3;
height = upV3.y - centerV3.y;
tiles.Clear();
foreach (Transform child in transform) tiles.Add(child);
}
// Update is called once per frame
/// 第一帧执行:此时 BgFit 已把每张背景缩放到铺满屏幕,读出来的高度才是最终值。
/// 记录每张背景 pivot 到底边/左边的距离,摆放时按底边、左边对齐,
/// 这样以后换图(pivot 不是左下角)也不会错位。
void CacheLayout()
{
Camera cam = Camera.main;
if (cam == null) return;
float visibleH = cam.orthographicSize * 2f; // 相机可见高度(随屏幕自适应)
unitsPerPixel = visibleH / Mathf.Max(Screen.height, 1);
float minTileH = float.MaxValue;
pivotToBottom.Clear();
pivotToLeft.Clear();
foreach (Transform t in tiles)
{
float minY = 0f;
float minX = 0f;
SpriteRenderer sr = t.GetComponent<SpriteRenderer>();
if (sr != null && sr.sprite != null)
{
Vector3 scale = t.lossyScale;
minTileH = Mathf.Min(minTileH, sr.bounds.size.y); // 真实图高:间距以它为准
minY = sr.sprite.bounds.min.y * scale.y;
minX = sr.sprite.bounds.min.x * scale.x;
}
pivotToBottom.Add(minY);
pivotToLeft.Add(minX);
}
height = minTileH == float.MaxValue ? visibleH : minTileH;
// 间距 = 图高 - 重叠,并按整像素取整(保证每张背景的边都在像素线上)
float overlapWorld = overlapPixels * unitsPerPixel;
float spacingPixels = Mathf.Round((height - overlapWorld) / unitsPerPixel);
spacing = Mathf.Max(spacingPixels, 1f) * unitsPerPixel;
marginWorld = Mathf.Round(bottomMargin * Screen.height) * unitsPerPixel;
layoutReady = true;
}
void Update()
{
float step = Time.deltaTime * speed;
currHeight += step;
foreach (Transform t in transform)
if (tiles.Count == 0) return;
if (!layoutReady) CacheLayout();
if (!layoutReady || spacing <= 0f) return;
Camera cam = Camera.main;
if (cam == null) return;
offset += speed * Time.deltaTime;
// 当前格子内的位移(0 ~ spacing)与已经滚过的格子数。
// 位移取整像素后所有背景共用同一个值,间距不会被各自取整破坏。
float phase = Snap(offset - Mathf.Floor(offset / spacing) * spacing);
int step = Mathf.FloorToInt(offset / spacing);
// 基准点:屏幕左下角,再往下留 bottomMargin,跟随相机(镜头震动也不会露边)
float leftX = Snap(cam.transform.position.x - cam.orthographicSize * cam.aspect);
float bottomY = Snap(cam.transform.position.y - cam.orthographicSize) - marginWorld;
int n = tiles.Count;
for (int i = 0; i < n; i++)
{
t.Translate(Vector3.down * step);
// 第 1 个子物体在最上面,初始占第 (n-1-i) 格;滚出屏幕后回到最上面
int slot = (n - 1 - i) - step;
slot = ((slot % n) + n) % n;
Vector3 p = tiles[i].position;
p.x = leftX + pivotToLeft[i];
p.y = bottomY + pivotToBottom[i] + slot * spacing - phase;
tiles[i].position = p;
}
if (currHeight > height*1.3f)
{
currHeight -= height;
Vector3 v3 = transform.GetChild(2).position;
v3.y += height*3;
transform.GetChild(2).position= v3;
transform.GetChild(2).SetAsFirstSibling();
}
}
}
/// 世界坐标吸附到屏幕像素
float Snap(float world)
{
if (!snapToPixel || unitsPerPixel <= 0f) return world;
return Mathf.Round(world / unitsPerPixel) * unitsPerPixel;
}
}