【游戏开发实战】使用Unity 2019制作仿微信小游戏飞机大战(十一):核弹掉落与全屏炸机

零、教程目录

使用Unity 2019制作仿微信小游戏飞机大战教程已完结。
文章目录如下:
《第一篇:开始游戏界面》
《第二篇:搭建基础游戏框架》
《第三篇:战斗界面UI》
《第四篇:主角飞机序列帧动画》
《第五篇:主角飞机的飞行控制》
《第六篇:根据配置随机生成敌机》
《第七篇:主角飞机碰撞与爆炸》
《第八篇:主角飞机开炮》
《第九篇:敌机受击与爆炸》
《第十篇:敌机血量与得分》
《第十一篇:核弹掉落与全屏炸机》
《第十二篇:敌机开炮》
《第十三篇:游戏暂停、结束与重新开始》

一、前言

嗨,大家好,我是新发。相信很多人玩过微信小游戏经典的飞机大战,如下:
在这里插入图片描述
想重温或体验微信这款经典的飞机大战的同学可以点这里:https://gamemaker.weixin.qq.com/ide#/
在这里插入图片描述

在网上已经有一些人已经出了Unity的制作教程,但是比较陈旧,里面使用了已经弃用的组件和写法,用了很陈旧的NGUI版本,如果使用Unity 2019或以上版本打开会各种报错,对新入门Unity的同学不大友好。

于是,我决定写一个全新的教程:《使用Unity2019制作仿微信小游戏飞机大战》,会使用最新的写法,并且使用尽量简洁的设计与代码来完成。

本教程的工程已上传到Github,感兴趣的同学自行下载学习。
喜欢的同学记得给个星星~
Github地址:https://github.com/linxinfa/UnityAircraftFight
在这里插入图片描述
Unity游戏开发有任何问题的,都欢迎在评论区留言,我都会看到的,并会进行认真解答,希望能帮助到想学Unity开发的同学,共勉。

二、本篇目标

核弹掉落与全屏炸机。
本篇的效果:
在这里插入图片描述

三、导入核弹图片资源

将核弹图片导入Unity工程中。
在这里插入图片描述
如下:
在这里插入图片描述

四、制作核弹预设

将核弹图片拖到场景中,此时会以SpriteRenderer的方式显示。
在这里插入图片描述
为其添加碰撞体BoxCollider2D和刚体Rigidbody2D组件。注意BoxCollider2D勾选Is TriggerRigidbody2D设置Gravity Scale为0。
在这里插入图片描述
将核弹保存为预设supply_bomb,存放在Resources/Bullet文件夹中。
在这里插入图片描述

五、核弹掉落与核弹数量显示

1、核弹生成器:SuperBombGenerator.cs

由于核弹出现的频率不高,所以我们就不做对象池了。
封装一个核弹生成器SuperBombGenerator.cs,代码如下:

// SuperBombGenerator.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 核弹生成器
/// </summary>
public class SuperBombGenerator
{
    public void Init()
    {
        ResetTargetInterval();
    }

    public void Update()
    {
        m_timer += Time.deltaTime;
        if (m_timer >= m_targetInterval)
        {
            ResetTargetInterval();
            if (Random.Range(0, 100) >= 30)
            {
                // 70%的概率掉落核弹
                GenerateSuperBomb();
            }
        }
    }

    /// <summary>
    /// 销毁根节点
    /// </summary>
    public void DestroyRoot()
    {
        if(null != m_bombRoot)
        {
            Object.Destroy(m_bombRoot.gameObject);
            m_bombRoot = null;
        }
    }

    /// <summary>
    /// 重置目标时间间隔
    /// </summary>
    private void ResetTargetInterval()
    {
        m_timer = 0;
        m_targetInterval = Random.Range(MIN_GEN_INTERVAL, MAX_GEN_INTERVAL);
    }

    private void GenerateSuperBomb()
    {
        if (null == m_bombRoot)
        {
            var rootObj = new GameObject("SuperBombRoot");
            m_bombRoot = rootObj.transform;
        }
        var prefab = ResourceMgr.instance.LoadRes<GameObject>("Bullet/supply_bomb");
        var obj = Object.Instantiate(prefab);
        obj.transform.SetParent(m_bombRoot, false);
        // 随机一个初始坐标
        var randomPos = new Vector3(Random.Range(100, Screen.width - 100), Screen.height + 100, 5);
        obj.transform.position = Camera.main.ScreenToWorldPoint(randomPos);
    }

    private float m_timer;
    private float m_targetInterval = MIN_GEN_INTERVAL;
    /// <summary>
    /// 最小生成间隔
    /// </summary>
    private const float MIN_GEN_INTERVAL = 5f;
    /// <summary>
    /// 最大生成间隔
    /// </summary>
    private const float MAX_GEN_INTERVAL = 15f;

    private Transform m_bombRoot;
}
2、核弹脚本:SuperBomb.cs

核弹有个下落的逻辑,创建核弹脚本SuperBomb.cs,代码如下:

// SuperBomb.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


/// <summary>
/// 核弹
/// </summary>
public class SuperBomb : MonoBehaviour
{
    public float dropSpeed = 5f;

    Transform m_selfTrans;

    private void Awake()
    {
        m_selfTrans = transform;
    }


    void Update()
    {
        m_selfTrans.position -= new Vector3(0, dropSpeed * Time.deltaTime, 0);

        // 超过屏幕下面
        if (Camera.main.WorldToScreenPoint(m_selfTrans.position).y <= -100)
        {
            DestroySelf();
        }
    }

    void DestroySelf()
    {
        Destroy(gameObject);
    }
}
3、游戏管理器调用核弹生成器

将核弹生成器SuperBombGenerator作为游戏管理器GameMgr的成员变量,并添加相应的调用。

// GameMgr.cs

/// <summary>
/// 开始游戏
/// </summary>
public void StartGame()
{
	// ...
	
    // 初始化核弹生成器
    m_superBombGenerator.Init();
    gameState = GameState.Playing;
}


public void Update()
{
    if (GameState.Playing == gameState)
    {
        // ...
        m_superBombGenerator.Update();
    }
}

private SuperBombGenerator m_superBombGenerator = new SuperBombGenerator();
4、GameMgr添加核弹数量属性

我们需要有核弹数量数据,在GameMgr添加核弹数量属性。

// GameMgr.cs

/// <summary>
/// 核弹数量
/// </summary>
public int BombCnt
{
    get { return m_bombCnt; }
    set
    {
        m_bombCnt = value;
        EventDispatcher.instance.DispatchEvent(EventDef.EVENT_UPDATE_BOMB_CNT);
    }
}

private int m_bombCnt;

其中EVENT_UPDATE_BOMB_CNT是核弹数量更新事件。

// EventDef.cs

public class EventDef 
{
	// ...
	
    /// <summary>
    /// 更新核弹数量
    /// </summary>
    public const string EVENT_UPDATE_BOMB_CNT = "EVENT_UPDATE_BOMB_CNT";
}
5、核弹碰撞处理

添加一个SuperBombTag
在这里插入图片描述
将核弹预设的Tag设置为SuperBomb
在这里插入图片描述
PlayerAircraft中编写核弹碰撞逻辑。

// PlayerAircraft.cs

/// <summary>
/// 碰撞检测
/// </summary>
/// <param name="other"></param>
public override void OnTriggerEnter2D(Collider2D other)
{
    switch(other.tag)
    {
        case "Enemy":
            {
                // 爆炸
                Explode();
            }
            break;
        case "SuperBomb":
            {
            	// 销毁核弹物体
                Destroy(other.gameObject);
                ++GameMgr.instance.BombCnt;
            }
            break;
    }
}
6、核弹数量显示

MainGamePanel.cs中监听核弹数量更新事件并显示核弹数量。

// MainGamePanel.cs

protected override void OnShow()
{
	// ...
    EventDispatcher.instance.Regist(EventDef.EVENT_UPDATE_BOMB_CNT, OnEventUpdateBombCnt);
}

protected override void OnHide()
{
    // ...
    EventDispatcher.instance.UnRegist(EventDef.EVENT_UPDATE_BOMB_CNT, OnEventUpdateBombCnt);
}
    
/// <summary>
/// 更新炸弹数量显示
/// </summary>
/// <param name="bombCnt"></param>
private void UpdateBombCntText(int bombCnt)
{
    m_bombCntText.text = bombCnt.ToString();
}

private void OnEventUpdateBombCnt(params object[] args)
{
    UpdateBombCntText(GameMgr.instance.BombCnt);
}

六、全屏炸机

我们需执行全屏炸机,得先知道屏幕中的所有敌机,所以需要把屏幕中的敌机存起来。
EnemyGenerator中将屏幕中的敌机存起来,并封装一个全屏炸机的接口。

// EnemyGenerator.cs

/// <summary>
/// 随机生成一个敌机
/// </summary>
private void RandomGenerateEnemy()
{
    EnemyAircraft enemy = null;
    var config = m_enemyRandom.Next();
    var aircraftType = (AircraftType)config.Index;
    if (m_reusePool.ContainsKey(aircraftType) && m_reusePool[aircraftType].Count > 0)
    {
        enemy = m_reusePool[aircraftType].Dequeue();
        enemy.ActiveSelf(true);
    }
    else
    {
        enemy = (EnemyAircraft)AircraftFactory.CreateAircraft((AircraftType)config.Index);
        enemy.backToPoolAction = () =>
        {
            // 对象回收
            if (!m_reusePool.ContainsKey(aircraftType))
            {
                m_reusePool[aircraftType] = new Queue<EnemyAircraft>();
            }
            m_reusePool[aircraftType].Enqueue(enemy);
			// 从屏幕中的敌机容器中移除
            if (m_aliveEnemy.Contains(enemy))
                m_aliveEnemy.Remove(enemy);
        };
    }
    enemy.blood = config.Blood;
    enemy.moveSpeed = Random.Range(config.MinSpeed, config.MaxSpeed);
    enemy.RandomStartPos();
    // 存到屏幕中的敌机容器中
    if (!m_aliveEnemy.Contains(enemy))
        m_aliveEnemy.Add(enemy);
}

/// <summary>
/// 全屏炸机
/// </summary>
public void KillAllEnemy()
{
    for (int i = 0; i < m_aliveEnemy.Count; ++i)
    {
        m_aliveEnemy[i].Explode();
    }
    m_aliveEnemy.Clear();
}

/// <summary>
/// 清空对象池
/// </summary>
public void ClearAll()
{
    m_reusePool.Clear();
    m_aliveEnemy.Clear();
}

/// <summary>
/// 屏幕中的敌机
/// </summary>
private List<EnemyAircraft> m_aliveEnemy = new List<EnemyAircraft>();

然后在GameMgr中封装一个KillAllEnemy接口。

// GameMgr.cs

/// <summary>
/// 全屏炸机
/// </summary>
public void KillAllEnemy()
{
	if (BombCnt <= 0) return;
    --BombCnt;
    m_enemyGenerator.KillAllEnemy();
}

最后,在游戏界面脚本MainGamePanel中,核弹按钮的点击响应中调用这个KillAllEnemy接口。

// MainGamePanel.cs

public override void SetUi(PrefabSlot slot)
{
	// ...
	
    slot.SetButton("BombBtn", (btn) =>
    {
        // 炸弹按钮被点击
        GameMgr.instance.KillAllEnemy();
    });
}

七、运行测试

运行Unity,测试效果如下:

在这里插入图片描述

八、下篇预告

敌机开炮。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林新发

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值