• Unity实验一 ---吃小球游戏


    一、实验概述

    1.1实验名称:

    Roll a ball

    1.2实验目的:

    本次实验的总的目的是通过具体的程序的编写与unity软件相结合,将所学的知识内化,即将在课堂上学到的知识集成在一起,并实现相关功能,从而锻炼自己的程序编写、程序调试能力以及对unity的掌握能力。

    1.3实验内容:

    实验内容是使用Unity软件完成一个小球滚动吃掉小立方体的游戏。

    本次实验是以windows操作系统为平台,通过unity软件进行本次实验的项目实现,unity是一个十分优秀的全面整合的专业游戏引擎。通过unity软件和编程工具的结合可以轻松创建各种3D模型,模拟模型动态以及插入互动内容。

    1.4实验要求:

    基本要求:

    1.构建一个小球滚动的游戏场景;

    2.创建一个小球,按键盘上的上下左右键,小球会朝相应的方向移动,小球移动的时候相机也要相应移动。

    3.在场景中创建多个立方体,每个立方体都在旋转;小球与立方体发生碰撞的时候,立方体消失,计分板上得分加“1”。

    4.当得分达到“5”分时,在屏幕上显示“XXX同学,你赢了!”,如果不能输出中文,可以用英文代替。

    加分项目:

    1. 添加小球和立方体发生碰撞的特效,添加立方体随机生成,添加小球撞击阻碍物的物理效果。
    2. 你能想到的可以实现的其他效果。

    1.4实验开发步骤指导

    l  创建地面并贴上纹理

    l  创建player

    l  设置摄像机

    l  随机创建食物

    l  设置碰撞

    l  得分音效

    l  计分板与获胜

    l  随机阻碍物

    l  player和food触发特效

    l  设置退出和重新开始

    二、实验过程

    提前导入unitychan的包

    1.创建地面并贴上纹理

    (1) 创建plane并修改大小至合适

    (2) 创建材质GroundMaterial并在Albedo处添加贴图

    2.创建player

    (1)  设置player,放入场景

    (2)  创建Animation Controller(player),添加Animator中的controller 

    (3)  添加rigidbody 并取消Use Gravity。

       否则由于重力原因会使unitychan下坠 

    (4)  设置animator

    A.创建BlendTree,添加动作

     

    B.调整PosX和PosY

     

    C.设置参数inputH和inputY,分别代表水平方向和竖直方向,通过这两个个参数的改变,可以调整动作的状态。

    (5)  添加脚本使人物可以进行移动

    代码思路:从键盘的上下左右键获取用户的输入,通过blendTree控制向前向后向左向右的四个运动状态,同时发生一定的旋转,改变方向。

    1.        //从键盘获取获取inputHinputV  

    2.        inputH = Input.GetAxis("Horizontal");  

    3.        inputV = Input.GetAxis("Vertical");  

    4.        //设置值  

    5.        anim.SetFloat("inputH", inputH);  

    6.        anim.SetFloat("inputV", inputV);  

    7.        //计算位移  

    8.        Vector3 moveX = transform.right * inputH * 100f * Time.deltaTime *speed;  

    9.        Vector3 moveZ = transform.forward *inputV * 100f * Time.deltaTime *speed;  

    10.    float rotey = inputH * 30f * Time.deltaTime * speed;  

    11.    //进行移动  

    12.    rbody.velocity = moveX + moveZ;  

    13.    //rbody.velocity = new Vector3(moveX, 0f, moveZ);  

    14.    this.transform.Rotate(new Vector3(0, rotey, 0)); 

    (6)  设置角色与场景间位移

    取消勾选Apply Root Motion勾上apply root motion对象的Transfrom变动会基于动画移动,不受脚本控制。 勾掉则Transform受到脚本控制。

    3.设置摄像机

    1)跟随player移动

    main camera 设置为unitychan的子对象,则可以跟随player的移动而移动。



    2)第三人称视角。

    设置相机的位置,使其位于player的背后

    3)设置camera

     

    最终效果:

    4.随机创建食物

    plane上随机位置随机时间间隔生成一个cube,如果没有被触发则在15s后销毁。

    (1)  创建prefab

    我们会在游戏中产生许多属性相同的小Cube作为食物,如果要控制每一个食物随机间隔时间出现,通过将其设为预制体可以减轻很多工作量。比如,给预制体添加一个脚本,则由预制体而来的游戏对象都有该脚本。

    (2)  贴图

    创建一个 Cube Material,赋给food

    (3)  设置旋转

    给预制体food添加脚本CubeRotate控制立方体的旋转。

    选用transform.Rotate函数

    function Rotate (axis : Vector3, angle : float, relativeTo : Space = Space.Self) : void

    transform.Rotate(new Vector3(0f, 1f, 1f));

     

    (4)  随机出现

    通过脚本设置食物在plane中随机时间,随机位置产生。并且在15s没有被吃时销毁。

    A.新建一个空的GameObject,添加脚本FoodControl

    代码如下:

     
         void Start () {
            float groundwidth=ground.GetComponent<Renderer>().bounds.extents.x;
            float foodwidth = myfood.GetComponent<Renderer>().bounds.extents.x;
            maxWidth = groundwidth - foodwidth;
            // Vector3 screnpos = new Vector3(Screen.width, 0, 0);
            // Vector3 moveWidth = Camera.main.ScreenToWorldPoint(screnpos);
            //食物自身宽度
            //maxWidth = moveWidth.x - foodwidth;
        }
    
        // Update is called once per frame
        void Update () {
            time -= Time.deltaTime;
            if (time < 0)
            {
                //产生一个随机数,代表实例化下一个food所需要的时间
                time = Random.Range(1.5f, 2.0f);
                //产生随机数Posx,PosY,代表实例化food的坐标
                float posX = Random.Range(-maxWidth, maxWidth);
                float posY = Random.Range(-maxWidth, maxWidth);
                Vector3 spawnPositon = new Vector3(posX, 2f, posY);
                //实例化food,15秒后销毁
                newmyfood = (GameObject)Instantiate(myfood, spawnPositon, Quaternion.identity);
                Destroy(newmyfood, 15);
            }
            }

     

    B.设置参数

     

    运行效果:


    5.设置碰撞

    1)为player添加Box Collider组件,编辑范围

    2) 碰撞检测

    A.在MonoBehaviour类中,OnCollisionEnterOnCollisionExitOnCollisionStay是碰撞时的回调方法,可以在脚本中重载它们。当绑定了Collision脚本组件的游戏物体发生碰撞时,OnCollisionEnter便会被触发调用一次。然后,在整个碰撞过程中会持续调用OnCollisionStay方法,直到碰撞接触被解除时,OnCollisionExit被触发一次。这三个方法都有一个Collision类型的参数,用于保存碰撞信息。

     

    撞检测
        /*
        void OnCollisionEnter(Collision collision)
        {   //获取碰撞到的游戏物体上的Collider
            // string name = collision.collider.name;
            //  print(name);
            if (collision.collider.tag == "food")
            {
                Destroy(collision.collider.gameObject);
            }
        }
        */

     

     

    B.添加脚本后,给playerRigidBody设置Constraints


    3)触发检测

    使用碰撞检测,发生碰撞的游戏物体之间会有碰撞模拟,例如撞到东西会反弹或者停顿一下。如果只想要检测物体与物体之间是否发生接触,但是不要产生碰撞的效果,可以使用触发器来进行接触检测。

    这样在游戏物体发生接触的时候就不会有碰撞的效果了,而是会直接穿过去。Unity的碰撞器有很多类型,Cube的碰撞器类型是盒子碰撞器,另外还有球形碰撞器、胶囊体碰撞器等。

    A.food设为触发器类型

    B.设置脚本

    使用MonoBehaviour类的OnTriggerEnterOnTriggerExitOnTriggerStay是触发检测的三个回调方法,OnTriggerEnter在游戏物体发生接触时调用一次,OnTriggerExit在游戏物体完全分离时调用一次,而OnTriggerStay在游戏物体接触过程中持续调用。 触发器回调的这三个方法的参数都是Collider类型,表示的就是被碰撞的游戏物体的触发器组件对象。

    在本次实验中使用的是OnTriggerEnter

     

     void OnTriggerEnter(Collider collider)
        {
            if (collider.tag == "food")
            {
                GetComponent<AudioSource>().Play();
                GameObject neweffect = (GameObject)Instantiate(effect, transform.position, effect.transform.rotation);
                neweffect.transform.parent = transform;
                Destroy(neweffect, 1.0f);
                score++;
                
    
                if (score == 5)
                {
                    wintext.SetActive(true);
                    wininmage.SetActive(true);
                    var z=GameObject.FindGameObjectsWithTag("food");
                    for(int i=1;i<z.Length;i++)
                    { Destroy(z[i]); }
                   
                    got.GetComponent<FoodControl>().enabled =  false;
                }
                Destroy(collider.gameObject);
                text.text = "your score:"+score.ToString();
            }
        }

     


    5)触发后cube消失

    当检测到触发后,说明player吃到了食物,就要将食物销毁。通过调用Destroy(),可以销毁想要销毁的游戏对象。

    触发器回调的参数都是Collider类型,表示的就是被碰撞的游戏物体的触发器组件对象。因此在Destroy()中传入collider.gameObject即可。


    6.得分音效

    1)添加AudioSource

    为避免在游戏启动时开启音效,取消勾选Play On Awake

     2)播放

    在脚本中触发检测中添加代码

    7.计分板与获胜

    1)计分

    player吃到food后分数会上升

    这一功能主要在触发检测中实现,通过定义一个intscore,来记录吃到food的个数,每当有触发被检测到,说明player吃到了food,则score加一。

    2)计分板

    Unity中使用UI可以通过GUIUGUI。在这里使用的是UGUI。但在操作过程中确实感受到了如果要想设置成自己想要的界面状态,需要大量的调整。

    添加画布,添加text对象,通过在代码中控制文本来显示分数。

     

     void OnGUI()
        {
            GUIStyle style = new GUIStyle();
            style.normal.background = null;
            style.normal.textColor = new Color(0, 0, 0);
            style.fontSize = 15;
            GUI.Label(new Rect(100, 20, 100, 40), "your score:" + score, style);
        }

     

    3youwin

    canvas中添加textimage,但并不显示,当score达到5后,通过代码进行显示。

    效果截图:

         

    4)胜利后清理环境

    当吃到五个食物后,清理环境中剩下的食物,并且停止产生新的食物。

    A.清理剩下的食物

    通过GameObject.FindGameObjectsWithTag()方法来获取所有标签为“food”的食物,并一一销毁。

    var z=GameObject.FindGameObjectsWithTag("food");
                    for(int i=1;i<z.Length;i++)
                    { Destroy(z[i]); }


    B.停止产生新食物

    通过关闭产生食物的脚本来停止产生新食物。

     got.GetComponent<FoodControl>().enabled =  false;


    8.随机阻碍物

    随即阻碍物的实现类似于随机生成食物。

    (1)  创建prefabs

    (2)  添加脚本

    随机生成一个数字a,在场景中生成相应个数的障碍物,player碰到障碍物时会被阻挡。

     

    void Start () {
            a = Random.Range(1, 4);    //生成 [1,4) 的随机整数
            float groundwidth = ground.GetComponent<Renderer>().bounds.extents.x;
            float foodwidth = myban.GetComponent<Renderer>().bounds.extents.x;
            maxWidth = groundwidth - foodwidth;
        }
        
        // Update is called once per frame
        void Update () {
            if (a > 0)
            { 
                float posX = Random.Range(-maxWidth, maxWidth);
                float posY = Random.Range(-maxWidth, maxWidth);
                Vector3 spawnPositon = new Vector3(posX, 1f, posY);
                //实例化阻碍物
                newmyban = (GameObject)Instantiate(myban, spawnPositon, Quaternion.identity);
                a--;
            }
        }

     

     

    效果截图

    9.playerfood触发特效

    (1)  导入effects资源


    (2)  编写代码

    在触发检测中添加以下代码,使得出发时播放effct效果,1s后销

                GameObject neweffect = (GameObject)Instantiate(effect, transform.position, effect.transform.rotation);
                neweffect.transform.parent = transform;
                Destroy(neweffect, 1.0f);

    效果截图:


    10.设置退出和重新开始

    1)利用UGUI,设置两个buttonexitrestart

    2)添加响应事件

    代码如下:

    1.        public void ReStart()  

    2.            {  

    3.                score = 0;  

    4.                wintext.SetActive(false);  

    5.                wininmage.SetActive(false);  

    6.                exitbutton.SetActive(false);  

    7.                restartbutton.SetActive(false);  

    8.                got.GetComponent<FoodControl>().enabled = true;  

    9.            }  

     

    1.        public void GameExit()  

    2.        {  

    3.            Application.Quit();  

    4.        }  

     

    10.设置空气墙

    1)添加4cube,分别调整至周围

    2)勾除mesh render

     

    最后的效果~~

     

     


  • 相关阅读:
    docker harbor 修改密码 重置密码 sql
    mongodb监控并在服务挂掉后自动重启脚本
    centos7 ffmpeg安装 rtsp相关
    vscode vue 自动格式化代码
    开启go module
    Python3.x:打包为exe执行文件(window系统)
    Docker 日志都在哪里?怎么收集?
    HttpsURLConnection信任任何证书
    SP3734 PERIODNI
    联赛前的记录
  • 原文地址:https://www.cnblogs.com/luo-he/p/12790116.html
Copyright © 2020-2023  润新知