21.小功能补充

21.游戏场景-游戏主逻辑-小功能补充


21.1 知识点

现在子弹自动销毁不会播特效。在延迟执行的函数中调用死亡,让子弹销毁时波特小,效果更好。

private void DealyDestroy()
{
    //直接执行死亡 会播放 特效
    Dead();
}

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

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

游戏场景的NGUI摄像机的EventSystem脚本中是默认隐藏鼠标的,要旋转取消勾选。

添加一个子弹层,给各个子弹预制体设置成子弹层。在PlayerObj脚本的Update检测中监听鼠标点击,发出射线碰撞到子弹则销毁子弹。

//射线检测 用于销毁子弹
if(Input.GetMouseButtonDown(0))
{
    RaycastHit hitInfo;
    //这里只检测子弹层
    if(Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hitInfo, 1000, 1 << LayerMask.NameToLayer("Bullet")))
    {
        BulletObject bulletObj = hitInfo.transform.GetComponent<BulletObject>();
        //直接让被点中的子弹 销毁
        bulletObj.Dead();
    }
}

给游戏场景添加背景音乐。


21.2 知识点代码

BulletObject

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

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()
    {
        //直接执行死亡 会播放 特效
        Dead();
    }

    //销毁场景上的子弹
    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();
        }
    }
    
    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;
        }
    }
}

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");
        //如果没有按我们的ad键 那么目标角度 就是000度
        if (hValue == 0)
            targetQ = Quaternion.identity;
        //如果按ad键 就是 0020 或者00-20 根据你按的左右决定
        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);
        }

        //射线检测 用于销毁子弹
        if(Input.GetMouseButtonDown(0))
        {
            RaycastHit hitInfo;
            //这里只检测子弹层
            if(Physics.Raycast(Camera.main.ScreenPointToRay(Input.mousePosition), out hitInfo, 1000, 1 << LayerMask.NameToLayer("Bullet")))
            {
                BulletObject bulletObj = hitInfo.transform.GetComponent<BulletObject>();
                //直接让被点中的子弹 销毁
                bulletObj.Dead();
            }
        }
    }
}


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

×

喜欢就点赞,疼爱就打赏