笔记30 Unity跑酷类型游戏

街区

在这里插入图片描述

添加雾

在这里插入图片描述

玩家跑步代码。为了进行街区的制作,先让玩家跑起来

  public int Hp = 1;
    // 速度
    public float Speed = 4;
   
    void Start()
    {        
    }

    void Update()
    {
        if(Hp <= 0)
        {
            //什么也不做了
            return;
        }
        //跑步(向前方*速度*转换成每秒)
        transform.Translate(transform.forward*Speed*Time.deltaTime);
    }

代码:街区GroundControl

    //地形预设体的数组
    public GameObject[] GroundPres;

    //玩家位置
    private Transform playerTrans;

    void Start()
    {
        //在这里得到。=得到玩家.位置
        playerTrans = GameObject.FindWithTag("Player").transform;
    }

    // Update is called once per frame
    void Update()
    {
        //如果玩家离开了当前地面,当前地面位置前进80米
        //因为地面Z轴长度是40米,只要大于20米,即算离开。
        //为了画面衔接更好,所以别20米大点。
        if(playerTrans.position.z - transform.position.z > 25)
        {
            //往前方前进80米
            transform.position += Vector3.forward * 80;
            //销毁当前地形,创建新地形
            Destroy(transform.GetChild(0).gameObject);
            //随机创建新的地形。创建(什么东西(随机一个),位置(和当前点的位置一样),旋转(不旋转))
            //创建出来之后,要当做当前点的子物体,所以在后面直接添加“.transform(拿到).SetParent设置父物体(transform当前点)”
            Instantiate(GroundPres[Random.Range(0, GroundPres.Length)], transform.position, Quaternion.identity).transform.SetParent(transform);
        }
    }

出现的一个小Bug

在这里插入图片描述

声音控制器+代码AudioManager

在这里插入图片描述

//单例
    public static AudioManager Instance;

    //播放器有两个
    public AudioSource MusicPlayer;
    public AudioSource SoundPlayer;

    //单例写在Awake这里
    void Awake()
    {
        Instance = this;
    }

    //方法有两个。一个是播放音乐
    public void PlayMusic(string name)
    {
        //如果音乐播放器没在播放
        if(MusicPlayer.isPlaying == false)
        {
            //就读取一个声音片段,声音判断是通过R加载上来的
            AudioClip clip = Resources.Load<AudioClip>(name);
            MusicPlayer.clip = clip;
            MusicPlayer.Play();
        }
    }
    //另一个是停止的方法
    public void StopMusic()
    {
        MusicPlayer.Stop();
    }

    //播放音效
    public void PlaySound(string name)
    {
        //加载声音片段
        AudioClip clip = Resources.Load<AudioClip>(name);
        SoundPlayer.PlayOneShot(clip);
    }

玩家

玩家左右变换跑道

未使用动画插件,切换较生硬(不好)

 //靠左边跑
        if(Input.GetKeyDown(KeyCode.A) && isGround == true)
        {
            //如果它在中间、右侧跑道(即X轴大于等于0),才可以靠左边跑
            if (transform.position.x >= 0)
            {            
                //transform.position.x -= 2;是会爆红的。因为,Vector3是可读可写,xyz是只读。所以,这里需要使用座标转换。
				//拿到当前座标
                Vector3 v = transform.position;
                //减
                v.x -= 2;
                //再赋值回来
                transform.position = v;
            }
        }
        //靠右边跑
        if (Input.GetKeyDown(KeyCode.D) && isGround == true)
        {
            //如果它在中间、左侧跑道(即X轴小于等于0),才可以靠右边跑
            if (transform.position.x <= 0)
            {
                //拿到当前座标
                Vector3 v = transform.position;
                //加
                v.x += 2;
                //再赋值回来
                transform.position = v;
            }
        }

使用动画插件,切换自然+代码

在这里插入图片描述

    /*
    是否在动画当中(因为,下面利用插件左右移动时,给的动画时间是0.5秒,
    如果在未到0.5秒(即未到指定位置,未播完动画),便按了其他按键,会导致位置不准确
    所以添加判断:是否在动画中
    */
    private bool isAni = false;
  
  
        //靠左边跑
        if(Input.GetKeyDown(KeyCode.A) && isGround == true)
        {
            //如果它在中间、右侧跑道(即X轴大于等于0),才可以靠左边跑
            if (transform.position.x >= 0 && isAni == false)
            {
                //播放音效
                AudioManager.Instance.PlaySound("变换跑道");

                //设定动画状态
                isAni = true;
                //目标位置。target的x = 当前位置的x减2
                float targetx = transform.position.x - 2;
                //创建动画。一个动画,就是一个Tween。增加了很多方法,此处用X轴移动(DOMoveX)
                //DOMoveX(目标位置,动画时间)
                Tween tween = transform.DOMoveX(targetx, 0.5f);
                /*
                 此处,应该讲动画的状态设置为false。
                 法一:在下面写一个结束方法,在这里“Invoke("AniEnd", 0.5f);”。
                 意思是,0.5秒以后,调用动画结束方法。
                 法二:在下面写一个结束方法,onComplete完成委托。TweenCallback委托(AniEnd方法)
                 两种方法,法二的优点是不需要知道动画播放时间,
                 所以如果动画的播放时间是随机的,该方法便是极好用的了。
                 */
                tween.onComplete = new TweenCallback(AniEnd);
            }
        }
        //靠右边跑
        if (Input.GetKeyDown(KeyCode.D) && isGround == true)
        {
            //如果它在中间、左侧跑道(即X轴小于等于0),才可以靠右边跑
            if (transform.position.x <= 0 && isAni == false)
            {
                //播放音效
                AudioManager.Instance.PlaySound("变换跑道");

                //设定动画状态
                isAni = true;
                //目标位置。target的x = 当前位置的x加2
                float targetx = transform.position.x + 2;
                //创建动画。一个动画,就是一个Tween。增加了很多方法,此处用X轴移动(DOMoveX)
                //DOMoveX(目标位置,动画时间)
                Tween tween = transform.DOMoveX(targetx, 0.5f);
                //完成委托
                tween.onComplete = new TweenCallback(AniEnd);
            }
        }

地面检测出现的小问题

在这里插入图片描述

障碍物

在这里插入图片描述

金币

创建金币,注意它所属的位置

在这里插入图片描述

金币特效

第一组粒子

在这里插入图片描述
在这里插入图片描述

第二组粒子

在这里插入图片描述

代码:金币CoinCollider

// 拿到金币特效
    public GameObject CoinEffect;

    void Start()
    {        
    }
    //金币是一直旋转的
    private void Update()
    {
        //注意金币是形变后得到的,所以要查看此时向上的是什么轴,此处是Y轴。
        //每秒旋转80度
        transform.Rotate(Vector3.forward, 80 * Time.deltaTime);
    }


    //如果玩家进来了
    private void OnTriggerEnter(Collider other)
    {
        if(other.tag == "Player")
        {
            //实例化特效。实例化(实例化什么,位置,旋转)
            Instantiate(CoinEffect, transform.position, Quaternion.identity);
            //播放碰到金币的音效
            AudioManager.Instance.PlaySound("金币");
            //销毁自己
            Destroy(gameObject);
        }
    }

自动销毁金币特效+代码AudioDestroy

在这里插入图片描述

// 金币特效是的粒子发射时间最长是0.5秒,所以,默认给它0.5秒
    public float DestroyTime = 0.5f;

    void Start()
    {
        Destroy(gameObject, DestroyTime);
    }

    void Update()
    {
        
    }

代码:玩家PlayerControl

 public int Hp = 1;
    // 速度
    public float Speed = 4;

    /*是否在动画当中(因为,下面利用插件左右移动时,给的动画时间是0.5秒,
    如果在未到0.5秒(即未到指定位置,未播完动画),便按了其他按键,会导致位置不准确
    所以添加判断:是否在动画中*/
    private bool isAni = false;
    //是否接触地面(因为,此游戏限定在空中不可以切换跑道)
    private bool isGround = false;

    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if(Hp <= 0)
        {
            //什么也不做了
            return;
        }
        //跑步(向前方*速度*转换成每秒)
        transform.Translate(transform.forward*Speed*Time.deltaTime);

        //判断有没有踩到地面有两种方法,此处使用射线检测
        //创建射线。此处应注意,这个模型的transform.position是紧贴地面的,所以要将射线的起始点上移一点点。
        //方向:Vector3.down向下
        Ray ray = new Ray(transform.position + Vector3.up * 0.05f, Vector3.down);
        RaycastHit hit;
        //射线检测。(检测谁ray, 检测结果out hit, 射线长度0.1f)
        bool res = Physics.Raycast(ray, out hit, 0.1f);
        //画出射线(无用,删除即可)。把上面小括号里射线的相关数据复制一下,添加长度,颜色
        //Debug.DrawRay(transform.position + Vector3.up * 0.05f, Vector3.down * 0.1f, Color.red);
        if(res = true && hit.collider.tag == "Ground")
        {
            isGround = true;
        }
        else
        {
            isGround = false;
        }
       
        //靠左边跑
        if(Input.GetKeyDown(KeyCode.A) && isGround == true)
        {
            //如果它在中间、右侧跑道(即X轴大于等于0),才可以靠左边跑
            if (transform.position.x >= 0 && isAni == false)
            {
                //播放音效
                AudioManager.Instance.PlaySound("变换跑道");

                //设定动画状态
                isAni = true;
                //目标位置。target的x = 当前位置的x减2
                float targetx = transform.position.x - 2;
                //创建动画。一个动画,就是一个Tween。增加了很多方法,此处用X轴移动(DOMoveX)
                //DOMoveX(目标位置,动画时间)
                Tween tween = transform.DOMoveX(targetx, 0.5f);
                /*
                 此处,应该讲动画的状态设置为false。
                 法一:在下面写一个结束方法,在这里“Invoke("AniEnd", 0.5f);”。
                 意思是,0.5秒以后,调用动画结束方法。
                 法二:在下面写一个结束方法,onComplete完成委托。TweenCallback委托(AniEnd方法)
                 两种方法,法二的优点是不需要知道动画播放时间,
                 所以如果动画的播放时间是随机的,该方法便是极好用的了。
                 */
                tween.onComplete = new TweenCallback(AniEnd);
            }
        }
        //靠右边跑
        if (Input.GetKeyDown(KeyCode.D) && isGround == true)
        {
            //如果它在中间、左侧跑道(即X轴小于等于0),才可以靠右边跑
            if (transform.position.x <= 0 && isAni == false)
            {
                //播放音效
                AudioManager.Instance.PlaySound("变换跑道");

                //设定动画状态
                isAni = true;
                //目标位置。target的x = 当前位置的x加2
                float targetx = transform.position.x + 2;
                //创建动画。一个动画,就是一个Tween。增加了很多方法,此处用X轴移动(DOMoveX)
                //DOMoveX(目标位置,动画时间)
                Tween tween = transform.DOMoveX(targetx, 0.5f);
                //完成委托
                tween.onComplete = new TweenCallback(AniEnd);
            }
        }

        //跳跃
        if(Input.GetKeyDown(KeyCode.Space) && isGround == true)
        {
            //给刚体一个向上的力
            GetComponent<Rigidbody>().AddForce(200f * Vector3.up);
            //播放跳跃音效
            AudioManager.Instance.PlaySound("跳");
        }
    }
    //动画结束
    void AniEnd()
    {
        //保障x永远是-2、0、2个值中的一个,使代码更严谨。
        //思路:判断结果是1.8,就直接改成2

        isAni = false;
    }
    
    //
    private void OnCollisionEnter(Collision collision)
    {
        if(collision.collider.tag == "Obs")
        {
            Hp--;
            if(Hp <= 0)
            {
                //停止背景音乐(自己填的第一条代码)
                AudioManager.Instance.StopMusic();
                //播放死亡音效。(我出现的问题:死亡音效发生二重唱!)
                AudioManager.Instance.PlaySound("死亡2");
                //播放死亡动画
                GetComponent<Animation>().Play("die");
            }
        }
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章