Godot Engine游戲引擎 ① 制作玩家跳躍精靈和場景——KinematicBody2D敦捧、Sprite

寫在前面:

寫文章時(shí)本人是在校大三學(xué)生,上周才接觸到Godot碰镜,也才初學(xué)三四天兢卵,如果文章有問題的話還請大佬們不吝賜教
這是第一篇教程,面向和我一樣的初學(xué)者绪颖,可能寫的有點(diǎn)啰嗦秽荤,請勿噴,哈哈柠横;其中窃款,有個(gè)單詞寫錯(cuò)了,我是想寫World的結(jié)果寫成Word了牍氛,請?jiān)徦募夁€沒過的我晨继,淚目!0峥 踱稍!前半部分圖片上的錯(cuò)字就不改了,大家知道就行悠抹,哈哈哈(不失禮貌的尬笑)

最終項(xiàng)目成果如下:

GIF.gif

知識(shí)內(nèi)容:

  • 認(rèn)識(shí)godot引擎編輯器
  • 基本的場景節(jié)點(diǎn)添加
  • 了解基本的碰撞體與碰撞形狀
  • 認(rèn)識(shí)KinematicBody2D 基本操作
  • 幀動(dòng)畫制作與切換

制作過程:

1. 新建項(xiàng)目

圖片.png
  • 1.填好項(xiàng)目名稱、選擇好一個(gè)項(xiàng)目目錄
  • 2.點(diǎn)擊“[創(chuàng)建|編輯]”打開項(xiàng)目扩淀,項(xiàng)目的所有文件都會(huì)保存在那個(gè)項(xiàng)目目錄下

如果你的菜單界面是英文楔敌,可以在新建項(xiàng)目的上方找到語言en改成zh_CN即可改成中文

2.初識(shí)編輯器布局

圖片.png

3.添加項(xiàng)目資源

  • 1.在項(xiàng)目目錄下新建image目錄,把所有的圖片資源放到image目錄下
    點(diǎn)我下載圖片
  • 2.可以看到資源管理面板新增了image目錄和目錄下的圖片驻谆,godot會(huì)默認(rèn)為每一個(gè)資源添加一個(gè)同名的后綴為".import"的文本文件


    圖片.png

4.制作World場景——背景卵凑、太陽庆聘、云

【編輯區(qū)的鼠標(biāo)操作】:滾輪控制編輯區(qū)的放大縮小,鼠標(biāo)中鍵按下并移動(dòng)鼠標(biāo)可以移動(dòng)編輯區(qū)內(nèi)容勺卢,鼠標(biāo)左鍵選中編輯區(qū)節(jié)點(diǎn)

  • 1.添加一個(gè)根節(jié)點(diǎn)Node2D重命名為“World"
    • (1)在場景窗口伙判,點(diǎn)擊"+"號添加


      圖片.png
    • (2)在彈出的節(jié)點(diǎn)選中窗口中選中Node2D,點(diǎn)擊創(chuàng)建


      圖片.png

      *(3)鼠標(biāo)單擊黑忱,重命名為”world"

    1. 為world添加子節(jié)點(diǎn)Sprite宴抚,并重命名為bg

Sprite表示精靈節(jié)點(diǎn),可以為該節(jié)點(diǎn)添加一個(gè)圖片Texture資源

場景窗口中鼠標(biāo)指向world甫煞,右鍵添加子節(jié)點(diǎn)菇曲,在節(jié)點(diǎn)選擇框搜索Sprite,選擇Sprite點(diǎn)擊創(chuàng)建抚吠,就在world下面新建了一個(gè)子節(jié)點(diǎn)常潮,重命名為bg


圖片.png

圖片.png
  • 3 為bg添加圖片
    場景中選中bg節(jié)點(diǎn),可以看到bg的屬性值


    圖片.png

    將資源窗口中的image文件夾下bg.png文件拖到bg的Texture屬性位置


    GIF.gif

    鼠標(biāo)選中編輯區(qū)bg移動(dòng)楷力,選中周圍的點(diǎn)拉大喊式,撐滿游戲窗口
    GIF.gif

編輯區(qū)那個(gè)紅綠線交叉點(diǎn)為原點(diǎn),第四象限的矩形框就是游戲窗口萧朝,在godot中岔留,游戲窗口的原點(diǎn)(0,0)在左上角,往右為x軸正方向剪勿,往下為y軸正方向

    1. 添加太陽sun節(jié)點(diǎn)

      這里我們采用直接把圖片拖進(jìn)編輯區(qū)的方法贸诚,我們直接將sun.png圖片拖曳進(jìn)編輯區(qū),在場景窗口也對應(yīng)生成一個(gè)與圖片文件同名的Sprite節(jié)點(diǎn)厕吉,如圖:
      GIF.gif
    1. 參照上一個(gè)步驟酱固,把兩片云彩添加進(jìn)來


      圖片.png

5.制作World場景——地面

因?yàn)橹鹘切枰偷孛孢M(jìn)行交互的,所以地面不能直接使用Sprite來做头朱,我們需要用到StaticBody2D節(jié)點(diǎn)运悲,然后再給StaticBody2D添加Sprite子節(jié)點(diǎn)來顯示圖片

  • 1.給World添加子節(jié)點(diǎn)StaticBody2D并重命名為floor,并選中編輯區(qū)組合按鈕项钮,如圖解釋


    圖片.png

    我們發(fā)現(xiàn)floor右邊有個(gè)黃色三角形的警告按鈕班眯,你可以點(diǎn)擊看看是因?yàn)槭裁磫栴}

因?yàn)槲覀冊O(shè)置的floor節(jié)點(diǎn)屬于StaticBody2D,表示的是一個(gè)物理靜態(tài)體烁巫,記住所有的物理靜態(tài)體在godot里都要添加碰撞形狀子節(jié)點(diǎn)

    1. 先給floor添加圖片吧
      之前說過Sprite節(jié)點(diǎn)可以添加圖片署隘,所以這里我們就給floor添加一個(gè)Sprite子節(jié)點(diǎn),并將land.png圖片拖到texture屬性里亚隙,將floor放到游戲窗口底部磁餐,最后如圖顯示


      圖片.png
    1. 添加碰撞區(qū)域

在前面我們知道floor右邊的警告三角形的信息需要添加一個(gè)形狀體,形狀體有兩種CollisionShape2D和CollisionPolygon2D阿弃,即規(guī)則形狀和多邊形形狀诊霹,

給floor添加CollisionShape2D子節(jié)點(diǎn)羞延,然后選擇CollisionShape2D的Shape屬性,選擇“新建RectangleShape2D”脾还,放大編輯區(qū)我們可以看到有一個(gè)淺藍(lán)色的矩形塊伴箩,這個(gè)矩形塊就是碰撞區(qū)域


圖片.png

選中藍(lán)色塊的邊緣兩個(gè)紅點(diǎn)其中一個(gè),拖動(dòng)設(shè)置藍(lán)色塊大小鄙漏,


圖片.png

使其如圖所示嗤谚,長度與圖片一致,寬度在垂直居中位置即可泥张,這個(gè)藍(lán)色塊的上邊決定了待會(huì)角色站的位置
圖片.png
  • 4 同理復(fù)制粘貼第二個(gè)地面呵恢,拼接好兩個(gè)地面,最終效果如圖:


    圖片.png

做了這么久還沒有保存過唉媚创,記得及時(shí)保存哦渗钉,萬一程序奔潰了呢,Ctrl+S保存钞钙,在彈出的窗口點(diǎn)擊保存即可


圖片.png

然后我們可以點(diǎn)擊右上角運(yùn)行按鈕
圖片.png
,
如果彈出一個(gè)請選擇主場景點(diǎn)擊選擇即可鳄橘,然后在新窗口選中我們保存的World.tscn文件,點(diǎn)擊打開芒炼,就可以看到彈出一個(gè)游戲窗口瘫怜,就能看到我們布置的場景啦,如圖
圖片.png

6.制作World場景 —— 椰樹本刽、草叢

與第四步添加背景的流程是一樣的鲸湃,大家自己添加(tree.png樹木, grass.png草叢)子寓,添加好之后的效果和場景節(jié)點(diǎn)順序如圖:


圖片

7.添加角色

我們的角色要會(huì)走暗挑,會(huì)跳,而且還會(huì)站到地面上斜友,可以用KinematicBody2D節(jié)點(diǎn)來創(chuàng)建角色炸裆,然后添加子節(jié)點(diǎn)Sprite來給角色添加圖片,所以基本操作跟制作floor類似

給world添加子節(jié)點(diǎn)KinematicBody2D并改名“player”鲜屏,選中組合按鈕防止子節(jié)點(diǎn)被選中烹看,給player添加子節(jié)點(diǎn)Sprite(texture屬性使用stand.png圖片)和CollisionShape2D并設(shè)置碰撞區(qū)為圖片大小,移動(dòng)到游戲窗口中央洛史,如下圖所示:
圖片.png

8.讓角色動(dòng)起來——添加腳本

godot使用內(nèi)置的GDScript腳本惯殊,是一種類似python的語言,如果你不懂GDScript但是有其他高級面向?qū)ο笳Z言(Java也殖,python靠胜,JavaScript,ruby等)基礎(chǔ)的話,可以參考官方文檔GDScript入門
當(dāng)然Godot還支持C#語言開發(fā)浪漠,你可以自己嘗試學(xué)習(xí)

    1. 給player添加腳本,鼠標(biāo)右鍵單擊選擇添加腳本霎褐,在彈出的窗口中選擇創(chuàng)建址愿,這時(shí)編輯區(qū)會(huì)顯示腳本編輯窗口
      圖片.png

      player.gd腳本文件內(nèi)容如下,它繼承了KinematicBody2D這個(gè)類冻璃,所以在腳本里面可以直接使用這個(gè)類或這個(gè)類的父類方法或?qū)傩裕?br> 其中_ready()函數(shù)是初始化函數(shù)响谓,_process(delta)函數(shù)是每一幀會(huì)運(yùn)行一次,通俗的講就是這個(gè)函數(shù)里的內(nèi)容會(huì)隔一段時(shí)間就運(yùn)行一次省艳,delta參數(shù)是相鄰兩次運(yùn)行的間隔時(shí)間
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. 移動(dòng)角色腳本編寫

腳本內(nèi)容如下所示:

extends KinematicBody2D

var speed = 200   # 移動(dòng)速度
var motion = Vector2()  # 移動(dòng)向量

func _process(delta):  # 每幀執(zhí)行一次
    if Input.is_action_pressed("ui_right"): # 當(dāng)按下右方向鍵時(shí)
        motion.x = speed;  # 移動(dòng)向量設(shè)置x正方向的向量變化值
    elif Input.is_action_pressed("ui_left"): # 當(dāng)按下右方向鍵時(shí)
        motion.x = -speed; # 移動(dòng)向量設(shè)置x負(fù)方向的向量變化值
    else: # 沒有按鍵按下
        motion.x = 0  # 設(shè)置x軸方向移動(dòng)向量為0
    move_and_slide(motion) # 按移動(dòng)向量方向移動(dòng)

Vector2是godot里面的一個(gè)數(shù)據(jù)類型娘纷,表示的是二維的向量,有x和y兩個(gè)方向?qū)傩?br> move_and_slide方法是KinematicBody2D對象的一個(gè)移動(dòng)控制方法跋炕,第一個(gè)參數(shù)是移動(dòng)向量赖晶,第二個(gè)參數(shù)是地面初始化向量,具體參考:

圖片.png

最后點(diǎn)擊運(yùn)行辐烂,按下鍵盤的左右方向鍵遏插,有以下效果:


GIF.gif

10. 讓角色有重力效果

添加移動(dòng)變量y方向加速度值,修改代碼_process()函數(shù)內(nèi)如下:

func _process(delta):  # 每幀執(zhí)行一次
    motion.y += 9.8  # 添加向下的加速度
    if Input.is_action_pressed("ui_right"): # 當(dāng)按下右方向鍵時(shí)
        motion.x = speed;  # 移動(dòng)向量設(shè)置x正方向的向量變化值
    elif Input.is_action_pressed("ui_left"): # 當(dāng)按下右方向鍵時(shí)
        motion.x = -speed; # 移動(dòng)向量設(shè)置x負(fù)方向的向量變化值
    else: # 沒有按鍵按下
        motion.x = 0  # 設(shè)置x軸方向移動(dòng)向量為0
    move_and_slide(motion) # 按移動(dòng)向量方向移動(dòng)

運(yùn)行后我們會(huì)看到角色先掉到地板上纠修,然后我們可以控制角色左右移動(dòng)
GIF.gif

11.讓角色跑起來

我們發(fā)現(xiàn)現(xiàn)在的角色移動(dòng)起來太搞笑了胳嘲,不生動(dòng)對吧,那我們就讓角色加點(diǎn)動(dòng)畫

    1. 第一步扣草,把player的Sprite節(jié)點(diǎn)換成AnimatedSprite節(jié)點(diǎn)了牛,在場景中選中player右鍵點(diǎn)擊“更換類型”桃煎,在節(jié)點(diǎn)選擇窗口搜索選擇AnimatedSprite
  • 2.切換成AnimatedSprite發(fā)現(xiàn)編輯區(qū)的角色不見了粮坞!選擇AnimatedSprite子節(jié)點(diǎn),在屬性Frames選擇“新建SpriteFrames”


    圖片.png
    1. 點(diǎn)擊Frames屬性的SpriteFrames內(nèi)容槽片,打開動(dòng)畫編輯窗口如下:


      圖片.png
    1. 重命名幀動(dòng)畫default為run上岗,然后把幀動(dòng)畫圖片添加進(jìn)右邊的動(dòng)畫幀福荸,操作如下圖:


      GIF.gif
  • 5 再添加一個(gè)幀動(dòng)畫stand,如圖:


    GIF.gif
  • 6 ok,動(dòng)畫制作好了肴掷,我們再去修改腳本:

因?yàn)槲覀兪侵苯痈骂愋土司慈瘢訟nimatedSprite子節(jié)點(diǎn)的名字還是之前的Sprite,這里記得修改下sprite為AnimatedSprite


圖片.png

腳本更新如下

 func _process(delta):  # 每幀執(zhí)行一次
    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)呆瞻,獲取子節(jié)點(diǎn)的節(jié)點(diǎn)對象台夺,這樣就可以調(diào)用子節(jié)點(diǎn)的方法,如AnimatedSprite的play方法

GIF.gif

我們發(fā)現(xiàn)奇怪的一幕出現(xiàn)了痴脾,當(dāng)角色往左行進(jìn)的時(shí)候角色的朝向是右邊颤介,因?yàn)閞un幀動(dòng)畫的圖片都是向右的!該如何解決這個(gè)問題呢?我們可以設(shè)置AnimatedSprite的flip_h屬性為true使其發(fā)生水平鏡像改變

修改腳本如下:

func _process(delta):  # 每幀執(zhí)行一次
    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. 跳躍起來吧

主角現(xiàn)在可以正常的左右跑動(dòng)了滚朵,現(xiàn)在我們要讓他跳起來冤灾;當(dāng)然,主角必須在地面上才可以跳躍辕近,所以不能只要按住上方向鍵就改變移動(dòng)向量的y值韵吨。我們需要先判斷它是否在地板上,這個(gè)時(shí)候move_and_slide()的第二個(gè)參數(shù)就可以用啦
設(shè)置向上初識(shí)向量為 const UP = Vector2(0,-1)
修改的代碼如下:

extends KinematicBody2D

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


func _process(delta):  # 每幀執(zhí)行一次
    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) # 修改了這里

當(dāng)整個(gè)demo運(yùn)行比較久時(shí)移宅,發(fā)現(xiàn)角色跳躍后下降的速度變快了归粉!原因就是我們的motion.y加速度一直在增加,所以為了避免這種情況漏峰,要把motion的值賦為當(dāng)前motion值糠悼,修改最后一句代碼就行

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

13.最終代碼

player.gd

extends KinematicBody2D

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


func _process(delta):  # 每幀執(zhí)行一次
    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. 拓展

你也可以給云朵添加動(dòng)畫,防止角色跳出屏幕等功能浅乔,如圖


GIF.gif

寫在最后

第一次覺得寫文檔好累倔喂,不過感覺還挺好,如果你喜歡就點(diǎn)個(gè)贊吧

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末童擎,一起剝皮案震驚了整個(gè)濱河市滴劲,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌顾复,老刑警劉巖班挖,帶你破解...
    沈念sama閱讀 222,627評論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異芯砸,居然都是意外死亡萧芙,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,180評論 3 399
  • 文/潘曉璐 我一進(jìn)店門假丧,熙熙樓的掌柜王于貴愁眉苦臉地迎上來双揪,“玉大人,你說我怎么就攤上這事包帚∮嫫冢” “怎么了?”我有些...
    開封第一講書人閱讀 169,346評論 0 362
  • 文/不壞的土叔 我叫張陵渴邦,是天一觀的道長疯趟。 經(jīng)常有香客問我,道長谋梭,這世上最難降的妖魔是什么信峻? 我笑而不...
    開封第一講書人閱讀 60,097評論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮瓮床,結(jié)果婚禮上盹舞,老公的妹妹穿的比我還像新娘产镐。我一直安慰自己,他們只是感情好踢步,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,100評論 6 398
  • 文/花漫 我一把揭開白布癣亚。 她就那樣靜靜地躺著,像睡著了一般贾虽。 火紅的嫁衣襯著肌膚如雪逃糟。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,696評論 1 312
  • 那天蓬豁,我揣著相機(jī)與錄音,去河邊找鬼菇肃。 笑死地粪,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的琐谤。 我是一名探鬼主播蟆技,決...
    沈念sama閱讀 41,165評論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼斗忌!你這毒婦竟也來了质礼?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,108評論 0 277
  • 序言:老撾萬榮一對情侶失蹤织阳,失蹤者是張志新(化名)和其女友劉穎眶蕉,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體唧躲,經(jīng)...
    沈念sama閱讀 46,646評論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡造挽,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,709評論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了弄痹。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片饭入。...
    茶點(diǎn)故事閱讀 40,861評論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖肛真,靈堂內(nèi)的尸體忽然破棺而出谐丢,到底是詐尸還是另有隱情,我是刑警寧澤蚓让,帶...
    沈念sama閱讀 36,527評論 5 351
  • 正文 年R本政府宣布乾忱,位于F島的核電站,受9級特大地震影響凭疮,放射性物質(zhì)發(fā)生泄漏饭耳。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,196評論 3 336
  • 文/蒙蒙 一执解、第九天 我趴在偏房一處隱蔽的房頂上張望寞肖。 院中可真熱鬧纲酗,春花似錦、人聲如沸新蟆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,698評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽琼稻。三九已至吮螺,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間帕翻,已是汗流浹背鸠补。 一陣腳步聲響...
    開封第一講書人閱讀 33,804評論 1 274
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留嘀掸,地道東北人紫岩。 一個(gè)月前我還...
    沈念sama閱讀 49,287評論 3 379
  • 正文 我出身青樓,卻偏偏與公主長得像睬塌,于是被迫代替她去往敵國和親泉蝌。 傳聞我的和親對象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,860評論 2 361

推薦閱讀更多精彩內(nèi)容