サイトのトップへ戻る

Cocos2d-x ドキュメント 日本語訳

サイト内検索

高度なテーマ

なんと! 最後の章まで来ました。素晴らしい! そろそろ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リクエストを使うことがあります。

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]);
  }
}


Shaders と Materials



Shaderとは何か

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: 基本的には、 これが シェーダーです。 これには頂点とフラグメントシェーダーが含まれています。
  • そしてstate。これは、基本的にはシェーダーの uniforms です。

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 ファイルから作成します。このファイルには以下の情報が含まれています。:

  • Material は複数の Techniqueオブジェクトの情報を持ちます
  • Technique は複数の Pass オブジェクトの情報を持ちます
  • Pass オブジェクトは以下の情報を持ちます:
    • RenderState オブジェクト
    • uniformsを含んだ 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
            }
        }
    }
}

そして以下は、MaterialSprite3Dへ設定する方法です:

Material* material = Material::createWithFilename("Materials/3d_effects.material");
sprite3d->setMaterial(material);

そして他の Techniqueへ切り替えをしたい場合は、以下を行う必要があります:

material->setTechnique("normal");


Techniques

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.



Passes

Technique は複数の passes、すなわちマルチパスレンダリングを持つことが出来ます。 そして各 Pass は二つのメインオブジェクトを持ちます:

  • RenderState: depthTestcullFacestencilTestなどのような、GPU の状態情報を保持します。
  • GLProgramState: 使用されるシェーダー (GLProgram) を保持します。その uniformsの情報も含みます。


Material ファイル形式の詳細

Material はMaterial ファイルを作成するのに最適化されたファイル形式を使用します。 このファイル形式は、GamePlay3Dのファイル形式やOGRE3Dのフィル形式といった他の既存のMaterial ファイル形式と非常に似ています。

Notes:

  • Material ファイルの拡張子は重要ではありません。ですが、拡張子としては.material を使用することを推奨します
  • material、 technique、 passにidを設定するかは任意です。
  • Materialsは必要に応じてparent_material_idを設定することで、他のmaterial から値を継承することができます
  • Vertex ファイル拡張子と fragment shader ファイル拡張子はどちらでも構いません。Cocos2d-xの慣習としては .vert.fragの拡張子を使用します
// 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_MIN_FILTER_ENUM  
NEAREST Lowest quality non-mipmapped
LINEAR Better quality non-mipmapped
NEAREST_MIPMAP_NEAREST Fast but low quality mipmapping
LINEAR_MIPMAP_NEAREST  
NEAREST_MIPMAP_LINEAR  
LINEAR_MIPMAP_LINEAR Best quality mipmapping
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:

  • scalar is float, int or bool.
  • vector は、コンマで区切られた floatのリストです。


あらかじめ定義されている uniforms

以下はCocos2d-xで使用されるあらかじめ定義された uniforms です。これらを shadersに使用することができます:

  • CC_PMatrix: A mat4 with the projection matrix
  • CC_MVMatrix: A mat4 with the Model View matrix
  • CC_MVPMatrix: A mat4 with the Model View Projection matrix
  • CC_NormalMatrix: A mat4 with Normal Matrix
  • CC_Time: a vec4 with the elapsed time since the game was started
  • CC_Time[0] = time / 10;
  • CC_Time[1] = time;
  • CC_Time[2] = time * 2;
  • CC_Time[3] = time * 4;
  • CC_SinTime: a vec4 with the elapsed time since the game was started:
  • CC_SinTime[0] = time / 8;
  • CC_SinTime[1] = time / 4;
  • CC_SinTime[2] = time / 2;
  • CC_SinTime[3] = sinf(time);
  • CC_CosTime: a vec4 with the elapsed time since the game was started:
  • CC_CosTime[0] = time / 8;
  • CC_CosTime[1] = time / 4;
  • CC_CosTime[2] = time / 2;
  • CC_CosTime[3] = cosf(time);
  • CC_Random01: A vec4 with four random numbers between 0.0f and 1.0f
  • CC_Texture0: A sampler2D
  • CC_Texture1: A sampler2D
  • CC_Texture2: A sampler2D
  • CC_Texture3: A sampler2D


あなたのCocos2d-x 製ゲームのグラフィックスパフォーマンスを最適化する方法



黄金律



ボトルネックを知ってそれを最適化する。

最適化を行う時、常にパレートの法則 (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

多くの場合、CPU はdrawの呼び出し回数やゲームループ内での重い演算処理によって制限を受けます。 ゲームでのdraw 呼び出しの総数は最小限に抑えるようにしてください。 可能な限り batch draw を使用しましょう。 Cocos2d-x 3.x では自動 batch をサポートしていますが、それを動作させるにはいくつかの作業が必要です。

また、プレイヤーがゲームをプレイしている時には入出力操作は避けるようにしてください。スプライトシートや音声やTTF フォントなどは事前に読み込んでおくようにしてください。

また、ゲームループ内で重い演算処理を行わないようにしてください。要するに、フレーム毎に重い処理を60回呼び出すようなことはしないでください。

絶対に駄目です!



GPU はしばしば overdraw(フィルレート)と帯域幅によって制限されます。

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

しかし、この問題についてそんなに心配はしないでください。実際のところは、パフォーマンスがそこまで酷くなるわけではありません。



Cocos2d-x ゲームを素早く作成するための簡単なチェックリスト

  1. 常に一括描写を使用します。 同レイヤーの sprite 画像を一つの大きな atlasにまとめます(Texture packer を使うと楽です)。
  2. 経験則として、draw の呼び出しは 50回以下に抑えるようにします。言い換えれば、draw 呼び出し回数は最小限に抑えるようにしてください。
  3. RAW 32bit(RGBA8888) テクスチャではなく 16bit(RGBA4444+ディザリング)を使用した方が良いです。
  4. 圧縮したテクスチャを使用します: iOS では PVRTC テクスチャを使用します。Android プラットフォームでは ETC1を使用します。 しかし、ETC1 はアルファ値を持っておらず、 カスタムシェーダーを記述してアルファチャンネル用の個別のETC1 画像を提供する必要があります。
  5. ゲームのスコアカウンターとしてシステムフォントを使用しないでください。システムフォントは遅いです。TTF かBMFontを使うようにしてください。どちらかといえば BMfont が良いでしょう。
  6. 音声やその他ゲームオブジェクトは、使用する前にあらかじめ読み込んでおくようにしてください。
  7. armeabi-v7a 使って Android ネイティブコードをビルドしてください。それで非常に高速な neon instructors が有効になります。
  8. Bake the lighting rather than using the dynamic light.
  9. 複雑なピクセルシェーダーの使用は避けてください。
  10. ピクセルシェーダーで discard と alpha test の使用は避けてください。HSR(隠面除去)が壊されてしまいます。必要な時のみ使用してください。