私がAndroidでボンバーマンを書いたとき

こんにちは、ハラジテリ。

プログラミングを始めたばかりの頃からゲームを書きたかった。 それで、Androidでゲームを書くことに挑戦しました。

彼はまた、秋にゲームを作り、それを市場に出しました。 確かに、コナミにはボンバーマンの権利があるため、削除されました。 しかし、もちろん、この記事はそれについてではありません。



ゲームの開発と並行して、彼はLibGDXに関するチュートリアルを作成し、人々は常にソースコードの配置を求めました。 それでも、私はそれらを共有し、開発について少し話すことにしました。 誰かがLibGDXの研究を手伝うかもしれません。 記事の下部にあるソースコードを使用して、リポジトリにリンクします。







小さな余談



それ以前は、Javaの経験はなく、Androidの経験もありました。 私は両方の実用的なタスクを勉強することにしました。 純粋なOpenGLで独自のエンジンを記述したくありませんでした。 ゲームを開発するエンジンに大きな違いはありませんでした。 私はLibGDXが好きで、それから始めることにしました。 ですから、あまり厳しく判断しないでください。 特定の計画やTKはありませんでした。 ライブラリを理解したので、彼はゆっくりとゲームを書きました。



建築



アーキテクチャに関しては、MVCが最適であるように思えました。 これについては、 アーキテクチャに関する記事ですでに説明しました



一般的に、すべてが非常にシンプルで明確です。 BomberMan



のメインゲームクラスはGame



から継承されます。 ゲーム自体、メインメニュー、勝利時のウィンドウなど、可能なすべてのゲーム画面へのリンクが含まれています。 setScreen()



メソッドを使用してこれらのクラスを切り替えるだけです。



Viewとして、ScreenインターフェイスとInputProcessorインターフェイスを実装するクラスがあります(これらの間で、 BomberMan



クラスが切り替わります)。 このクラスでは、ユーザーアクションを処理し、オブジェクトをレンダリングします。 オブジェクトの変更とその後のレンダリングは、このクラスの1つのメソッドで行われます。 最初に、必要に応じてオブジェクトの状態を変更し(大まかに言うと、物理学を操作します)、次にレンダリングします:

 @Override public void render(float delta) { controller.update(delta); renderer.render(); }
      
      







コントローラーはモデルで動作することは明らかだと思います。 ほとんどのロジックはその中にあります。 どこにロジックをプッシュすればよいかよくわかりませんでした。 その結果、ロジックの一部がコントローラー自体のオブジェクト(衝突処理)に転送され、爆発、殺害(つまり、オブジェクトが他のオブジェクトに影響を与える必要がある場合)を処理するためのロジックが転送されました。 メッセージを使用してこれを実装するというアイデアがありました。 つまり、各オブジェクトで、メッセージを処理して何らかの形で応答するハンドラーを定義します。 しかし、その後、同期の問題が発生しました。 したがって、すべてを同期的に処理することにしました。

その結果、コントローラーでは、単に世界のすべてのオブジェクトを順番に処理します。

 public void update(float delta) { processInput(); checkBombsTimer(); if(!world.bonus) destroyBricks(); removeDeadNpc(); killByBoom(); removeHiddenObjects(); bomberman.update(delta); for(NpcBase npc : world.getNpcs()){ npc.update(delta); } removeBooms(); }
      
      







モデルを説明するには、図を提供する方が簡単だと思います。





World



は、ブロック、ボーナス、プレイヤー、npcのすべてのオブジェクトを含むコンテナです。 ロジックはありません。 オブジェクト自体にのみ、それらのロジックの一部があります(上で書いたように)。 完全なクラス図は示しませんでした。

すべてのnpcタイプはNpcBaseを継承します。 HiddenObjectからのすべてのオブジェクト(ドア、ボーナス)。



試作機





最初はテクスチャとサテンを扱いました。 最初は、すべてのスプライトは別々のファイルにありました。 その後、すべてを1つのアトラスに結合し、作業を加速しました。 そして問題がありました。 携帯電話(HTC One S)のすべてをAndroid 4.0でテストしました。 以前のバージョンで試してみると、ゲームがクラッシュしました。 判明したように、テクスチャサイズの制限により、古いデバイスは落ちています。 たとえば、1024x1024を超えるスプライトをサポートしなかったものもありました。 さらに、当初、アトラスの寸法は2のべき乗ではなかったため、多くのデバイスで問題が発生しました。



だから:

1)大きすぎる地図を作成しないでください。

2)寸法は2のべき乗でなければなりません。



物事はかなり明白ですが、開発フォーラムをさまよい、多くの人が同様のエラーに苦しんでいました)。 すべてを1つのアトラスに集め、領域の選択とアニメーションの設定方法を見つけた後、衝突の処理を開始しました。



ほとんどのオブジェクトには整数座標があり、それほど頻繁には変化しません。 配列public int[][] map



を定義し、絶えずオブジェクトのリストを実行しないようにアクセスしました。 一番下の行は、すべてのブロックが整数座標上にあるということです。そのため、配列を使用することで速度が向上しました。 物理学を更新するときは、プレーヤー/ npcから周囲のオブジェクトまでの距離を単純に調べます。

次のようなもの:

 if(around[0][1] ==0 && Math.abs(getPosition().x-x1)<SIZE/2 && Math.abs(getPosition().x-x1)>0.05){ if(getPosition().x-x1<0){ getVelocity().x = +speed; getVelocity().y = +speed; } if(getPosition().x-x1>0){ getVelocity().x = -speed; getVelocity().y = +speed; } }
      
      





すっごく間違った決定です。 彼の次のゲームでは、すべての衝突処理はデルタに基づいており、最後のレンダリングから経過した時間を示しています。 しかし、ここではすべてがとても悲しいです= /



NPC



テクスチャと衝突処理を理解した後、ゲームにnpcを追加しました。 本質的に、彼らは行動の3つの戦略のみを持っています:

1)ランダムな方向に移動します。 一定の時間が経過すると、方向がランダムに変わります。

2)全体として最初のように。 しかし、npcがプレーヤーを見ると、プレーヤーは彼に向かって動き始めます。 プレイヤーが視野から消えると、npcは動きの方向をランダムな方向に変更します。

3)一般に、2番目の戦略として。 しかし、プレーヤーの視界を失っても、最後にプレーヤーを見た方向に進みます。



すべての種類のNpcBase



から継承され、メソッドを実装する必要があります。

 public abstract void changeDirection(float delta); public abstract void update(float delta) ;
      
      







GUI



GUIもLibGDXを使用して実装されます。 すべてのインターフェイス要素はクラスの形式で表示され、そのインスタンスはWorld



クラスに含まれています。 各要素のプロパティには座標とサイズがあるため、ユーザーが実際にクリックした要素を画面上のテープで確認できます。



2つの制御方法を実装しました。

1)矢印。



2)ジョイスティック。





設定では、必要なオブジェクトの位置を設定できます。





まとめ



1つの投稿での開発プロセス全体は適合しません。 このエンジンに興味があれば、人々自身が記事のトピックを提案するだろうと思いました。 LibGDXを使用する際の開発の最も興味深い側面、または最も興味深い点について説明します。



ソースをgithubにアップロードしました。

また 、誰かがこのエンジンを使用したい場合は、LibGDXでの私のレッスンを見ることができます



All Articles