使用Unity 2019制作仿微信小游戏飞机大战(十二):敌机开炮

文章目录

一、前言

嗨,大家好,我是新发。相信很多人玩过微信小游戏经典的飞机大战,如下:
使用Unity 2019制作仿微信小游戏飞机大战(十二):敌机开炮
想重温或体验微信这款经典的飞机大战的同学可以点这里:https://gamemaker.weixin.qq.com/ide#/
使用Unity 2019制作仿微信小游戏飞机大战(十二):敌机开炮

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

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

我会根据内容点分成多篇文章来讲解,完结后会将工程上传到GitHub,大家请耐心等待。

二、本篇目标

敌机开炮。
本篇的效果:
使用Unity 2019制作仿微信小游戏飞机大战(十二):敌机开炮

三、导入子弹图片资源

将子弹图片导入Unity工程中。
使用Unity 2019制作仿微信小游戏飞机大战(十二):敌机开炮
如下:
使用Unity 2019制作仿微信小游戏飞机大战(十二):敌机开炮

四、制作敌机子弹预设

制作成预设enemy_bullet,注意敌机子弹预设的Tag设置为Enemy

制作子弹预设的方法与之前主角子弹的预设制作方法一致,参见之前这篇文章:《使用Unity 2019制作仿微信小游戏飞机大战(八):主角飞机开炮》

使用Unity 2019制作仿微信小游戏飞机大战(十二):敌机开炮

五、敌机子弹脚本:EnemyBullet.cs

封装敌机子弹脚本:EnemyBullet.cs。将脚本挂到敌机子弹预设上。
使用Unity 2019制作仿微信小游戏飞机大战(十二):敌机开炮

代码如下:

// EnemyBullet.cs

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

public class EnemyBullet : MonoBehaviour
{
    public float speed = 1f;
    /// <summary>
    /// 自我旋转
    /// </summary>
    public bool rotateSelf = false;

    /// <summary>
    /// 回收委托
    /// </summary>
    public Action backToPoolAction;

    private Transform m_selfTrans;
    private GameObject m_selfGo;
    private Vector3 m_targetDir;

    private void Awake()
    {
        m_selfGo = gameObject;
        m_selfTrans = transform;
    }


    public void SetStartPos(Vector3 pos)
    {
        m_selfTrans.position = pos;
    }

    public void SetTargetDir(Vector3 dir)
    {
        m_targetDir = dir.normalized;
    }

    public void SetAngles(Vector3 rot)
    {
        m_selfTrans.eulerAngles = rot;
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if("Player" == collision.tag)
        {
            BackToPool();
        }
    }

    private void Update()
    {
        // 子弹向上飞行
        m_selfTrans.position += m_targetDir * speed * Time.deltaTime;

        // 超过屏幕外面
        var screenPos = Camera.main.WorldToScreenPoint(m_selfTrans.position);
        if (screenPos.y <= -50 || screenPos.x < -50 || screenPos.x > Screen.width + 50)
        {
            BackToPool();
        }

        if(rotateSelf)
        {
            m_selfTrans.Rotate(0, 0, 30);
        }
    }

    /// <summary>
    /// 回收
    /// </summary>
    private void BackToPool()
    {
        ActiveSelf(false);
        if (null != backToPoolAction)
        {
            backToPoolAction();
        }
    }

    /// <summary>
    /// 激活
    /// </summary>
    public void ActiveSelf(bool active)
    {
        m_selfGo.SetActive(active);
    }
}

六、敌机子弹生成器:EnemyBulletGenerator.cs

封装一个敌机子弹生成器EnemyBulletGenerator.cs,负责生成敌机子弹和对象池管理。

// EnemyBulletGenerator.cs

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

public class EnemyBulletGenerator
{
    /// <summary>
    /// 根据敌机类型创建子弹
    /// </summary>
    /// <param name="aircraftType">敌机类型</param>
    /// <param name="aircraftPos">敌机坐标</param>
    public static void GenerateBulletByAircraftType(AircraftType aircraftType, Vector3 aircraftPos)
    {
        if (null == s_enemyBulletRoot)
        {
            var rootObj = new GameObject("EnemyBulletRoot");
            s_enemyBulletRoot = rootObj.transform;
        }
        switch (aircraftType)
        {
            case AircraftType.Enemy2:
                {
                    GenerateEnemy2Bullet(aircraftPos);
                }
                break;
            case AircraftType.Enemy3:
                {
                    GenerateEnemy3Bullet(aircraftPos);
                }
                break;
        }
    }

    /// <summary>
    /// 创建敌机2的子弹
    /// </summary>
    /// <param name="aircraftPos"></param>
    private static void GenerateEnemy2Bullet(Vector3 aircraftPos)
    {

        var bullet = CreateBulletObj(aircraftPos);
        bullet.rotateSelf = true;
        var playerPos = GameMgr.instance.GetPlayerPos();
        if(Vector3.zero != playerPos)
            bullet.SetTargetDir(playerPos - aircraftPos);
        else
            bullet.SetTargetDir(-Vector3.up);
    }

    /// <summary>
    /// 创建敌机3的子弹
    /// </summary>
    /// <param name="aircraftPos"></param>
    private static void GenerateEnemy3Bullet(Vector3 aircraftPos)
    {
        for (int i = 0; i < 8; ++i)
        {
            var bullet = CreateBulletObj(aircraftPos);
            bullet.transform.Rotate(0, 0, 180 - 90f / 2 + 90f / 7 * i);
            bullet.SetTargetDir(bullet.transform.up);
            bullet.rotateSelf = false;
        }

    }

    /// <summary>
    /// 创建子弹物体
    /// </summary>
    /// <param name="startPos"></param>
    /// <returns></returns>
    private static EnemyBullet CreateBulletObj(Vector3 startPos)
    {
        EnemyBullet bullet = null;
        if (s_reusePool.Count > 0)
        {
            bullet = s_reusePool.Dequeue();
        }
        else
        {
            var prefab = ResourceMgr.instance.LoadRes<GameObject>("Bullet/enemy_bullet");
            var obj = Object.Instantiate(prefab);
            obj.transform.SetParent(s_enemyBulletRoot, false);
            bullet = obj.GetComponent<EnemyBullet>();
            bullet.backToPoolAction = () =>
            {
                s_reusePool.Enqueue(bullet);
            };
        }
        bullet.speed = 5f;
        bullet.SetStartPos(startPos);
        bullet.SetAngles(Vector3.zero);
        bullet.ActiveSelf(true);
        return bullet;
    }

    /// <summary>
    /// 清理
    /// </summary>
    public static void CLear()
    {
        if(null != s_enemyBulletRoot)
        {
            Object.Destroy(s_enemyBulletRoot.gameObject);
            s_enemyBulletRoot = null;
        }
        s_reusePool.Clear();
    }

    private static Transform s_enemyBulletRoot;
    private static Queue<EnemyBullet> s_reusePool = new Queue<EnemyBullet>();
}

子弹会打向主角,其中用到了GameMgr的一个接口GetPlayerPos

// GameMgr.cs

/// <summary>
/// 获取主角飞机的坐标
/// </summary>
/// <returns></returns>
public Vector3 GetPlayerPos()
{
    if(null != player && null != player.gameObject)
    {
        return player.transform.position;
    }
    return Vector3.zero;
}

七、调用敌机生成器

给敌机脚本EnemyAircraft添加开炮计时器,并调用敌机生成器的接口。

// EnemyAircraft.cs

// 开炮计时器
private float m_timeToFire = -1;

public void ResetTimeToFire(float t)
{
    m_timeToFire = t;
}

private void Update()
{
	// ...
	
    if (m_timeToFire > 0)
    {
        m_timeToFire -= Time.deltaTime;
        if (m_timeToFire <= 0)
        {
            EnemyBulletGenerator.GenerateBulletByAircraftType(aircraftType, m_selfTrans.position);
        }
    }
}

在敌机生成时重置开炮计时器。

// EnemyGenerator.cs

/// <summary>
/// 随机生成一个敌机
/// </summary>
private void RandomGenerateEnemy()
{
  	// ...
    enemy.ResetTimeToFire(1);
    // ...
}

八、运行测试

运行Unity,测试效果如下:
使用Unity 2019制作仿微信小游戏飞机大战(十二):敌机开炮

九、下篇预告

游戏暂停、结束与重新开始。

上一篇:字节跳动游戏客户端开发面经


下一篇:python小游戏,飞机大战外星人,主要是面向对象编程,看一看我的代码和感悟与总结,发表出你的意见建议吧!