ゲームストーリー





この記事では、クロスプラットフォームのCocos2D-xエンジン(v3.1)で2番目のAndroidゲームを作成する方法について説明します。 コードは主にC ++で、一部の場所ではJavaとLuaです。 開発の主なポイントについて簡単に説明しようと思います。





エントリー



私が真剣にこの業界に参入することを決めてからちょうど1年が経ちました。 その後、モバイルプラットフォームの開発は非常に有望であるように思われ、そのような比較的単純なゲームの開発は単純です。 プログラミングとグラフィックスのスキルがほとんどない18歳の学生として、大きな野望を抱いていた私は、自分自身の何か、巨大で完璧な何かをしたかったのです。 現実はすぐに整ったので、小さなことをするが、私の経験とスキルを最大限に活用することにしました。 時間制限の欠如と自分自身に対する責任の欠如は、ゲームの開発を拡大し、Google Playへのアクセスは現在(2014年)の3月末にすでに行われました。 さまざまなフォーラムでの非常に暖かいレビューにもかかわらず、結果はまったく満足していませんでした-全体で200ダウンロード、広告ごとに約0.30€。



最初のパンケーキはゴツゴツしている








失望は興奮だけを追加しました。 失敗を分析し、少しの文献を読んだ後、1​​か月半後に、1か月または2か月の開発に投資する簡単なものを書くことにしました。 すぐに言ってやった! パズルを作りたかった。 ゲームの本質は、画像と画像要素が異なる形式(たとえば、半透明と反転)で与えられ、簡単な操作でそれらを配置する必要があることです。



最初のレベル






Cocos2D-x



Cocos2D-x-iOS用の人気のあるエンジンのポート。 無料でクロスプラットフォーム。 携帯端末向けのゲームの作成を開始するだけで、選択するエンジンがわからない場合は、必ずオプションとして検討してください。



主な利点:





完全なドキュメントとレッスンが不足しているため、エンジンでの作業の開始が複雑になりますが、一般的に非常に優れていることが判明しました。 さらに、コミュニティはその機能とドキュメントを常に拡大しています。 OpenGL ES関数を直接呼び出すことができるため、ほとんどすべての複雑な2Dゲームを作成できます。



興味がある人は、「Hello、world!」と要点の作成に関する小さなチュートリアルを書くことができます。



コンセプト



したがって、前述のように、ゲームのコンセプトは、画像が与えられ、その一部(要素)が異なる場所に散らばることです。 プレーヤーのタスクは、すべての要素を適切な場所に配置することです。 要素にはさまざまなプロパティを設定できます。たとえば、回転、透明度、サイズ変更などです。 異なるフォームと異なる動作を作成する機能も必要です。



回転レベルの例






設計



プロのデザイナーを雇う機会はありません。 不必要な詳細なしに、設計をできるだけシンプルにすることが決定され、私はこのタスクに適切に対処したように思えます。



レベル選択メニュー




レベル補完
左側-レベル選択メニューを終了し、中央-画像名と作成者、右側-次のレベルに移動します。









レベルの1つのスクリーンショットを、Google Playおよびアプリケーション自体のアイコンとして使用しました。

あらゆる種類のアイコン






レベル実装



説明から明らかなように、主なタスクは、問題なく再コンパイルせずに異なるレベルを作成でき、同時に異なるタイプの要素を作成するのに十分な柔軟性を維持できるようなコードを作成することです。 これらの目的のために、XMLとLuaが選択されました。 XMLは、要素のレベル、位置、写真上の位置、形状、透明度、サイズなどを記述します。 また、Luaで記述されたコードを挿入できるタグもあります。



XMLのレベルの1つを記述する例
<level pack="1" id="9"> <element shape="circle2.png" x="-196" y="124" texx="-196" texy="124" width="100" height="" rotation="100"> <onCreate> e4Opacity = 5 e4BeginOpacityAnimation = false element:setOpacity(e4Opacity) </onCreate> <onTouchMovedFunction> local dX = touch:getLocation().x - touch:getPreviousLocation().x local dY = touch:getLocation().y - touch:getPreviousLocation().y local scale = level:getScale() element:setRotation(element:getRotation() + dX / 2 / scale+ dY / 2 / scale) </onTouchMovedFunction> <onUpdateFunction> if not e4BeginOpacityAnimation then return end if 150 > e4Opacity then e4Opacity = e4Opacity + 1 element:setOpacity(e4Opacity) end </onUpdateFunction> <onDestroy> e4Opacity = nil e4BeginOpacityAnimation = nil </onDestroy> </element> <element shape="square2.png" x="-359" y="-177" texx="-359" texy="-177" width="100" height="" rotation="180"> <onCreate> e3Opacity = 5 e3BeginOpacityAnimation = false element:setOpacity(e3Opacity) </onCreate> <onTouchMovedFunction> local dX = touch:getLocation().x - touch:getPreviousLocation().x local dY = touch:getLocation().y - touch:getPreviousLocation().y local scale = level:getScale() element:setRotation(element:getRotation() + dX / 2 / scale+ dY / 2 / scale) </onTouchMovedFunction> <onUpdateFunction> if not e3BeginOpacityAnimation then return end if 150 > e3Opacity then e3Opacity = e3Opacity + 1 element:setOpacity(e3Opacity) end </onUpdateFunction> <onDestroy> e3Opacity = nil e3BeginOpacityAnimation = nil e4BeginOpacityAnimation = true </onDestroy> </element> <element shape="triangle2.png" x="319" y="69" texx="319" texy="69" width="150" height="" rotation="180"> <onCreate> e2Opacity = 5 e2BeginOpacityAnimation = false element:setOpacity(e2Opacity) </onCreate> <onTouchMovedFunction> local dX = touch:getLocation().x - touch:getPreviousLocation().x local dY = touch:getLocation().y - touch:getPreviousLocation().y local scale = level:getScale() element:setRotation(element:getRotation() + dX / 2 / scale+ dY / 2 / scale) </onTouchMovedFunction> <onUpdateFunction> if not e2BeginOpacityAnimation then return end if 150 > e2Opacity then e2Opacity = e2Opacity + 1 element:setOpacity(e2Opacity) end </onUpdateFunction> <onDestroy> e2Opacity = nil e2BeginOpacityAnimation = nil e3BeginOpacityAnimation = true </onDestroy> </element> <element shape="waves.png" x="311" y="-227" texx="-365" texy="30" width="200" height="0"> <onCreate> e1Opacity = 10 e1BeginOpacityAnimation = false element:setOpacity(e1Opacity) </onCreate> <onTouchBeganFunction>e1BeginOpacityAnimation = true</onTouchBeganFunction> <onTouchMovedFunction> local dY = touch:getLocation().y - touch:getPreviousLocation().y local dX = touch:getLocation().x - touch:getPreviousLocation().x local scale = level:getScale() element:setPosition(element:getPositionX() + dX / scale, element:getPositionY() + dY / scale) </onTouchMovedFunction> <onUpdateFunction> if not e1BeginOpacityAnimation then return end if 200 > e1Opacity then e1Opacity = e1Opacity + 2 element:setOpacity(e1Opacity) end </onUpdateFunction> <onDestroy> e1Opacity = nil e1BeginOpacityAnimation = nil e2BeginOpacityAnimation = true </onDestroy> </element> <element x="-50" y="50" texx="300" texy="50" width="100" height="100"> <onTouchMovedFunction> local dY = touch:getLocation().y - touch:getPreviousLocation().y local dX = touch:getLocation().x - touch:getPreviousLocation().x local scale = level:getScale() element:setPosition( element:getPositionX() + dX / scale, element:getPositionY() + dY / scale) </onTouchMovedFunction> </element> <element x="50" y="50" texx="-300" texy="-50" width="100" height="100"> <onTouchMovedFunction> local dY = touch:getLocation().y - touch:getPreviousLocation().y local dX = touch:getLocation().x - touch:getPreviousLocation().x local scale = level:getScale() element:setPosition( element:getPositionX() + dX / scale, element:getPositionY() + dY / scale) </onTouchMovedFunction> </element> <element x="-50" y="-50" texx="-400" texy="-100" width="100" height="100"> <onTouchMovedFunction> local dY = touch:getLocation().y - touch:getPreviousLocation().y local dX = touch:getLocation().x - touch:getPreviousLocation().x local scale = level:getScale() element:setPosition( element:getPositionX() + dX / scale, element:getPositionY() + dY / scale) </onTouchMovedFunction> </element> <element x="50" y="-50" texx="400" texy="-100" width="100" height="100"> <onTouchMovedFunction> local dY = touch:getLocation().y - touch:getPreviousLocation().y local dX = touch:getLocation().x - touch:getPreviousLocation().x local scale = level:getScale() element:setPosition( element:getPositionX() + dX / scale, element:getPositionY() + dY / scale) </onTouchMovedFunction> </element> </level>
      
      









Luaを使用すると、次のような関数を作成できます。





要素自体、要素スプライト、フォームスプライト、レベル、レベルスプライトなどの変数が各関数に転送されます。 「onTouch」機能は、「Touch」タイプの変数も転送します。この変数には、タッチ位置や以前の位置などのデータが含まれています。 Cocos2D-xはLuaをサポートしているため、Cocos2D-xの関数とオブジェクトを直接操作して、引数として渡すことができます。 このようなレベルの実装は、非常に効果的で非常に柔軟であることが判明しました(たとえば、要素をクリックするか、他の要素を制御することでゲームを閉じることもできるため)。



Cocos2D-x上の要素のLua関数を呼び出す実装は、次のようになります(要素が作成されるときに呼び出されるonCreate関数を使用)。

非表示のテキスト
 if (!m_scriptFunctionOnCreate.empty()) { LuaEngine* engine = LuaEngine::getInstance(); LuaStack* luaS = engine->getLuaStack(); luaS->executeString(m_scriptFunctionOnCreate.c_str()); lua_getglobal(luaS->getLuaState(), "onCreate"); luaS->pushObject(this, "cc.Node"); // element luaS->pushObject(m_sprite, "cc.Sprite"); // element sprite if (m_shapeMaskSprite != nullptr) { luaS->pushObject(m_shapeMaskSprite, "cc.Sprite"); // shape } else { luaS->pushNil(); } luaS->pushObject(getParent(), "cc.Node"); // level luaS->pushObject(((Level*)getParent())->getLevelSprite(), "cc.Sprite"); // levelSprite lua_call(luaS->getLuaState(), 5, 0); luaS->clean(); }
      
      









結論の代わりに



このゲームを作成する主な目標はむしろ「やること」でした。そのため、成功する見込みはありません。 おそらく近い将来、ソースコードを投稿して無料でアクセスできるようになるでしょう。

興味深い場合は、次の記事でAdMobとGoogleアナリティクスをCocos2D-xで記述されたゲームに接続する方法について説明します。



All Articles