Flappy Bird:根据已实例化预制体调整生成逻辑实现动态难度
实现方案
你原有代码存在两个明显问题:
- 分数边界判断有漏洞,分数恰好等于8、18、29时不会触发任何管道生成
InvokeRepeating不支持动态调整间隔、临时暂停,无法适配关卡过渡的需求
以下改造方案可直接覆盖你提的三个需求:统一管理生成的管道实例、动态调整难度参数、升级时暂停生成播放过渡动画。
第一步:新增所需变量
首先替换原有类的全局变量定义,新增列表、状态标记、难度配置项:
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PipeSpawner : MonoBehaviour { [Header("基础配置")] public GameObject basePipePrefab; public float minHeight = -1f; public float maxHeight = 1f; [Header("难度配置")] public float baseGapSize = 3f; // 初始管道间隙 public float baseSpawnRate = 2f; // 初始生成间隔 public float gapShrinkPerLevel = 0.2f; // 每级间隙缩小值 public float spawnRateSpeedUpPerLevel = 0.15f; // 每级生成间隔缩短值 public float minGapSize = 1f; // 最小管道间隙,避免完全无法通过 public float minSpawnRate = 0.8f; // 最小生成间隔,避免难度过高 // 关卡分数阈值,需要加新关卡直接往数组里填值即可 private int[] levelThresholds = new int[] { 8, 18, 29 }; private int currentLevel = 0; // 运行时状态 private List<GameObject> spawnedPipes = new List<GameObject>(); // 所有已生成管道的管理列表 private bool isLevelTransitioning = false; // 关卡过渡状态标记 private float currentGapSize; private float currentSpawnRate;
第二步:替换启动逻辑
用协程替代原有的InvokeRepeating,方便控制暂停和间隔调整:
private void Start() { // 初始化初始难度 currentGapSize = baseGapSize; currentSpawnRate = baseSpawnRate; // 启动管道生成循环 StartCoroutine(PipeSpawnLoop()); }
第三步:实现核心逻辑
包含生成循环、升级检测、过渡动画、管道生成几个部分:
// 管道生成循环协程 private IEnumerator PipeSpawnLoop() { // 初始等待0.5秒再出第一个管道,和原有逻辑对齐 yield return new WaitForSeconds(0.5f); while (true) { // 关卡过渡中暂停生成,每帧等待直到过渡结束 if (isLevelTransitioning) { yield return null; continue; } // 检测是否触发升级 CheckLevelUp(); // 生成新管道 SpawnPipe(); // 按当前难度的间隔等待 yield return new WaitForSeconds(currentSpawnRate); } } // 升级检测 private void CheckLevelUp() { for (int i = currentLevel; i < levelThresholds.Length; i++) { if (GameManager.score >= levelThresholds[i] && currentLevel == i) { currentLevel++; // 触发关卡过渡流程 StartCoroutine(PlayLevelTransitionAnim()); // 更新难度参数 currentGapSize = Mathf.Max(minGapSize, baseGapSize - gapShrinkPerLevel * currentLevel); currentSpawnRate = Mathf.Max(minSpawnRate, baseSpawnRate - spawnRateSpeedUpPerLevel * currentLevel); // 如果需要同步修改屏幕上已有管道的参数,直接在这里遍历spawnedPipes调整即可 break; } } } // 关卡过渡动画协程 private IEnumerator PlayLevelTransitionAnim() { isLevelTransitioning = true; // 在这里触发你的"新关卡"文本飞屏逻辑,比如激活UI对象、播放Animator动画 // 示例:levelTextUI.SetActive(true); levelTextAnimator.Play("FlyAcross"); // 等待动画播放完成,这里的时长替换成你自己动画的实际长度即可,也可以用动画事件在动画末尾触发状态切换 yield return new WaitForSeconds(1.5f); isLevelTransitioning = false; } // 管道生成逻辑 private void SpawnPipe() { GameObject newPipe = Instantiate(basePipePrefab, transform.position, Quaternion.identity); // 给新管道设置当前难度的间隙,如果你管道预制体上有控制间隙的脚本,直接传值即可 // 示例:newPipe.GetComponent<PipeController>().SetGap(currentGapSize); // 随机上下偏移 newPipe.transform.position += Vector3.up * Random.Range(minHeight, maxHeight); // 将新管道加入管理列表 spawnedPipes.Add(newPipe); } }
注意事项
- 管道销毁时记得从列表移除:当管道移出屏幕被销毁时,调用
spawnedPipes.Remove(要销毁的管道对象),避免列表中残留空引用导致遍历报错。 - 间隙调整适配:如果你的管道是上下两个独立碰撞体,在
SpawnPipe里根据currentGapSize调整两个管道的局部坐标即可,不需要准备多套不同间隙的预制体。 - 动画时间校准:如果不想硬编码等待时长,可以给飞屏动画添加Animation Event,在动画最后一帧绑定方法把
isLevelTransitioning设为false,时间匹配更精准。
内容的提问来源于stack exchange,提问作者FratNightGaming
相关产品推荐
相关产品推荐

