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(,,) * 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 = ;
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 + ;
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 = ;
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 + ;
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流程详解》
Unity3d项目入门之Rolling Ball的更多相关文章
- Unity3d项目入门之打Apk包
②结合Android Studio编译器打安卓包 在安卓官网下载AS,按照步骤正常安装编译器完毕,运行AS,点击右下图的图标打开SDK Manager, 选择下载安装相关的“SDK Platform” ...
- Unity3d项目入门之虚拟摇杆
Unity本身不提供摇杆的组件,开发者可以使用牛逼的EasyTouch插件或者应用NGUI实现相关的需求,下面本文通过Unity自身的UGUI属性,实现虚拟摇杆的功能. 主参考 <Unity:使 ...
- 转 猫都能学会的Unity3D Shader入门指南(二)
猫都能学会的Unity3D Shader入门指南(二) 关于本系列 这是Unity3D Shader入门指南系列的第二篇,本系列面向的对象是新接触Shader开发的Unity3D使用者,因为我本身自己 ...
- Unity3D Shader入门指南(二)
关于本系列 这是Unity3D Shader入门指南系列的第二篇,本系列面向的对象是新接触Shader开发的Unity3D使用者,因为我本身自己也是Shader初学者,因此可能会存在错误或者疏漏,如果 ...
- unity3d从入门到精通要掌握什么内容
Unity3d就业方向广.游戏行业占据了65%的比例,也有虚拟现实,增强现实等方向,就业前景火爆.可以从事的岗位:游戏开发工程师.移动应用开发工程师.游戏场景设计师.游戏特效设计师.VR开发工程师.A ...
- 猫都能学会的Unity3D Shader入门指南(二)
关于本系列 这是Unity3D Shader入门指南系列的第二篇,本系列面向的对象是新接触Shader开发的Unity3D使用者,因为我本身自己也是Shader初学者,因此可能会存在错误或者疏漏,如果 ...
- 在MyEclipse下创建Java Web项目 入门(图文并茂)经典教程
http://jijiaa12345.iteye.com/blog/1739754 在MyEclipse下创建Java Web项目 入门(图文并茂)经典教程 本文是一篇在Myeclipse下构建Jav ...
- SVN对unity3d项目版本进行管理的不方便问题,研究ing
unity3d项目版本控制遇到些问题,找了以下资料做参考,现在mark一下,以后慢慢解决,之后总结. Unity开启meta. meta:版本控制文件,在新加入项时,Unity3D会产生一个同名的.m ...
- Unity3D项目实战笔记(10):Unity3D编译IPA的PostEvents–节约时间利器
最近,SDK支付等接入差不多了,就从Unity3D生成IPA (企业版License), 然,需要手动执行的PostEvents竟然多大10项+, 这些我默默的承受了1周时间,每次约浪费20分钟-额外 ...
随机推荐
- mysql原生分页
select * from table limit (pageNo-1)*pageSize, pageSize; 一:分页需求: 客户端通过传递start(页码),limit(每页显示的条数)两个参数 ...
- 在linux中输出每个group的用户成员
先提供使用文件一步一步获取相关信息: 1. 获取所有的用户: awk -F: '{print $1 > "1.txt"}' /etc/passwd 2. 获取每个用户, 及其 ...
- Python【每日一问】09
问:请分别写一段Python代码实现一下功能: (1)计算一个文件中的大写字母数量 (2)输入中文,返回相应的拼音,并写入文件中 答: (1)计算一个文件中的大写字母数量 file_name = &q ...
- 知识点:Mysql 索引原理完全手册(1)
知识点:Mysql 索引原理完全手册(1) 知识点:Mysql 索引原理完全手册(2) 知识点:Mysql 索引优化实战(3) 知识点:Mysql 数据库索引优化实战(4) Mysql-索引原理完全手 ...
- 一则ORACLE进程都在但是无法进入实例的问题
[oracle@localhost ~]$ ps -ef|grep smonoracle 14809 1 0 Sep25 ? 00:13:02 ora_smon_mailp3[oracle@local ...
- 使用 ping++做支付的流程
获取支付凭据 /// <summary> /// 获取支付凭据 /// </summary> /// <param name="model">& ...
- linux Ubuntu 16.04安装 postgresql
两次的重装系统安装数据库折磨的死去活来. 安装步骤: 1,运行 sudo apt-get update --这个用来查找数据源 2 ,运行 apt install postgresql ...
- shell编程变量介绍与表达式详解
shell变量简介 变量是任何一种编程语言都必不可少的组成部分,变量用来存放各种数据.脚本语言在定义变量时通常不需要指明类型,直接赋值就可以,Shell 变量也遵循这个规则. 在 Bash shell ...
- 升级到 .NET Core 2.1
从 .NET Core 2.0 升级到 .NET Core 2.1 最近在翻译 <Pro ASP.NET Core MVC 2>这本书,书中的示例是以 .NET Core 2.0 为基础的 ...
- 如何在vue+element中实现选择框和穿梭框的根据拼音以及拼音首字母以及汉字的模糊搜索
1.汉字: 直接添加对应的 filterable 2.拼音: 穿梭框和选择器的实现方式有所不同 选择器: <1>下载pinyin-match: npm i --save ...