この「ゲーム」を書いたとき、スプライトのループについて多くの質問がありました。一定時間後に表示されるようになりました。2つのスプライトの衝突の検出などにも問題がありました。インターネットでは、質問に対する通常の答えが見つからず、自分でやらなければなりませんでした。 この投稿は何のふりもしていません。Android向けのゲーム開発は初めてで、この業界の初心者向けに書いています。 誰が面白くなったのか、猫をお願いします。
問題文:
ゲームは、忍者と幽霊がいるフィールド(シーン)である必要があります。 忍者は、これらの幽霊を攻撃することで、これらの幽霊から基地を守る必要があります。
このようなゲームの例は、 Android Market'eで見ることができます。 私は強く手を振ったが、私たちは同様の考えしか持たないだろう。
ゲームは次のようになります。
![画像](https://habrastorage.org/getpro/habr/post_images/896/7b6/ca9/8967b6ca914c9adb68ebc0bc4b938d4c.jpg)
開発開始
プロジェクトを作成します。 Eclipseの起動-ファイル-Androidプロジェクト-防御-Main.java
Main.javaファイルを開き、すべてのコードを以下のコードに変更します。
Main.java
public class Main extends Activity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // , setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE); // , getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN); // requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(new GameView(this)); } }
以下のコードは、メイン関数に、テーマの* .xmlファイルではなく、シーン自体であるクラスを実行する必要があることを伝えています。
setContentView(new GameView(this));
次に、すべてのオブジェクトが描画されるメインクラスとして機能するGameView.javaクラスを作成する必要があります。 また、このクラスにはストリームがあります。このストリームでは、ストリーム内のオブジェクトの描画が処理され、プロセッサのゲーム負荷が軽減されます。 ステージで何も起こらない場合、クラスは次のようになります。
Gameview.java
import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Random; import towe.def.GameView.GameThread; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Color; import android.view.MotionEvent; import android.view.SurfaceHolder; import android.view.SurfaceView; public class GameView extends SurfaceView { /** GameLoopThread*/ private GameThread mThread; public int shotX; public int shotY; /** */ private boolean running = false; //-------------Start of GameThread--------------------------------------------------\\ public class GameThread extends Thread { /** */ private GameView view; /** */ public GameThread(GameView view) { this.view = view; } /** */ public void setRunning(boolean run) { running = run; } /** , */ public void run() { while (running) { Canvas canvas = null; try { // Canvas- canvas = view.getHolder().lockCanvas(); synchronized (view.getHolder()) { // onDraw(canvas); } } catch (Exception e) { } finally { if (canvas != null) { view.getHolder().unlockCanvasAndPost(canvas); } } } } } //-------------End of GameThread--------------------------------------------------\\ public GameView(Context context) { super(context); mThread = new GameThread(this); /* */ getHolder().addCallback(new SurfaceHolder.Callback() { /*** */ public void surfaceDestroyed(SurfaceHolder holder) { boolean retry = true; mThread.setRunning(false); while (retry) { try { // mThread.join(); retry = false; } catch (InterruptedException e) { } } } /** */ public void surfaceCreated(SurfaceHolder holder) { mThread.setRunning(true); mThread.start(); } /** */ public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { } }); } /** */ protected void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE); } }
コメントから、どの機能が何をするのかが明確であることを願っています。 このクラスは基本的なものであるため、ゲーム内で発生するすべてのアクション(機能)を実行しますが、最初にさらにいくつかのクラスを実行する必要があります。
スプライト作成
スプライトは、動き回る2Dゲームの小さな写真です。 それは、男性、弾薬、さらには雲です。 このゲームでは、3種類のスプライトを使用します。Ninja
![画像](https://habrastorage.org/getpro/habr/post_images/f94/0d4/701/f940d4701623ffb88b4806b90aa0a4e6.png)
![画像](https://habrastorage.org/getpro/habr/post_images/1ed/61a/788/1ed61a788d9f7fd91746e3a041b32744.png)
![画像](https://habrastorage.org/getpro/habr/post_images/b25/048/e4d/b25048e4d28a878808bdfa9c8ddd48f7.png)
今はアニメーション化されていないスプライトを使用しますが、今後はプロジェクトにスプライトを挿入します。スプライトの作成方法に興味がある場合は、Android向けゲームの作成に関する2番目のレッスンでお願いします。
次に、これらの画像をres / drawableフォルダーにアップロードして、Eclipseがこれらの画像を表示してプロジェクトに貼り付けられるようにします。
次の図は、プレーヤーが画面上でどのように配置されるかを視覚的に理解するのに役立ちます。
![画像](https://habrastorage.org/getpro/habr/post_images/304/d8d/686/304d8d68695250ecc8941c7d171f2d20.png)
退屈な写真...このまさしくそのプレーヤーを作成しましょう。
画面にスプライトを配置する必要があります、どうすればいいですか? クラスPlayer.javaを作成し、以下を記述します:
Player.java
import android.graphics.Bitmap; import android.graphics.Canvas; public class Player { /** */ GameView gameView; // Bitmap bmp; // int x; int y; // public Player(GameView gameView, Bitmap bmp) { this.gameView = gameView; this.bmp = bmp; // this.x = 0; // this.y = gameView.getHeight() / 2; // } // public void onDraw(Canvas c) { c.drawBitmap(bmp, x, y, null); } }
すべてが非常にシンプルで明確であり、プレイヤーはじっと立ち、敵を撃つ以外に何もしませんが、射撃は次に行う弾丸(シェル)のクラスで実装されます。
別のクラスファイルを作成し、Bullet.javaと呼びます。このクラスは、飛行の座標、飛行速度、および弾丸の他のパラメーターを決定します。 そのため、ファイルを作成し、次の内容を書き込みます。
Bullet.java
import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Rect; public class Bullet { /***/ private Bitmap bmp; /***/ public int x; public int y; /** =15*/ private int mSpeed=25; public double angle; /***/ public int width; /***/ public int height; public GameView gameView; /***/ public Bullet(GameView gameView, Bitmap bmp) { this.gameView=gameView; this.bmp=bmp; this.x = 0; // this.y = 120; // this.width = 27; // this.height = 40; // // angle = Math.atan((double)(y - gameView.shotY) / (x - gameView.shotX)); } /** , */ private void update() { x += mSpeed * Math.cos(angle); // mSpeed angle y += mSpeed * Math.sin(angle); // -//- } /** */ public void onDraw(Canvas canvas) { update(); // canvas.drawBitmap(bmp, x, y, null); } }
コメントから、弾丸が実行するアクションは1つだけであることが明確になっているはずです-弾丸はプレイヤーが指示した方向に飛ぶはずです。
ステージにスプライトを描く
作成したこれらの2つのクラスを描画するには、GameView.javaクラスのコードを編集し、写真を返すいくつかのメソッドを追加する必要があります。 すべてのコードを書くのではなく、必要なメソッドのコードのみを提供します。
まず、画面に表示するためにBulletクラスとPlayerクラスのオブジェクトを作成する必要があります。そのために、弾丸のリストを作成して、それらが終わりにならないようにし、通常のプレーヤークラスオブジェクトを作成します。
GameView Hat
private List<Bullet> ball = new ArrayList<Bullet>(); private Player player; Bitmap players;
次に、クラスに画像を割り当て、GameViewコンストラクターを見つけて、最後に2行を挿入する必要があります。
GameView.java-GameViewコンストラクター
players= BitmapFactory.decodeResource(getResources(), R.drawable.player2); player= new Player(this, guns);
また、onDraw(Canvas c)メソッドでは; これらのスプライトを表示します。 リストで生成されたアイテムのコレクション全体を調べます。
GameView、Java
/** */ protected void onDraw(Canvas canvas) { canvas.drawColor(Color.WHITE); Iterator<Bullet> j = ball.iterator(); while(j.hasNext()) { Bullet b = j.next(); if(bx >= 1000 || bx <= 1000) { b.onDraw(canvas); } else { j.remove(); } } canvas.drawBitmap(guns, 5, 120, null); }
また、画面をクリックしたときに弾丸が飛び出すようにするには、createSprites()メソッドを作成する必要があります。 スプライトが返されます。
Gameview.java
public Bullet createSprite(int resouce) { Bitmap bmp = BitmapFactory.decodeResource(getResources(), resouce); return new Bullet(this, bmp); }
最後に、もう1つのメソッドonTouch()を作成します。 画面上のすべてのタッチを実際にキャッチし、画面がクリックされたポイントに弾丸を向けます。
Gameview.java
public boolean onTouchEvent(MotionEvent e) { shotX = (int) e.getX(); shotY = (int) e.getY(); if(e.getAction() == MotionEvent.ACTION_DOWN) ball.add(createSprite(R.drawable.bullet)); return true; }
クリックが1回処理されないようにする場合、つまり 1プレス-1弾、1プレス-放すまで撃ちますが、 if(e.getAction()== MotionEvent.ACTION_DOWN){}を削除する必要があります
そして、 ball.add(createSprite(R.drawable.bullet))のみを残します。 。
それだけです、ゲームを実行して、撃ってみてください。 これは次のようになります。
敵
飽きさせないために、敵を作成する必要があります。 これを行うには、Enemy.javaと呼ばれる別のクラスを作成する必要があります。このクラスは、敵を表示して、基地に向けることができます。 クラスは非常に単純なので、次のコードを参照してください。
Enemy.java
import java.util.Random; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Rect; public class Enemy { /** */ public int x; public int y; /***/ public int speed; /** */ public int width; public int height; public GameView gameView; public Bitmap bmp; /** */ public Enemy(GameView gameView, Bitmap bmp){ this.gameView = gameView; this.bmp = bmp; Random rnd = new Random(); this.x = 900; this.y = rnd.nextInt(300); this.speed = rnd.nextInt(10); this.width = 9; this.height = 8; } public void update(){ x -= speed; } public void onDraw(Canvas c){ update(); c.drawBitmap(bmp, x, y, null); } }
そして、このクラスで何が起こるのでしょうか? 敵、高さ、幅、座標の重要な変数を宣言しました。 それらをステージに配置するために、私はRandom()クラスを使用して、それらがステージに表示されるとき、それらが1つのポイント、異なるポイント、異なる座標ですべてに表示されるようにしました。 また、速度はランダムであるため、各敵は異なる速度で進み、速度は0から始まり、10、10で終わります。これは、敵が到達できる最高速度です。 それらは右から左に移動するので、ステージ上ですぐに表示されないように、画面を見やすくするために900ピクセルで投じました。 そのため、攻撃者は攻撃に完全に備えることができます。
次に、ステージ上に敵を表示する必要があります。これを行うには、GameView.javaクラスで以下を実行します。
敵のリストを作成して終了しないようにし、スプライトを含むビットマップを作成します。
GameView Hat
private List<Enemy> enemy = new ArrayList<Enemy>(); Bitmap enemies;
次に、新しいスレッドを作成して、画面に表示される敵の速度を設定します。
GameView Hat
private Thread thred = new Thread(this);
そして、Runubleクラスを実装します。これがGameViewクラスの初期化の外観です。
public class GameView extends SurfaceView implements Runnable
これで、Eclipseでrun()メソッドを作成し、作成する必要があります。次のようになります。
GameViewクラスの一番下
public void run() { while(true) { Random rnd = new Random(); try { Thread.sleep(rnd.nextInt(2000)); enemy.add(new Enemy(this, enemies)); } catch (InterruptedException e) { e.printStackTrace(); } } }
ここでは、0〜2000ミリ秒、または0、1、2秒ごとにスプライトを作成するストリームを作成します。
最後のコンストラクターで、シーンに表示するクラスで初期化スプライトを記述します。
GameViewコンストラクター
enemies = BitmapFactory.decodeResource(getResources(), R.drawable.target); enemy.add(new Enemy(this, enemies));
そしてもちろん、onDraw()でこれらのメソッドを宣言する必要があります。 つまり、次のように記述します。
GameViewのOnDraw()メソッド
Iterator<Enemy> i = enemy.iterator(); while(i.hasNext()) { Enemy e = i.next(); if(ex >= 1000 || ex <= 1000) { e.onDraw(canvas); } else { i.remove(); } }
繰り返しますが、イテレータを使用して敵のコレクションを調べ、敵が1000ピクセルの制限を超えた場合、それを削除します。メモリを削除しないと、読み込みが停止し、電話がフリーズしますが、そのような問題は必要ありません。 ゲーム全体を実行する準備が整いました。
ゲームを開始し、何が表示されますか? そして、ここに何があります:
しかし、私は何を見ますか? ああいや!!! 弾丸は私たちの幽霊を殺しませんか? そして、何をすべきかを説明します。各スプライトの周りに長方形を形成するメソッドを作成する必要があります-衝突でそれらを比較します。 次のトピックはこれについてです。
衝突検知
それで、スプライトがあり、シーンがあり、私たち全員が美しく動きますが、ステージ上でこれらのスプライトを除いて何も起こらないとき、これらすべての使用は何ですか?
この機能を使用して、私は完全に自分自身を食べましたが、どういうわけか私はおかしくなり、通りを散歩しました))最も難しい方法ですが、完全に無害に見えますが...
さて、このメソッドを作成して、あまり話さないでください... GameViewクラスの最後のどこかでtestCollision()メソッドを作成し、次のコードを記述します。
GameView.javaクラスの一番下
/* */ private void testCollision() { Iterator<Bullet> b = ball.iterator(); while(b.hasNext()) { Bullet balls = b.next(); Iterator<Enemy> i = enemy.iterator(); while(i.hasNext()) { Enemy enemies = i.next(); if ((Math.abs(balls.x - enemies.x) <= (balls.width + enemies.width) / 2f) && (Math.abs(balls.y - enemies.y) <= (balls.height + enemies.height) / 2f)) { i.remove(); b.remove(); } } } }
そして、この方法で何が起こっているのでしょうか? イテレータを1つ作成し、ループを実行してスプライトのコレクション全体を表示し、後続の各ブレットスプライトが最初になると言います。
次に、スプライトの異なるリストを持つ別のイテレータを作成して再定義し、次の敵のスプライトがそれぞれ最初になると言います。 そして、分岐演算子を作成します-if()は実際にスプライトの衝突をチェックします。 その中で、2つの長方形から絶対整数を返す数学関数モジュール(abs)を使用しました。
ifa内では、2つの長方形が比較されます。モジュールは(X座標の弾丸からX座標の敵座標を引いたものが、弾丸の幅+敵の幅/ 2(長方形の中心を見つけるために2で割る)以下)および(Y座標の弾丸-座標Y座標の敵は、弾丸の幅+敵の幅/ 2(長方形の中心を見つけるために2で割る)以下です);
そして、すべての終わりに、弾丸が敵に到達した場合、シーンミートから彼を削除します。
さて、この関数が機能するために、onDraw()描画メソッドの下のGameThreadクラスにあるrun()メソッドに書き込みます。
以下は、アプリケーションを起動した後に得られるものです。