Godot3游戏引擎入门之三:移动我们的主角
2018-09-18 by Liuqingwen | Tags: Godot | Hits
一、前言
说明:我目前使用的 Godot 3.1 预览版,所以会与 Godot 3 的版本有一些区别,界面影响不大,如果要使用我上传的 Github Demo 代码,记得去官网下载 3.1 预览版(或者等之后正版发布)然后就可以正常打开运行 Demo 了。
主要内容: Godot 2D 小游戏入门之使用键盘控制移动 阅读时间: 4-5 分钟 永久链接:https://cloud.tencent.com/developer/article/1381575 系列主页: http://liuqingwen.me/blog/introduction-of-godot-series/
二、正文
本篇目标
- 了解图片材质在 Godot 中的导入功能
- 创建简单的场景,调整节点渲染次序,给节点添加脚本
- 简单的 GDScript 脚本功能介绍和使用
创建场景
首先是创建我们的游戏主场景,相比上一节,这个场景会更加简单,首先场景尺寸我在项目设置中设成了 600x600 ,添加一个 Node2D 节点作为根节点,并改名为 Game ,然后添加两个子节点,一个是我们的主角 Sprite 节点,命名为 Knight ,再添加一个 Sprite 节点作为游戏中的地面,单击,命名为 Ground ,接着修改相应的图片材质属性。这里的操作有几点需要注意:
1. 图片的导入
如果你滚动鼠标滚轮,放大我们的视窗,你会发现我们的主角:骑士的图片放大后有点模糊,这里我希望能像有些像素游戏一样能够清晰地显示图片各个像素( 2D 游戏中一般叫完美像素: Pixel Perfect ),那样即使图片很小,像素化后依然显得更加逼真,如何在 Godot 中实现呢?非常简单, Godot 已经为我们预制好了,选中图片,在属性面板上方导入设置中进行相应的设置即可,非常简单,记得设置好之后一定要点击 Reimport 重新导入:
经过像素设置,我们的主角图像放大后像素更加清晰,是不是感觉更加 2D 了?熟悉 Unity 的同学知道,其 2D 场景是伪 3D 场景打造所以并没有 Pixel Perfect 功能。想深入了解 Godot 中更多关于图片压缩模式的知识,可以参考官方的压缩文档: Importing Images - Compression
2. 重铺图片导入
接着是地面的图片设置,还是使用上一节中的图片,之前我已经提到了如何设置普通图片材质的平铺属性,不过,之前的设置在重新打开后会丢失,如果保存平铺设置?我们需要在图片导入的时候进行相关的设置,保存并重新导入即可,相关设置如下图:
大致的步骤就是:先选中图片,启用 Repeat 功能,最后点击 Reimport 重新导入图片材质,接着选中地面 Ground 节点,开启图片的 Region 区域设置,设置高度和图片原高度相等,为 256 ,宽度设置为你想要的宽度,比如我设置的是 800 (或者更高)。最后你会发现我们的地面图片在宽度方向上会沿着 X 轴方向自动平铺, OK ,完美解决!
3. 节点渲染顺序
有一个小问题是在我们添加了两个子节点后,移动位置,我们的场景显示是这样的:
主角干嘛躲在草丛后面啊?别怂,出来干啊!哈哈,其实原因在上图我已经说明了,这是由于 Godot 中节点的渲染顺序引起的,越在上面的节点,渲染顺序越前,所以下面的节点会最后渲染,造成的结果就是:可能会覆盖之前渲染的上面的一些节点。解决方案很简单,移动一下地面和主角节点的次序就可以了。
添加脚本
简单的场景打造好了,接下来就是如何使用键盘输入控制骑士的位置移动了,学习 GDScript 脚本语言的最佳时机到来,本篇作为脚本开场白,仅仅做一个简单的介绍,然后编写代码实现一些简单的功能。
在了解 GDScript 脚本之前,我想比较一下 Godot 与 Unity 脚本的一些共同点,如果你有游戏开发经验,你会发现他们有很多相似点。首先,我们选中 Game 根节点,然后在右上角点击添加脚本,创建一个简单的脚本文件,写上一些方法( # 号代表注释,和其他语言里的 // 一样):
代码语言:javascript复制# 节点激活后运行该方法
func _ready():
print('ready!')
# 每帧运行此方法
func _process(delta):
print('process with delta time: ', delta)
# 处理物理引擎的方法
func _physics_process(delta):
print('physics process with delta time: ', delta)
# 处理设备输入的方法
func _input(event):
print('input event: ', event)
# 处理设备输入的另一个方法
func _unhandled_input(event):
print('unhandled input event: ', event)
上面的代码通过方法名字和我的注释说明应该能明白它的含义了,现在看下 Unity 中 C# 脚本组件的语法:
代码语言:javascript复制void Awake()
{
Debug.Log("Awake");
}
void Start()
{
Debug.Log("Start");
}
void Update()
{
Debug.Log("Update: " Time.deltaTime);
}
void LateUpdate()
{
Debug.Log("LateUpdate: " Time.deltaTime);
}
void FixedUpdate()
{
Debug.Log("FixedUpdate: " Time.deltaTime);
}
惊人的相似,不是吗?所以说,开发游戏有时候只是软件不同,思路大体还是相同的,正所谓道不同、理相同!好的,装逼到此结束!开始拿起笔头编写脚本吧,这里我把基本完工的脚本贴出来,你可以从英文单词释义或者我的注释中得到每一行代码的功能是什么样的,具体如下:
代码语言:javascript复制# 继承于Node2D
extends Node2D
# 常量,表示速度(像素)
const SPEED = 200
# 定义一些变量,不需要类型
var maxX = 600 # 角色运动右边界
var minX = 0 # 角色运动左边界
var knight # 骑士节点
# 节点进入场景开始时调用此方法,常用作初始化
func _ready():
# 获取节点并赋值给变量knight
knight = self.get_node("Knight")
# 每一帧运行此方法,delta表示每帧间隔
func _process(delta):
# Input表示设备输入,这里D和右光标表示往右动
if Input.is_key_pressed(KEY_D) or Input.is_key_pressed(KEY_RIGHT):
moveKnightX(1, SPEED, delta)
elif Input.is_key_pressed(KEY_A) or Input.is_key_pressed(KEY_LEFT):
moveKnightX(-1, SPEED, delta)
# 自定义函数,direction表示方向,speed表示速度,delta是帧间隔
func moveKnightX(direction, speed, delta):
if direction == 0:
return
# position属性为节点当前置,Vector2向量简单乘法
knight.position = Vector2(SPEED, 0) * delta * direction
# 越界检测
if knight.position.x > maxX:
knight.position = Vector2(maxX, knight.position.y)
elif knight.position.x < minX:
knight.position = Vector2(minX, knight.position.y)
OK ,大功告成,运行我们的游戏,效果是这样的:
不过……有点问题啊:主角显然能置身于场景之外啊,而且往左移动的时候居然是迈克尔杰克逊附身——没有转身!别急,解决方法非常简单:
第一个:场景边界问题,在 _ready()
方法中的最后加入代码:
# get_rect方法获取节点边框
maxX -= knight.get_rect().size.x / 2
minX = knight.get_rect().size.x / 2
第二个:左移转身问题,只需在 moveKnightX(...)
方法的最后加入代码:
# 节点的scale属性为缩放矢量
# 缩放矢量x值为1就是往右,-1表示往左缩放
knight.scale = Vector2(direction, 1)
终于完工,尽管没有真正的角色跑步动作(后续文章会讲解如何使用 Godot 强大的动画工具创建角色动画),但是我们的移动功能算是完整了,看图,最终结果:
三、总结
本篇讲解到的知识点:
- 图片材质的导入模式
- 节点渲染顺序
- 最基础的 GDScript 脚本入门
- 使用脚本获取节点属性,侦听输入控制主角移动
PS: 我使用的是 Godot 3.1 版本,源码已经上传到 Github ,如果需要在 Godot 3.0 版本上运行你可以自行创建节点,把图片和代码复制过去即可,建议使用最新 3.1 预览版,因为 3.1 即将发布!哦吼!