UGF游戏框架实例开发教程—FlappyBird(六)循环滚动背景图与定时生成管道功能的实现

从本篇开始我们要编写实体相关的业务逻辑代码

先去EntityComponent中添加EntityGroup




为背景实体创建实体数据类,命名为BgData,继承自EntityData



定义出需要用到的数据的字段,并提供构造方法

    /// <summary>
    /// 背景实体数据
    /// </summary>
    public class BgData : EntityData
    {
        /// <summary>
        /// 移动速度
        /// </summary>
        public float MoveSpeed { get; private set; }

        /// <summary>
        /// 到达此目标时产生新的背景实体
        /// </summary>
        public float SpawnTarget { get; private set; }

        /// <summary>
        /// 到达此目标时隐藏自身
        /// </summary>
        public float HideTarget { get; private set; }

        /// <summary>
        /// 移动起始点
        /// </summary>
        public float StartPostion { get; private set; }

        public BgData(int entityId, int typeId, float moveSpeed, float startPostion) : base(entityId, typeId)
        {
            MoveSpeed = moveSpeed;
            SpawnTarget = -8.66f;
            HideTarget = -26.4f;
            StartPostion = startPostion;
        }
    }

然后创建对应的背景实体逻辑脚本,命名为Bg,继承自Entity



在为其编写业务逻辑代码之前,我们先去EntityExtension里找到TODO的地方,仿照它来封装一个专门用来显示背景实体的方法


        /// <summary>
        /// 显示背景实体
        /// </summary>
        public static void ShowBg(this EntityComponent entityComponent, BgData data)
        {
            entityComponent.ShowEntity(typeof(Bg), "Bg", data);
        }


然后回到Bg类中,开始编写循环滚动的代码

    /// <summary>
    /// 背景实体脚本
    /// </summary>
    public class Bg : Entity
    {
        /// <summary>
        /// 背景实体数据
        /// </summary>
        private BgData m_BgData = null;

        private bool m_IsSpawn = false;

        protected override void OnShow(object userData)
        {
            base.OnShow(userData);
            m_BgData = (BgData)userData;
            //修改开始位置
            CachedTransform.SetLocalPositionX(m_BgData.StartPostion);
        }

        protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
        {
            base.OnUpdate(elapseSeconds, realElapseSeconds);

            //控制背景实体移动
            CachedTransform.Translate(Vector3.left * m_BgData.MoveSpeed * elapseSeconds, Space.World);
            if (CachedTransform.position.x <= m_BgData.SpawnTarget && m_IsSpawn == false)
            {
                //显示背景实体
                GameEntry.Entity.ShowBg(new BgData(GameEntry.Entity.GenerateSerialId(), m_BgData.TypeId, m_BgData.MoveSpeed, 17.92f));
                m_IsSpawn = true;
            }

            if (CachedTransform.position.x <= m_BgData.HideTarget)
            {
                //隐藏实体
                GameEntry.Entity.HideEntity(this);
            }
        }

        protected override void OnHide(object userData)
        {
            base.OnHide(userData);
            m_IsSpawn = false;
        }
    }

接着打开ProcedureMain,重写OnEnter方法,在其中显示背景实体

    /// <summary>
    /// 主流程
    /// </summary>
    public class ProcedureMain : ProcedureBase
    {
        protected override void OnEnter(IFsm<IProcedureManager> procedureOwner)
        {
            base.OnEnter(procedureOwner);

            GameEntry.Entity.ShowBg(new BgData(GameEntry.Entity.GenerateSerialId(), 1, 1f, 0));
        }
    }

现在点击运行,然后点击菜单上的开始,可以看到实现了背景图的无缝循环滚动功能(如果没实现,可以自己手动测试后修改ProcedureMain显示背景实体时传给BgData的startPosition参数与BgData构造方法里的SpawnTarget等数值)



接下来为管道实体创建实体数据类

    /// <summary>
    /// 管道实体数据
    /// </summary>
    public class PipeData : EntityData
    {
        /// <summary>
        /// 移动速度
        /// </summary>
        public float MoveSpeed { get; private set; }

        /// <summary>
        /// 上管道偏移
        /// </summary>
        public float OffsetUp { get; private set; }

        /// <summary>
        /// 下管道偏移
        /// </summary>
        public float OffsetDown { get; private set; }

        /// <summary>
        /// 到达此目标时隐藏自身
        /// </summary>
        public float HideTarget { get; private set; }

        public PipeData(int entityId, int typeId,float moveSpeed) : base(entityId, typeId)
        {
            MoveSpeed = moveSpeed;
            OffsetUp = Random.Range(4.1f, 7f);
            OffsetDown = Random.Range(-3f, -4.5f);
            HideTarget = -9.4f;
        }
    }


创建实体逻辑脚本

    /// <summary>
    /// 管道实体脚本
    /// </summary>
    public class Pipe : Entity
    {
        /// <summary>
        /// 管道实体数据
        /// </summary>
        private PipeData m_PipeData = null;

        /// <summary>
        /// 上管道
        /// </summary>
        private Transform m_UpPipe = null;

        /// <summary>
        /// 下管道
        /// </summary>
        private Transform m_DownPipe = null;

        protected override void OnShow(object userData)
        {
            base.OnShow(userData);
            m_PipeData = (PipeData)userData;

            //设置初始位置
            CachedTransform.SetLocalPositionX(10f);

            if (m_UpPipe == null || m_DownPipe == null)
            {
                m_UpPipe = transform.Find("UpPipe");
                m_DownPipe = transform.Find("DownPipe");
            }

            //设置上下管道的偏移
            m_UpPipe.SetLocalPositionY(m_PipeData.OffsetUp);
            m_DownPipe.SetPositionY(m_PipeData.OffsetDown);

           
            
        }

        protected override void OnUpdate(float elapseSeconds, float realElapseSeconds)
        {
            base.OnUpdate(elapseSeconds, realElapseSeconds);

            CachedTransform.Translate(Vector3.left * m_PipeData.MoveSpeed * elapseSeconds, Space.World);
            if (CachedTransform.position.x <= m_PipeData.HideTarget)
            {
                //隐藏自身
                GameEntry.Entity.HideEntity(this);
            }


        }
        

        protected override void OnHide(object userData)
        {
            base.OnHide(userData);
            m_UpPipe.gameObject.SetActive(true);
            m_DownPipe.gameObject.SetActive(true);

            
        }


    }


到EntityExtension里封装一个显示管道的方法

        /// <summary>
        /// 显示管道实体
        /// </summary>
        public static void ShowPipe(this EntityComponent entityComponent, PipeData data)
        {
            entityComponent.ShowEntity(typeof(Pipe), "Pipe", data);
        }


回到ProcedureMain中,编写定时产生管道的业务逻辑代码

    /// <summary>
    /// 主流程
    /// </summary>
    public class ProcedureMain : ProcedureBase
    {
        /// <summary>
        /// 管道产生时间
        /// </summary>
        private float m_PipeSpawnTime = 0f;

        /// <summary>
        /// 管道产生计时器
        /// </summary>
        private float m_PipeSpawnTimer = 0f;

        protected override void OnEnter(IFsm<IProcedureManager> procedureOwner)
        {
            base.OnEnter(procedureOwner);

            GameEntry.Entity.ShowBg(new BgData(GameEntry.Entity.GenerateSerialId(), 1, 1f, 0));

            //设置初始管道产生时间
            m_PipeSpawnTime = Random.Range(3f, 5f);
        }

        protected override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds, float realElapseSeconds)
        {
            base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);

            m_PipeSpawnTimer += elapseSeconds;
            if (m_PipeSpawnTimer >= m_PipeSpawnTime)
            {
                m_PipeSpawnTimer = 0;
                //随机设置管道产生时间
                m_PipeSpawnTime = Random.Range(3f, 5f);

                //产生管道
                GameEntry.Entity.ShowPipe(new PipeData(GameEntry.Entity.GenerateSerialId(), 2, 1f));

            }
        }

点击运行,可以看到会在随机一段时间的间隔后产生出管道,并且两个管道之间的上下距离也是随机


  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值