赞
踩
这个系列(坑) 来自一个用Unity开发的2D横版射击游戏的开发过程,用来记录学习进度以及一些学习心得。和大家分享共勉,有错误的话请评论指出,我会积极回复。
=+=+=+=+=+=+=+=+=+=
=+=+=+=+=+=+=+=+=+=
上一次,我们提到了Rigidbody2D
以及Collider2D
,总而言之,如果你希望你的物体运动、碰撞,那么是Collider2D
在负责。而受力是Rigidbody2D
的特性。 如果你希望创建一个拥有运动逻辑的活物,比如一个Player,给他一个Rigidbody2D
吧
你好,我是Player,你想让我动起来?凭啥?
确实,我们用什么方法让它动起来呢?你可能会说WASD,或者抄起你的手柄一通猛搓。
但是并没有什么用,因为你还什么都没写呢。
虽然你什么都没写,但是在这个时候其实你的输入已经被Unity读取了,这是通过我们的Input Manager实现的,你可以在Edit -> Project Settings -> Input Manager 里找到它。
Like this ↑
有了这个,我们可以开始着手编写脚本Script
了。
脚本是你操纵Unity中的物体的遥控器,就像Minecraft的创造模式的控制台指令一样,你可以通过写下一些简单的代码来实现对组件参数的定义和操作。 同样地,你所需要的逻辑判断、数值系统,也都需要写在脚本里。可以说,脚本就是一个物体的灵魂Soul
。
确保你的Visual Studio有Unity支持组件,有C#编译环境
并且,确保你的Edit -> Preferences -> External Tools里面的External Script Editor是你正在使用的Visual Studio。
当然了,如果你不需要自动补全,也可以用记事本写代码,Unity无所谓的。
在你这个项目的随便什么地方(我建议创建一个Scripts文件夹)里,右键新建一个C# Script,然后打开它。你可以将它命名为Player或者PlayerController或者aaabc之类的。
你应该会看到这样的景象
上面的using是库函数引用,你现在不用管他们。
public class
公共的类,并且:
继承了MonoBehaviour
。MonoBehaviour
是个啥? 它是一个继承了Component
的脚本基类,所有的Unity脚本都得继承MonoBehaviour
。当然, 如果你不需要Unity,自己写脚本,或者你的所有方法里都没有用到Unity提供的组件和函数,那你自然也不必要继承MonoBehaviour
。Start()
Update()
,是我们获取Component
和捕捉信号,判断逻辑的地方。Start()
顾名思义,这个方法在对象被创建时用来初始化我们的脚本,获取一些必要的信息,比如我们需要的Rigidbody2D
,巧妇难为无米之炊,如果没有刚体,我们又怎么能让刚体运动呢?Update()
更新方法,这个方法每一帧都会被执行一次,所以你不能将所有的代码内容放到这个里面,至少我不建议你这么做。我们需要在Update
里面来读取一些基本的输入信息,更新/维护我们的人物状态。总而言之,在保证功能能够正常实现的情况下,Update里执行的代码行数越少越好。我们考虑实现运动所需要的组件是什么,因为我们要在Start()
里面去获取它。
答案呼之欲出:Rigidbody2D
但是首先,我们需要在代码中先创建一个空的Rigidbody2D
[SerializeField] Rigidbody2D RB;
你也可以不加
[SerializeField]
将它改成public
,这都是为了让我们能够在Unity里面看见这个属性,没错,这是脚本的一个属性,稍后我们需要将Player的Rigidbody2D
组件拖动到Player的Player(Script)的这个位置。
然后,在你的Start()
中写下这样一行:
RB = GetComponent<Rigidbody2D>();
这样,我们就从脚本附着的对象上摘取了它的名为Rigidbody2D
的Component了,我们就成功了一半了,接下来,你对RB做的所有改变,都能如实地在你的Player身上体现。
Start()
写完了,接下来让我们把目光转向Update()
。
我们该从Unity那里搞点输入数据过来了,没有输入数据的话我怎么给你算这个东西应该怎么运动啊(恼)
很多时候写脚本就像老妈子唠叨一样,跟Unity问这问那,有没有这个啊,整点这个,啊啊那我明白了,应该得是这样的吧,你看看怎么动一下子。
在Unity给我们提供的库里,有这样的一系列方法,他们叫Input
,一般来说,你可以从他们的名字来读出他们的用处,前提是你认识那些词汇的话,当然不认识也没关系,可以翻译一下,词汇量非常少。比如我们这里用到的
direction = Input.GetAxis("Horizontal");
在C#中,.
是一种声明父子关系的符号,所以Input.GetAxis("Horizontal")
就是Input
类里面的一个用来获取某一条轴上的输入的方法。它返回一个-1~1的浮点数。"Horizontal"
是它的参数,你也可以改成"Vertical"
或者其它的什么轴,总之,现在我们的direction
就是你的输入数值。(噢,别忘了声明direction作为一个float变量,然后设置合适的权限,比如private,这个我就不多赘述了)
GetAxis
方法,而一转使用GetAxisRaw
,GetAxisRaw
只会返回-1,0,1
之中的一个数。GetButtonDown
或者GetKeyDown
,不知道怎么用的话,将鼠标悬停在他们的名字上,你可以看到这个方法的使用手册。在现实中,我们希望一个物体运动,有什么办法呢?
给一个力推它,给它一个速度(当然现实中你无法给瞬时速度),或者使用传送魔法
好消息是,这些方法在Unity中都能实现,你猜猜哪种最好用?
这一部分代码你可以写在Update()
中或者是FixedUpdate()
中,因为你需要时刻检测物体是否运动。
Update()
检测周期 T = 1/fps(s) fps是你的电脑帧率FixedUpdate()
检测周期 T = 1/50(s)
首先我们忽略传送术,就算是Dash,我们也不是将人物直接传送到目标位置。直接修改坐标的方法我们留到有用的时候再说。
那么现在还剩两种方法:调用刚体的AddForce
方法和直接修改刚体的velocity
属性
它提供了一个加速度,这意味着你的物体在你的按键下会做一个匀加速直线运动,不可或缺地,这样方式操作的运动会有一个很平滑的速度曲线,像Mario里面的黄油手感一样。AddForce
方法有两种施力模式,默认下是Force
,也就是原力 ,你还可以通过在第一个参数后再加一个参数声明ForceMode2D.Impulse
,如此一来,就算你按住,这个力也只会被施加一次给这个刚体,你可以看成提供了一个碰撞冲量。
RB.AddForce(Vector2D.right * force);
整个参数是一个二维向量,force
是我们自己定义的一个推力大小,建议设置成float类型。而Vector2D.right
其实就是new Vector2D(1,0)
的简便写法。
如此一来,我们就添加了一个二维的恒力。它会提供一个恒定的 (大概) 加速度。 现在回到Unity里,开始你的Game,人物应该能左右平移了。
相似地,我们也可以通过直接设置刚体的速度velocity
来实现移动的效果,事实上,我正在使用的以及比较推荐初学者使用的就是这种。
像下面这样使用:
RB.velocity = new Vector2(direction * speed, RB.velocity.y);
我们新建一个二维向量,x
是我们的输入乘以速度系数speed
,同样是一个需要定义的float变量。而y
是刚体目前的纵向速度。我们在左右移动时不希望垂直速度被改变,所以这样引用。你会发现,形如RB.velocity.y
这样的引用,你可以把.
翻译成的
。
所以这一条的意思就是RB
的速度velocity
的y轴投影
大小
这样写完之后,你的人物理论上就可以以一个匀速在大部分时间内运动了,当然,速度不会突变,就像现实中那样。起步由于前面提到键盘输入的累加性,必然是一个加速的过程,然后匀速。
如此你会发现,在你松开方向键时,你其实是希望他马上停下来的,然而他会因为输入延迟等因素向前滑行一小段。有可能使血压升高。
所以我推荐这样的写法:
if (Mathf.Abs(direction) > 0.2f)//0.2f的意思是一个大小为0.2的浮点数
{
RB.velocity = new Vector2(direction * speed, RB.velocity.y);
}
else
{
RB.velocity = new Vector2(0, RB.velocity.y);
}
也就是在输入绝对值小于0.2时,我们认为用户根本没在输入了,因为这个值足够小,以致于推手柄都不太好达到这个值以下。于是我们将水平速度设置为0。
现在,你的人物可以左右移动了,今天我们写了第一个C#脚本,这是珍贵的一步,代表着你正式开始使用Unity了!
试着自己写写跳跃的代码吧!
虽然,现在离你心目中的运动
还有很大区别,首先,人物不会掉头,而且,他也没有跑步的动作。有关于贴图Sprite
、动画机Animator
、状态控制我们将在下一期进行讲解
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。