【Unity基础】太空大战中的 【子弹发射器】&&【散射、追踪子弹】

好处

把射出子弹抽象出一个类,专门管理射出子弹的一系列动作,
这样的话就没必要在每个类中写生成子弹,
还可以方便改变子弹的发射方式:

在这里插入图片描述通过显示其中一个GameObject选择子弹发射方式

子弹发射器类:

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

/// <summary>
/// 子弹数据初始化功能
/// </summary>
public abstract class ShootBase : MonoBehaviour
{
    public GameObject prefab; //子弹预制体
    public int maxBulletNum = 20; //最大数量

    public float speed = 5.0f; //子弹速度
    public float acceleration = 20.0f; //加速度
    public float accelerationTurn = 0f;//旋转加速度
    public bool useMaxSpeed;
    [UbhConditionalHide("useMaxSpeed")]
    public float maxSpeed;

    public bool useMinSpeed;
    [UbhConditionalHide("useMinSpeed")]
    public float minSpeed;


    public float life = 5.0f;
    protected bool isShooting; //是否发射中

    public UnityEvent fireEvent = new UnityEvent();//每发射一颗子弹调用的事件
    public UnityEvent finishFireEvent = new UnityEvent();//子弹发射完之后调用的事件

    public abstract void shoot();

    public Bullet getBullet(Transform transPoint)
    {

        GameObject goBullet = Instantiate(prefab, transPoint.position,transPoint.rotation);
        print("goBullet=" + goBullet);
        if (!goBullet)
        {
            return null;
        }
        Bullet b = goBullet.GetComponent<Bullet>();
       
        return b;
    }

    public void shootBullet(Bullet b, float speed, float acceleration,
        float accelerationTurn, float offsetAngle, bool useMaxSpeed = false,
        float maxSpeed = 20f, bool useMinSpeed = false, float minSpeed = 0f, float life = 5f)
    {
        b.shoot(speed, acceleration, maxSpeed, minSpeed, useMaxSpeed, useMinSpeed, accelerationTurn, life, offsetAngle);
    }

    public void finishShoot()
    {
        isShooting = false;
        finishFireEvent.Invoke();
    }

    protected void firedShoot()
    {
        fireEvent.Invoke();
    }
}

直线发射

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

public class LineShoot : ShootBase
{
    public float dtTime = 0.2f; //发射间隔
    float remainTime; //剩余时间
    public Transform firePoint;
    int curBulletNum; //当前子弹数量
    protected float offsetAngle; //发射器的旋转角度
    public override void shoot()
    {
        isShooting = true;
        remainTime = 0;
        curBulletNum = 0;
    }
    void Start()
    {
        isShooting = true;
    }
    public virtual void Update()
    {
        print("LineShootUpdate");
        if (!isShooting)
        {
            print("isShooting");
            return;
        }
        if (remainTime>0)
        {
            remainTime -= Time.deltaTime;
            if (remainTime>0)
            {
                return;
            }
        }
        //发射子弹
        Bullet b = getBullet(firePoint);
        print("B=" + b);
        if (!b)
        {
            return;
        }
        shootBullet(b, speed, acceleration, accelerationTurn, offsetAngle);
        curBulletNum++;
        if (curBulletNum>=maxBulletNum)
        {
            finishShoot();
        }
        else
        {
            remainTime = dtTime;
        }
    }
}

直线追踪子弹

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

public class LineAimShoot : LineShoot
{
    public string tagName = "Player";
    Transform targetTransform;
    public bool isAiming = true;

    public Transform getTransformWithTagName()//获取Player游戏对象的transform
    {
        if (string.IsNullOrEmpty(tagName))
        {
            return null;
        }
        GameObject goTarget = GameObject.FindWithTag(tagName);
        if (!goTarget)
        {
            return null;
        }
        return goTarget.transform;
    }

    public void aimTarget()
    {
        if (!targetTransform)
        {
            targetTransform = getTransformWithTagName();
        }
        else
        {
            Vector3 dir = (targetTransform.position - transform.position).normalized;
            float aimAngle = Quaternion.LookRotation(dir).eulerAngles.y;
            offsetAngle = aimAngle - transform.eulerAngles.y;//计算偏移角度
        
        }
    }
    public override void shoot()
    {
        aimTarget();
        base.shoot();
    }

    public override void Update()
    {
        if (isShooting && isAiming)
        {
            aimTarget();
        }
        base.Update();
    }
}

散射子弹

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

public class NWayShoot : ShootBase
{
    public int wayNum = 5;//线路数量
    public float rotateAngle = 0f;//发射的旋转角度
    [Range(0f, 360f), FormerlySerializedAs("_BTAngle")]
    public float betweenAngle = 10f;//每条线路之间的角度
    float remainTime;//下一次发射剩余时间
    public float delayTime = 0.2f;//发射间隔时间
    private int curBulletNum;//当前子弹数量
    public override void shoot()
    {
        isShooting = true;
        remainTime = 0f;
        curBulletNum = 0;
    }

    void Start()
    {
        shoot();
    }
    public float GetShiftedAngle(int wayIndex, float baseAngle, float betweenAngle)
    {
        float angle = wayIndex % 2 == 0 ?
                      baseAngle - (betweenAngle * (float)wayIndex / 2f) :
                      baseAngle + (betweenAngle * Mathf.Ceil((float)wayIndex / 2f));
        return angle;
    }

    protected virtual void Update()
    {
        if (!isShooting) return;
        if (remainTime > 0)
        {
            remainTime -= Time.deltaTime;
            if (remainTime > 0) return;
        }
        for (int i = 0; i < wayNum; i++)
        {
            Bullet b = getBullet(transform);
            if (!b) break;
            float baseAngle = wayNum % 2 == 0 ? rotateAngle - (betweenAngle / 2f) : rotateAngle;

            float _offsetAngle = GetShiftedAngle(i, baseAngle, betweenAngle);
            print("_offsetAngle=" + _offsetAngle);
            shootBullet(b, speed, acceleration, accelerationTurn, _offsetAngle);
            curBulletNum++;
            if (curBulletNum >= maxBulletNum)
            {
                break;
            }
        }
        firedShoot();
       
        if (curBulletNum >= maxBulletNum)
        {
            finishShoot();
        }
        else
        {
            remainTime = delayTime;
        }
    }
}

散射追踪子弹

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

public class NWayAimShoot : NWayShoot
{
    public string tagName = "Player";
    Transform target;
    public bool isAiming = true;
    public Transform getTransformWithTagName()
    {
        if (string.IsNullOrEmpty(tagName))
        {
            return null;
        }
        GameObject goTarget = GameObject.FindWithTag(tagName);
        if (!goTarget)
        {
            return null;
        }
        return goTarget.transform;
    }
    public void aimTarget()
    {
        if (target == null)
        {
            target = getTransformWithTagName();
        }
        else
        {
            Vector3 dir = (target.position - transform.position).normalized;
            float aimAngle = Quaternion.LookRotation(dir).eulerAngles.y;
            rotateAngle = aimAngle - transform.eulerAngles.y;
        }

    }
    public override void shoot()
    {
        aimTarget();
        base.shoot();
    }
    protected override void Update()
    {
        if (isShooting && isAiming)
        {
            aimTarget();
        }
        base.Update();
    }
}

随机散射子弹

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

public class RandomShoot : ShootBase
{
    private float m_delayTimer;

    private List<int> m_numList;
    [FormerlySerializedAs("_RandomSpeedMin")]
    public float m_randomSpeedMin = 1f;
    [FormerlySerializedAs("_RandomSpeedMax")]
    public float m_randomSpeedMax = 3f;
    [Range(0f, 360f), FormerlySerializedAs("_RandomCenterAngle")]
    public float m_randomCenterAngle = 0;

    [Range(0f, 360f), FormerlySerializedAs("_RandomRangeSize")]
    public float m_randomRangeSize = 360f;

    [FormerlySerializedAs("_EvenlyDistribute")]
    public bool m_evenlyDistribute = true;//是否使用均匀分布

    [FormerlySerializedAs("_RandomDelayMin")]
    public float m_randomDelayMin = 0.01f;
    [FormerlySerializedAs("_RandomDelayMax")]
    public float m_randomDelayMax = 0.1f;
    public override void shoot()
    {
        if (maxBulletNum <= 0 || m_randomSpeedMin <= 0f || m_randomSpeedMax <= 0)
        {
            return;
        }

        if (isShooting)
        {
            return;
        }

        isShooting = true;
        m_delayTimer = 0f;

        if (m_numList != null)
        {
            m_numList.Clear();
            m_numList = null;
        }

        m_numList = new List<int>(maxBulletNum);
        for (int i = 0; i < maxBulletNum; i++)
        {
            m_numList.Add(i);
        }
    }

    // Start is called before the first frame update
    void Start()
    {
        shoot();
    }

    // Update is called once per frame
    void Update()
    {
        if (isShooting == false)
        {
            return;
        }

        if (m_delayTimer >= 0f)
        {
            m_delayTimer -= Time.deltaTime;
            if (m_delayTimer >= 0f)
            {
                return;
            }
        }

        int index = Random.Range(0, m_numList.Count);

        Bullet bullet = getBullet(transform);
        if (bullet == null)
        {
            return;
        }

        float bulletSpeed = Random.Range(m_randomSpeedMin, m_randomSpeedMax);

        float minAngle = m_randomCenterAngle - (m_randomRangeSize / 2f);
        float maxAngle = m_randomCenterAngle + (m_randomRangeSize / 2f);
        float angle = 0f;

        if (m_evenlyDistribute)
        {
            float oneDirectionNum = Mathf.Floor((float)maxBulletNum / 4f);
            float quarterIndex = Mathf.Floor((float)m_numList[index] / oneDirectionNum);
            float quarterAngle = Mathf.Abs(maxAngle - minAngle) / 4f;
            angle = Random.Range(minAngle + (quarterAngle * quarterIndex), minAngle + (quarterAngle * (quarterIndex + 1f)));
        }
        else
        {
            angle = Random.Range(minAngle, maxAngle);
        }

        shootBullet(bullet, speed, acceleration, accelerationTurn, angle);
        firedShoot();

        m_numList.RemoveAt(index);

        if (m_numList.Count <= 0)
        {
            finishShoot();
        }
        else
        {
            m_delayTimer = Random.Range(m_randomDelayMin, m_randomDelayMax);
        }
    }
}
  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值