18.子弹逻辑

  1. 18.游戏场景-游戏主逻辑-子弹相关-逻辑处理
    1. 18.1 知识点
      1. 创建子弹对象BulletObject脚本,继承MonoBehaviour类。创建一个私有字段info用于存储子弹数据。定义三个公共方法InitInfo、DealyDestroy和Dead,分别用于初始化子弹数据、延迟销毁子弹对象和销毁场景上的子弹。在InitInfo方法中,初始化子弹数据并调用Invoke方法延迟销毁子弹对象,延迟的时间是从配置信息里面拿的。使用延迟函数更安全,因为延迟函数所在的脚本被删除了延迟函数就不会被执行,注意不怕Destroy的时候报错了。在DealyDestroy方法中,它调用Destroy方法销毁子弹对象。在Dead方法中,实例化死亡特效并设置特效位置,然后调用Destroy方法延迟销毁特效对象和销毁子弹对象。在OnTriggerEnter方法中,实现了碰撞逻辑。当碰撞到玩家对象时,获取玩家PlayerObject 脚本并调用Wound方法使玩家受伤。然后调用Dead方法销毁子弹对象。
      2. 创建一个私有字段time,用于存储计时变量。在Update方法中,处理子弹对象的移动。首先根据子弹数据中的forwardSpeed字段沿着面朝向移动。然后根据子弹数据中的type字段处理其他移动逻辑。注意要把玩家脚本PlayerObject 设置成单例,好获取玩家的位置。
        1. 子弹不同type具体移动逻辑详解
        2. 子弹代码
      3. 拖一个子弹预制体到场景,子弹预制体添加子弹脚本。脚本中添加测试代码,开始时初始化数据。调整测试代码中的索引看看不同配置的效果,根据效果修改配置。测试完删除测试代码。
      4. 给各个子弹预制体的父对象的碰撞器设置为触发器。给每个玩家飞机对象设置标签为Player,也添加碰撞器并添加刚体。不使用重力。
    2. 18.2 知识点代码
      1. BulletObject
      2. PlayerObject

18.游戏场景-游戏主逻辑-子弹相关-逻辑处理


18.1 知识点

创建子弹对象BulletObject脚本,继承MonoBehaviour类。创建一个私有字段info用于存储子弹数据。定义三个公共方法InitInfo、DealyDestroy和Dead,分别用于初始化子弹数据、延迟销毁子弹对象和销毁场景上的子弹。在InitInfo方法中,初始化子弹数据并调用Invoke方法延迟销毁子弹对象,延迟的时间是从配置信息里面拿的。使用延迟函数更安全,因为延迟函数所在的脚本被删除了延迟函数就不会被执行,注意不怕Destroy的时候报错了。在DealyDestroy方法中,它调用Destroy方法销毁子弹对象。在Dead方法中,实例化死亡特效并设置特效位置,然后调用Destroy方法延迟销毁特效对象和销毁子弹对象。在OnTriggerEnter方法中,实现了碰撞逻辑。当碰撞到玩家对象时,获取玩家PlayerObject 脚本并调用Wound方法使玩家受伤。然后调用Dead方法销毁子弹对象。

public class BulletObject : MonoBehaviour
{
    //子弹使用的数据
    private BulletInfo info;

    //用于曲线移动的 计时变量
    private float time;

    //初始化子弹数据的方法
    public void InitInfo(BulletInfo info)
    {
        this.info = info;
        //根据生命周期函数 决定自己什么时候 延迟移除
        //Destroy(this.gameObject, info.lifeTime);
        Invoke("DealyDestroy", info.lifeTime);
    }

    private void DealyDestroy()
    {
        Destroy(this.gameObject);
    }

    //销毁场景上的子弹
    public void Dead()
    {
        //创建死亡特效
        GameObject effObj = Instantiate(Resources.Load<GameObject>(info.deadEffRes));
        //设置特效的位置 创建在当前子弹的位置
        effObj.transform.position = this.transform.position;
        //1秒后延迟移除特效对象
        Destroy(effObj, 1f);

        //销毁子弹对象
        Destroy(this.gameObject);
    }

    //和对象碰撞时(触发)
    private void OnTriggerEnter(Collider other)
    {
        if(other.gameObject.CompareTag("Player"))
        {
            //得到玩家脚本
            PlayerObject obj = other.GetComponent<PlayerObject>();
            //玩家受伤减血
            obj.Wound();

            //销毁自己 
            Dead();
        }
    }
}

创建一个私有字段time,用于存储计时变量。在Update方法中,处理子弹对象的移动。首先根据子弹数据中的forwardSpeed字段沿着面朝向移动。然后根据子弹数据中的type字段处理其他移动逻辑。注意要把玩家脚本PlayerObject 设置成单例,好获取玩家的位置。

子弹不同type具体移动逻辑详解

  1. 直线运动。这种情况下,子弹只朝着自己的面朝向移动。
  2. 曲线运动。这种情况下,子弹会在直线运动的基础上进行左右摇摆。它使用Mathf.Sin函数和time变量来计算左右位移量,并使用Transform.Translate方法进行移动。
  3. 右抛物线。这种情况下,子弹会在直线运动的基础上向右旋转。它使用Quaternion.AngleAxis方法和info.roundSpeed字段来计算旋转角度,并使用Transform.rotation属性进行旋转。
  4. 左抛物线。这种情况下,子弹会在直线运动的基础上向左旋转。它使用Quaternion.AngleAxis方法和info.roundSpeed字段来计算旋转角度,并使用Transform.rotation属性进行旋转。
  5. 跟踪导弹。这种情况下,子弹会不断调整自己的朝向,以便朝着玩家对象移动。它使用Quaternion.LookRotation方法计算和PlayerObject的向量

子弹代码

//用于曲线移动的 计时变量
private float time;

void Update()
{
    //所有移动的共同特点 都是朝自己的面朝向动
    this.transform.Translate(Vector3.forward * info.forwardSpeed * Time.deltaTime);
    //接着再来处理 其它的移动逻辑
    //1 代表 只朝自己面朝向移动 直线运动
    //2 代表 曲线运动 
    //3 代表 右抛物线
    //4 代表 左抛物线
    //5 代表 跟踪导弹
    switch (info.type)
    {
        case 2:
            time += Time.deltaTime;
            //sin里面值变化的快慢 决定了 左右变化的频率
            //乘以的速度 变化的大小 决定了 左右位移的多少
            //曲线运动时 roundSpeed旋转速度 主要用于控制 变化的频率
            this.transform.Translate(Vector3.right * Time.deltaTime * Mathf.Sin(time * info.roundSpeed) * info.rightSpeed);
            break;
        case 3:
            //右抛物线 无非 就是 去改变 旋转角度
            this.transform.rotation *= Quaternion.AngleAxis(info.roundSpeed * Time.deltaTime, Vector3.up);
            break;
        case 4:
            //左抛物线 无非 就是 去改变 旋转角度
            this.transform.rotation *= Quaternion.AngleAxis(-info.roundSpeed * Time.deltaTime, Vector3.up);
            break;
        case 5:
            //跟踪移动 不停的计算 玩家和我之间的方向向量 然后得到四元数 然后自己的角度 不停的 变化为这个目标四元数
            this.transform.rotation = Quaternion.Slerp(this.transform.rotation,
                                                       Quaternion.LookRotation(PlayerObject.Instance.transform.position - this.transform.position),
                                                       info.roundSpeed * Time.deltaTime);
            break;
    }
}

拖一个子弹预制体到场景,子弹预制体添加子弹脚本。脚本中添加测试代码,开始时初始化数据。调整测试代码中的索引看看不同配置的效果,根据效果修改配置。测试完删除测试代码。

给各个子弹预制体的父对象的碰撞器设置为触发器。给每个玩家飞机对象设置标签为Player,也添加碰撞器并添加刚体。不使用重力。


18.2 知识点代码

BulletObject

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

public class BulletObject : MonoBehaviour
{
    private BulletInfo info;

    public void InitInfo(BulletInfo info)
    {
        this.info = info;
        Invoke("DealyDestroy", info.lifeTime);
    }

    private void DealyDestroy()
    {
        Destroy(this.gameObject);
    }

    public void Dead()
    {
        GameObject effObj = Instantiate(Resources.Load<GameObject>(info.deadEffRes));
        effObj.transform.position = this.transform.position;
        Destroy(effObj, 1f);

        Destroy(this.gameObject);
    }

    private void OnTriggerEnter(Collider other)
    {
        if (other.gameObject.CompareTag("Player"))
        {
            PlayerObject obj = other.GetComponent<PlayerObject>();
            obj.Wound();

            Dead();
        }
    }

    private float time;

    void Update()
    {
        this.transform.Translate(Vector3.forward * info.forwardSpeed * Time.deltaTime);

        switch (info.type)
        {
            case 2:
                time += Time.deltaTime;
                this.transform.Translate(Vector3.right * Time.deltaTime * Mathf.Sin(time * info.roundSpeed) * info.rightSpeed);
                break;
            case 3:
                this.transform.rotation *= Quaternion.AngleAxis(info.roundSpeed * Time.deltaTime, Vector3.up);
                break;
            case 4:
                this.transform.rotation *= Quaternion.AngleAxis(-info.roundSpeed * Time.deltaTime, Vector3.up);
                break;
            case 5:
                this.transform.rotation = Quaternion.Slerp(this.transform.rotation,
                                                            Quaternion.LookRotation(PlayerObject.Instance.transform.position - this.transform.position),
                                                            info.roundSpeed * Time.deltaTime);
                break;
        }
    }
}

PlayerObject

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

public class PlayerObject : MonoBehaviour
{
    private static PlayerObject instance;

    public static PlayerObject Instance => instance;

    public int nowHp;
    public int maxHp;

    public int speed;
    public int roundSpeed;
    private Quaternion targetQ;

    public bool isDead;

    private Vector3 nowPos;
    private Vector3 frontPos;

    private void Awake()
    {
        instance = this;
    }

    public void Dead()
    {
        isDead = true;
        GameOverPanel.Instance.ShowMe();
    }

    public void Wound()
    {
        if (isDead)
            return;

        this.nowHp -= 1;
        GamePanel.Instance.ChangeHp(this.nowHp);

        if (this.nowHp <= 0)
            this.Dead();
    }

    private float hValue;
    private float vValue;
    void Update()
    {
        if (isDead)
            return;

        hValue = Input.GetAxisRaw("Horizontal");
        vValue = Input.GetAxisRaw("Vertical");

        if (hValue == 0)
            targetQ = Quaternion.identity;
        else
            targetQ = hValue < 0 ? Quaternion.AngleAxis(20, Vector3.forward) : Quaternion.AngleAxis(-20, Vector3.forward);

        this.transform.rotation = Quaternion.Slerp(this.transform.rotation, targetQ, roundSpeed * Time.deltaTime);

        frontPos = this.transform.position;
        this.transform.Translate(Vector3.forward * vValue * speed * Time.deltaTime);
        this.transform.Translate(Vector3.right * hValue * speed * Time.deltaTime, Space.World);

        nowPos = Camera.main.WorldToScreenPoint(this.transform.position);

        if (nowPos.x <= 0 || nowPos.x >= Screen.width)
        {
            this.transform.position = new Vector3(frontPos.x, this.transform.position.y, this.transform.position.z);
        }

        if (nowPos.y <= 0 || nowPos.y >= Screen.height)
        {
            this.transform.position = new Vector3(this.transform.position.x, this.transform.position.y, frontPos.z);
        }
    }
}


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com

×

喜欢就点赞,疼爱就打赏