unity之跳一跳(完整版)

1.场景

(1)creat->3D objict->plane 并重命名为ground,做为地面(如下图)图一
(2)并调整颜色,大小至适合(如下图)
调正颜色:创建material(project:creat->Material)用与当作groud的材质,调整颜色,并赋到ground上
在这里插入图片描述
在这里插入图片描述

2.制作模型(即预制体:prefab)

(1)创建盒子:creat,调整盒子大小及位置,并将其拖入到事先建立好的prefabs文件夹中,使之作为一个预制体
在这里插入图片描述
(2)创建人物:
建立一个空物体(Creat empty),并将其重命名为player
在这里插入图片描述
在player里建立一个圆柱和球体,给player添加刚体组件,调正颜色(过程和标题1中ground的调色差不多),调正大小比例使其形成下图模样(图中transform参数可作为参考)
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
至此我们游戏所需模型制作完毕

3.生成第二个盒子

创建Scripts文件夹,在其中创建C#脚本(C# Script)
在这里插入图片描述
打开编辑(话不多说,上代码)

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

public class player : MonoBehaviour
{
    public float maxDis;//生成盒子与上一个盒子的最大距离
    public GameObject _box;//获取生成的盒子对应的预制体
    

    private Vector3 _dir = new Vector3(1, 0, 0);//生成第二个盒子的方向变量
    private Rigidbody rig1;//获取player刚体组件
    // Start is called before the first frame update
    void Start()
    {
        rig1 = GetComponent<Rigidbody>();//获取player的Rigidbody组件,因为此脚本挂在player上,所以默认获取player的刚体组件,可以查资料学习一下怎样获取指定物体组件
        putBox();//调用生成盒子函数
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    void putBox()
    {
        var box = Instantiate(_box);//实例化盒子
        box.transform.position = _box.transform.position + _dir * Random.Range(3f, maxDis);//设置盒子位置
        var a = Random.Range(1f, 2);//生成一个随机数
        box.transform.localScale = new Vector3(a, 1.108432f, a);//改变盒子scale(尺寸)中的x(长)与z(宽)全部为生成的随机数
    }

    void Random_dir()//随机盒子生成方向
    {
        var a = Random.Range(0, 2);//随机生成0,1两个数
        if (a == 0)
        {
            _dir = new Vector3(1, 0, 0);
        }
        else
        {
            _dir = new Vector3(0, 0, 1);
        }
    }
}

编辑完后 ctrl+s保存,返货到unity界面执行下面操作
在这里插入图片描述
运行结果如图
在这里插入图片描述
至此我们完成了生成盒子的操作

4.使player能够完成跳动

在脚本中updata中添加如下代码

if (Input.GetKeyDown(KeyCode.Space))//判断是否按下space
        {
            start_time = Time.time;//记录按下space的时间
        }

        if (Input.GetKeyUp(KeyCode.Space))//判断是否松开按键
        {
            var time = Time.time - start_time;//计算按键时间
            jump(time);
        }

创建使player跳跃函数

void jump(float time)
    {
        //给player添加瞬间力
        //Factor为控制player跳跃速度的控制基数
        rig1.AddForce((new Vector3(0, 2, 0) + _dir) * time * Factor, ForceMode.Impulse);
    }

5.调整player的重心

我们发现此实player跳跃后容易摔倒,所以我们要经过下面操作调整player重心,使其不倒

首先在player上建立空物体,并将其位置移动到player最低端在这里插入图片描述

然后通过代码调正重心
在这里插入图片描述
在这里插入图片描述

6.实现盒子及player按下space时的动画

在这里插入图片描述
将updata中代码改成这样

if (Input.GetKeyDown(KeyCode.Space))//判断是否按下space
        {
            _head = head.transform.localPosition;//记录缩放前头部位置
            _body = body.transform.localScale;//记录缩放前身体大小
            _stand_box = stand_box.transform.localScale;//记录盒子大小
            start_time = Time.time;//记录按下space的时间
        }

        if (Input.GetKeyUp(KeyCode.Space))//判断是否松开按键
        {
            var time = Time.time - start_time;//计算按键时间
            jump(time);
            body.transform.localScale = _body;//身体还原
            head.transform.localPosition = _head;
            stand_box.transform.localScale = _stand_box;//盒子还原
        }
        if (Input.GetKey(KeyCode.Space))
        {

            head.transform.localPosition += new Vector3(0, -1, 0) * 0.1f * Time.deltaTime;//头动画缩小
            body.transform.localScale += new Vector3(1, -1, 1) * 0.05f * Time.deltaTime;//身体动画缩小

            stand_box.transform.localScale += new Vector3(1, -1, 1) * 0.05f * Time.deltaTime;//盒子动画缩小

        }

7.当player跳落在盒子上生成下一个盒子以及销毁前一个盒子

当判断player落在盒子上时,要使用碰撞事件函数,而碰撞事件函数的基条件是存在碰撞器,所以我们要在player和盒子上添加碰撞器(collider)
在这里插入图片描述
然后调成碰撞其大小及位置使其将player完全笼罩
(盒子碰撞器添加方法和player相似 在此不多说,注意:盒子添加完碰撞器后要将prefab中的盒子替换

然后我们需要添加碰撞事件的函数

  void OnCollisionEnter(Collision collision)//碰撞事件函数
    {
        Debug.Log(collision.gameObject.name);//打印与player碰撞的物体的名字
        Collider collider_box = stand_box.GetComponent<Collider>();//获取player原来所在盒子的碰撞器
        if (collision.gameObject.name.Contains("Cube") && collider_box != collision.collider)//判断是否与盒子碰撞且碰撞的盒子是否不同于上一个盒子
        {
            GameObject destory_box = stand_box;//定义将要销毁的盒子
            stand_box = new_box;//将player所在盒子进行刷新
            putBox();//生成新的盒子
            Destroy(destory_box);

        }
        if (collision.gameObject.name == "ground")
        {
            SceneManager.LoadScene(0);//重新开始游戏,需要引入头文件:using UnityEngine.SceneManagement;
        }
    }

同时需要将原来的代码进行少许改动
在这里插入图片描述
在这里插入图片描述

运行了一下,发现盒子生成时可能会产生bug:盒子会形成相互重叠,原因是盒子大小和生成距离的范围有关,自行进行调整即可
在这里插入图片描述
在这里插入图片描述

还有一个bug就是盒子总是按照一个方向生成,原因是在生成盒子函数中未调用随机生成方向函数,自己填补即可

8.实现相机跟随

首先需要定义一个相机的位置的公共变量和一个相机与player位之差的常量
在这里插入图片描述
然后在脚本执行开始时计算相机与player的位置差
在这里插入图片描述
随后添加相机移动函数

void MoveCamera()//相机跟随函数
    {
        Camera.position = transform.position + _cameraRelativeTranfrom;//移动相机:相机位置等于小人目前位置加相对位置
    }

9.分数显示

创建text 并将其位置进行调整,然后在属性栏中进行自适应(途中将其设置为左上角显示)
自适应之后无论装口大小怎样改变,其位置依然在左上角
在这里插入图片描述
添加下面两个变量
在这里插入图片描述
在start中初始化
在这里插入图片描述
在成功跳跃后分数加一
在这里插入图片描述

10.蓄力效果

在player中添加例子特效(如图),并对其在属性栏中进行大小形状设置
在这里插入图片描述

在代码中定义public Object lizi;

开启代码:lizi.SetActive(true);
关闭代码:lizi.SetActive(false);

整个程序源码

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class player : MonoBehaviour
{
    public GameObject stand_box;//当前player所在盒子
    public float maxDis;//生成盒子与上一个盒子的最大距离
    public GameObject _box;//获取生成的盒子对应的预制体
    public float Factor;//实现速度基数
    public Transform transform1;//获取player中空物体的位置
    public Transform head;//记录player的头部位置
    public Transform body;//记录player的身体位置
    public Transform Camera;//相机位置,实现相机跟随时用到
    public Text sco;//记录分数,需要添加:using UnityEngine.UI;
    public GameObject lizi;//例子特效


    private Vector3 _dir = new Vector3(1, 0, 0);//生成第二个盒子的方向变量
    private Rigidbody rig1;//获取player刚体组件
    private float start_time;//记录按下开始space的时间
    private GameObject new_box;//新生成的盒子
    private static Vector3 _cameraRelativeTranfrom;//相机需要移动距离
    //记录player位置和大小及当前盒子大小
    Vector3 _head = new Vector3(0, 0, 0);
    Vector3 _body = new Vector3(0, 0, 0);
    Vector3 _stand_box = new Vector3(0, 0, 0);
    private int _sco;

    // Start is called before the first frame update
    void Start()
    {
        lizi.SetActive(false);//默认粒子特效为关闭状态
        _sco = 0;//分数初始化
        sco.text = _sco.ToString();//分数更新
        _cameraRelativeTranfrom = Camera.position - transform.position;//计算相机对于player的相对位置
        rig1 = GetComponent<Rigidbody>();//获取player的Rigidbody组件,因为此脚本挂在player上,所以默认获取player的刚体组件,可以查资料学习一下怎样获取指定物体组件
        rig1.centerOfMass = transform1.localPosition;//将物体重心放在playwe中空物体的位置
        putBox();//调用生成盒子函数
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))//判断是否按下space
        {
            lizi.SetActive(true);//开启粒子特效
            _head = head.transform.localPosition;//记录缩放前头部位置
            _body = body.transform.localScale;//记录缩放前身体大小
            _stand_box = stand_box.transform.localScale;//记录盒子大小
            start_time = Time.time;//记录按下space的时间
        }

        if (Input.GetKeyUp(KeyCode.Space))//判断是否松开按键
        {
            lizi.SetActive(false);//关闭粒子特效
            var time = Time.time - start_time;//计算按键时间
            jump(time);
            body.transform.localScale = _body;//身体还原
            head.transform.localPosition = _head;
            stand_box.transform.localScale = _stand_box;//盒子还原
        }
        if (Input.GetKey(KeyCode.Space))
        {

            head.transform.localPosition += new Vector3(0, -1, 0) * 0.1f * Time.deltaTime;//头动画缩小
            body.transform.localScale += new Vector3(1, -1, 1) * 0.05f * Time.deltaTime;//身体动画缩小

            stand_box.transform.localScale += new Vector3(1, -1, 1) * 0.05f * Time.deltaTime;//盒子动画缩小

        }
    }

    void putBox()
    {
        Random_dir();//调用随机生成盒子方向函数
        new_box = Instantiate(_box);//实例化盒子
        new_box.transform.position = stand_box.transform.position + _dir * Random.Range(4.5f, maxDis);//设置盒子位置
        var a = Random.Range(1f, 2);//生成一个随机数
        new_box.transform.localScale = new Vector3(a, 1.108432f, a);//改变盒子scale(尺寸)中的x(长)与z(宽)全部为生成的随机数
    }

    void Random_dir()//随机盒子生成方向
    {
        var a = Random.Range(0, 2);//随机生成0,1两个数
        if (a == 0)
        {
            _dir = new Vector3(1, 0, 0);
        }
        else
        {
            _dir = new Vector3(0, 0, 1);
        }
    }

    void jump(float time)
    {
        //给player添加瞬间力
        //Factor为控制player跳跃速度的控制基数
        rig1.AddForce((new Vector3(0, 2, 0) + _dir) * time * Factor, ForceMode.Impulse);
    }

    void OnCollisionEnter(Collision collision)//碰撞事件函数
    {
        Debug.Log(collision.gameObject.name);//打印与player碰撞的物体的名字
        Collider collider_box = stand_box.GetComponent<Collider>();//获取player原来所在盒子的碰撞器
        if (collision.gameObject.name.Contains("Cube") && collider_box != collision.collider)//判断是否与盒子碰撞且碰撞的盒子是否不同于上一个盒子
        {
            _sco++;//分数加一
            sco.text = _sco.ToString();//将分数更新
            MoveCamera();
            GameObject destory_box = stand_box;//定义将要销毁的盒子
            stand_box = new_box;//将player所在盒子进行刷新
            putBox();//生成新的盒子
            Destroy(destory_box);

        }
        if (collision.gameObject.name == "ground")
        {
            SceneManager.LoadScene(0);//重新开始游戏,需要引入头文件:using UnityEngine.SceneManagement;
        }
    }

    void MoveCamera()//相机跟随函数
    {
        Camera.position = transform.position + _cameraRelativeTranfrom;//移动相机:相机位置等于小人目前位置加相对位置
    }
}

工程下载地址:链接:https://pan.baidu.com/s/16_drASFV6Fk5ILGQU5QGlA
提取码:ew0g

unity开发跳一跳至此告一段落
留给大家些许bug,评论区见,欢迎大家前来指点

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章