advanced east_SpriteKit Advanced —如何构建2,5D游戏(第二部分)
advanced east
by Luke Konior
盧克·科尼爾(Luke Konior)
SpriteKit Advanced —如何構(gòu)建2,5D游戲(第二部分) (SpriteKit Advanced — How to build a 2,5D game (Part II))
介紹 (Intro)
This article shows how to write basic shaders in the SpriteKit. It’s split into two parts: first we play, then we learn.
本文介紹如何在SpriteKit中編寫基本著色器。 它分為兩個部分:首先我們玩,然后學(xué)習(xí)。
It also contains information how to use SKAttribute and SKAttributeValue classes that were added in iOS SDK 10.0.
它還包含有關(guān)如何使用iOS SDK 10.0中添加的SKAttribute和SKAttributeValue類的信息。
If you haven’t already read it, here’s part 1 of this article series.
如果您還沒有閱讀它,請參閱本系列文章的第1部分 。
準(zhǔn)備項(xiàng)目 (Prepare the project)
Let’s get quick and dirty.
讓我們變得快速又骯臟。
- Open XCode 8 and create a new project from template: iOS > Game. 打開XCode 8,然后從以下模板創(chuàng)建一個新項(xiàng)目:iOS>游戲。
Open the GameScene.sks and remove the label in the center of the screen.
打開GameScene.sks并刪除屏幕中心的標(biāo)簽。
Download this and put it inside Assets.xcassets
下載此文件并將其放入Assets.xcassets
- Name it “Trees” 命名為“樹木”
Open the GameScene.m
打開GameScene.m
- remove all instance variables 刪除所有實(shí)例變量
- remove all methods 刪除所有方法
片段著色器 (The Fragment Shader)
Now we create an empty fragment shader In XCode:
現(xiàn)在,我們在XCode中創(chuàng)建一個空的片段shader :
- In the Project Navigator select Supporting Files 在項(xiàng)目瀏覽器中,選擇“支持文件”
- Choose: File > New > File… 選擇:文件>新建>文件…
- Select: Other > Empty 選擇:其他>空
Name it “myShader.fsh” and press Create.
將其命名為“ myShader.fsh ”,然后按創(chuàng)建。
- Put this inside: 放在里面:
Above fragment shader does nothing perceptible. Quick explanation:
片段shader上方?jīng)]有任何可察覺的內(nèi)容。 快速說明:
void main()
void main()
this function gets called for each pixel of the sprite and outputs color for that pixel
為精靈的每個像素調(diào)用此函數(shù),并輸出該像素的顏色
Gets input data from surrounding globals and must set the
從周圍的全局變量獲取輸入數(shù)據(jù),并且必須設(shè)置
gl_FragColor variable
gl_FragColor變量
vec2, vec3and vec4 are the types similar to C's: float array[2], float array[3] and float array[4]
vec2 , vec3和vec4與C的類型相似: float array[2] , float array[3]和float array[4]
u_texture is a texture ID
u_texture是紋理ID
Leave it alone :-)
不要管它 :-)
v_tex_coord is a vec2 which contains our current position in texture
v_tex_coord是一個vec2 ,其中包含我們當(dāng)前的紋理位置
texture2D(tex , p) is a function that returns color from texture tex in point p as vec4
texture2D(tex , p)是一個函數(shù),將point p處紋理tex顏色返回為vec4
which contains rgba
其中包含rgba
gl_FragColor is an output color
gl_FragColor是輸出顏色
We must assign it a
我們必須給它分配一個
vec4
vec4
正在加載代碼 (Loading code)
What’s left is the loading code.
剩下的就是加載代碼。
Open the GameScene.m
打開GameScene.m
add method -didMoveToView:
添加方法-didMoveToView:
Ensure that myShader.fsh figures in ProjectFile > Target > Build Phases > Copy Bundle Resources!
確保myShader.fsh數(shù)字位于ProjectFile>目標(biāo)>構(gòu)建階段>復(fù)制捆綁資源中!
You may now run the project on the iOS device. There shall be no errors in the XCode’s console and you should see a screen similar to this below:
您現(xiàn)在可以在iOS設(shè)備上運(yùn)行該項(xiàng)目。 XCode的控制臺中應(yīng)該沒有錯誤,并且您應(yīng)該看到類似于以下的屏幕:
讓我們玩吧! (Let’s play a bit!)
Now is the fun part. We’ll replace the shader’s main function.
現(xiàn)在是有趣的部分。 我們將替換著色器的主要功能。
顏色為紅色,保留alpha (Color with red with alpha preservation)
void main( void ){ vec4 color = texture2D(u_texture, v_tex_coord); float alpha = color.a; gl_FragColor = vec4(1,0,0, 1.0) * alpha; //google "premultiplied alpha"}縮小2倍 (Scale down by 2x)
void main( void ){ vec4 color = texture2D(u_texture, v_tex_coord * 2.0); gl_FragColor = color;}1秒后交換顏色 (Swap colors after 1 second)
void main( void ){ vec4 color = texture2D(u_texture, v_tex_coord); float alpha = color.a; float phase = mod(u_time, 3); vec3 outputColor = color.rgb; if (phase < 1.0) { outputColor = color.bgr; } else if (phase < 2.0) { outputColor = color.brg; } gl_FragColor = vec4(outputColor, 1.0) * alpha;}隨時間著色 (Colorize over time)
void main( void ){ vec4 color = texture2D(u_texture, v_tex_coord); float alpha = color.a; float r = (sin(u_time+ 3.14 * 0.00)+1.0)*0.5; float g = (sin(u_time+ 3.14 * 0.33)+1.0)*0.5; float b = (sin(u_time+ 3.14 * 0.66)+1.0)*0.5; gl_FragColor = vec4(r,g,b, 1.0) * alpha;}波浪 (Waves)
void main( void ){ float deltaX = sin(v_tex_coord.y*3.14*10 + u_time * 4)*0.01; vec2 coord = v_tex_coord; coord.x = coord.x + deltaX; vec4 color = texture2D(u_texture, coord); gl_FragColor = color;}新屬性 (New Attributes)
At WWDC 2016 Apple introduced an important update to SpriteKit — the SKAttribute and SKAttributeValue classes.
蘋果在WWDC 2016上對SpriteKit進(jìn)行了重要更新,即SKAttribute和SKAttributeValue類。
Before this SDK update, if we wanted to pass custom parameters into the shader program, we had to pass the data through a uniform value.
在此SDK更新之前,如果我們想將自定義參數(shù)傳遞給shader程序,則必須通過統(tǒng)一值傳遞數(shù)據(jù)。
This had two serious drawbacks:
這有兩個嚴(yán)重的缺點(diǎn):
- every uniform change caused shader recompilation 每次統(tǒng)一更改都會導(dǎo)致著色器重新編譯
- shader program handled every sprite in the exact same way 著色器程序以完全相同的方式處理每個精靈
For example: if we wanted to dye a group of sprites red, and one of them blue, we had two ways. First we create two separate SKShader instances and change our custom myColor uniform.
例如:如果我們想將一組精靈染成紅色,而其中一個染成藍(lán)色,則有兩種方法。 首先,我們創(chuàng)建兩個單獨(dú)的SKShader實(shí)例,并更改我們的自定義myColor制服。
Second we make one shader instance and change its uniform which causes a recompilation.
其次,我們制作一個shader實(shí)例并更改其統(tǒng)一性,從而導(dǎo)致重新編譯。
Both ways cannot be drawn on same pass. And the second one requires complex management code.
兩種方法不能同時繪制。 第二個要求復(fù)雜的管理代碼。
SDK 10.0 introduced the SKAttribute and SKAttributeValue classes. These two allow (finally!) passing data to the shader programs without recompilation. The usage algorithm is simple:
SDK 10.0引入了SKAttribute和SKAttributeValue類。 這兩個允許(最終!)將數(shù)據(jù)傳遞到著色器程序,而無需重新編譯。 用法算法很簡單:
- The shader part: 著色器部分:
Create a shader program
創(chuàng)建一個著色器程序
Create a shader programSKShader
創(chuàng)建一個著色器程序SKShader
Create an array of SKAttributes
創(chuàng)建一個SKAttributes數(shù)組
The sprite part:
sprite部分:
Assign a dictionary of SKAttributeValues
分配SKAttributeValues字典
屬性示例 (Example with attributes)
In the last example, we’ll add two more sprites. Every one of them will have the same shader program and will differ only in attributes. Let’s modify the -didMoveToView: inGameScene.m:
在最后一個示例中,我們將再添加兩個精靈。 它們中的每一個將具有相同的著色器程序,并且僅在屬性上有所不同。 讓我們修改- didMoveToView: inGameScene.m:
- (void)didMoveToView:(SKView *)view { NSString *file = [[NSBundle mainBundle] pathForResource:@"myShader" ofType:@"fsh"]; NSString *sourceString = [NSString stringWithContentsOfFile:file encoding:NSUTF8StringEncoding error:nil]; SKShader *shader = [SKShader shaderWithSource:sourceString]; // 1. Add a custom attribute to shader SKAttribute *attrProgress = [SKAttribute attributeWithName:@"THE_MIGHTY_DARK_FACTOR" type:SKAttributeTypeFloat]; shader.attributes = @[attrProgress]; // 2. Create tree sprites NSArray *trees = @[ [self createTreeWithShader:shader mightyFactor:0.3f zPosition:1], [self createTreeWithShader:shader mightyFactor:0.6f zPosition:2], [self createTreeWithShader:shader mightyFactor:0.9f zPosition:3], ]; for (SKSpriteNode *tree in trees) { [self addChild:tree]; }}- (SKSpriteNode*)createTreeWithShader:(SKShader*)shader mightyFactor:(CGFloat)mightyFactor zPosition:(CGFloat)zPosition { SKSpriteNode *treeNode = [SKSpriteNode spriteNodeWithImageNamed:@"Trees"]; treeNode.shader = shader; // 3. Fill the custom attribute on the sprite treeNode.attributeValues = @{@"THE_MIGHTY_DARK_FACTOR": [SKAttributeValue valueWithFloat:mightyFactor]}; treeNode.zPosition = zPosition;return treeNode;}… and the shader program:
…和著色器程序:
void main( void ){ vec4 color = texture2D(u_texture, v_tex_coord * (2.5 * THE_MIGHTY_DARK_FACTOR)); float alpha = color.a; vec3 baseColor = color.rgb * THE_MIGHTY_DARK_FACTOR; gl_FragColor = vec4(baseColor, 1.0) * alpha;}... and see the parameterized result!
...并查看參數(shù)化結(jié)果!
注意事項(xiàng) (Caveats)
The shader’s source code is typically loaded from a .fsh file to a plain NSString
著色器的源代碼通常從.fsh文件加載到純NSString
This code must compile on the target device during the runtime
此代碼必須在運(yùn)行時在目標(biāo)設(shè)備上編譯
no buildtime checks!
沒有構(gòu)建時間檢查!
Older devices may use different version of OpenGL ES so beware GLSL syntax differences!
較舊的設(shè)備可能使用不同版本的OpenGL ES,因此請注意GLSL語法的不同!
In Raft Challenge’s case there was the need to replace
在Raft Challenge的情況下,需要更換
__constant (valid in OpenGL ES 3.0) to const for OpenGL ES 2.0.
__constant (在OpenGL ES 3.0中有效)以const表示OpenGL ES 2.0。
It’s a good idea to keep a reference to SKShader object somewhere and reuse it as frequently as needed to avoid visible frame rate drop
最好在某個地方保留對SKShader對象的引用,并根據(jù)需要重復(fù)使用它,以避免可見的幀速率下降
While allocation and shader compilation takes less than 1/60 sec, it may become a huge burden in render loop
雖然分配和著色器編譯花費(fèi)的時間少于1/60秒,但它可能會成為渲染循環(huán)中的巨大負(fù)擔(dān)
When using SpriteKit’s Texture Atlases be cautious of vtexcoord
使用SpriteKit的Texture vtexcoord謹(jǐn)慎使用vtexcoord
XCode may rotate some textures which swap
XCode可能會旋轉(zhuǎn)一些交換的紋理
X and Y axis
X和Y軸
X and Y axisColor modification is safe, geometry is not
X和Y軸顏色修改是安全的,幾何圖形不是
摘要 (Summary)
We learned by examples how to use fragment shaders in the Sprite Kit. We added parameters to sprites so our shader program can render every instance in a different way without any performance loss.
我們通過示例學(xué)習(xí)了如何在Sprite Kit中使用片段著色器。 我們向精靈添加了參數(shù),以便我們的著色器程序可以以不同的方式呈現(xiàn)每個實(shí)例而不會造成性能損失。
The complete project is available for a download.
完整的項(xiàng)目可下載。
You can read part 3 of this series here.
您可以在這里閱讀本系列的第3部分 。
About the author: Kamil Zi?tek is an iOS Developer at www.allinmobile.co
關(guān)于作者:KamilZi?tek是www.allinmobile.co上的iOS開發(fā)人員
翻譯自: https://www.freecodecamp.org/news/spritekit-advanced-how-to-build-a-2-5d-game-part-ii-30ddb613b568/
advanced east
總結(jié)
以上是生活随笔為你收集整理的advanced east_SpriteKit Advanced —如何构建2,5D游戏(第二部分)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何使用json开发web_如何通过使用
- 下一篇: 实习生解雇_我们解雇了我们的顶尖人才。