unity fixedupdate_Unity之滚球游戏(上)

d4066385e47b0f82f8e286d669606d4d.png

程序员那些事

真正的程序员喜欢兼卖爆米花,他们利用CPU散发出的热量做爆米花,可以根据米花爆裂的速度听出正在运行什么程序。

创建一个项目

打开unity,在Projects中可以查看当前的本地项目或者云端项目,点击New project或者右上角的New都可以新建项目。d80ef19f26603225e9fc81658515be7c.png然后在1处填写创建项目的名称,2处选择创建地址,3处选择Template(模板),可以选中3D或者2D。9b232ca77726a70795dfa0605c24ebd1.png稍等片刻即可进入unity的主页面。

保存Scene并管理Assets

进入unity之后,可以看到已经预设的SampleScene和其中的Main Camera(主摄像机)和Directional Light(平行光)组件,如果你不喜欢这些预设的名字,直接点击修改并使用Ctrl+S保存你的修改即可。41298399b153f0722896dce7498e01ca.png为了使我们的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以后还会慢慢使用。f01177392eea173f0ad38a533c79af88.png这里只需要创建一个Plane并将其命名为Ground来作为我们游戏的“地面”,可以看到Plane出现在了MainScene中,同时我们可以注意到Hierarchy视窗中的MainScene右上角出现了一个*号,这就表示该Scene处于待保存的状态,可以通过菜单栏的File->Save或者快捷键Ctrl+S保存Scene。ad31da449ec4f19f898a3d2c7ba790e6.png选中刚刚创建的Ground,Inspector视窗中就会出现其所有的Components,这些都是预先被untiy设置给Plane的,点击Transform这一Component的右侧的齿轮状图标,可以选择Reset(重置)选项,这样,刚刚创建的Plane的Transform就会被重置为初始值,它的Position会被设置为(0,0,0),这是整个游戏世界的原点坐标,游戏中的所有GameObject的坐标都是基于此原点进行计算的。63b53d5ccf55b908fab8a51170090359.png选中任何一个GameObject,比如选中Ground,然后按F键,或者在菜单栏中点击Edit->Frame Select可以快速地调整Scene的角度,让我们有一个非常合适的角度来观察Ground的全貌。

改变Transform

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

直接赋值

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

拖动输入框调节

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

在Scene窗口中改变

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

创建Sphere

接下来创建小球,同样地,在MainScene下右键->3D Object->Sphere来创建一个unity预置的Sphere(球体),命名为Player,并通过reset其Transform来使其位置重置到原点。767819ebfede9873a788fad6adb52d19.png这样我们看到小球的中心已经被定位到了(0,0,0)处,为了让小球能在平面上滚动,我们需要将小球放到平面上。观察小球的Transform我们可以得到,它的Scale的值为(1,1,1),也就是说它的三个方向的大小都为1单位,为了让小球放到平面上边,显然我们需要将其向上移动半个球的距离,即将Position的Y值设置为0.5,小球就刚好在平面上了。47d2800b05ab2e6136fe87ca4df8b136.png

关于光源

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

创建Material

为了使GameObject美观,我们通常会对其表面进行一系列装饰,而其表面的表现是通过为这个GameObject添加Material(材料)来实现的。接下来为我们的Ground和Player添加最简单材料:纯颜色。在Assets下新建Materials目录用于管理各种材料,然后右键该目录选择Create->Material新建一个材料命名为Background。daae4b129952af43e650c28f2b8128ea.png选中Background,就可以看到它的Inspector面板了,我们在Albedo(反射率)一栏中可以选择一种颜色,在下方的预览中就可以看到效果了,这里我们选择RGB色(0,32,64)作为我们的Background的颜色。c7a2cd7e0fcce0d43e8fff7f6f2522ea.png想要将创建的Material运用在某个GameObject上,很简单,只需要拖动该Material到Scene中的目标GameObject上或者拖动到Hierarchy的该GameObject上即可。97a13a341c1bd024ac031ae4d731998b.png可以看到我们的Ground已经变成了蓝色019ad60c746a7a91d6acdf10454210e1.png

让小球滚动起来

让小球拥有成为刚体

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

为小球添加控制脚本

有了刚体属性的小球需要在我们的控制下滚动,比如我们规定使用W,S,A,D四个按键来控制小球的方向,那么对于一个有物理属性的刚体来说,为了能够动起来,当然需要力(Force)作用在物体上,这些有关于如何控制GameObject的方法需要我们使用脚本(Scripts)来完成,假如你已经拥有了一定的C#编程基础。同样我们在Assets下创建Scripts目录来管理脚本,在该目录处右键->Create->C# Script创建一个脚本,这里我们命名为PlayerController。4288712a2e6f23e556191b0f8b0d2097.png为了让我们创建的脚本与Player联系起来,可以在Player的Inspector面板下选择Add Component,在其中搜索我们的脚本名字就可以找到该脚本,根据unity的命名规范,喜欢将脚本各个单词使用“驼峰法”并且首字母同样大写的方式,有趣的是,unity对于这些脚本通常都会在每个大写字母处将这些单词分开,我也不知道为什么。简单点儿的话可以直接将Assets中的脚本拖到Inspector面板下,就可以添加成功。b4aebed04680673860acdbd9ee246632.png

打开脚本

编辑脚本需要编辑器,Visual Studio是较好的选择,它和unity之间有很好的合作关系,使用起来也很方便。双击脚本文件或者在Inspector面板中点击脚本的右上角的齿轮图标选择Edit Scrpit都可以打开编辑器对其进行编辑。ba57771c43f89701b772ede3b5d39cde.pngunity已经为我们预置好了脚本的最基本结构,最基本的,我们可以看到所有的unity脚本都继承自MonoBehaviour类,然后有两个预设函数,Start函数是在第一帧开始渲染前调用,Update函数在每一帧刷新前调用,都是非常常用的函数。接下来思考我们要做的事情,我们需要检测用户的输入,并且通过输入的按键来控制小球的滚动方向,检测用户的输入同时也需要识别输入的是哪一个按键,除此之外我们还需要一些物理学有关的逻辑,比如我们需要添加一个力来控制小球的移动,这就是物理学逻辑,这些逻辑当然是每一帧都要进行一次,所以我们需要将这些逻辑写在每一帧更新都要执行的函数中。显然我们可以写到Update函数下,因为Update函数是每一帧刷新前都会调用的,同时我们还有另外的选择,即使用FixedUpdate函数,它在每一次进行物理学运算的时候调用,每次检测到用户输入都需要进行物理学运算,所以我们可以将逻辑写到FixedUpdate函数下。

开始编写脚本

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

private Rigidbody rigidbodyPlayer;

void Start()
{
    rigidbodyPlayer = GetComponent();
}
123456

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

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

通过以上两行代码我们就可以将用户的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);
}
123456

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

完整的代码:

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

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

    void Start()
    {
        rigidbodyPlayer = GetComponent();
    }
    void FixedUpdate()
    {float moveHorizontal = Input.GetAxis("Horizontal");float moveVertical = Input.GetAxis("Vertical");
        Vector3 movement = new Vector3(moveHorizontal,0.0f,moveVertical);
        rigidbodyPlayer.AddForce(movement*speed);
    }
}
123456789101112131415161718192021222324

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

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

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

完整的代码:

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;
    }
}
12345678910111213141516171819

为了不让小球总是滚落到Plane之外,可以在其四周围建立起一圈儿围墙,很简单,使用预设的Cube就可以了。为了更好的管理四个围墙,我们可以先创建一个空的GameObject,将其命名为Walls,Reset使其重置位置,然后在其上右键新建一个Cube,并命名为WestWall,这样这个Cube就成为了Walls的子物体。f6129e8ca19ebd762b3728727bf810d6.png接下来如何调整这面墙的大小、位置就很简单了,可以在Inspector中直接输入具体数值,也可以直接在Scene中拖动和缩放,最好我们可以得到这个墙体结构。cb1c4f856c237d5b10eb3891b4f6c0b2.png为了简单方便,只要选中WestWall,在菜单栏的Edit中选择Duplicate(复制)(快捷键:Ctrl+D)即可,然后将复制好的墙拖动到适合的地点,在复制,最后可以得到四面墙。f437743fcc62302beb44d48f2bc69a3f.png接下来测试游戏,墙起作用了!

-- END --

c27c80dc95c4dc0de6549d21e4d8549a.gif

  • unity实战之战棋小游戏
  • unity实战之fly bird

  • Unity实战之塔防游戏(一)

  • Unity实战之塔防游戏(二)

公众号后台回复「资料」获取超多学习福利

771d1b1f929c7a2b2cf59f743f61fad9.gif

>>> 点击进入技术讨论群 <<<▽想深入了解么?

9eb3975ef27c3b5f312342003953e4b8.png

长按/扫码关注我吧↑↑↑

觉得不错就点个在看吧!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值