Godot学习-2D物体运动

一、移动物体

首先,我们要实现的一个小目标,就是让一个物体动起来,听起来很简单吧,没错,做起来也很简单。
首先我们需要一个Sprite2D节点来显示我们的飞机,将我们预先准好的图片放置在texture一项内。

接下来,我们在这个精灵上添加代码,首先需要想下,1.物体运动需要通过速度来改变位置 2.速度为向量 3.位置移动为向量 4.循环移动(简单讲下:向量是一个数学对象,表示数量和方向的组合。)

因此我们先声明个变量为速度velocity,那么因为向量的方向决定了它的方向,而它的长度则代表了速度,因此
var velocity = Vector2(200,0) 代表着沿x轴向右为方向,200为速度,我们速度搞定了,接下来就是通过速度来改变位置,Godot自带position,直接使用,position += velocity,位置改变也搞定了。最后就是循环这些,让它一直动,我们需要_process函数,这个函数可以处理发生在每一帧

这里需要讲下delta的概念,由于这个函数是以帧为单位循环的,但游戏、计算机不同,以及不同时刻游戏引擎需要计算的内容不同,不同的帧需要相对而言或多或少的时间才能显示出来,如果我们不使用delta作为参数的话,每个电脑实际移动的位置可能就会有所不同,因此我们需要速度乘以delta,因为它代表着时间差,自上一帧以来经过的时间,以秒为单位,来让运动从基于帧率变为基于时间。这就可以保证每帧之间的变化更稳定。

最后简单的移动代码如下


但是还有个问题就是如果我们将方向改为x轴左侧还是y轴移动时,它的方向不会根据改变

这里就需要使用angle(),它会返回该向量与x轴正方向的夹角,因此我们将物体的旋转角度与向量与x轴正方向的夹角呈一致,则可改变物体的方向,代码如下

二、键盘控制移动

前面了解了运动的基础原理,我们要去加上键盘控制,因此我们需要Input(它是处理键盘按键、鼠标按钮及移动、游戏手柄、输入动作等的单例)。还需要知道一个函数get_vector(),(它是通过指定正负XY轴的四个动作来获取输入向量,方向向量的最大长度为1)。同时我们需要四个输入操作,在这个项目设置里,我们可以添加输入映射


增加输入映射
这里我已经添加完了,我们再添加个方向变量direction来储存按键方向,这样的话,direction = Input.get_vector(“move_left”,”move_right”,”move_up”,”move_down”)
这里需要讲下这个输入操作顺序是按照由负到正的顺序,由left到right是由负到正,很好理解。但是up到down也是由负到正,这是因为游戏中的坐标轴为下图所示,越向下则y值越大,因此up到down也是由负到正

按照我们之前的逻辑,position += velocity * delta,那么velocity = direction * max_speed,还需要增加个max_speed变量来相乘,因为direction最大值为1,而delta的值非常小,因此不乘以个比较大的数,移动的就会不明显。

现在我们可以用键盘来控制物体移动了

三、丝滑转向

我们可以从动图看到,飞机转向一点也不丝滑很生硬。我们如果要丝滑转向,需要转向向量,可以看下图,这个圆就是我们的最大向量值,AB代表着我们实际的速度向量,AC为我们转向时期望的速度向量,如果没有转向向量,则会生硬的转向,因此需要一个转向向量:BC,下面的动图可以更直观的看待这三者的关系

那么在向量减法中,我们知道BC=AC-AB,因此转向向量=期望向量-实际向量,增加对应变量名,steering_vector,desired_velocity,我们之前写的内容里转向实际上都是期望速度向量,因此desired_velocity = direction * max_speed,那么steering_vector = desired_velocity - velocity,接下来就是实际向量,我们需要将这个转向矢量的一部分添加到当前速度中。velocity会逐帧逐渐改变,使我们的船根据我们的输入加速或减速。velocity += steering_vector * drag_factor
如果没有这个值,则velocity = desired_velocity*,那么还是会按照期望向量直接转向,如果要每帧仅添加一部分转向矢量,值最好在0.1-0.3之间,值越低,飞船的惯性就越大:它转弯、加速和减速的速度会慢得多。值越高,船的反应性就越强:它会急转弯,迅速达到最大速度,并在一瞬间停止。

这样的话就可以看到物体比较丝滑的转向了。

四、氮气加速

我们想要让这个物体点击空格,就会速度飙升,一段时间之后就会重置速度,首先要添加输入操作空格,我将它命名为move_fast,这里需要if判断是否点击空格按键,因此需要.is_action_just_pressed()函数,当用户在当前帧按下指定按键返回true,这里我们再新增两个变量,一个是加速后的速度,一个是重置后的速度nor_speed,fast_speed,这样可以更能看明白自己的代码,那么判断为true后执行max_speed = fast_speed
那么我希望一段时间速度就重置,这里需要使用倒计时器Timer节点,它可以帮你记录时间,所以我希望按键之后就开始倒计时,如何触发倒计时器呢,使用get_node()函数来获取节点,获取后通过start来触发它,get_node(“Timer”).start(),这样它就可以开始倒计时了。


Timer节点

Timer属性
那开始的有了,如何让他结束触发速度重置事件呢,这里需要使用信号,信号允许节点相互通信和响应。它们是节点在发生某些事情时发出的消息。
它就如同名字一样,当这个节点的某个事件被触发了,你的其他节点也不知道啊,因此需要一个信号给到其他节点来告诉它,我这里发生了什么事件,拿我们这个举例,timer节点倒计时结束了,但是谁也不知道啊,你需要去连接信号到你想要通知的节点去,比如想让time结束后,告诉到sprite该开始重置速度了,因此我们打开timer的节点,有个timeout()的信号,这个就是倒计时结束的信号,右击点击到我们的sprite

Timer信号

连接信号
连接成功这里会有个信号标志,同时它也自动将连接信号帮我们打上了:func _on_timer_timeout() -> void:

Timer节点

我们只需写上max_speed = nor_speed即可,至此我们就完成了氮气加速的部分了