こんにちはHabr!
今日は、Canvasを使用してAndroid OS用のシンプルなロジックゲームを作成する方法についてお話します。 約5年前に携帯電話でこのゲームに出会いました。 名前は忘れられており、いくつかのテーマ別フォーラムで検索しても何ももたらされなかったため、このゲームの独自の実装を作成することにしました。 私は小さなプロジェクトに取り組むこともありますが、開発は私の趣味です。 少し考えてから、エンジンを使用せず、自分で書くことにしました。 この決定の理由:Canvasでの経験を得たいという願望。
一番下の行は...
チェス盤に似た競技場がありますが、セルを白黒に分割しません。 フィールドのサイズは任意ですが、2x3より小さいフィールドでプレイするのはあまり意味がありません。 10x10のフィールドでプレーするのが好きです。
プレイヤーの数は任意ですが、私の意見では、一緒にプレイするか4人でプレイする方が面白いと思います。 長方形のフィールドで3人で一緒にプレーすると、プレーヤーの1人が「空の」コーナーから遠くなるため、不均衡が発生します。 4人以上でプレイする場合、戦略を実行することは困難です。
各プレイヤーは、1つのオブジェクト(アトムと呼びます)をフリーセルまたはそのアトムが既に存在するセルに配置する必要があります。 「臨界質量」が隣接セルの数に等しいセルに蓄積すると、このセルの原子は隣接セルに移動しますが、隣接セルの原子は「捕獲」されます。 それらは現在、原子が散らばっているプレイヤーのものです。
ポイントを明確にするためのいくつかの写真。
各セルの臨界質量を示す空の4x4フィールド。

3番目の移動後のゲームの状況。

4回目の移動後のゲームの状況(最初は青くなります)。 重大な数の原子が左上隅に蓄積されていることがわかります。

ああ! それらは散乱し、セル[2] [1]に2つの青い原子を捕獲しました。 そして、このセル[0] [1]でも重要な量になりました。 連鎖反応!

拡張後の状況。 4番目の動きの終わり。 これで、青が5番目の動きになります。

実装。 グラフィック部分。
実装に取りかかりましょう。 Viewから派生したクラスを作成しましょう。
public class GameView extends View { private Bitmap mBitmap; private Canvas mCanvas; private Paint paint, mBitmapPaint; private float canvasSize; private final int horizontalCountOfCells, verticalCountOfCells; public GameView(Context context, AttributeSet attrs) { super(context, attrs);
ここでは、低品質
のコードを少し許可しました。つまり、プレイフィールドのセルとビューのサイズを分ける線の色が300 dpに等しいと見なされるコードにハードコードされています。 このサイズはAttributeSetクラスのattrsオブジェクトから取得できますが、コードが乱雑になることはありません。
また、アクティビティをすぐにスケッチして、すべてが美しく描画されるようにします。
public class GameActivity extends Activity { Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } }
そして、マークアップmain.xml
<LinearLayout xmlns:android=«schemas.android.com/apk/res/android» android:orientation=«vertical» android:layout_width=«fill_parent» android:layout_height=«fill_parent» android:background="#aaa" android:gravity=«center_horizontal»> <com.devindi.chain.GameView android:layout_width=«300dp» android:layout_height=«300dp» android:id="@+id/game_view" android:layout_gravity=«center» android:background="#000"/> </LinearLayout>
このステップの後のコード。さて、プレイフィールドのスケールを変更する機能を追加しましょう。サイズが小さいため、目的のセルを超えてミスが発生する可能性があるためです。 これを行うには、GameViewクラスのOnScaleGestureListenerインターフェイスのScaleGestureDetector.SimpleOnScaleGestureListenerを実装するために必要なメソッドを再定義します。
private final ScaleGestureDetector scaleGestureDetector; private final int viewSize; private float mScaleFactor; public GameView(Context context, AttributeSet attrs) {
結果のコード拡大値の境界が設定され(増加は1から2になります)、ゲームフィールドがズームポイント(指の間のポイント)までスクロールされ、プレイフィールドの外側の領域が表示されることに注意してください。 ズームポイント(焦点)へのスクロールは次のように実行されます-キャンバスの先頭(左上隅)に対する焦点の座標が計算され、ズーム係数が乗算され、ビューに対する点の座標が減算されます。 その後、競技場外へのスクロールを防ぐために、間隔[0、canvasSize -viewSize]から最も近い値を取得します。
ここで、スクロール、シングルタップ、ダブルタップの処理を記述します(ダブルタップは競技場の元のスケールに戻ります)。
private final GestureDetector detector; public GameView(Context context, AttributeSet attrs) { ... detector=new GestureDetector(context, new MyGestureListener()); }
結果のコードシングルタップで、タップしたセルの座標を計算します。たとえば、左上のセルの座標は0,0になります。
アトム描画メソッドdrawAtomsを書きましょう。 メソッドのパラメーター-原子、色、原子の数を描画するセルの座標。
void drawAtoms(int cellX, int cellY, int color, int count){
現時点では、この方法には原子のサイズと原子間の距離の絶対値という形の欠陥があります。 これは何につながりますか? フィールドサイズが10x10未満の場合、原子は小さく見え、フィールドサイズが大きいとセルに収まらない場合があります。
スクロールバーを追加するために残ります。 このプロセスは
habrahabr.ru/post/120931で詳しく説明されてい
ます 。
ゲームロジックの説明に進む前に、GameLogicタイプのグローバル変数(ロジックを説明するクラス)に名前logicを追加し、onSingleTapConfirmedをシングルタップの処理メソッドに追加します。
新しいアトムを追加する論理処理のfutureメソッドを呼び出します。
logic.addAtom(cellX、cellY);
この変数にはセッターも必要です。
コード。実装。 ゲームロジック。
ゲームのロジックを記述するGameLogicクラスを作成します。 また、フィールドクラスセルのパラメーターを格納する内部クラスCellが必要です。
public class GameLogic { private class Cell{ int player=0, countOfAtoms=0;
GameLogicクラス自体
private final GameView view; private final GameActivity activity; private int moveNumber=0, currentPlayer=0; private final int COUNT_OF_PLAYERS, BOARD_WIDTH, BOARD_HEIGHT; private final Cell[][] cells; private final int[] colors={0xff1d76fc, 0xfffb1d76, 0xff76fb1d, 0xffa21cfb};
コード。ここでは、Cellオブジェクトの2次元配列を作成するコンストラクターと、セルが眼球への原子で満たされている場合に、シングルタップビューとそれ自体から呼び出されるaddAtomメソッドを確認します。
これで、原子をセルに追加できます。原子がセルに蓄積すると、すぐにばらばらになります。 ただし、この2秒間に原子を追加できます。 isLockフラグ変数とisLock()、lock()、およびunlock()メソッドをGameViewクラスに追加して、これを取り除きます。
また、移動後にプレーヤーの変更を追加し、ゲームの終了をスコアリングして処理する必要があります(すべてのアトムが1人のプレーヤーに属し、各プレーヤーが少なくとも1回移動した場合)。
次のコードをaddAtom()メソッドの最後に追加します
int[] score=scoring(); if(moveNumber==0){ endTurn(score); }else {
全コードメソッドの実装を記述することは残っています
void setPlayerName(int playerID){} void setScore(int[] score){} void setMoveNumber(int moveNumber){} void endGame(int winnerID, int score){}
これは宿題になります。 ここではすべてが簡単です。
組み立て後、ファイル
次に、ゲームをカスタマイズするアクティビティを作成する形で、結果のアプリケーションをわずかに仕上げる必要があります(プレイフィールドのサイズ、プレーヤーの数、アトムの色、プレーヤーの名前ですが、これはこの記事のトピックではありません。最終的なコードは
githubで確認できます。
この記事が誰かの役に立つことを願っています。
大きな石を投げないようにお願いします。 私はコードの品質が低いことを認め、たわごとを避けるよう努力することを約束します。 ご清聴ありがとうございました。
PSこれはHabrに関する私の最初の記事です。