【Unity3D】二、制作滚球游戏学习Unity3D(下)

上一篇文章:https://www.jianshu.com/p/78e21fb7e09e

创建碰撞小立方体

新建Cube

我们在游戏场地中加入一些旋转的小方块儿,然后由球来碰撞这些小方块儿,碰撞之后就加一定的分数。
很简单地,创建一个Cube,并命名为PickUp,使其Reset,然后我们调整一下它的Rotation和Scale,使得其变成一个斜放的小立方体,(为了方便看,这里暂时隐藏了Player,只要在Player的Inspector面板中将其前边的对勾打掉它就会隐藏)。


建立小立方体并改变其角度

让小立方体旋转起来

为了让小方块儿更有趣,我们来添加一个脚本让他旋转起来,新建脚本Rotator,并添加给PickUp,编辑此脚本。
这个逻辑中是不需要Start函数的,我们只需要每一帧都让小方块儿转动一下,所以将逻辑写到Update函数中,这里使用Ratate方法,需要一个Vector3作为参数,为了不让旋转过快,我们给每一帧都乘以一个小的时间量。

private Vector3 rotation = new Vector3(15,30,45);

void Update()
{
    transform.Rotate(rotation * Time.deltaTime);
}

保存脚本,运行游戏可以看到小方块旋转起来了。


让小立方体旋转起来

创建Prefab

接下来我们需要多放置一些立方体在游戏的平面上,在此之前,我们需要把这个设计好的立方体生成一个Prefab(预设体),让它变成一个asset,这样我们可以从prefab创建这个立方体的实例,这样我们才能分别控制每一个由prefab生成的实例或者控制prefab本身,在这个游戏中,被小球碰撞到的小立方体会消失,这也就是我们需要更新每一个小立方体的状态,所以我们需要创建一个Prefab。

a prefab is an asset that contains a template, or blueprint of a game object or game object family.
(预设体是包含游戏对象或游戏对象族的模板或设计大纲的一种资源。)

在Assets下新建Prefabs目录来管理预设体,只需要将MainScene中的PickUp拖拽到新建的目录下就可以生成对应的asset了,这时也会看到MainScene中的PickUp变成了一个蓝色的图标。


创建一个Prefab

此时在MainScene中新建一个空的GameObject来管理所有的小立方体,命名为PickUps,将刚刚的第一个PickUp拖拽到它的上边使其成为其子物体。


调整父子GameObject的关系

放置更多的立方体

接下来放置小立方体,为了调整一个好的视角,我们可以点击Scene中右上角的方位标志的Y轴的小锥体,就会调整视角到俯视的角度,这是一个便捷的小技巧。


调整视角成俯视

由于我们的小立方体是一个斜放的立方体,在原本的坐标轴下很难调整立方体在水平面上的位置,这里还有一个小技巧,我们点击右上角的Local变成Global,这样就会在Global的坐标中对小立方体进行调整了,可以看到,小立方体的三个坐标轴变成了只有两个方向的轴,非常方便就可以调整了。


将坐标改为Global

接下来只需要Duplicate几个或者使用Ctrl+D来重复放置一些小立方体即可。这里粗略地摆放了八个小立方体。
摆放8个小立方体

为小立方体涂色

让后再通过添加一种Material的方式将他们涂成黄色。
这里可以通过两种方式完成。
第一种,将Material拖拽给任意一个PickUp立方体,然后再该PickUp的Inspector的Prefab的Overrides(重载)下选择Apply All来让所有PickUp都被涂成黄色。


为小立方体涂色

第二种方法会更加简单,直接将Material用于Assets中的小立方体的Prefab就可以啦,找到Assets中的PickUp的Prefab,点击Inspector面板中的Open Prefab,就会在Scene窗口中预览该Prefab,这是再拖动黄色的Material到他上边,这个Prefab就会被染成黄色了。

为小立方体涂色

为小立方体涂色

完成碰撞

为PickUp添加标签

如果小球碰撞了旋转的立方体,那么小立方体就会消失。那么如何识别我们的小球Player碰撞的是小立方体呢?我们通过为PickUp添加特定的标签来识别。添加标签再Prefab上,在Assets中找到我们的Prefab并打开它,可以在它的Inspector面板中发现它还没有添加标签(Untagged),点击Tag后的按钮选择Add Tag…,来添加一个名为PickUp的标签,然后再回到最开始的面板处选择新添加的这个标签,这样PickUp的标签就添加好了。


新建并添加PickUp标签

完成碰撞逻辑

重新编辑PlayerController的脚本,这里我们将碰撞发生的逻辑写到函数OnTriggerEnter中,这个函数在发生碰撞事件的时候调用,而且用碰到的Collider(碰撞机)作为参数,也就是我们的Player碰到的Collider。可见,如果要检测到的碰撞,被碰撞的物体需要由碰撞引擎,也就是要有Collider的属性,其实我们会发现,作为Cube保存的一个Prefab在创建之初就已经有Box Collider的这一Component了,所以不再需要我们自己添加。


Box Collider属性

OnTriggerEnter函数用其碰撞到的Collider作为参数,现在就需要我们识别这个碰到的Collider是不是一个PickUp了,显然可以使用Tag来鉴别,这里使用gameObject的CompareTag方法来完成,该方法以一个字符串作为参数,返回一个布尔值,如果gameObject的Tag和字符串一致,就返回true。
接下来完成控制小立方体消失的逻辑,很简单,使用gameObject的方法SetActive来完成,这个方法控制的就是我们在Inspector面板中看到的每一个GameObject前的小对勾,该方法接受一个布尔值作为参数来控制GameObject的消失与显现。
完整的代码如下:

void OnTriggerEnter(Collider other)
{
    if (other.gameObject.CompareTag("PickUp"))
    {
        other.gameObject.SetActive(false);
    }
}

关于碰撞的简单原理

此时运行游戏,在小球碰到小立方体的时候小立方体并没有像我们像的那样消失,这里的原因需要我们了解一定的Unity对与碰撞到原理。Unity将Collider(碰撞机)分为静态碰撞机(Static Collider)和动态碰撞机(Dynamic Collider)两种。静态的碰撞机比如墙面、地板等一些列静态的物体,与他们碰撞时,不允许两个Collider相互重合,也就是说会发生反弹,而为了让我们的碰撞能够实现,我们需要将立方体设置为动态的(Trigger)触发器,成为Trigger的Collider是可以被穿过的,这样才会引发我们的“碰撞事件”的逻辑。这里我们找到PickUp的Prefab,在它的Box Collider的Component中,勾选Is Trigger选项,这样它就成为了一个触发器。


选择Trigger属性

此时运行游戏可以发现,小立方体在受到碰撞后完美消失。


小立方体被碰撞后消失

优化

这里有一个有关物理引擎的优化,首先我们区分了静态碰撞机和动态碰撞机,Untiy对于静态碰撞机,会将它们的体积记录在一个缓存中,这是很合理的,因为静态即不动,所以并不需要在每一帧都计算器和重新绘制它的体积,而动态的则不同,因为它是运动的,所以必须在每一帧处都计算和绘制,这个过程是需要耗费资源的。

Any game object with a collider and a rigid body is considered dynamic.
Any game object with a collider attached but no physics rigid body is expected to be static.
(任何同时带有Collider和Rigidbody属性的GameObject称为动态的,任何只有Collider而没有Rigidbody属性的GameObject称为静态的)

为了让PickUp成为动态的,这样不需要每一次都计算它的体积,我们为PickUp的Prefab添加Rigidbody属性,运行游戏,发现神奇的事情发生了,所有的PickUp居然掉了下去,这当然是由于所有的刚体都受到了重力的影响,所以PickUp会下落。


小立方体受到重力下落

为了解决这一问题,移步到PickUp的Prefab下刚刚添加的Rigidbody属性处,会发现有两个选项,分别是Use Gravity和Is Kinematic。


更改其成为Kinematic Rigid body

显然,我们可以直接将Use Gravity的对勾打掉,这样它不再受重力,自然不会下落,这是一个解决办法,但是并不完美,因为这里我们只取消了重力,但对于一个刚体来说,还会受到其他的力从而使其改变Transform,所以更好的做法是选中下方的Is Kinematic选项,接下来解释Kinematic:
Kinematic Rigid body(运动刚体)的含义是它的Transform也就是位置、角度、大小不会随着力的作用而改变而是单纯地根据Transform设置的值来改变,也就是说我们不能通过对其作用力来改变它的Transfrom,改变的唯一方法是直接调节其Transform下的各个值。

运行游戏,完美!

添加计分机制

添加计数器

接下来添加一个计数器,每撞到一个小球就使计数器数值增加一,自然需要编辑PlayerController脚本,声明一个int类型的变量,在Start函数中初始化为0,在每一次碰撞到小立方体后都增加一,这似乎是一个很简单事情,这里还特地将count每次更新后的值都打印到控制台来验证其正确性。

private int count;
void Start()
{
    rigidbodyPlayer = GetComponent<Rigidbody>();
    count = 0;
}
void OnTriggerEnter(Collider other)
{
    if (other.gameObject.CompareTag("PickUp"))
    {
        other.gameObject.SetActive(false);
        count++;
        Debug.Log(count);
    }
}
控制台显示计分结果

添加UI在游戏界面中显示分数

显然,将分数显示在游戏界面中才是更好的选择,这里需要用到UI组件。
在Hierarchy面板中右键,选择UI->Text,就会创建一个UI组件,但是我们会发现其实Text外还有一层Canvas(画布),下方还出现了一个EventSystem,这些都是Unity为我们自动创建的,这是因为:

The single most important thing to know about these additional items is that all UI elements must be the child of a canvas to behave correctly.
(所有的UI元素都必须是一个Canvas(画布)的子元素才能正常工作)

这里将Text命名为CountText,这时候的CountText处于一个非常奇怪的位置,接下来我们来调整Text的位置。


新建Text和Canvas

在Inspector面板中,我们可以调整Text显示的内容,字体的样式,字体颜色以及这个UI组件的位置,先把文字显示改为Count Text,接下来改变其字体颜色为白色。


改变字体颜色

接下来调整Text的位置,找到Inspecctor的Rect Transform,可以看到UI的Transform和一般GameObject的定位方式不同,这个位置的确定是相对于游戏屏幕的,点击左边的这个方框,展开位置选择的面板,根据提示:按住Shift键选择中心轴(pivot),按住Alt键选择位置(position)。我们选择同时按住Shift和Alt键,将Text放到Canvas的左上角:
更改Text的位置

这样就可以看到Count Text放置到了Game窗口的左上角。接下来可以改变Rect Transform的Pos X的值和Pos Y的值让Count Text稍微离左边缘和顶部边缘一段距离:


加入偏移量

编辑脚本来显示分数

接下来当然是将分数显示到Text中,继续编辑PlayerController脚本,首先需要添加新的Namespace:

using UnityEngine.UI;

然后自然需要创建一个Text变量来表示CountText的一个引用,我们将此Text变量声明为public的类型,为了可以在Inspector中对其进行直接的赋值。接下来要初始化CountText中所显示的文字,使用Text的text变量即可,在Start函数中进行初始化,然后再每一次碰撞到小立方体的时候再重新更新Text的内容:

public Text countText;
void Start()
{
    rigidbodyPlayer = GetComponent<Rigidbody>();
    count = 0;
    countText.text = "Count: " + count.ToString();
}
void OnTriggerEnter(Collider other)
{
    if (other.gameObject.CompareTag("PickUp"))
    {
        other.gameObject.SetActive(false);
        count++;
        countText.text = "Count: " + count.ToString();
    }
}

保存脚本回到Unity,将CountText拖动到Inspector中新产生的这个Text变量处来实例化它即可。


实例化Text

运行游戏,完美!


游戏正常运行

添加完成提示

最后,当所有的小立方体都被收集后,再屏幕中心显示“You Win!”的字样,这看起来就很简单了,同样是:添加一个新的Text组件、命名、改变字体颜色大小和位置、在脚本中新建一个Text变量、在Start函数中将其初始值设为空、满足count值大于等于8的时候即显示“You Win!”、将新的Text拖动到Inspector面板中的变量处。
主要的代码:

public Text winText;
winText.text = "";
if (count >= 8)
{
    winText.text = "You Win!";
}

运行游戏,完美!


添加You Win!的信息

Build游戏

最后就是创建我们的游戏了!Unity创建游戏的平台非常广泛,我们可以无需任何其他插件的前提下创建Windows、Mac和Linux平台下的游戏,但是如果创建诸如Android、IOS端的游戏需要额外的工作,比较复杂,以后会单独提到,这里先创建一个Windows平台的.exe文件。
先保存Scene,然后选择File下的Build Settings…。


进入Build Settings

默认即PC,Mac & Linux Standalone,这里还需要我们通过Add Open Scene来选择我们需要创建的Scene,不过本游戏只有一个Scene,不进行选择也是可以的。点击Build,选择要保存到目标目录,然后稍等片刻,就会得到了最终的.exe文件。


Build游戏

打开文件即可直接运行,整个游戏的所有工程也就全部完成了!
打开游戏程序

游戏完美运行!

参考资料:https://unity3d.com/learn/tutorials/s/roll-ball-tutorial
本节内容的完整官方教程视频分享(英文无字幕):https://pan.baidu.com/s/1TNMMFjs7pZqLPhGQZ1tPqQ 提取码:1u70


转载请注明出处,本文永久更新链接:https://blogs.littlegenius.xin/2019/02/10/从滚球游戏初步体验Unity3D/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,928评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,192评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,468评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,186评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,295评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,374评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,403评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,186评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,610评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,906评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,075评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,755评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,393评论 3 320
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,079评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,313评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,934评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,963评论 2 351

推荐阅读更多精彩内容

  • 前言 在Unity官方教程 2D UFO(上)中,我们学会了: 新建一个项目Project 从资源商店下载素材包 ...
    小巷里有只猫阅读 4,745评论 8 15
  • 一、Unity简介 1. Unity界面 Shift + Space : 放大界面 Scene界面按钮渲染模式2D...
    MYves阅读 8,191评论 0 22
  • Unity3D塔防开发流程 配置环境及场景搭建 编程语言:C#,略懂些许设计模式,如果不了解设计模式,BUG Mo...
    Grape_葡萄阅读 2,931评论 1 3
  • 很久很久都没有写点什么东西了,真是有愧于我中文系的专业,以后多多练习,作家的梦想怕是不能实现了,那就我手写我心吧,...
    榛木清阅读 423评论 0 0
  • 相信就可以做到 很多时候我们都想要相信,却又不得不怀疑,于是总是在不断纠结,其实都是我们的大脑去影响的。 改变大脑...
    Janewei阅读 185评论 0 0