zoukankan      html  css  js  c++  java
  • Unity3d项目入门之Rolling Ball

      下面通过分析制作一个简单的收集特定物体的滚球游戏来入门unity,包括操作面板和C#脚本的编写导入,创建Game Object和给Object添加组件等等。

      一 初始设置

      在Assert下创建主场景MainScene。往场景中添加一3D Obj - “平面” Plane,rename 为Ground,

      

      创建玩家 Player 对象(Sphere),选中球以此点击“Edit”->“Frame Select”或者快捷键“F”,可聚焦到当前所选的obj。设置0.5个unity单位让球脱离地面。

      

      新增Materials材质文件夹,给Ground对象设置颜色。设置Albedo(反射率,直接影响反射光照)的RGB为(0,32,64),然后把“衣服”材质拖到Ground上。

      二 移动玩家

      玩家移动需要接收键盘输入,同时碰到边缘需要停下来,因此给玩家添加一物理刚体 - “Rigibody”

               (可以通过up和down调整组件的顺序)

      因为要接收键盘输入,故给玩家添加一C#脚本,命名为PlayerController

           

      注意,通过组件的方式添加脚本会生成在项目根目录下,我们可以新建一Scripts文件夹保持项目的组织架构的清晰,把相关的脚本都拖到这个脚本文件夹中。 本例中脚本代码如下:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class PlayerController : MonoBehaviour {
        private Rigidbody rb;
    
        void Start()
        {
            rb = GetComponent<Rigidbody>();
        }
    
        //目的是每一帧都检测一下用户的输入,然后每一帧都把输入应用到游戏对象上
        private void FixedUpdate()
        {
            //获得用户输入
            float moveHorization = Input.GetAxis("Horizontal");
            float moveVertical = Input.GetAxis("Vertical");
    
            //注意y方向是上下移动,则这里只需x,z
            Vector3 movement = new Vector3(moveHorization, 0.0f, moveVertical);
            rb.AddForce(movement);
        }
    }

      每帧检测有两种方法:①Update每一帧展示之前被调用;②Fixed Update:进行任何的物理计算之前被调用,物理代码在这里执行。 对刚体施加力的作用使球移动起来,是物理系统,则本例在Fixed Update里添加代码。

      运行Play游戏,发现有两个问题:一是太慢;二是移动一会就脱离视野看不到了。

    public class PlayerController : MonoBehaviour {
        //只有public变量才会出现Inspector面板
        public float speed;
    
        ... ...
    
        private void FixedUpdate()
        {
            ... ...
            rb.AddForce(movement* speed);
        }
    }

      

      运行游戏,可以手动调节移动的速度了。

      三 移动摄像机

      上述的问题,显然因为摄像机不会移动导致看到的视野很有限,这就需要将摄像机和玩家角色绑定。 首先沿y轴向上95单位,再沿x轴旋转45度,

      

      然后把摄像机当做是玩家角色的子对象,这就是所谓的“第三人称视角”。 但仅仅简单绑定到玩家对象上,会发现摄像机的x,y,z值在疯狂无规律变化,转得眼花缭乱,显然不正确。其实摄像机不需要随着玩家对象一直翻滚,所以直接绑定是不正确的。  回想一下打CF的FTS游戏时,可以发现摄像头和爆头枪始终保持在一个相同的距离和角度的参数。 故给Camera添加脚本CameraController控制如下:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class CameraController : MonoBehaviour {
        //跟随对象
        public GameObject player;
        private Vector3 offset;
    
        void Start () {
            //第一帧开始计算好摄像机和玩家角色对象的偏移
            offset = transform.position - player.transform.position;
        }
        
        void LateUpdate () {
            //每帧保持恒定间隔 从而每帧显示之前先移动到跟角色相关的新的位置
            transform.position = player.transform.position + offset;
        }
    }

      注意!:上述代码每帧更新的方法最好使用LateUpdate。 LateUpdate和Update一样都是每帧都会执行,但它执行在所有的东西都Update之后。这样就能确定玩家角色在这一帧内已经移动完成,紧接着的摄像机做的运算是最新的。

      运行游戏,发现游戏是不会跟着动的?what!  别忘了把当前玩家即那个球拖动到player的变量赋值,正常,实现了第三人称视角。

      四 设置游戏场地

      这节要解决的问题主要有两点,一是围栏阻挡的添加,二是计分物的增加。创建一Empty Object,命名为Wall,作为父空对象。然后创建一Cube方格,命名为WestWall,reset重置到原点。将WestWall作为Wall的子对象。 快捷键F聚焦得下图:

      

      设置尺寸为宽x:0.5,高y:2,长z:10,设置x位置为-5。同理创建另外三面墙体的Game Object,

      

      因为新建的Cube有Box Collider,则会和玩家刚体发生碰撞检测,

      

      五 创建收集物

      新建一Cube,命名为PickUp,同理重置reset位置。为取消Player对象的视觉阻挡,可取消选择Name属性,实质是游戏对象的Active勾选框取消选择会让该游戏对象在场景中不可见

      

      缩小并沿各个轴旋转45度,然后添加脚本Rotator控制持续的转动,根据unity官方文档可知旋转和移动都有对应的公用方法接口,如下:

      

        

         

       

         

      脚本代码如下:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    
    public class Rotator : MonoBehaviour {
        void Update () {
            //注意旋转接口函数是类对象的公共方法,所以需要通过对象来调用,故必须小写t开头transform
            transform.Rotate(new Vector3(15,30,45) * Time.deltaTime);//为使旋转更平滑乘以deltaTime
        }
    }

      运行游戏,能看到收集物每帧实时更新旋转角度。 接下来,就需要在场景中添加多个类似的这种拾取物,这里有个很重要的概念点:预设体prefab),指一个资源,它包含一个游戏对象或对象组的模板或原型。prefab的作用在于,对一个预设的实例做变更改变预设资源本身,则场景中所有的这个预设对象(如此例中的拾取物对象)都会做同样的变更!  所谓的“分身”作用,这里的收集物显然可做成预设体:

      (根目录新建Prefabs目录装预设体)

      将某个对象 A 拖到Prefabs文件夹,能发现对象A的Name变蓝,表示成为了预设体,如下图:

      

      创建一空对象作为父节点,单独装载所有预设体实例instance。这里要注意一点,即每个instance实例对象坐标系的选择,主要有两种:一是Local本地坐标系,  是伴随对象自身变换而改变的坐标系,如下:

      

      二是Global世界坐标系, 不会因对象旋转变换而改变坐标系,如下:

      

      本例中为了保持各个拾取物都处于同一个水平面,故应该切换成Global模式,

      (y轴方向不拖动便能保持同一水平面)

      为了更突出,可更改预设体的材质颜色,直接复用上面的一个材质,然后把材质应用到预设体上。 这里有个方法:

      ①直接替换材质到预设体基类上。如下图:

          

      ②替换材质到某一个预设体instance实例上,但必须要记得点击“Apply”才能应用到预设体及其所有实例对象,如下:

           

      六 展示分数和文本

      显然需要两部分实现本例内容,一是展示分数,二是计算统计分值。在PlayerController中添加一count私有变量用来存储当前分数,初始值为0;每次发生碰撞时自增1,然后传递给UI控件显示。

      1)右键选UI部分往场景添加一个Text控件,法线画布Canvas和事件系统EventSystem也随之创建(UI控件内容都是放置在一画布中,规定所有的UI元素都是画布Canvas的子元素)。

      

      和Game Object不同的是,Transform变量变成了Rect Transform,可见UI元素可设置锚点和轴心等因素:

         

      如这里把锚定至画布左上角,同时把轴心设置在了左上角,设置x = 10,y = -10设置边间距。到此UI相关设置完毕,下面要在脚本中获取这个UI控件:

      注意!:UI箱中的所有UI元素的详细信息都在一个叫“UI”的namespace命名空间中,和脚本代码中已有的 “using UnityEngine;” 和 “using System.Collections;”等一样的道理,因此在脚本开头加上:

      using UnityEngine.UI;

      或者在VS编辑器跳转到定义能看到命名空间中对应UI类的定义,

      

      接下来就能在下面编写UI代码,先定义一个public变量来引用保存UI文本组件,然后再初始化UI文本显示值。代码如下:

    using System.Collections;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class PlayerController : MonoBehaviour {
        public Text CountText_;
        private int count;
    
        void Start()
        {
            rb = GetComponent<Rigidbody>();
            count = 10;
            CountText_.text = "Count Text:" + count.ToString();
        }
        ... ... ...
    }

      2)简单说,就是和拾取物发生碰撞时,通知玩家对象对count变量自增并更新UI显示;同时把被碰撞的拾取物隐藏不可见。  总结两点:

      ①隐藏不可见用SetActive,但要先获取实体类对象gameObject再调用; 销毁对象用Destroy

      ②碰撞事件监听OnTriggerEnter

      

      这里注意一点,就是要对发生碰撞的类型过滤下,因为此例中和围栏发生碰撞也会进入这个事件通知,代码如下:

        private void OnTriggerEnter(Collider other)
        {
            if (other.gameObject.CompareTag("fuck"))
            {
                count = count + 1;
                CountText_.text = "Count Text:" + count.ToString();
            }
        }

      运行游戏,发现发生碰撞的时候并没有响应事件更新显示控件。oh My God! 查阅资料,发现有一重要点忽略了,就是“trigger开关”! 接收碰撞物体的是Collider,有一 Is Trigger属性,如下:

      

      默认不勾选的,则会有碰撞停止的物理效果。当勾选激活此项时,会调用碰撞双方的脚本 OnTrigger***, 反之,脚本方面没有任何反应。 但激活带来的副作用就是不会再有物理效果,如本例中若把player的Collider激活会发现球直接穿墙出去,同时自由落体掉下去了。 故这里只把拾取物的prefab的trigger开关全部打开接收碰撞响应(因为拾取物没有RigidBody刚体),总体代码如下:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class PlayerController : MonoBehaviour {
        public float speed;
        private Rigidbody rb;
        public Text CountText_;
        private int count;
    
        void Start()
        {
            rb = GetComponent<Rigidbody>();
            count = 0;
            CountText_.text = "Count Text:" + count.ToString();
        }
    
        private void FixedUpdate()
        {
            float moveHorization = Input.GetAxis("Horizontal");
            float moveVertical = Input.GetAxis("Vertical");
            Vector3 movement = new Vector3(moveHorization, 0.0f, moveVertical);
            rb.AddForce(movement* speed);
        }
    
        private void OnTriggerEnter(Collider other)
        {
            if (other.gameObject.CompareTag("fuck"))
            {
                other.gameObject.SetActive(false);
                count = count + 1;
                CountText_.text = "Count Text:" + count.ToString();
            }
        }
    }

      运行游戏,正常运行!

      参考资料链接:

      https://blog.csdn.net/goodai007/article/details/44679591 (Unity3D碰撞检测)

      https://www.cnblogs.com/zengbinsi/p/zengbinsi_unity3d_004.html (【Unity入门】碰撞检测与触发检测)

      七 编译发布

      (或快捷键 Ctrl + Shift + B)

      选择不同的平台,

      

      

      把需要编译的场景添加至Build Settings窗口,可以通过“Add Open Scenes”来添加当前场景,或者从项目视图中拖拽任意场景到Build Settings窗口的顶部区域。注意,我们无需包含项目中的每个场景,只包含需要的场景即可。 甚至窗口中没有添加任何场景也能编译,因为Unity会选择当前正在打开编辑的场景。 最后点击build按钮,开始编译。

      

      PS.编译过程需要Android SDK,若没有安装则会编译失败。

      参考资料链接:

      《unity3d-配置Android环境,打包发布Apk流程详解

  • 相关阅读:
    django admin site配置(二)
    MyEclipse中无法将SVN检出来的项目部署到tomcat中
    遍历目录树,清理编译目录
    axis2学习, ant 构建axis2 ws
    [置顶] 2013 Multi-University Training Contest 8
    Cocos2d-x 关于在iOS平台真机测试的一些注意
    SharePoint 2013的100个新功能之社交
    路由共享上网原理
    red ant
    nginx正向代理访问百度地图API
  • 原文地址:https://www.cnblogs.com/pyqLoner/p/9660299.html
Copyright © 2011-2022 走看看