
一、前言
本篇是上一節(jié)文章:Godot3游戲引擎入門之五:上下左右移動動畫(上)的繼續(xù)。上一篇使用動畫和代碼實現(xiàn)了玩家的上下左右移動功能,接下來我們解決一個問題:給游戲添加碰撞體,讓玩家在有限的地圖中移動。
注意:我目前使用的是 Godot 3.1 預覽版,與 Godot 3.0 正式版有一些區(qū)別,不過界面上影響不大,如果要使用我所上傳的 Github Demo 代碼,記得去官網下載 3.1 預覽版然后就可以正常打開運行 Demo 了。 Good luck!
主要內容: Godot 2D 中玩家的上下左右移動及碰撞實現(xiàn)
閱讀時間: 4-5 分鐘
永久鏈接:http://liuqingwen.me/blog/2018/10/11/introduction-of-godot-3-part-5-the-basic-top-down-movement-part-2/
系列主頁:http://liuqingwen.me/blog/tags/Godot/
二、正文
本篇目標
- 使用 AnimationPlayer 節(jié)點工具創(chuàng)建狀態(tài)動畫(上)
- 使用代碼控制玩家的上下左右移動功能(上)
- 簡單的攝像機使用和地圖碰撞檢測實現(xiàn)(上下)
- 通過代碼實現(xiàn) RigidBody2D 剛體節(jié)點的運動(下)
場景和代碼
基本場景的制作已經在上篇中詳細解說過了,另外我們還在場景中增加了一個 Camera2D 攝像機節(jié)點,讓場景的視窗時刻聚焦在玩家周圍,但是玩家依然可以“鯉魚躍龍門”,對場景中的墻壁視而不見,豪邁奔放!游戲運行結果如下:

接下來利用物理引擎相關知識解決玩家移動范圍限制的問題。
添加碰撞體
首先要做的是給墻壁添加上碰撞體,限制場景運動區(qū)域范圍。由于墻壁是靜止不動的物體,所以我們給它添加一個 StaticBody2D 靜態(tài)碰撞體節(jié)點。你可以直接在 Sprite 節(jié)點下添加一個靜態(tài)碰撞體,并設置好碰撞體大??;也可以把 Sprite 作為 StaticBody2D 的子節(jié)點,這也是推薦的流程。但是在沒有特殊用途下(比如不需要添加代碼等),你可以隨便安排, Godot 中的節(jié)點是非常靈活的。
這里為了正確設置碰撞體的形狀,我把之前單一的墻壁背景拆分為了四面獨立的墻,然后分別設置碰撞體形狀。接著要在玩家節(jié)點上添加碰撞體,這里我們需要謹慎操作:第一是注意節(jié)點的類型,和墻壁不同,玩家是可以移動的,且擁有物理屬性,所以不能使用靜態(tài)碰撞體;第二是節(jié)點的父子關系的順序問題,我們因為要移動碰撞體,而不是 Sprite 精靈圖片節(jié)點,所以 Sprite 應該作為碰撞體節(jié)點的子節(jié)點,且不能弄反!詳細解說在我的入門文章第二篇中有詳述: Godot3 游戲引擎入門之二:第一個簡單的游戲場景。
和大名鼎鼎的 Box2D 開源物理引擎類似, Godot 中也有三種常用的物理碰撞體: StaticBody2D | RigidBody2D | KinematicBody2D ,同屬于 PhysicsBody2D 類型下,它們之間的異同點大致如下;
| 節(jié)點名 | StaticBody2D | RigidBody2D | KinematicBody2D |
|---|---|---|---|
| 節(jié)點名稱 | 靜態(tài)碰撞節(jié)點( 2D ) | 剛體節(jié)點( 2D ) | 運動學節(jié)點( 2D ) |
| 基本特性 | 自動碰撞檢測,位置固定不變 | 自動碰撞檢測,產生碰撞響應:有線速度、角速度等 | 參與碰撞檢測,無自動響應,完全由代碼控制移動 |
| 使用場景 | 一般用于固定的墻壁、地面等 | 一般用于受外界影響而產生運動的物體,比如球體、隕石等 | 主要用于由代碼控制的帶物理屬性的玩家 |
了解了這三種節(jié)點后,得出的結論是不是應該給我們的主角添加一個 KinematicBody2D 運行學節(jié)點呢?嗯……然而并不是,如果使用 KinematicBody2D 節(jié)點,我們需要自己手動控制物理反饋,雖然絕大多數的游戲應該這樣,但是這不是本篇文章的做法,盡量不要動代碼是我的出發(fā)點,以后再介紹 KinematicBody2D 節(jié)點,現(xiàn)在我們暫時使用簡單一點的 RigidBody2D 剛體節(jié)點進行嘗試。(是不是聽上去有點不符合直覺?其實在有些游戲中,比如太空飛船射擊游戲,就可以使用 RigidBody2D 作為玩家節(jié)點進行開發(fā)。)
理論到此為止,給我們的游戲場景添加一個 RigidBody2D 剛體節(jié)點,改名為 Player ,然后把之前的玩家 Player ( Sprite )節(jié)點拖到 RigidBody2D 節(jié)點下作為其子節(jié)點,同時 AnimationPlayer 節(jié)點也要作為剛體節(jié)點的子節(jié)點,保持和 Player 節(jié)點平級的關系,最后添加一個 CollisionShape2D 節(jié)點用于設置碰撞體的形狀。

最終場景中的節(jié)點如上圖,唯一要設置的是把 RigidBody2D 的重力影響屬性 Gravity Scale 設置為 0 ,即完全擺脫重力的影響,不這么設置的話,你會發(fā)現(xiàn)玩家會“情不自禁”地做自由落體運動。另外,值得注意的是,我在改名的過程中,原來的 Player 節(jié)點自動更名為 Player1 ,然后動畫全部失效,解決辦法很簡單,在動畫面板里把軌道的名字改過來即可,如下圖:

最終代碼
場景一切就緒,接下來的任務就是修改代碼了!因為我們的節(jié)點關系產生了變化,還有節(jié)點的行為也變了( Sprite -> RigidBody2D ),所以對于新手朋友我要特別提醒的是:玩家已經轉變成 RigidBody2D 剛體節(jié)點了,剛體節(jié)點是會自動產生物理響應的,所以我們不能像剛才那樣直接使用代碼操作玩家的位置,相反,我們應該通過設置剛體的線速度、角速度來實現(xiàn)對剛體運動的控制!
具體修改我都在代碼中做了注釋,代碼量不大,相信大家都能看懂吧。這里全部的代碼我就不貼出來了,修改部分如下:
onready var animationPlayer = $Player/AnimationPlayer # 修改后
onready var camera = $Camera2D
player.linear_velocity = velocity # 添加部分,設置線速度,速度為0時有用
player.angular_velocity = 0 # 添加部分,設置角速度,防止player打轉
# 速度不為0,移動玩家位置,同時更新攝像機
if velocity.length() > 0:
# 注意這里normalize速度矢量
# player.position += velocity.normalized() * speed * delta # 刪除
player.linear_velocity = velocity.normalized() * speed # 添加,更新速度
# 更新攝像機,玩家始終在視窗內活動
updateCameraPosition()
# 省略代碼……
終于完工,按 F5 運行游戲,看看我們的杰作吧:

三、小結(下)
相對來說,這篇的知識點還是非常簡單的,當然對于編程初學者來說,代碼還是一個需要克服的地方。在接下來的文章里,我會針對 2D 游戲中的地圖創(chuàng)建做幾篇文章,也就是 TileMap 節(jié)點的功能介紹和使用,打造一個游戲該有的豐富世界!
最后,本篇上下節(jié)結束后,我要提醒新手朋友們幾個注意點:
- 我們實際項目中使用 RigidBody2D 來作為玩家還是比較少的,相對多的還是 KinematicBody2D 節(jié)點
- 我們對物理碰撞的處理不應該放在
_process(delta)方法中,而應該放在_physics_process(delta)方法中,后續(xù)再講 - 地圖太簡單了,這也是這篇要埋下的伏筆,下篇介紹,“等著瞧”,哈哈
原創(chuàng)實屬不易,希望大家喜歡! :smile:
我的博客地址: http://liuqingwen.me ,歡迎關注我的微信公眾號:
IT自學不成才
