欢迎来到我的博客小站。  交流请加我微信好友: studyjava。  也欢迎关注同名公众号:Java学习之道

[转]Unity之滚球游戏(下)

  |   0 评论   |   0 浏览

新建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);
}
123456

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

创建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变成了一个蓝色的图标。

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

放置更多的立方体

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

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

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

为小立方体涂色

让后再通过添加一种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的标签就添加好了。

完成碰撞逻辑

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

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);
    }
}
1234567

关于碰撞的简单原理

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

显然,我们可以直接将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);
    }
}
123456789101112131415

添加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的位置。

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

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

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

编辑脚本来显示分数

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

using UnityEngine.UI;
1

然后自然需要创建一个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();
    }
}
12345678910111213141516

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

运行游戏,完美!

添加完成提示

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

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

运行游戏,完美!

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

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

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

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


原文链接:https://blog.csdn.net/qq_38962621/article/details/86930869


标题:[转]Unity之滚球游戏(下)
作者:shirln
地址:https://mmzsblog.cn/articles/2020/10/27/1603760732739.html
-----------------------------
如未加特殊说明,此网站文章均为原创。
网站转载须在文章起始位置标注作者及原文连接,否则保留追究法律责任的权利。
公众号转载请联系网站首页的微信号申请白名单!

个人微信公众号 ↓↓↓                 

微信搜一搜爱上游戏开发