最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

從零開始獨立游戲開發(fā)學(xué)習(xí)筆記(七十二)--Godot 學(xué)習(xí)筆記(五)--指南(三)-2D

2023-12-04 15:50 作者:oyishyi  | 我要投稿

本來想著給我的游戲做了鍵盤輸入后,接著開始做動畫 sprite。那就學(xué)一下動畫。但是誰又能想到,Godot 指南里的 Animation 并不是這個 animation sprite。而是“動起來的畫”,用關(guān)鍵幀制作的動畫那種。然后我看了一下 Godot 的界面,還真是兩個不同的界面。。。

So,今天學(xué)的是 2D 版塊。

1. Canvas Layer

1.1 ViewPort 和 Canvas Items

CanvasItem 是所有 2D 節(jié)點的基礎(chǔ)。無論是 Node2D 還是 Control 都是繼承自此。

CanvasItem 節(jié)點肯定是 viewport 節(jié)點的直接或者間接子節(jié)點。(因為 root 節(jié)點本身就是一個 viewport,所以平時不會對這件事有感覺),viewport 會展示 CanvasItem 節(jié)點。

Viewport 的屬性 Viewport.canvas_transform 屬性,改變這個屬性可以用于改變其內(nèi)部所有 canvasItem 節(jié)點在屏幕上的位置。Camera2D 正是運用這個特性來調(diào)整屏幕。

但是注意,想達成像是滾動等效果,比起調(diào)整屏幕,調(diào)整 canvas 的 transform 性能上更加高效。

1.2 CanvasLayers

很多時候,我們并不想游戲中的所有東西都跟隨 canvas transform,比如:

  • Parallax Backgrounds:背景移動的速度比其他地方慢一些。

  • UI:尤其是 HUD。

  • Transition 場景過渡:有些過渡效果(淡入淡出等)我們希望在屏幕上位置不變。

如何在同一個場景樹中達成上面的效果? CanvasLayers 節(jié)點會添加一個完全分離的 2d 渲染層。完全可以把不想隨 Viewport 移動的東西放這個節(jié)點下面。該節(jié)點有一個 layer 屬性,普通視角的layer 是 0。CanvasLayers 可以根據(jù)需求決定放哪一層。CanvasLayers 的 tranform 不會受到別的影響,所以能固定在屏幕上。

一個比較常見的場景如下:

因為背景需要慢速移動,HUD 需要固定,所以用 CanvasLayer 放在了不同層上。

因為 CanvasLayer 和在場景樹上的位置無關(guān),所以可以隨時隨地根據(jù)需求實例化。

雖然可以做到,但是 CanvasLayer 本意并不是用來調(diào)整場景前后位置的。正確標(biāo)準的做法應(yīng)該是認真調(diào)整你的 scene 里節(jié)點的位置關(guān)系。在一個 scene 中,和直覺相反,最上面的節(jié)點繪制在最后面的圖層?;蛘咄ㄟ^ CanvasItem.z_index 來調(diào)整繪制順序。

有時候覺得,Godot 很多概念真的有點像前端。比如輸入事件的處理像是冒泡,這里z_index也是和 css 屬性一樣的名字,以及父節(jié)點可以獲取子節(jié)點的屬性但反過來卻不好取,有點像 react。也許我真的選對了引擎?

2. Viewport 和 Canvas transform

這一節(jié)講的是比較底層的東西,就是節(jié)點如何被繪制到屏幕上。

2.1 Canvas Transform

上一節(jié)提到過,每一個 canvasItem 都有一個自己的 Canvas Layer(不是 CanvasLayer 節(jié)點)。每一個 Canvas Layer 都有自己的 transform。

默認所有節(jié)點都被渲染在 Layer 0 上。

2.2 全局 canvas transform

前面說過,Viewport 也有一個 canvas transform,這個是全局 canvas transform,這個 transform 會影響其他的 canvas 的 transform。

2.3 拉伸 transform

Viewport 還有一個 stretch transform,用于對屏幕尺寸進行改變。后面會講.

2.4 Window transform

這里的 window 不是 windows 系統(tǒng)的窗口,而是 Godot 的一個節(jié)點類型。為了能夠?qū)Υ翱趦?nèi)容進行拉伸,每一個 Window 都包含一個 Window tansform。用于處理類似于窗口黑邊之類的東西。

2.5 transform order

為了把一個 CanvasItem 的坐標(biāo)轉(zhuǎn)化為實際屏幕上的坐標(biāo),大概是下圖的機制:

2.6 transform function

上面的圖中用到了許多 transform function。從右往左,乘以一個 transform function 就往左一步。

你可以在 CanvasItem 中使用這些函數(shù),雖然大部分時間你用不上。

2.7 傳遞輸入事件

有了這些知識,可以自己發(fā)送輸入事件了,即使用戶并沒有真的按下事件。

js

var local_pos = Vector2(10, 20)var ie = InputEventMouseButton.new()ie.button_index = MOUSE_BUTTON_LEFTie.position = get_viewport().get_screen_transform() * get_global_transform_with_canvas() * local_posInput.parse_input_event(ie)

這樣子會在這個節(jié)點的 (10, 20) 的位置執(zhí)行一個鼠標(biāo)左鍵點擊的事件。

上面講了很多告訴你如何獲取屏幕的精確坐標(biāo),但大部分時間你應(yīng)該用本地坐標(biāo)來完成,因為后者會自適應(yīng)屏幕分辨率。

3. 渲染

3.1 2D 燈光

默認情況下,Godot 里的 2D 場景是未著色的,且沒有燈光也沒有陰影。Godot 提供了實時 2D 光照和陰影??梢院芎玫卦黾佑螒虻木吧罡小?br>一套完整的 2D 光照系統(tǒng),包含如下節(jié)點:

  • CanvasModulate:能夠給場景整個著色,類似于“環(huán)境光”的感覺。如果一個地方?jīng)]有收到其他 2D 光照,那就是這個光來著色了。這個光照會讓整個場景變暗,如果不加的話,2D 光照會讓場景變得特別亮。

  • Sprite2D,TileMap:用于接受光照。

  • PointLight2D/DirectionalLight2D:用于照亮場景。

  • LightOccluder2D:用于告訴著色器哪一部分需要投射陰影。Occluder 可以作為一個單獨的節(jié)點放置,也可以作為 TileMap 的一部分。只有有光源的地方才會有陰影。雖然像是廢話,但是畢竟沒有光源也可以看得見各個物體。

背景色不會接受任何光照信息,如果希望陰影投射在背景上,需要用一個 visual representation 來表示背景,比如 Sprite2D。

3.1.1 點光源 PointLight2D

點光源又叫位置光源,是最常見的 2D 光源。
在 Inspector 中,點光源具有以下屬性:

  • Texture:用于光源的紋理。Texture 的大小就是光的大小。如果紋理有 ALpha 通道,那在 Mix 混合模式中會很有用。不過如果用 add 或者 subtract 模式則不需要。

  • Offset:和直接改光的位置有區(qū)別。offset 不會更改陰影的位置。

  • Texture Scale:增大燈光的尺寸。越大越耗費性能。

  • Height:虛擬的高度,當(dāng)有法線的時候,燈光的虛擬高度。默認情況下,light 與物體表面里的非常近,所以如果使用了法線,燈光會變得很難看見,所以需要增加這個高度。沒有法線的表面不會受到這個值的影響。

3.1.2 定向光 DirectionLight2D

這是 4.0 新增的功能。一般用于表現(xiàn)陽光或者月光。光線是平行投射的。

DirectionLight2D 提供以下屬性:

  • 高度:虛擬高度,效果和點光源一樣。高度不會影響陰影的樣子。

  • 最大距離:為了避免計算在相機外的物體投射陰影誕生了這個,這個距離是離相機中心的距離,超過這個距離的物體不會被計算陰影。不然在場景開始就算計算場景終點的陰影不劃算。這個屬性不會受到相機的縮放的影響,因為它計算的只是和相機中心的距離。

定向光源的陰影永遠都是無限長,這個是定向光線的渲染方式造成的缺陷。想要投射正常的陰影,應(yīng)該取消定向光源的陰影。轉(zhuǎn)而使用自定義的 shader。

3.1.3 一些共享的屬性

點光源和定向光源都具有這些屬性,當(dāng)然這指的就是 Ligh2D 這個基類的屬性。

  • Enabled:是否開啟光源。關(guān)閉這個和直接隱藏節(jié)點的區(qū)別在于,關(guān)閉這個不會對子節(jié)點有影響。

  • Editor Only:開啟后,光源僅會在編輯器中起作用。游戲中不會起效果。

  • Color:顏色。

  • Energy:光線強度。

  • Blend Mode:與被照亮物體的顏色計算方式。默認是 add,光線疊加,會變亮。subtract 一般用于特殊效果,會變暗。mix 則是線性疊加,不會變亮也不會變暗。

  • Range:Zmin, Zmax,Layer Min,Layer Max,決定了光線會影響哪些 zindex 和 layer 的物體。

  • Range - Item Cull Mask:兩個作用。①通過被照射物體上的 canvasItem -> Light Mask 來控制體是都會受到光照影響。(注意:這里有一個坑,就是如果你創(chuàng)建了一個 Player,然后改變其 Light Mask,你會發(fā)現(xiàn)還是受到光線影響,這是因為你要改的不是 Player 的 Light Mask,你應(yīng)該進入 Player Scene,然后更改 Player 下面的 Sprite 或者 Animated2D 節(jié)點,更改其 Light Mask 才行。(所以也不能叫坑吧,算是一個小知識,這就是 How it Works)) ②如果有 Occluder,那么還可以用 Occluder Light Mask 來控制是否投射陰影。

3.1.4 設(shè)置陰影

光是開啟光源里的陰影是看不到陰影的,因為要有陰影就要有阻擋物,也就是 Occluders。

2D 陰影必須要有 LightOccluder2D 才能形成,這個節(jié)點需要靠多邊形來匹配 sprite 的形狀。此外,還具有兩個屬性:

  • SDF Collision:用于著色器,不過開啟了也不會影響性能,所以干脆默認開啟。

  • Occluder Light Mask:與光源的 Item Cull Mask 一起控制物體是否會形成陰影。

3.1.5 如何創(chuàng)建 LightOccluder2D

兩種方式,一種手動,一種自動。

自動創(chuàng)建

選中一個 Sprite2D 節(jié)點,編輯器上方(就是選擇/縮放/網(wǎng)格的工具欄那里)會多出一個選項可以自動生成 LightOccluder2D 或者 Polygon2D。

手動創(chuàng)建

創(chuàng)建 Polygon2D,自己手動一點點畫出來。

陰影屬性

陰影可以配置各種屬性:

  • Color:陰影的顏色。

  • Filter,三種方式,其實就是硬陰影,軟陰影。PCF5 和 PCF13 區(qū)別可以簡單的通過更改 Filter Smoooth 看到,5 就是邊緣 5 層不同的透明度來模擬,13 就是 13 層。PCF13 盡量少用,因為性能消耗大。

  • Filter Smooth:調(diào)一下就知道了。

  • Item Cull Mask:和 Range->Item Cull Mask 不一樣,這個只會影響陰影,但不會影響光源。

3.1.5 陰影繪制順序

LighOccluder2D 遵循通常的 2D 繪制順序。借此您可以控制遮擋物怎么遮擋。(就像之前說的,盡量用 Scene 里節(jié)點的順序來控制圖層,少用 layer,z_index 這些),好的架構(gòu)最重要。

如果 LightOccluder2D 節(jié)點是 Sprite 的 sibling,且如果 Occluder 節(jié)點在下面,那么就會遮擋這個 sprite。

如果遮擋物是 sprite 的 child,就會遮擋 sprite。但如果開啟了 Show Behind Parent,那就不會遮擋,不過默認是關(guān)閉的。

3.1.6 法線貼圖和高光貼圖

這兩個可以應(yīng)用于所有的 2D 元素。提高真實感。

這里有一個自動生成 2D 法線的工具,叫做?Laigter。

簡單的就不錯:

比如說對于 Sprite2D 來說,加 CanvasTexture ,然后就可以配置 Normal Map,Specture Map 等。

3.1.7 附加 Sprite 來使 2D 燈光渲染更快

使用 2D 燈光會造成一些性能問題,所以有時候可以附加 Sprite 來作為替代。原理很簡單,就是用一個燈光顏色的 sprite,然后選擇 blend mode 為 add。反正 2D 燈光的本質(zhì)其實也就是改變顏色而已。

這個方法顯然比用燈光性能高很多很多,因為不需要通過一個單獨的渲染管線。此外,這個方法還可以用來和 AnimatedSprite2D 結(jié)合使用,這樣就有創(chuàng)造了一個動畫的“燈光”。

當(dāng)然,附加 Sprite 自然有它的缺點:

  • 首先混合模式附加的顏色,相比真正的燈光而言并不正確。如果場景光線很充足這倒無所謂,但如果光線比較昏暗就能看到明顯區(qū)別。最極端的案例是完全黑暗的場景,附加的 Sprite 并不能用來照亮區(qū)域。

  • 不能投射陰影。當(dāng)然了,它又不是燈光。它只是看起來像燈光的顏色而已。

  • 不受法線,高光貼圖的影響。

所以使用場景應(yīng)該是在不太需要燈光的真實效果的地方。

這種方式經(jīng)常用于短暫的動態(tài)效果,比如子彈或者爆炸。因為他們很快,不需要很真實的光效。

使用方法

創(chuàng)建一個 Sprite2D 節(jié)點中,先添加 Texture(就像 PointLight2D 里的那個一樣),在 CanvasItem->Material 里添加 CanvasItemMaterial 材質(zhì),然后選擇混合模式為 Add 就行了,現(xiàn)在這個 Sprite2D 就可以作為。如下圖:

和原生燈光對比

這是原生燈光:

這是附加燈光

可以看到效果還是不錯的,因為這里光線充足,我也沒有添加法線,兩者唯一區(qū)別就是沒有陰影。所以有些時候?qū)毠?jié)要求不高確實可以用用。

3.2 2D 網(wǎng)格(2D Meshes)

2D 中用的圖片比較多,很少用網(wǎng)格。注意 2D 網(wǎng)格是二維幾何體并不是 3D。生成 2D 的方式一個是導(dǎo)入 OBJ 文件,還有一個是通過 Sprite2D 創(chuàng)建。

3.2.1 為啥要用 2D 網(wǎng)格

這是一種優(yōu)化方式。Godot 會渲染圖片的所有像素,即使透明的也是如此。如果你有一個尺寸很大的圖片,但大部分邊緣面積都是透明的,會很耗費性能。尤其是使用 ParallaxBackground 將多個具有大透明區(qū)域的圖片分層時。

而轉(zhuǎn)成 2D Mesh 則會忽略透明部分。

3.2.2 如何將 Sprite2D 轉(zhuǎn)成 2D Mesh

Sprite2D 的節(jié)點的編輯器工具欄上有一個按鈕(就是之前生成 Occluder 的地方),調(diào)整下參數(shù)很方便就能生成了。

3.3 2D Sprite Animation

終于到這了,本來只是為了學(xué)這個,怎么前面這么多啊。

3.3.1 添加動畫

這個之前教程里說了,沒什么多的東西。

3.3.2 控制動畫

同樣

3.3.3 SpriteSheet

Godot 可以讀取 Spreadsheet 格式的動畫。

3.3.4 帶有 AnimationPlayer 的 SpriteSheet

還有一種方式是先用一個普通的 Sprite2D 展示 Tetxture,然后使用 AnimationPlayer 來控制動畫。

  1. 先創(chuàng)建一個 Sprite2D,把 SpriteSheet 拖到 Texture 上,在 Animation 部分選擇 Hframes,VFrames 來自動切割,就和 AnimatedSprite2D 里做的一樣。

  2. 然后選擇 AnimationPlayer,選擇下方的動畫。點擊“動畫”按鈕(看起來像是個不能點的文字框,但其實是個按鈕),新建動畫。右邊把時間改成 0.6(這個是教程的值,實際上應(yīng)該是下方 snap 的值(默認是 0.1) * 你有多少動畫幀), 然后勾選 loop 成為循環(huán)動畫。

  3. 回到 Sprite2D 節(jié)點,點擊 frame 右邊的一個鑰匙的按鈕。我說為啥是鑰匙呢,原來是關(guān)鍵幀。那就簡單了,AE 沒有白學(xué)。

AnimationPlayer 使用方式和 AnimatedPlayer2D 一模一樣,Script 里的方法也一模一樣。

如果同時動畫和某個屬性同時改變,play() 并不會立刻反應(yīng),要下一個動畫幀才能改變。所以會造成故障幀。比如說你在做一個轉(zhuǎn)身的動畫,你先改變 h_flip 來轉(zhuǎn)身,然后 play() 播放轉(zhuǎn)身動畫。但是實際上,人物會轉(zhuǎn)身然后保持跑動的動畫過一幀,然后才變成轉(zhuǎn)身動畫。要解決這個問題,請在 play() 之后調(diào)用?advanced(0)?來更新動畫。

3.3.5 選哪個?AnimationPlayer 還是 AnimatedSprite2D

用過了就會發(fā)現(xiàn),AnimationPlayer 更復(fù)雜,而 AnimatedSprite2D 連簡單的一次性播放動畫都做不到。

所以一般來說動畫復(fù)雜的,比如說玩家,肯定是要用 AnimationPlayer 的。簡單的小動畫那就用 AnimatedSprite2D 就可以了。

當(dāng)然還有更狠的,給 AnimatedSprite2D 配上 AnimationPlayer,因為前者也有 frame 屬性也可以加關(guān)鍵幀。反正 AnimationPlayer 主打一個萬能配。

AnimatedSprite2D 配 AnimationPlayer

就是在 animatedSprite2D 里弄好動畫后,在 AnimationPlayer 里切換 animation 和 frame 來控制動畫,而不用 animatedSprite2D 自身的動畫。個人感覺這樣更清晰,如果用 animationPlayer 的話,所有的 sprite 幀都要放在一個大的 Sprite Sheet 里面,區(qū)分動畫靠幀數(shù),還要去專門記攻擊動畫是 15-36 幀這種東西。

3.4 2D 粒子系統(tǒng)

3.4.1 粒子節(jié)點

Godot 有兩個粒子節(jié)點,GPUParticles2D 和 CPUParticles2D。能選肯定選 GPU,性能更好。唯一可能選 CPU 的原因可能只是 GPU 遇到瓶頸了幫忙分擔(dān)點。

3.4.2 ParticleProcessMaterial

加了一個節(jié)點,但是啥都沒有點。因為沒有加 ParticleProcessMaterial,也沒有添加 Texture。
直接創(chuàng)建一個 ParticleProcessMaterial。
Texture 同理。

3.4.3 Animation flipbook

Animation flipbook 是一種特殊的 Texture,可以看作是粒子的 SpriteSheet。是一系列的粒子動畫幀,如下圖。

使用 flipbook 比起單個 Texture 需要更多的設(shè)置。

首先把一個 flipbook 圖片加載進 Texture,然后在這個節(jié)點的 CanvasItem->Material 里添加一個 CanvasItemMaterial(之前你們用來模擬燈光的那個),然后在生成的 Material 里可以看到有一個 Particle Animation 的選項,勾選后會提供 hframe 和vframe。熟悉的操作。(如果 flipback 背景是黑色的而不是透明的,則可以把混合模式調(diào)成 add,當(dāng)然最好的是事先修改好圖片)

這個時候,再回到 ParticleProcessMaterial 里,有一個 animation 部分就可以對動畫進行控制了。

粒子系統(tǒng)玩的主要是各種調(diào)參,所以這里對每個參數(shù)進行介紹(前面部分是粒子節(jié)點本身的參數(shù),后面部分是介紹 ParticleProcessMaterial 的參數(shù)):

3.4.4 Time 參數(shù)

Lifetime

每個粒子的存活時間,每個粒子消失的時候就會有新的來代替。

One Shot

很好懂,發(fā)射一次就結(jié)束。

Preprocess

假設(shè)粒子已經(jīng)運行的時間。
比如說你想做一個霧的場景,但是粒子系統(tǒng)生成霧也是要從某個點開始往外噴發(fā)直到某個時間段穩(wěn)定了才形成霧的樣子。但你不可能讓玩家看到這個過程,所以要使用 preprocess 來跳過這個生成階段。

Speed Scale

直接明了

Explosiveness

粒子系統(tǒng)默認是平均生成,i.e. 如果 lifetime 為 1,粒子數(shù)量為 10.那么會每 0.1 秒生成一個粒子。
如果把 Explosiveness 設(shè)置為 1,那么就會一次性生成 10 個粒子,等 1秒再生成 10 個粒子。

且這個值是可以取中間值的,提供一些靈活性。

Randomness

直接明了

Fixed FPS

改變粒子系統(tǒng)的 fps,注意這一選項不會改變粒子系統(tǒng)的速度,只是平穩(wěn)和卡,物理計算該到哪里還是哪里。
如果改成 0,那么就是按照實際游戲幀率來渲染了,游戲多少幀粒子就多少幀(同上不會影響物理效果,不用擔(dān)心)。

Fract Delta

一種計算方式,說是開了會更平滑。

3.4.5 Drawing 參數(shù)

Visibility Rect

這個矩形控制是否渲染粒子,如果這個矩形在視口之外,則不會渲染粒子。
W 和 H 控制矩形寬度和高度。X 和 Y 則是矩形的左上角的坐標(biāo)(相對粒子發(fā)射器的坐標(biāo))。

Godot 可以自動生成這個矩形(就像你生成 Occulder 和 Mesh 那樣,在關(guān)卡編輯器上方),Godot 會模擬粒子系統(tǒng)跑一陣子,然后生成適合的矩形。

Local Coords

開啟意味著所有被發(fā)射的粒子都與該節(jié)點綁定,移動節(jié)點的時候,所有已經(jīng)噴出的粒子也會跟著一起移動。
關(guān)閉意味著已經(jīng)發(fā)射的粒子位置不會再改變了。

Draw Order

這個繪制順序指的不是先后,而是圖層前后。

3.4.6 ParticleProcessMaterial

Initial velocity

初速度的大小,粒子剛發(fā)射時候的速度大小 Pixels/Sec。

Angular Velocity

初始角速度。

Spin Velocity

旋轉(zhuǎn)速度。

Orbit Velocity

沿著中心旋轉(zhuǎn)的速度。上面的 spin 是粒子的中心,這個是粒子發(fā)射器的中心。

Direction

粒子剛發(fā)射時候的初速度的方向,默認是 (1,0,0) 按理來說是向右,但實際上粒子動畫看起來是向下,因為這是初速度。粒子默認還有一個向下的重力。

Spread

顧名思義,沿著初速度,向兩邊的角度,粒子會在這個區(qū)域發(fā)射。因為是兩邊,所以最大值是 180,拉滿就是全方向了。

Flatness

僅對 3D 有用,其實就是另一方向的 Spread。

Gravity

就剛剛提到的重力。

Linear Acceleration

線性加速度

Radial Accl

徑向加速度,就是粒子和發(fā)射器之間的方向。正值會遠離發(fā)射器,負值會靠近發(fā)射器。

Tangential Accl

切向加速度,就是和徑向垂直的方向。(這里有一個英語的問題,雖然 Tangential 翻譯為切向,但其實所謂的切向速度,并不一定和速度相切,叫橫向加速度更好理解,因為一定是和徑向垂直的)(以下圖為例,切向從定義來講應(yīng)該是 Velocity,但實際上指的是垂直徑向的那個)

至于上面有一個 orbit Velocity,應(yīng)該才是上圖中的那個 Velocity,軌道速度,但在 godot 里,我感覺指的估計還是橫向速度。

Damping

阻尼,用于創(chuàng)造摩擦力。對于像是爆炸,火花等一開始速度快,最后速度慢的效果來說很好用。

Angle

角度,最經(jīng)常被用來隨機的屬性。畢竟角度隨機比較容易看出來隨機的感覺。

Scale

簡單明了

Color

簡單明了

Hue Variation

簡單明了

Animation

只有用 canbaseItem Material 加 flipbook 的時候才有用。
如果關(guān)閉循環(huán),且在粒子生命周期內(nèi)動畫播放完了,會持續(xù)顯示最后一幀(如果你發(fā)現(xiàn)不是,也許你最后一幀是透明的)。

如果 speed 設(shè)置為 1,則粒子動畫會剛好播放一整個生命周期。

如果 flipbook spritesheet 里并不是一個粒子的全程動畫,而是你想用這個 spritesheet 達成每個粒子從中挑選一個動畫來播放。那么請把 speed 調(diào)整為 0,然后 offset max 調(diào)整為 1(min 為 0)。那么每個粒子就會從中隨機挑選一個來使用了。

3.4.7 發(fā)射形狀

有一個叫發(fā)射遮罩的東西,決定了粒子從哪里發(fā)射。
在關(guān)卡編輯器上方(對,還是那里)前期,有一個加載發(fā)射遮罩的選項。

有三種類型:

  • Solid Pixels(實體像素):粒子會從 Texture 的所有非透明的地方發(fā)射。

  • Border Pixels(邊界像素):粒子只會從 Texture 的外邊界發(fā)射。

  • Directed Border Pixels(有向邊界像素):和 Border Pixels 相似,但是粒子可以從邊界往外發(fā)射。選擇了這個會導(dǎo)致部分屬性失效,我自己測的是初始方向和Spread會無效,因為會按照這個 Texture 來。

選擇捕獲像素顏色,那么發(fā)射的粒子會繼承 Texture 發(fā)射點像素的的顏色。

生成的 Mask 會在 ParticleProcessMaterial 的 Spwan->Position 里。
剛才生成的 Mask 會在這里的 Point Texture 和 Normal Texture 里,如果勾選了顏色則會在 Color Texture 里。這三個東西如果你不是特別清楚原理那就別自己換,最好全靠自動生成。

3.5 2D 抗鋸齒(2D antialiasing)

因為分辨率的原因,2D 場景經(jīng)常會出現(xiàn)鋸齒現(xiàn)象。 尤其是在 Linea2D,Polygon2D,TextureProgressBar 中最為明顯,部分 Custom Drawing 也會。

3.5.1 Line2D,Polygon2D 和 Custom Drawing 上的抗鋸齒屬性

部分節(jié)點會提供一個 Antiliased 的屬性,這個屬性對性能影響很小,是最推薦的方式。

這個屬性并不要求打開 MSAA,也就是說基礎(chǔ)性能消耗就很少。

不過,因為這個方法通過生成幾何體來起作用。所以如果你的幾何體是一個很復(fù)雜,且一直在變化的話,這個方式的性能消耗就會上來。

3.5.2 多重采樣抗鋸齒(MSAA/Multisample Antialiasing)

MSAA 在 2D 的使用范圍是有限制的:

  • 幾何邊緣,比如 Line,Polygon 的邊緣,

  • Sprite 的邊緣。但這里指的是整個 Texture 的邊緣,而不是由透明度產(chǎn)生的邊緣。見下面的圖。

MSAA 的缺點很明顯,就是只適用于邊緣。MSAA 會增加 Coverage 采樣的數(shù)量,但不會增加 Color 采樣的數(shù)量,fragment shader 仍然只對每個像素執(zhí)行一次。因此 MSAA 不會以任何方式影響以下的鋸齒:

  • 應(yīng)用了 nearest-neightbor filter 的 texture(像素畫)

  • 自定義 2D shader 產(chǎn)生的鋸齒。

  • 使用 Light2D 產(chǎn)生的 Specular 鋸齒。

  • 字體渲染時候的鋸齒

MSAA 可以在項目設(shè)置里設(shè)置。

MSAA 的效果如下。重點看下面的像素畫,可以看到 godot 的 logo 沒有任何區(qū)別,它們雖然是邊緣,但這種邊緣是透明度帶來的,不是真正的邊緣。真正的邊緣是后面的綠色背景的正方形邊緣,可以看到在第 2,3 個的正方形邊緣上確實有抗鋸齒的效果。

3.6 Custom Drawing in 2D

godot 提供了 sprite,line,polygon,particles 等東西。如果這都不夠你表達所需的話,你可以使用任意 2D 節(jié)點(Node2D 或者 Control)為基礎(chǔ)來自定義繪制。

自定義繪制有很多使用場景,比如:

  • 繪制現(xiàn)有節(jié)點無法完成的形狀和邏輯。比如特殊的動畫多邊形,移動殘影等。

  • 特殊的視覺效果。

  • 繪制大量的簡單物體。因為自定義繪制可以避免一次性生成多個節(jié)點。可以提高性能。

  • 自定義 UI 控制。雖然 godot 提供了盡量多的方式,但是游戲不是 web 應(yīng)用,總有很多特殊的控制方式是獨特的。

3.6.1 繪制

首先添加腳本(一定得是繼承 CanvasItem 節(jié)點),通常是 Node2D 和 Control。然后重寫?_draw()?函數(shù)。
里面能使用很多繪制方法,在?CanvasItem 的 class reference 里有詳細說明,這些方法都只能在?_draw()?里使用。

3.6.2 更新

_draw()?只會被調(diào)用一次,然后不會再被調(diào)用。這是為了節(jié)省性能,避免每幀都重繪。

如果想要重新繪制,要手動調(diào)用?CanvasItem.queue_redraw()?函數(shù),然后?_draw()?就會被重新調(diào)用。

所以,如果想要每幀都重繪,在?_process()?里調(diào)用 queue_draw() 即可。

3.6.3 坐標(biāo)

draw 方法使用的是 CanvasItem 的坐標(biāo)系統(tǒng),會跟著 CanvasItem 的 transform 而變換(簡單來說就是 local transform)。當(dāng)然,也有像是?draw_set_transform()?等方法來自定義 transform。

使用?draw_line()?,draw_rect()?等方法的時候,注意如果寬度是奇數(shù),那么線的位置應(yīng)該移動 0.5 來保持中心,如下圖:

如果從 (1,0) 到 (4,0),但寬度是 3,那么只能是左 2 右 1 或者左 1 右 2,這樣線不會是中心點。會造成各種問題。

3.6.4 使用案例:繪制圓弧(重要)

Godot 里有一個?draw_circle()?來畫整圓,但是如果我們想要畫的是圓弧怎么辦?那就只能自己寫代碼了。(笑死,現(xiàn)在 Godot 已經(jīng)提供了 draw_arc 來畫圓弧,但是重點不是這個,重點是你要自己寫代碼來完成 Godot 沒有提供的功能,我們假設(shè) Godot 沒有提供這個方法好了)

圓弧的基本功能

為了畫圓弧,我們需要圓心位置,半徑,起始角度和終止角度,這里我們花哨一點,再加一個顏色。

重點來了,在屏幕上繪制形狀,其本質(zhì)是一個一個點/邊互相鏈接。對于圓弧這種曲線而言,點越多就越平滑,點越少就越棱角。沒錯,如果你要用?_draw(),你就需要考慮這些事情了。如果你要更細節(jié)一點,那么這里可以做 LOD(Levels of Detail),如果形狀很大,那么需要的點肯定也會很多才能看起來平滑,如果形狀小,那么很少的點就可以表現(xiàn)很平滑了。(在 3D 中,這個表現(xiàn)為離相機近和遠,其實所謂的近和遠也就是大和小的區(qū)別了) 。不過,說是這么說,為了方便,我們這里就不搞 LOD 了,全用固定點。

先上代碼:

js

func draw_circle_arc(center, radius, angle_from, angle_to, color): var nb_edges = 32 var points_arc = PackedVector2Array() for i in range(nb_edges + 1): var angle_edge = deg_to_rad(angle_from + i * (angle_to-angle_from) / nb_edges - 90) points_arc.push_back(center + Vector2(cos(angle_edge), sin(angle_edge)) * radius) for index_point in range(nb_points): draw_line(points_arc[index_point], points_arc[index_point + 1], color)

  1. nb_edges 是組成形狀的邊的個數(shù),為了圖方便我們用固定的 32。

  2. 然后初始化一個 Vector2 的 Array 用來存放點的位置數(shù)據(jù)。

  3. 32 個邊由 33 個點組成,在第一個 for 循環(huán)里,我們計算這 33 個點應(yīng)該存在的位置。使用 deg_to_rad 把角度轉(zhuǎn)換成弧度。但是因為人的直覺來看角度的 0 度是 12 點鐘方向,但是弧度實際上是把 3 點鐘方向作為 0 度。所以這里減 90 度,這樣子以后就可以用 12 點鐘作為角度的 0 度了,比較利于人類思考。

  4. Vector2(cos(angle_edge), sin(angle_edge)) 就是圓心到這個點的標(biāo)準向量。乘以半徑就是帶長度的向量。加上 center 就是點的實際位置了。

  5. 拿到 33 個點的實際位置后,我們只需要在每個點之間?draw_line()?畫線就行了。這就是第二個 for 循環(huán)做的事情。

  6. 然后,您只需要在?_draw()?里調(diào)用這個方法就行了。

如果想變成實心,把 draw_line 改成 draw_polygon 即可。

3.6.5 動態(tài)自定義繪圖

我們現(xiàn)在學(xué)會了畫靜態(tài)圖,那么我們要畫動態(tài)圖了。
也很簡單,假設(shè)我們想讓上面的圓弧動起來,那么我們只需要把 angle_from 和 angle_to 改成全局變量即可(或者從其他節(jié)點里獲取等)。這樣我們就可以在?_process()?里更改變量,然后調(diào)用 queue_draw() 就行了。

注意:如果你是通過增大角度來旋轉(zhuǎn),這里角度可能會無限增長,比如 425°,雖然 godot 依然能夠計算。但是隨著時間增長,這個度數(shù)可能會達到 2**31 - 1,也就是整數(shù)的最大值,造成 bug 的產(chǎn)生。所以要用 wrap()/wrapf() 來標(biāo)準化。

速度

別忘了 delta,因為渲染必須在 process 里使用,沒法依賴 physical_process。所以我們要給這些速度乘以 delta。

3.6.6 抗鋸齒

部分繪制方法提供了抗鋸齒,比如 draw_line。如果不提供的話,那你只能用 MSAA 了,但別忘了這一開就是影響整個視口。并且只針對特定元素(請回顧上一大節(jié))。

4. 物理與移動

4.1 2D 移動

介紹一些常用的方法。

4.1.1 基本設(shè)置

一般都是以 CharacterBody2D 開始,配上 Sprite2D 和 CollisionShape2D 兩個子節(jié)點。
然后在項目設(shè)置里設(shè)置 InputMap。

在?_physics_process?里改變 velocity,然后調(diào)用 move_and_slide() 。

4.1.2 朝向鼠標(biāo)的方向

調(diào)用 look_at() 函數(shù),可以改變節(jié)點的旋轉(zhuǎn)方向,參數(shù)使用鼠標(biāo)的位置,那就變成了看向鼠標(biāo)的方向了。

4.1.3 移動到鼠標(biāo)點擊的位置

獲取鼠標(biāo)的位置后,有兩個有用的方法:

  • Vector2.direction_to():獲取方向,一般這么用?velocity = position.direction_to(target) * speed

  • Vector2.distance_to():獲取到某點的距離。一般這么用?var distance = position.distance_to(target)

5. 工具

5.1 TileSets

TileMap 用于創(chuàng)建游戲布局場景的好工具,可以用圖塊來繪制場景,好處一個是不用創(chuàng)建大量的 Sprite,二個是比用大量的 Sprite 性能要更好。TileMap 可以添加各種功能。

不過,在使用 TileMap 前,需要創(chuàng)建 TileSet,TileSet 就是在 TileMap 里使用的圖塊的幾何。創(chuàng)建好一個 TileSet 后,在 TileMap 編輯器里來使用它們。

TileSet 的創(chuàng)建需要一個和 Spritesheet,F(xiàn)ilpbook 類似的東西,叫做 TileSheet。

5.1.1 創(chuàng)建 Tileset

先創(chuàng)建一個 TileMap,然后在檢查器里新建一個 TileSet 資源。
展開后,可以發(fā)現(xiàn),TileSet 的圖塊形狀除了方形還有很多種。
設(shè)置好圖塊的大小。

然后我們前往編輯器底部的 TileSet,添加圖集(atlas),圖集的作用是確定那些部分會被作為 tileset,因為不是圖片的所有部分都會作為 tileset。會提示你是否自動創(chuàng)建,如果你已經(jīng)正確設(shè)置了圖塊的大小,則點擊確認。一個 atlas 可以創(chuàng)建多個 atlas,以便使用多個 tilesheet 圖片

如果有一些 tiles 不需要,可以用橡皮擦擦掉?;蛘哂益I刪除也是一樣的作用。

左邊的 setup 是創(chuàng)建和刪除圖塊(如果自動創(chuàng)建會自動全添加為圖塊了)。這里可以調(diào)整 atlas 的屬性。

  • ID:用于排序

  • Name:名字,最好用一些描述性名字,比如“區(qū)域”,“裝飾物”等

  • Margins:有些 tilesheet 周圍有些邊距,導(dǎo)致按照圖塊大小分分不完。一般這種事網(wǎng)絡(luò)上下載的比較多,如果不想改圖片的話,那就這里改。

  • Separation:如果圖塊之間有間隔,可以用這個。

  • Texture Region Size:圖塊分割大小。tilesheet 會按照這個大小區(qū)域分割。

  • Use Texture Padding:勾選后,所有的 tile 都會有 1 像素大小的透明邊緣。防止在使用 filter 的時候發(fā)生紋理滲色現(xiàn)象。一般來說除非這個導(dǎo)致渲染出事了,不然保持開啟最好。

橡皮擦右邊的三個點里有一些自動創(chuàng)建圖塊的選項,創(chuàng)建 atlas 時的自動創(chuàng)建和這個效果一樣。

5.1.2 使用場景合集

Godot 4.0 開始可以把場景作為 tiles 了。比如你創(chuàng)建了一個商店場景,那就可以批量放置了。當(dāng)然節(jié)點不限,像是音頻啊,粒子啊,各種都可以放。

但是注意,這個并不會帶來什么性能好處。如果非必要的話,還是用 atlas 比較好。不要做出什么把 sprite2D 節(jié)點作為場景來安放的傻事,除非有什么特殊需求。

5.1.3 把多個 atlas 合并為一個 atlas

添加 atlas 的右邊有三個點,這里可以選擇合并。

Tileset 有一個 tile proxies 的特性。用于替換 tilemap 里的 tileset。當(dāng)合并 atlas 的時候,會自動替換。如果你想替換 atlas 為另一個 atlas,也可以使用這個。

5.1.4 給 tileset 添加碰撞,導(dǎo)航,和遮擋物

我們現(xiàn)在成功創(chuàng)建了一個基礎(chǔ) TileSet,已經(jīng)可以使用 tilemap 了。不過我們還想添加一些額外功能像是碰撞,導(dǎo)航,遮擋物等功能。

為了添加碰撞,我們在 tilemap 檢查器中添加一個 physical layer。導(dǎo)航和遮擋物同理也有對應(yīng)的 layer。

在 tileset 面板中,調(diào)整到“選擇”工具,選中圖塊,可以看到物理層屬性了,下面有一個多邊形編輯器,這里可以編輯碰撞區(qū)域。你也可以按 f 來快速創(chuàng)建區(qū)域。

5.1.5 Custom Data Layer

使用 Custom Data Layer,可以按照圖塊來分配自定義數(shù)據(jù),可以用于儲存類似于玩家觸碰圖塊是否會受傷,或者是否可摧毀圖塊等信息。

不過由于數(shù)據(jù)是和 tileset 相關(guān)聯(lián)而不是 tilemap,所以每個實例圖塊都共享相同的數(shù)據(jù)。也可以構(gòu)建 Alternative Tile 來為某個圖塊專門儲存信息,這個后面會講。

注意 tileset 里數(shù)據(jù)層屬性不顯示名字,而是按照定義的順序。

屬性繪制也可以適用于自定義數(shù)據(jù)

5.1.6 創(chuàng)建地形集(以前的自動填充)

很多地形集都有這種地形--在邊緣,角落處會有特殊變體,手動放置會很麻煩,先放頭,然后放一堆中間,再放尾。

可以使用地形來自動執(zhí)行這種連接。地形被分組為地形集,每個地形集都可以分配為“匹配角和邊”,“匹配角”,“匹配邊”模式。

先在檢查器里創(chuàng)建一個地形集,創(chuàng)建地形集后還要創(chuàng)建一個或者多個地形。
創(chuàng)建完后,在 tileset 里設(shè)置屬性,也可以在繪制里設(shè)置。 設(shè)置完地形集和地形后,會出現(xiàn)一個地形鄰接位(繪制屬性列里不會出現(xiàn)這個,必須在選擇列里配置)。

地形鄰接位

地形鄰接位用來控制放置哪個圖塊。數(shù)值是地形的 index。比如:

這么設(shè)置的意思是,第一張圖因為是在左側(cè),所以只能右側(cè)放 index 為 0 的 tile。所以設(shè)置右邊緣為 0,其他設(shè)置為 -1。第二張圖因為在中間,左右兩邊都可以放,所以左右側(cè)邊緣都設(shè)置為 0,其他設(shè)置為 -1。

設(shè)置完后,在 tilemap 里地形板塊就可以很方便繪制了。

5.1.7 多個 tile 屬性配置

選擇多個

在 “選擇”列,可以選擇多個 tile,再配置,這樣就可以批量配置了。需要注意的是,在這里,多選是 shift 而不是 ctrl,按住 shift 再點擊可以多選。

屬性繪制

很明顯這個指南的順序是瞎配的,這個明明前面都提到無數(shù)次了,結(jié)果真正提在這么老后面,我真服了。
這個不難,搗鼓一下就會了。

5.1.8 創(chuàng)建備選圖塊 Alternative Tile

有時候你希望某個 tile 實例具有單獨的配置,而不想影響到其他實例。

創(chuàng)建很簡單,選中 tile,右鍵即可創(chuàng)建。如果處于選擇模式,新創(chuàng)建的備選圖塊已經(jīng)處于選擇狀態(tài)可以編輯了(注意備選圖塊不會繼承基礎(chǔ)圖塊的屬性,你需要一個個添加)。如果不是,依然可以創(chuàng)建,但想要更改就要去選擇模式了。

備選圖塊的屬性和基礎(chǔ)圖塊是不同的,可以自己試試。

5.2 TileMap

如果想讓多個 TileMap 重用同一個 TileSet,最好的方法是把 TileSet 保存為外部資源。

5.2.1 創(chuàng)建 TileMap 圖層

Godot 4.0 開始,可以把多個圖層放在單個 TileMap 節(jié)點中,這樣可以在相同位置放上多個圖塊。

默認情況下只有一層,如果想添加,在 tilemap 檢查器的圖層部分添加,每個層都有一些屬性。

  • 名字:區(qū)分

  • 啟用:打開或者關(guān)閉圖層

  • Modulate:可以調(diào)整這一層所有圖塊的顏色。如果剛才你自己玩的話,會發(fā)現(xiàn)其實每個圖塊也有這個 Modulate(調(diào)制) 屬性。這些 Modulate 之間是相乘的效果,所以乘的越多會越暗。

  • Y Sort Enabled:根據(jù)圖塊在 tilemap 上的 y 位置來對圖塊進行排序,可以用于某些排序問題。

  • Y Sort Origin:用于 Y 排序的垂直偏移,開啟 Y 排序的時候才有用。

  • Z Index:控制該圖層的繪制順序,越高就越在畫面前面。如果相同,那列表最下面的圖層會在最頂部繪制。

注意:刪除圖層會刪除該圖層上的所有圖塊。

5.2.2 打開 TileMap 編輯器

在編輯器的底部,tileset 面板的右邊,你肯定早就看見也玩過了,如果沒玩過那我不知道前面 tileset 部分你是怎么看懂的。

5.2.3 選擇用于繪畫的圖塊

在 tileset 上選擇圖塊作為畫筆,然后右邊選擇畫在哪一層上。沒錯,因為 layer 是 tilemap 的屬性,和實例有關(guān),只和畫出來的圖塊實例有關(guān)。而之前的物理層啥的都是 tileset 的屬性,是應(yīng)用于所有的 tile 的。

選擇圖塊的時候可以多選的,把多個圖塊一起畫,注意多選按鈕還是 shift 不是 ctrl。這對于繪制樹木啥的很有用。

5.2.4 繪畫模式和工具

選擇工具

在屏幕上選擇 tile,這里要注意,這里快捷鍵又變了。按 shift 多選,但是移除單個要按住 ctrl,挺迷惑的設(shè)計,不過后面會說原因,雖然那個原因也沒啥說服力就是了。

選擇后按 del 鍵可以移除。

在繪制工具的時候,按住 ctrl 會臨時轉(zhuǎn)成選擇模式,這就是為啥 ctrl 是移除。但其實這個臨時的選擇模式是一個根本連按住 shift 多選都做不到的一個下位選擇模式(其實就只是一個取色器)。所以這個說法也沒啥說服力。總結(jié)就是這段肯定印度人設(shè)計的。

選擇模式還可以 copy paste,ctrl + c/v 就行。

繪制工具

左鍵繪制,右鍵刪除。

鼠標(biāo)點擊前按住 Shift 可以畫直線。按住 ctrl + shift 可以畫矩形。

按住 ctrl 可以在畫面上做到取色器的效果,不過取的是 tile。

直線工具

就是標(biāo)準的直線工具。和按 shift 一模一樣。

矩形工具

和按 ctrl + shift 一模一樣

油漆桶 Bucket Fill

標(biāo)準的油漆桶工具,除了顏色和 tile 腦子要轉(zhuǎn)換一下其它沒區(qū)別。連續(xù)就是是否沿著對角線填充。

所有這三個工具,按右鍵都會有相匹配的刪除效果。
另外兩個工具拾取器和橡皮擦就不說了,很簡單的效果。注意拾取器可以拖動來拾取一個區(qū)域。

散布隨機繪畫

是工具欄上骰子樣的那個圖標(biāo),勾選后會在選取的 tileset 中隨機選一個 tile 來繪畫(所以要多選后才起作用),或者如果修改散布值大于 0,那么還會有概率不放置任何 tile(一般用于放一些偶爾的非重復(fù)的細節(jié),比如草,碎屑等)。

這個可以和所有工具一起用,直線,矩形,油漆都可以。

5.2.5 圖案

雖然現(xiàn)在已經(jīng)可以多選來放置樹木這種東西了,但是很多時候還是希望把這些當(dāng)做一個預(yù)制的圖案來使用而不是每次都要多選。

切換到圖案板塊,在屏幕上選擇后,拖到下面來,或者選擇后按 ctrl + c,鼠標(biāo)點擊圖案的部分聚焦后按 ctrl + v。

圖案可以當(dāng)做普通 tile 來使用,所有的工具都可以用。

另外,圖案也是屬于 tileset 資源,雖然只能在 tilemap 部分創(chuàng)建。但回到 tileset 版塊可以看到。這樣子可以保證當(dāng)使用外部資源重用 tileset 的時候,圖案也能一并保存過去。

5.2.6 使用地形

前面 tileset 部分我們創(chuàng)建了地形集,現(xiàn)在我們要使用了。

切到地形板塊,選擇一個地形,可以看到有三種繪制模式(一開始只能看到兩種):

  • Connect 模式:圖塊可以連接到同一個 tilemap 圖層的其他圖塊。

  • Path 模式:圖塊只會自動連接同一筆畫出來的圖塊(直到鼠標(biāo)松開)。

  • 特殊圖塊模式:專門處理某些特殊情況,地形系統(tǒng)無法支持的自定義情況。

Connect 模式很好用方便,Path 模式更加靈活。比如你只是想畫兩個平行的線,結(jié)果 connect 模式自作聰明給你把兩個線連在一起了。

至于第三種模式,如果你前面在 tileset 設(shè)置地形集的時候,地形鄰接位設(shè)置的不會有矛盾的地方,那就不會出現(xiàn)。只有某些之間可能會有模糊不清的情況出現(xiàn)的時候,就會自動生成:

5.2.7 缺失 tile

如果你因為刪除/修改 tilseset 或者調(diào)整 id 啥的,導(dǎo)致 tilemap 找不到 tileset 資源。屏幕會用一個感嘆號圖塊來代替。(有些情況會直接刪除,比如說刪除圖層)

缺失 tile 不會被渲染,如果有新的 tile 匹配上這個 ID 的話,這些缺失會被補全。

缺失占位符只有在選中 tilemap 節(jié)點的時候才會出現(xiàn)。


從零開始獨立游戲開發(fā)學(xué)習(xí)筆記(七十二)--Godot 學(xué)習(xí)筆記(五)--指南(三)-2D的評論 (共 條)

分享到微博請遵守國家法律
循化| 诸城市| 清水县| 炉霍县| 正蓝旗| 乾安县| 肥城市| 获嘉县| 襄垣县| 虞城县| 安阳市| 龙州县| 山东| 修文县| 龙胜| 武穴市| 柏乡县| 扶风县| 昌邑市| 闽清县| 二连浩特市| 宣威市| 惠来县| 寻甸| 莒南县| 昭苏县| 峨山| 普定县| 灵武市| 霍州市| 水富县| 翁牛特旗| 永安市| 全南县| 札达县| 忻城县| 隆子县| 长白| 桃园县| 布尔津县| 静海县|