なんと! 最後の章まで来ました。素晴らしい! そろそろCocos2d-xでのゲーム作成を快適に感じてきたのではないでしょうか。 しかし、作成できるものに制限はないということを理解してください。 この章では 高度な コンセプトについて説明しています。 この章の内容と形式はより技術的なものになるので注意してください。
stdio.hの 関数を使ってファイルにアクセスできますが、 この方法はいくつかの理由により不便です。: ファイルのフルパスを取得するのにシステム固有のAPIを実行する必要があります。 インストールした後、リソースはAndroidの.apkファイルに一纏めにされます。 * あなたは解像度に基づいて自動的にリソース(写真のような)を読み込みたいでしょう。
FileUtils
クラスはこうした問題を解決するために作成されました。
FileUtils
とは、Resources
ディレクトリ配下にあるファイルにアクセスするのを助けてくれるクラスです。
これには、ファイルからデータを読み込んだり、ファイルが存在するかどうかを確認したりする機能があります。
これらの関数は異なるファイルのファイルを読み込み、異なるデータ型を戻り値として返します:
関数名 | 戻り値の型 | サポートしているパスタイプ |
---|---|---|
getStringFromFile | std::string | 相対パスと絶対パス |
getDataFromFile | cocos2d::Data | 相対パスと絶対パス |
getFileDataFromZip | unsigned char* | 絶対パス |
getValueMapFromFile | cocos2d::ValueMap | 相対パスと絶対パス |
getValueVectorFromFile | std::string | cocos2d::ValueVector |
これらの関数はファイルやディレクトリを管理します:
関数名 | サポートしているパスタイプ |
---|---|
isFileExist | 相対パスと絶対パス |
isDirectoryExist | 相対パスと絶対パス |
createDirectory | 絶対パス |
removeDirectory | 絶対パス |
removeFile | 絶対パス |
renameFile | 絶対パス |
getFileSize | 相対パスと絶対パス |
時には、他のソースからリソースやデータを取得することがゲーム制作で役立つかもしれません。
これを行うために一般的な方法の一つに、 HTTP
リクエストを使うことがあります。
HTTP ねっどワーク処理には三つのステップがあります:
1. HttpRequest
を作成する
2. リクエストに応答するための setResponseCallback() コールバック関数を作成する
3. HttpClient
を使って HttpRequest
を送信する
HttpRequest
は、 POST, PUT, DELETE, UNKNOWNの四つのタイプを持ちます。
何も指定しなかった場合、既定のタイプはUNKNOWNとなります。
HTTPClient
オブジェクトはrequest の送信とコールバック上でのデータの受信を制御します。
HTTPRequest
を使って処理を行う簡単な例です:
HttpRequest* request = new (std :: nothrow) HttpRequest();
request->setUrl("http://just-make-this-request-failed.com");
request->setRequestType(HttpRequest::Type::GET);
request->setResponseCallback(CC_CALLBACK_2 (HttpClientTest::onHttpRequestCompleted, this));
HttpClient::getInstance()->sendImmediate(request);
request->release();
応答を受け取った時のためにsetResponseCallback()メソッドを設定していることに注目してください。 これを行うことで、戻ってきたデータを見て必要な場合にはそのデータを使用することが出来ます。 また、この処理はシンプルで、簡単に行うことが出来ます:
void HttpClientTest::onHttpRequestCompleted(HttpClient* sender, HttpResponse* response)
{
if (!response)
{
return;
}
// Dump the data
std::vector<char>* buffer = response->getResponseData();
for (unsigned int i = 0; i <buffer-> size (); i ++)
{
log ("% c", (* buffer) [i]);
}
}
wikipediaより引用:
コンピューターグラフィックスの分野では、 shader とはシェーディングを行うために使用されるコンピュータープログラムのことです: シェーディングとは、画像内における適切なレベルの色の生成、現代においては特殊効果の生成や映像のポスト処理などです。 一般的な用語における定義は、「具体的かつ特殊な方法で、コンピューターにどのような描写を行わせるかを指示するプログラム」でしょうか。
言い換えれば、GPU (CPUではありません)上で動作して各 Cocos2d-xノードを描写するコードのことです。
Cocos2d-x はシェーダーに OpenGL ES Shading Language v1.0を使用しています。 しかし GLSL 言語の記述についてはこの文書の範疇ではありません。 GLSL 言語についてもっと学ぶためには、OpenGL ES Shading Language v1.0 Specを参照してください。
Cocos2d-xでは、 描写可能な全ての Node
オブジェクトはシェーダを使用します。
例として、Sprite
は 2d sprites用に最適化されたシェーダーを使用し、 Sprite3D
は3dオブジェクト用に最適化されたシェーダーを使用している、など。
Cocos2d-xの Node
上から以下を実行することで、ユーザーはあらかじめ定義されたシェーダーに変更できます:
sprite->setGLProgramState(programState);
sprite3d->setGLProgramState(programState);
このGLProgramState
オブジェクトは二つの重要なものを含んでいます。:
GLProgram
: 基本的には、 これが シェーダーです。 これには頂点とフラグメントシェーダーが含まれています。uniformという用語に聞き馴染みが無く、それがなぜ必要かをあまり知らない場合は、OpenGL Shading Language Specificationを参照してください。
GLProgramState
にuniforms を設定するのは以下のように簡単にできます:
glProgramState->setUniformFloat("u_progress", 0.9);
glProgramState->setUniformVec2("u_position", Vec2(x,y));
glProgramState->setUniformMat4("u_transform", matrix);
uniform 値にはコールバックを設定することもできます:
glProgramState->setUniformCallback("u_progress", [](GLProgram* glProgram, Uniform* uniform)
{
float random = CCRANDOM_0_1();
glProgram->setUniformLocationWith1f(uniform->location, random);
}
);
また、GLProgramState
オブジェクトを手動で設定することは可能ですが、より簡単な方法は Material
オブジェクトを使うことです。
あなたは、以下のような球体を描写したいとします:
最初にしなければならないのは、以下のようなジオメトリを定義することです。:
...それから以下のようなレンガのテクスチャを定義します。:
その回答は、平易で簡単なテクスチャの代わりにMaterial
を使うことです。
実際Material
を使用すれば、複数のテクスチャを持ち、マルチパスレンダリングのようなより多くの機能を持つことが出来ます。
Material
オブジェクトは .material
ファイルから作成します。このファイルには以下の情報が含まれています。:
Material
は複数の Technique
オブジェクトの情報を持ちますTechnique
は複数の Pass
オブジェクトの情報を持ちますPass
オブジェクトは以下の情報を持ちます:RenderState
オブジェクトShader
オブジェクト例として、以下は material ファイルがどのようなものかです:
// A "Material" file can contain one or more materials
material spaceship
{
// A Material contains one or more Techniques.
// In case more than one Technique is present, the first one will be the default one
// A "Technique" describes how the material is going to be renderer
// Techniques could:
// - define the render quality of the model: high quality, low quality, etc.
// - lit or unlit an object
// etc...
technique normal
{
// A technique can contain one or more passes
// A "Pass" describes the "draws" that will be needed
// in order to achieve the desired technique
// The 3 properties of the Passes are shader, renderState and sampler
pass 0
{
// shader: responsible for the vertex and frag shaders, and its uniforms
shader
{
vertexShader = Shaders3D/3d_position_tex.vert
fragmentShader = Shaders3D/3d_color_tex.frag
// uniforms, including samplers go here
u_color = 0.9,0.8,0.7
// sampler: the id is the uniform name
sampler u_sampler0
{
path = Sprite3DTest/boss.png
mipmap = true
wrapS = CLAMP
wrapT = CLAMP
minFilter = NEAREST_MIPMAP_LINEAR
magFilter = LINEAR
}
}
// renderState: responsible for depth buffer, cullface, stencil, blending, etc.
renderState
{
cullFace = true
cullFaceSide = FRONT
depthTest = true
}
}
}
}
そして以下は、Material
を Sprite3D
へ設定する方法です:
Material* material = Material::createWithFilename("Materials/3d_effects.material");
sprite3d->setMaterial(material);
そして他の Technique
へ切り替えをしたい場合は、以下を行う必要があります:
material->setTechnique("normal");
Since you can bind only one Material
per Sprite3D
, an additional feature
is supported that's designed to make it quick and easy to change the way you
render the parts at runtime. You can define multiple techniques by giving them
different names. Each one can have a completely different rendering technique,
and you can even change the technique being applied at runtime by using
Material::setTechnique(const std::string& name). When a material is loaded,
all the techniques are loaded ahead too. This is a practical way of handling
different light combinations or having lower-quality rendering techniques, such
as disabling bump mapping, when the object being rendered is far away from the
camera.
Technique
は複数の passes、すなわちマルチパスレンダリングを持つことが出来ます。
そして各 Pass
は二つのメインオブジェクトを持ちます:
RenderState
: depthTestや cullFaceやstencilTestなどのような、GPU の状態情報を保持します。GLProgramState
: 使用されるシェーダー (GLProgram
) を保持します。その uniformsの情報も含みます。Material はMaterial ファイルを作成するのに最適化されたファイル形式を使用します。 このファイル形式は、GamePlay3Dのファイル形式やOGRE3Dのフィル形式といった他の既存のMaterial ファイル形式と非常に似ています。
Notes:
// When the .material file contains one material
sprite3D->setMaterial("Materials/box.material");
// When the .material file contains multiple materials
sprite3D->setMaterial("Materials/circle.material#wood");
material material_id : parent_material_id | ||
{ | ||
renderState {} | [0..1] | block |
technique id {} | [0..*] | block |
} |
technique technique_id | ||
{ | ||
renderState {} | [0..1] | block |
pass id {} | [0..*] | block |
} |
pass pass_id | ||
{ | ||
renderState {} | [0..1] | block |
shader {} | [0..1] | block |
} |
renderState | ||
{ | ||
blend = false | [0..1] | bool |
blendSrc = BLEND_ENUM | [0..1] | enum |
blendDst = BLEND_ENUM | [0..1] | enum |
cullFace = false | [0..1] | bool |
depthTest = false | [0..1] | bool |
depthWrite = false | [0..1] | bool |
} | ||
frontFace = CW | CCW | [0..1] | enum |
depthTest = false | [0..1] | bool |
depthWrite = false | [0..1] | bool |
depthFunc = FUNC_ENUM | [0..1] | enum |
stencilTest = false | [0..1] | bool |
stencilWrite = 4294967295 | [0..1] | uint |
stencilFunc = FUNC_ENUM | [0..1] | enum |
stencilFuncRef = 0 | [0..1] | int |
stencilFuncMask = 4294967295 | [0..1] | uint |
stencilOpSfail = STENCIL_OPERATION_ENUM | [0..1] | enum |
stencilOpDpfail = STENCIL_OPERATION_ENUM | [0..1] | enum |
stencilOpDppass = STENCIL_OPERATION_ENUM | [0..1] | enum |
shadershader_id | ||
{ | ||
vertexShader = res/colored.vert | [0..1] | file path |
fragmentShader = res/colored.frag | [0..1] | file path |
defines = semicolon separated list | [0..1] | string |
uniform_name = scalar | vector | [0..*] | uniform |
uniform_name = AUTO_BIND_ENUM | [0..*] | enum |
sampler uniform_name {} | [0..*] | block |
} |
sampler uniform_name | ||
{ | ||
path = res/wood.png | @wood | [0..1] | image path |
mipmap = bool | [0..1] | bool |
wrapS = REPEAT | CLAMP | [0..1] | enum |
wrapT = REPEAT | CLAMP | [0..1] | enum |
minFilter = TEXTURE_MIN_FILTER_ENUM | [0..1] | enum |
magFilter = TEXTURE_MAG_FILTER_ENUM | [0..1] | enum |
} |
Enums:
TEXTURE_MAG_FILTER_ENUM | |
---|---|
NEAREST | Lowest quality |
LINEAR | Better quality |
BLEND_ENUM | |
---|---|
ZERO | ONE_MINUS_DST_ALPHA |
ONE | CONSTANT_ALPHA |
SRC_ALPHA | ONE_MINUS_CONSTANT_ALPHA |
ONE_MINUS_SRC_ALPHA | SRC_ALPHA_SATURATE |
DST_ALPHA |
CULL_FACE_SIDE_ENUM | |
---|---|
BACK | Cull back-facing polygons. |
FRONT | Cull front-facing polygons. |
FRONT_AND_BACK | Cull front and back-facing polygons. |
FUNC_ENUM | |
---|---|
NEVER | ALWAYS |
LESS | GREATER |
EQUAL | NOTEQUAL |
LEQUAL | GEQUAL |
STENCIL_OPERATION_ENUM | |
---|---|
KEEP | REPLACE |
ZERO | INVERT |
INCR | DECR |
INCR_WRAP | DECR_WRAP |
Types:
以下はCocos2d-xで使用されるあらかじめ定義された uniforms です。これらを shadersに使用することができます:
CC_PMatrix
: A mat4
with the projection matrixCC_MVMatrix
: A mat4
with the Model View matrixCC_MVPMatrix
: A mat4
with the Model View Projection matrixCC_NormalMatrix
: A mat4
with Normal MatrixCC_Time
: a vec4
with the elapsed time since the game was startedCC_SinTime
: a vec4
with the elapsed time since the game was started:CC_CosTime
: a vec4
with the elapsed time since the game was started:CC_Random01
: A vec4
with four random numbers between 0.0f and 1.0fCC_Texture0
: A sampler2D
CC_Texture1
: A sampler2D
CC_Texture2
: A sampler2D
CC_Texture3
: A sampler2D
最適化を行う時、常にパレートの法則 (80–20の法則として知られる)を念頭に置くようにしてください。 この場合、パフォーマンス問題のうち80%はたった20%のコードが原因で発生しています。
グラフィックスパフォーマンスを調査するのに使用できるツールはたくさんあります。 あなたがAndroidのゲーム開発を行っていたとしても、OS X搭載のMac を持っているのであればXCode もデバッグの助けとなります。 Xcode Profile ツールでOpenGL ESをデバッグすると公式のApple の文書はどちらも素晴らしい記事なので読んでおいて下さい。
現在、主要なモバイル GPU ベンダーは三社あり、その三社は優れたグラフィックスプロファイリングツールを提供しています。:
グラフィックスパフォーマンスの問題で困った場合はこれらのツールを使用してください。 あなたが対象とする端末の CPU/GPUファミリーを知ることは重要です。 時には、パフォーマンス問題は特定の端末でのみ発生することがあります。 You might find they share the same kind of GPU. パフォーマンス問題を追跡する場合は、そのシステムの全ての面を考慮することが重要です。 グラフィックスパフォーマンス問題はGPUではなくCPUが原因の場合もあることを覚えておいて下さい。
多くの場合、CPU はdrawの呼び出し回数やゲームループ内での重い演算処理によって制限を受けます。 ゲームでのdraw 呼び出しの総数は最小限に抑えるようにしてください。 可能な限り batch draw を使用しましょう。 Cocos2d-x 3.x では自動 batch をサポートしていますが、それを動作させるにはいくつかの作業が必要です。
また、プレイヤーがゲームをプレイしている時には入出力操作は避けるようにしてください。スプライトシートや音声やTTF フォントなどは事前に読み込んでおくようにしてください。
また、ゲームループ内で重い演算処理を行わないようにしてください。要するに、フレーム毎に重い処理を60回呼び出すようなことはしないでください。
絶対に駄目です!
2D ゲームを作成していて複雑なシェーダーを記述していない場合は、GPU の問題に困らされることはないかもしれません。 しかしoverdraw 問題のトラブルの可能性はまだ残っており、それにより帯域幅が大量に消費されてグラフィックスパフォーマンスが低下することがあります。
現代のモバイルGPU は TBDR(タイルベース遅延レンダリング) アーキテクチャを搭載していますが、PowerVRの HSR(隠面消去)のみがoverdraw 問題を大幅に減少させることが出来ます。 他のGPU ベンダーは TBDR と Early-Z テストのみ実装しており、これだと不透明のジオメトリを順番どおり(前から後ろの順)に送信した場合のみoverdraw 問題を減少させます。 しかもCocos2d-xでは常に後ろから前の順に描写コマンドを送信します。 なぜなら、 2Dゲームでは多くの透明な画像を使う可能性があり、この順番で描写しないとブレンド処理が正しく行えないからです。
メモ: poly trianglesを使用することで、このフィルレートを向上させることが出来ます。詳細情報については以下の記事を参照してください: https://www.codeandweb.com/texturepacker/tutorials/cocos2d-x-performance-optimization
しかし、この問題についてそんなに心配はしないでください。実際のところは、パフォーマンスがそこまで酷くなるわけではありません。