【转】Godot3游戏引擎入门之七:地图添加碰撞体制作封闭的游戏世界

一、前言

在前面的文章中,我分别介绍了如何上下左右移动玩家,以及使用瓦片集制作丰富的游戏地图,现在,是时候结合在一起,制作一个简单的游戏世界了,这个游戏世界既有丰富的场景元素,也有合理的碰撞检测,玩家可以在封闭的世界里自由移动。

Godot3游戏引擎入门之五:上下左右移动动画(下)

Godot3游戏引擎入门之六:制作TileMap瓦片地图

上面的第一篇文章中,其实我们已经实现了一个简单的封闭世界,我们是这样实现碰撞检测的:给场景中的墙壁添加静态碰撞体,给玩家节点添加 RigidBody2D 刚体属性,我们在代码中设置玩家的线速度,而大部分物理属性由 Godot 引擎帮我们实现了。在第二篇文章中,我们又通过学习 TileSet 和 TileMap 可以在游戏中制作出复杂的场景,但问题是:地图上还缺少碰撞体,无法和玩家进行交互。

所以,这篇文章要解决上面两个小问题:第一,使用 KinematicBody2D 节点作为玩家对象,这样我们能自由控制物理反馈,实现相关的游戏功能;第二,我们需要给地图添加更多的真实的碰撞体,比如墙壁、障碍物等。这也是我们游戏开发的正常流程。

主要内容: 给 TileMap 地图添加碰撞体并测试

阅读时间: 4-6 分钟

永久链接:http://liuqingwen.me/blog/2018/10/22/introduction-of-godot-3-part-7-add-collision-and-move-player-in-map/

系列主页:http://liuqingwen.me/blog/tags/Godot/

二、正文

本篇目标

给地图中的瓦片添加碰撞体
玩家添加碰撞体,在地图中移动测试
学习几个实用的脚本函数
添加碰撞体

在上篇文章的基础上,我们需要给每一个瓦片添加上碰撞体,这个操作很简单,直接添加具有碰撞体功能的节点即可。在 Godot 3.1 新版本中,设置步骤稍微繁琐,但是效果更加直观,效率也会更高。两种方式我们都了解一下,具体操作方式可以根据你的 Godot 版本而定。

3.0 版本

首先打开我们之前保存过的用于创建 TileSet 资源的游戏场景文件(Tileset_Sprites.tscn 和 Tileset_SpriteSheet.tscn ),然后直接给每一个节点添加碰撞体。场景中的 Sprite 节点最终都会转化为 Tile 瓦片,要给每个瓦片添加碰撞体,只需要在每个 Sprite 节点下添加一个 StaticBody2D 静态碰撞体作为子节点,然后给静态碰撞体添加 CollisionShape2D 节点并设置碰撞体形状即可。

这些都在前面的文章里已经详细介绍过了,不过要特别注意的是:给所有 Sprite 节点都添加了碰撞体后,必须重新保存以覆盖之前的 TileSet 资源,才能把碰撞体更新到地图中,否则设置了碰撞体也不会有效果。文章后面我会介绍 Godot 中强大的 Debug 功能对碰撞体进行可视化测试,避免意外情况。

3.1 版本

Godot 3.1 新版本关于 TileMap 的一些新特性上一篇文章已经介绍过了,基本流程类似:划分 Region 区域 -> 标记 Bitmask 掩码 -> 添加 Collision 碰撞体区域。新版本不需要添加任何子节点,直接在相应的瓦片上绘制碰撞体形状即可。如下图,相关参数上一篇文章已经介绍过了:

注:黄色代表已绘制的碰撞体,蓝色代表正在绘制的碰撞体。操作提示:如果不方便设置自动吸附的参数,那么在绘制碰撞体形状的时候会出现很难精确点位的问题,这个时候我们可以取消吸附,选择粗略绘制完的碰撞体,点击Points 属性值,对每一个点进行手动修改调整即可。

一般我们给墙壁和不可穿越物体设置碰撞体即可。设置完每一个瓦片集的碰撞体形状后,地图上就会出现相应的静态碰撞体了,新版本操作起来非常简单快捷!

添加主角

游戏世界里怎么能缺少玩家呢?老生常谈的话题,前面的文章已经多次介绍如何制作完整的 Player 玩家节点了,这里我们的地图是支持 Player 上下左右移动的,实现起来也不难,具体请参考上一篇文章的详细介绍:Godot3 游戏引擎入门之五:上下左右移动动画(下)。本次我们的主角 Player 主要有两种状态:静止( idle )和跑动(run ),注意设置动画的总时长和开启循环播放。另外,由于原图稍大,不能直接放在地图中,我对玩家 Sprite 节点进行了缩放。

说明:和前面几篇文章不同的是,这里我使用了游戏中常用于制作玩家根节点的 KinematicBody2D 图形学节点作为 Player 对象的根节点,并添加一个 CollisionShape2D 节点作为碰撞体。这样做既能让 Player 参与物理响应,又能在代码中操作其移动。

另外有三个需要注意的地方:

第一个是碰撞体形状中的 Extends 属性值表示半宽和半高,这和 Box2D物理引擎一样
第二个是我们设置的碰撞体形状要比图片稍小,这样能防止意外碰撞,产生不必要的碰撞运算和效果
第三个,也是非常重要的一点:不要缩放碰撞体形状,即:不要设置scale 属性
第三点同样是为了防止产生意外碰撞情形,不过这点貌似在 Godot 3.1 版本中已经修正了:在绘制碰撞体图形时不能直接拖拽鼠标进行缩放碰撞体了:

准备工作已经完成,接下来就是最关键的部分:脚本代码了。

编写代码

给游戏场景的根节点 Game 添加一个 GDScript 脚本,参考前面学习到的知识, 代码量并不多,新的方法已经做了注释,全部的代码如下:

extends Node2D

export使变量能在属性窗口中显示和设置值

export(float) var speed = 1
onready var player = Player onready var sprite =Player/Sprite
onready var animationPlayer = $Player/AnimationPlayer

在这里不使用_process(delta)方法处理物理引擎,

而应该使用_physics_process(delta)方法进行处理

func _physics_process(delta):
var velocity = Vector2()
var isMoving = false

if Input.is_action_pressed('ui_left'):
    velocity.x += -1
    sprite.flip_h = true
    isMoving = true
if Input.is_action_pressed('ui_right'):
    velocity.x += 1
    sprite.flip_h = false
    isMoving = true
if Input.is_action_pressed('ui_up'):
    velocity.y += -1
    isMoving = true
if Input.is_action_pressed('ui_down'):
    velocity.y += 1
    isMoving = true
    
if velocity.length() > 0:
    velocity = velocity.normalized() * speed
    # 关键代码:移动并测试碰撞体,参数为玩家的移动速度
    player.move_and_collide(velocity)

if isMoving and animationPlayer.current_animation != 'run':
    animationPlayer.current_animation = 'run'
elif ! isMoving and animationPlayer.current_animation != 'idle':
    animationPlayer.current_animation = 'idle'

新的关键词和脚本函数介绍;

export 关键字修饰的变量能在编辑器的属性窗口中显示并设置值,类似 Unity 中的 public/[Serialized] 关键词
flip_h 布尔值表示图片是否水平翻转,产生向左或者向右的效果,相比使用 scale 缩放属性更加方便简洁
move_and_collide(Vector2) 这是本文 Demo 代码的精髓部分,传递一个速度矢量参数,游戏引擎将移动并处理物理碰撞,简洁又强大

效果调试

全部完成了,按 F5 运行游戏,测试我们的最终成果吧。感觉如何?反正我还是有点激动的,“尽情”探索一个“未知世界”吧:有围墙,有障碍物,有墙壁,各种地形等,如果在跑动过程发现有任何问题,别慌,你还可以对地图的所有碰撞体进行 Debug 调试!这也是 Godot 的强大功能之一,在 Debug 菜单下勾选 Visible Collision Shapes 选项即可开启!

开启碰撞调试后运行游戏的效果:

注意图中的蓝色形状体就是地图碰撞体,是不是和预期一样?调试的时候,我稍微放大了Player 节点图片,测试的时候看得清楚些,如果你之前有多余的地图,那么场景中可能有多余的不可见的碰撞体存在,这样会影响游戏运行,避免的方法可以直接删除之前的TileMap 测试地图,也可以在瓦片地图属性下对碰撞图层进行设置,取消碰撞图层和碰撞掩码即可,关于碰撞图层和掩码设置我在后面再讲,操作如下图:

确认场景没有问题后,关闭调试,运行游戏,享受一下自己的成果吧! :smiley:

三、总结

本篇文章可以算是之前文章的一个结合,是不是感觉越来越简单了?开始动手实现自己的小游戏吧,骚年!不吹逼了,总结下本篇的知识点:

Tile 瓦片碰撞体设置
Debug 调试地图、玩家的碰撞体运行状态
几个有用的 GDScript 脚本代码技巧

原文链接:https://blog.csdn.net/SpkingR/article/details/83312676

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念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