Godot Engine游戏引擎 ① 制作玩家跳跃精灵和场景——KinematicBody2D、Sprite

写在前面:

写文章时本人是在校大三学生,上周才接触到Godot,也才初学三四天,如果文章有问题的话还请大佬们不吝赐教
这是第一篇教程,面向和我一样的初学者,可能写的有点啰嗦,请勿喷,哈哈;其中,有个单词写错了,我是想写World的结果写成Word了,请原谅四级还没过的我,泪目!!!前半部分图片上的错字就不改了,大家知道就行,哈哈哈(不失礼貌的尬笑)

最终项目成果如下:

GIF.gif

知识内容:

  • 认识godot引擎编辑器
  • 基本的场景节点添加
  • 了解基本的碰撞体与碰撞形状
  • 认识KinematicBody2D 基本操作
  • 帧动画制作与切换

制作过程:

1. 新建项目

图片.png
  • 1.填好项目名称、选择好一个项目目录
  • 2.点击“[创建|编辑]”打开项目,项目的所有文件都会保存在那个项目目录下

如果你的菜单界面是英文,可以在新建项目的上方找到语言en改成zh_CN即可改成中文

2.初识编辑器布局

图片.png

3.添加项目资源

  • 1.在项目目录下新建image目录,把所有的图片资源放到image目录下
    点我下载图片
  • 2.可以看到资源管理面板新增了image目录和目录下的图片,godot会默认为每一个资源添加一个同名的后缀为".import"的文本文件


    图片.png

4.制作World场景——背景、太阳、云

【编辑区的鼠标操作】:滚轮控制编辑区的放大缩小,鼠标中键按下并移动鼠标可以移动编辑区内容,鼠标左键选中编辑区节点

  • 1.添加一个根节点Node2D重命名为“World"
    • (1)在场景窗口,点击"+"号添加


      图片.png
    • (2)在弹出的节点选中窗口中选中Node2D,点击创建


      图片.png

      *(3)鼠标单击,重命名为”world"

    1. 为world添加子节点Sprite,并重命名为bg

Sprite表示精灵节点,可以为该节点添加一个图片Texture资源

场景窗口中鼠标指向world,右键添加子节点,在节点选择框搜索Sprite,选择Sprite点击创建,就在world下面新建了一个子节点,重命名为bg


图片.png

图片.png
  • 3 为bg添加图片
    场景中选中bg节点,可以看到bg的属性值


    图片.png

    将资源窗口中的image文件夹下bg.png文件拖到bg的Texture属性位置


    GIF.gif

    鼠标选中编辑区bg移动,选中周围的点拉大,撑满游戏窗口
    GIF.gif

编辑区那个红绿线交叉点为原点,第四象限的矩形框就是游戏窗口,在godot中,游戏窗口的原点(0,0)在左上角,往右为x轴正方向,往下为y轴正方向

    1. 添加太阳sun节点

      这里我们采用直接把图片拖进编辑区的方法,我们直接将sun.png图片拖曳进编辑区,在场景窗口也对应生成一个与图片文件同名的Sprite节点,如图:
      GIF.gif
    1. 参照上一个步骤,把两片云彩添加进来


      图片.png

5.制作World场景——地面

因为主角需要和地面进行交互的,所以地面不能直接使用Sprite来做,我们需要用到StaticBody2D节点,然后再给StaticBody2D添加Sprite子节点来显示图片

  • 1.给World添加子节点StaticBody2D并重命名为floor,并选中编辑区组合按钮,如图解释


    图片.png

    我们发现floor右边有个黄色三角形的警告按钮,你可以点击看看是因为什么问题

因为我们设置的floor节点属于StaticBody2D,表示的是一个物理静态体,记住所有的物理静态体在godot里都要添加碰撞形状子节点

    1. 先给floor添加图片吧
      之前说过Sprite节点可以添加图片,所以这里我们就给floor添加一个Sprite子节点,并将land.png图片拖到texture属性里,将floor放到游戏窗口底部,最后如图显示


      图片.png
    1. 添加碰撞区域

在前面我们知道floor右边的警告三角形的信息需要添加一个形状体,形状体有两种CollisionShape2D和CollisionPolygon2D,即规则形状和多边形形状,

给floor添加CollisionShape2D子节点,然后选择CollisionShape2D的Shape属性,选择“新建RectangleShape2D”,放大编辑区我们可以看到有一个浅蓝色的矩形块,这个矩形块就是碰撞区域


图片.png

选中蓝色块的边缘两个红点其中一个,拖动设置蓝色块大小,


图片.png

使其如图所示,长度与图片一致,宽度在垂直居中位置即可,这个蓝色块的上边决定了待会角色站的位置
图片.png
  • 4 同理复制粘贴第二个地面,拼接好两个地面,最终效果如图:


    图片.png

做了这么久还没有保存过唉,记得及时保存哦,万一程序奔溃了呢,Ctrl+S保存,在弹出的窗口点击保存即可


图片.png

然后我们可以点击右上角运行按钮
图片.png
,
如果弹出一个请选择主场景点击选择即可,然后在新窗口选中我们保存的World.tscn文件,点击打开,就可以看到弹出一个游戏窗口,就能看到我们布置的场景啦,如图
图片.png

6.制作World场景 —— 椰树、草丛

与第四步添加背景的流程是一样的,大家自己添加(tree.png树木, grass.png草丛),添加好之后的效果和场景节点顺序如图:


图片

7.添加角色

我们的角色要会走,会跳,而且还会站到地面上,可以用KinematicBody2D节点来创建角色,然后添加子节点Sprite来给角色添加图片,所以基本操作跟制作floor类似

给world添加子节点KinematicBody2D并改名“player”,选中组合按钮防止子节点被选中,给player添加子节点Sprite(texture属性使用stand.png图片)和CollisionShape2D并设置碰撞区为图片大小,移动到游戏窗口中央,如下图所示:
图片.png

8.让角色动起来——添加脚本

godot使用内置的GDScript脚本,是一种类似python的语言,如果你不懂GDScript但是有其他高级面向对象语言(Java,python,JavaScript,ruby等)基础的话,可以参考官方文档GDScript入门
当然Godot还支持C#语言开发,你可以自己尝试学习

    1. 给player添加脚本,鼠标右键单击选择添加脚本,在弹出的窗口中选择创建,这时编辑区会显示脚本编辑窗口
      图片.png

      player.gd脚本文件内容如下,它继承了KinematicBody2D这个类,所以在脚本里面可以直接使用这个类或这个类的父类方法或属性;
      其中_ready()函数是初始化函数,_process(delta)函数是每一帧会运行一次,通俗的讲就是这个函数里的内容会隔一段时间就运行一次,delta参数是相邻两次运行的间隔时间
extends KinematicBody2D

# class member variables go here, for example:
# var a = 2
# var b = "textvar"

func _ready():
    # Called when the node is added to the scene for the first time.
    # Initialization here
    pass

#func _process(delta):
#   # Called every frame. Delta is time since last frame.
#   # Update game logic here.
#   pass

9. 移动角色脚本编写

脚本内容如下所示:

extends KinematicBody2D

var speed = 200   # 移动速度
var motion = Vector2()  # 移动向量

func _process(delta):  # 每帧执行一次
    if Input.is_action_pressed("ui_right"): # 当按下右方向键时
        motion.x = speed;  # 移动向量设置x正方向的向量变化值
    elif Input.is_action_pressed("ui_left"): # 当按下右方向键时
        motion.x = -speed; # 移动向量设置x负方向的向量变化值
    else: # 没有按键按下
        motion.x = 0  # 设置x轴方向移动向量为0
    move_and_slide(motion) # 按移动向量方向移动

Vector2是godot里面的一个数据类型,表示的是二维的向量,有x和y两个方向属性
move_and_slide方法是KinematicBody2D对象的一个移动控制方法,第一个参数是移动向量,第二个参数是地面初始化向量,具体参考:

图片.png

最后点击运行,按下键盘的左右方向键,有以下效果:


GIF.gif

10. 让角色有重力效果

添加移动变量y方向加速度值,修改代码_process()函数内如下:

func _process(delta):  # 每帧执行一次
    motion.y += 9.8  # 添加向下的加速度
    if Input.is_action_pressed("ui_right"): # 当按下右方向键时
        motion.x = speed;  # 移动向量设置x正方向的向量变化值
    elif Input.is_action_pressed("ui_left"): # 当按下右方向键时
        motion.x = -speed; # 移动向量设置x负方向的向量变化值
    else: # 没有按键按下
        motion.x = 0  # 设置x轴方向移动向量为0
    move_and_slide(motion) # 按移动向量方向移动

运行后我们会看到角色先掉到地板上,然后我们可以控制角色左右移动
GIF.gif

11.让角色跑起来

我们发现现在的角色移动起来太搞笑了,不生动对吧,那我们就让角色加点动画

    1. 第一步,把player的Sprite节点换成AnimatedSprite节点,在场景中选中player右键点击“更换类型”,在节点选择窗口搜索选择AnimatedSprite
  • 2.切换成AnimatedSprite发现编辑区的角色不见了!选择AnimatedSprite子节点,在属性Frames选择“新建SpriteFrames”


    图片.png
    1. 点击Frames属性的SpriteFrames内容,打开动画编辑窗口如下:


      图片.png
    1. 重命名帧动画default为run,然后把帧动画图片添加进右边的动画帧,操作如下图:


      GIF.gif
  • 5 再添加一个帧动画stand,如图:


    GIF.gif
  • 6 ok,动画制作好了,我们再去修改脚本:

因为我们是直接更新类型了,所以AnimatedSprite子节点的名字还是之前的Sprite,这里记得修改下sprite为AnimatedSprite


图片.png

脚本更新如下

 func _process(delta):  # 每帧执行一次
    motion.y += 9.8
    if Input.is_action_pressed("ui_right"):
        motion.x = speed;  
        $AnimatedSprite.play("run")
    elif Input.is_action_pressed("ui_left"):
        motion.x = -speed; 
        $AnimatedSprite.play("run")
    else:
        motion.x = 0  
        $AnimatedSprite.play("stand")
    move_and_slide(motion)

$childNodeName符号表示的是get_node(childNodeName),获取子节点的节点对象,这样就可以调用子节点的方法,如AnimatedSprite的play方法

GIF.gif

我们发现奇怪的一幕出现了,当角色往左行进的时候角色的朝向是右边,因为run帧动画的图片都是向右的!该如何解决这个问题呢?我们可以设置AnimatedSprite的flip_h属性为true使其发生水平镜像改变

修改脚本如下:

func _process(delta):  # 每帧执行一次
    motion.y += 9.8
    if Input.is_action_pressed("ui_right"):
        motion.x = speed;  
        $AnimatedSprite.play("run")
        $AnimatedSprite.flip_h = false
    elif Input.is_action_pressed("ui_left"):
        motion.x = -speed; 
        $AnimatedSprite.play("run")
        $AnimatedSprite.flip_h = true
    else:
        motion.x = 0  
        $AnimatedSprite.play("stand")
    move_and_slide(motion)

12. 跳跃起来吧

主角现在可以正常的左右跑动了,现在我们要让他跳起来;当然,主角必须在地面上才可以跳跃,所以不能只要按住上方向键就改变移动向量的y值。我们需要先判断它是否在地板上,这个时候move_and_slide()的第二个参数就可以用啦
设置向上初识向量为 const UP = Vector2(0,-1)
修改的代码如下:

extends KinematicBody2D

var speed = 200   # 移动速度
var motion = Vector2()  # 移动向量
const UP = Vector2(0, -1)
const JUMP_HEIGHT = -380


func _process(delta):  # 每帧执行一次
    motion.y += 9.8
    if Input.is_action_pressed("ui_right"):
        motion.x = speed;  
        $AnimatedSprite.play("run")
        $AnimatedSprite.flip_h = false
    elif Input.is_action_pressed("ui_left"):
        motion.x = -speed; 
        $AnimatedSprite.play("run")
        $AnimatedSprite.flip_h = true
    else:
        motion.x = 0  
        $AnimatedSprite.play("stand")
    if is_on_floor():
        if Input.is_action_just_pressed("ui_up"):
            motion.y = JUMP_HEIGHT
    move_and_slide(motion, UP) # 修改了这里

当整个demo运行比较久时,发现角色跳跃后下降的速度变快了!原因就是我们的motion.y加速度一直在增加,所以为了避免这种情况,要把motion的值赋为当前motion值,修改最后一句代码就行

func _process(delta):
    ...
    motion = move_and_slide(motion, UP)

13.最终代码

player.gd

extends KinematicBody2D

var speed = 200   # 移动速度
var motion = Vector2()  # 移动向量
const UP = Vector2(0, -1)
const JUMP_HEIGHT = -380


func _process(delta):  # 每帧执行一次
    motion.y += 9.8
    if Input.is_action_pressed("ui_right"):
        motion.x = speed;  
        $AnimatedSprite.play("run")
        $AnimatedSprite.flip_h = false
    elif Input.is_action_pressed("ui_left"):
        motion.x = -speed; 
        $AnimatedSprite.play("run")
        $AnimatedSprite.flip_h = true
    else:
        motion.x = 0  
        $AnimatedSprite.play("stand")
    if is_on_floor():
        if Input.is_action_just_pressed("ui_up"):
            motion.y = JUMP_HEIGHT
    motion = move_and_slide(motion,UP)

14. 拓展

你也可以给云朵添加动画,防止角色跳出屏幕等功能,如图


GIF.gif

写在最后

第一次觉得写文档好累,不过感觉还挺好,如果你喜欢就点个赞吧

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,723评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,485评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,998评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,323评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,355评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,079评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,389评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,019评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,519评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,971评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,100评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,738评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,293评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,289评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,517评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,547评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,834评论 2 345

推荐阅读更多精彩内容

  • 第一部分 HTML&CSS整理答案 1. 什么是HTML5? 答:HTML5是最新的HTML标准。 注意:讲述HT...
    kismetajun阅读 27,422评论 1 45
  • 一 “我一推,你就跌倒。” “为什么?” “因为我有超能力,我一伸手,就能打败你。” “不行,我要有超能力。” “...
    瑊玏阅读 538评论 0 1
  • 草图有点惨第一天,迈出了第一步。 坚持一个月人体结构。
    salen小伦阅读 295评论 1 2
  • r1第一天-20171009今天是第一天,耗时较长。这一周一定要坚持下来,每天晚上主要就是完成精进日记,等养成了习...
    精进精进再精进阅读 399评论 0 0
  • 前几天看到一款叫「Now!」的 snapchat 仿品,从整体交互、文案等细节看,做得还不错(「评论家」最是廉价,...
    笨上加笨阅读 631评论 0 8