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

从创建项目开始

创建一个项目

打开unity,在Projects中可以查看当前的本地项目或者云端项目,点击New project或者右上角的New都可以新建项目。


创建一个项目

然后在1处填写创建项目的名称,2处选择创建地址,3处选择Template(模板),可以选中3D或者2D。


创建一个项目

稍等片刻即可进入unity的主页面。

保存Scene并管理Assets

进入unity之后,可以看到已经预设的SampleScene和其中的Main Camera(主摄像机)和Directional Light(平行光)组件,如果你不喜欢这些预设的名字,直接点击修改并使用Ctrl+S保存你的修改即可。


保存Scene

为了使我们的Assets文件夹管理地更加井井有条,推荐对不同的assets进行分文件夹管理,这时一些文件夹的命名可以自己定义,但通常可以遵循一定的不成文的规定,比如通常将场景存放在Scenes目录、将脚本存放在Scripts目录等等,要根据自己来管理好Assets目录,以后对于大量的assets可以很方便快捷。

创建游戏场景

创建Plane

可以使用unity的内置GameObject的Plane(平面)类型来作为游戏场景的“地面”。
可以在Hierarchy视窗下右键选择3D Object下找到Plane创建,也可以在顶部菜单栏的GameObject下的3D Object下找到Plane创建。当然也可以看到unity为我们创建了很多预置的Game Object,比如3DO bject、2D Object、Effects、Light、Audio、 Video、UI、Camera等等,当然每一个分类下还有更详细的分类,这些都可以直接拿来使用,非常方便,一些重要的Game Object以后还会慢慢使用。


新建GameObject的Plane

这里只需要创建一个Plane并将其命名为Ground来作为我们游戏的“地面”,可以看到Plane出现在了MainScene中,同时我们可以注意到Hierarchy视窗中的MainScene右上角出现了一个*号,这就表示该Scene处于待保存的状态,可以通过菜单栏的File->Save或者快捷键Ctrl+S保存Scene。


待保存的Scene

选中刚刚创建的Ground,Inspector视窗中就会出现其所有的Components,这些都是预先被untiy设置给Plane的,点击Transform这一Component的右侧的齿轮状图标,可以选择Reset(重置)选项,这样,刚刚创建的Plane的Transform就会被重置为初始值,它的Position会被设置为(0,0,0),这是整个游戏世界的原点坐标,游戏中的所有GameObject的坐标都是基于此原点进行计算的。
初始化Transform

选中任何一个GameObject,比如选中Ground,然后按F键,或者在菜单栏中点击Edit->Frame Select可以快速地调整Scene的角度,让我们有一个非常合适的角度来观察Ground的全貌。

改变Transform

改变Transform的三组值的方法有很多。

直接赋值

可以在Inspector面板中对Transform的九个值直接输入数值来设置


在Inspector面板中设置Transform的值

拖动输入框调节

当我们把鼠标指向每一个值的输入框的左侧边界时,就会发现鼠标成为了一个左右双箭头的形状,此时按下鼠标左键所有拖动,就会发现该输入框变成了蓝色,并可以随着拖动改变它的值。


拖动输入框

在Scene窗口中改变

在左上方有六个按钮,分别表示对Scene中GameObject的操作。
这里提一句:不管选中六个按钮中的哪一个,只要按住Alt键在Scene中拖动鼠标就可以转动视角,只要滚动鼠标滚轮即可放大/缩小视角。
这六个按钮从左到右依次为:


六个改变Scene中GameObject的选项
  • 第一个:拖动Scene的视角
  • 第二个:选中后,再选中Scene中的任何一个GameObject,就可以通过拖动它的三个方向箭头(x、y、z)以及三个平面(xy平面、xz平面、yz平面)来改变Position的值。


    改变Position
  • 第三个:选中后可以在Scene中对选中的GameObject改变其Rotation的值


    改变Rotation
  • 第四个:选中后在Scene中可以对选中的GameObject进行三个方向的Scale的调整


    改变Scale
  • 第五个:选中后可以在Scene中对选中的GameObject进行顶点的位置调整从而改变Scale的值


    改变Scale
  • 第六个:选中后可以同时改变Position、Rotation、Scale的值,是第二三四个的结合。


    同时改变所有的Transform

创建游戏对象

创建Sphere

接下来创建小球,同样地,在MainScene下右键->3D Object->Sphere来创建一个unity预置的Sphere(球体),命名为Player,并通过reset其Transform来使其位置重置到原点。


新建一个Sphere

这样我们看到小球的中心已经被定位到了(0,0,0)处,为了让小球能在平面上滚动,我们需要将小球放到平面上。
观察小球的Transform我们可以得到,它的Scale的值为(1,1,1),也就是说它的三个方向的大小都为1单位,为了让小球放到平面上边,显然我们需要将其向上移动半个球的距离,即将Position的Y值设置为0.5,小球就刚好在平面上了。


将小球放到平面上

关于光源

其实我们可以看到小球是有影子的,这是最开始unity为我们准备的Directional Light作用的结果,我们可以看到Scene中的一个小太阳的标志,这个就是我们的光源,使用Directional Light来模拟太阳的平行光。它的Transform则显示了光源的位置、角度(也就是平行光的照射方向),如果我们将这个GameObject去掉的话就没有了光的效果。
当然通过改变Rotation的值就可以调节光源的方向,比如为了效果我将Rotation的Y值改为60。


关闭光源后的效果

创建Material

为了使GameObject美观,我们通常会对其表面进行一系列装饰,而其表面的表现是通过为这个GameObject添加Material(材料)来实现的。
接下来为我们的Ground和Player添加最简单材料:纯颜色。
在Assets下新建Materials目录用于管理各种材料,然后右键该目录选择Create->Material新建一个材料命名为Background。


新建一个Material

选中Background,就可以看到它的Inspector面板了,我们在Albedo(反射率)一栏中可以选择一种颜色,在下方的预览中就可以看到效果了,这里我们选择RGB色(0,32,64)作为我们的Background的颜色。


为Material选择颜色

想要将创建的Material运用在某个GameObject上,很简单,只需要拖动该Material到Scene中的目标GameObject上或者拖动到Hierarchy的该GameObject上即可。
将Material运用到Scene中

可以看到我们的Ground已经变成了蓝色
成功改变Plane的颜色

让小球滚动起来

让小球拥有成为刚体

为了让小球有滚动的效果,我们需要小球拥有一系列的物理属性,物理属性已经由unity内置,我们只需为需要增加物理属性的GameObject添加一个Rigidbody的Component即可。如上一节中所示,选中Player,在Inspector面板中通过Add Component中找到Physics下的Rigidbody即可。


添加Rigidbody属性

为小球添加控制脚本

有了刚体属性的小球需要在我们的控制下滚动,比如我们规定使用W,S,A,D四个按键来控制小球的方向,那么对于一个有物理属性的刚体来说,为了能够动起来,当然需要力(Force)作用在物体上,这些有关于如何控制GameObject的方法需要我们使用脚本(Scripts)来完成,假如你已经拥有了一定的C#编程基础。
同样我们在Assets下创建Scripts目录来管理脚本,在该目录处右键->Create->C# Script创建一个脚本,这里我们命名为PlayerController。


新建脚本

为了让我们创建的脚本与Player联系起来,可以在Player的Inspector面板下选择Add Component,在其中搜索我们的脚本名字就可以找到该脚本,根据unity的命名规范,喜欢将脚本各个单词使用“驼峰法”并且首字母同样大写的方式,有趣的是,unity对于这些脚本通常都会在每个大写字母处将这些单词分开,我也不知道为什么。简单点儿的话可以直接将Assets中的脚本拖到Inspector面板下,就可以添加成功。


将脚本添加给GameObject

打开脚本

编辑脚本需要编辑器,Visual Studio是较好的选择,它和unity之间有很好的合作关系,使用起来也很方便。双击脚本文件或者在Inspector面板中点击脚本的右上角的齿轮图标选择Edit Scrpit都可以打开编辑器对其进行编辑。


Unity的预置脚本内容

unity已经为我们预置好了脚本的最基本结构,最基本的,我们可以看到所有的unity脚本都继承自MonoBehaviour类,然后有两个预设函数,Start函数是在第一帧开始渲染前调用,Update函数在每一帧刷新前调用,都是非常常用的函数。
接下来思考我们要做的事情,我们需要检测用户的输入,并且通过输入的按键来控制小球的滚动方向,检测用户的输入同时也需要识别输入的是哪一个按键,除此之外我们还需要一些物理学有关的逻辑,比如我们需要添加一个力来控制小球的移动,这就是物理学逻辑,这些逻辑当然是每一帧都要进行一次,所以我们需要将这些逻辑写在每一帧更新都要执行的函数中。
显然我们可以写到Update函数下,因为Update函数是每一帧刷新前都会调用的,同时我们还有另外的选择,即使用FixedUpdate函数,它在每一次进行物理学运算的时候调用,每次检测到用户输入都需要进行物理学运算,所以我们可以将逻辑写到FixedUpdate函数下。

开始编写脚本

首先我们需要创建一个对于这个Player小球的引用,这样才能知道我们控制的是哪个小球,这里小球是刚体,所以我们创建一个刚体(Rigidbody)的引用,并且需要在第一帧开始渲染之前通过GetComponent方法来找到小球创建刚体的引用,这一逻辑自然就需要写到Start函数中了。

private Rigidbody rigidbodyPlayer;

void Start()
{
    rigidbodyPlayer = GetComponent<Rigidbody>();
}

接下来对用户输入的读取就需要写到FiexedUpdate函数中了,我们使用Input类的GetAxis方法来获取水平或者垂直的运动轴,这个方法会返回一个float值作为该轴的移动距离。

float moveHorizontal = Input.GetAxis("Horizontal");
float moveVertical = Input.GetAxis("Vertical");

通过以上两行代码我们就可以将用户的W,S,A,D输入转化为水平轴和垂直轴的移动距离,分别存储在moveHorizontal和moveVertical两个float类型的变量中。

接下来通过Rigidbody类的AddForce方法可以为刚体添加作用力,AddForce方法接受一个三维向量(Vector3)参数,这个三维向量就可以表示力,显然我们的三维向量可以用刚才的moveHorizontal和moveVertical两个变量作为X值和Z值,同时我们是不需要小球在Y方向上移动的,也就是将Y方向的力作用设置为0.0f即可,经过调试我们会发现小球的移动速度过慢,为了方便调节小球的速度,只需要在表示力的三维向量前乘以一个倍数即可,为了方便调整,我们设置一个public的float类型的变量speed来调节这个乘积。
这里必须说明的是,凡在unity的脚本中被声明为public类型的变量,在unity的Inspector界面中的该脚本的Component下都会出现一个可以设置的值的方框。

public float speed;
void FixedUpdate()
{
    Vector3 movement = new Vector3(moveHorizontal,0.0f,moveVertical);
    rigidbodyPlayer.AddForce(movement*speed);
}
更改public的Speed的值

此处我们将speed的值设为10比较合理,运行游戏就会发现通过W,S,A,D的控制,小球动了起来。


让小球滚动起来

完整的代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerController : MonoBehaviour
{
    private Rigidbody rigidbodyPlayer;
    public float speed;

    void Start()
    {
        rigidbodyPlayer = GetComponent<Rigidbody>();
    }

    void FixedUpdate()
    {
        float moveHorizontal = Input.GetAxis("Horizontal");
        float moveVertical = Input.GetAxis("Vertical");

        Vector3 movement = new Vector3(moveHorizontal,0.0f,moveVertical);

        rigidbodyPlayer.AddForce(movement*speed);
    }
}

当然你也会发现,小球超出了Plane的边界居然掉了下去,其实这是合理的,因为小球为刚体,也就拥有物理引擎,当然受到重力的影响,在没有Plane的向上的作用力的情况下自然会下落。

设置摄像机

可以发现,我们的Camera的角度和位置都比较刁钻,这导致我们的游戏看到的画面并不完整,接下来我们对Camera进行设置,使其能够跟随我们的小球滚动来同时移动。
首先调节Main Camera的Position和Rotation使得画面和角度比较合适,比如这里将Position的Y值设为6,Z值设为-6,将Rotation的X值设为45得到了一个较为合适的位置。


改变摄像机的Transform

接下来通过脚本控制Main Camera跟随小球Player一同移动,即在Position上保持相对静止。
可能你会想到,只需要将Main Camera拖动给Player使其成为Player的子物体不就可以保持两者相对位置不变化了吗?但是问题在于球体Player是滚动的,如果两者的位置完全相对静止,就会导致球滚动时Main Cmaera也会跟着球滚动,有一种天旋地转的感觉。感兴趣的话可以尝试一下。
新建脚本CameraController并添加给Main Camera做一个Component。为了使Main Camera的Transform的Position和Player的保持相对静止,Rotation并不和其保持一致,可以想到一个办法:设置一个偏移量,这个值初始化为游戏开始时Main Camera和Player之间的Position的差值,然后在球滚动时,每一次滚动都改变Main Cmaera的Position,使其新的Position等于现在球的Position的值加上刚才的偏移量,这样就会在每次球的位置改变时Main Camera都会跟上它的步骤。
显然,偏移量的设置需要在Start函数中完成,每一次球的位置发生变化时的逻辑可以在Update函数中完成,但还有一个更好的选择,就是LateUpdate函数,该函数在每次有GameObject发生变动时才会调用。
同时,我们的脚本使加在Main Camera上的,所以Main Camera的Transform可以直接调用,但是球的Transform则需要单独获取,这里我们设置一个public的GameObject量,然后在unity中将球Player拖动到这个量处作为参数即可。

private Vector3 offset;
public GameObject player;

void Start()
{
    offset = transform.position - player.transform.position;
}

void LateUpdate()
{
    transform.position = player.transform.position + offset;
}
添加Player实例

这时候运行游戏就可以发现Main Camera的位置随着球的改变而发生了改变。


MainCamera成功跟随小球变化位置

完整的代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraController : MonoBehaviour
{
    private Vector3 offset;
    public GameObject player;

    void Start()
    {
        offset = transform.position - player.transform.position;
    }

    void LateUpdate()
    {
        transform.position = player.transform.position + offset;
    }
}

建立围墙

为了不让小球总是滚落到Plane之外,可以在其四周围建立起一圈儿围墙,很简单,使用预设的Cube就可以了。
为了更好的管理四个围墙,我们可以先创建一个空的GameObject,将其命名为Walls,Reset使其重置位置,然后在其上右键新建一个Cube,并命名为WestWall,这样这个Cube就成为了Walls的子物体。


新建Cube

接下来如何调整这面墙的大小、位置就很简单了,可以在Inspector中直接输入具体数值,也可以直接在Scene中拖动和缩放,最好我们可以得到这个墙体结构。


改变Cube的Transform

为了简单方便,只要选中WestWall,在菜单栏的Edit中选择Duplicate(复制)(快捷键:Ctrl+D)即可,然后将复制好的墙拖动到适合的地点,在复制,最后可以得到四面墙。
复制Cube建立围墙

接下来测试游戏,墙起作用了!
围墙正常运行

下一篇文章:https://www.jianshu.com/p/7e0e85092e5a

参考资料: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阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容