【マインスイーパー開発】タッチしたタイルの場所を判定する(その2)

Android & Kotlin

Android & Kotlinの環境でマインスイーパーをアプリ開発する方法を説明します。

今回は、前回の記事で配置した9x9のタイルに対して、タッチしたタイルの場所が縦、横何番目なのかを判定します。

そそたた
そそたた

タイルの描画には、Matrxを使用した拡大縮小、縦横斜めのスクロールができるカスタムイメージビューを使用しているので計算が少し複雑です。

動作イメージ

黄色●をタッチすると0オリジンで横3番目、縦1番目のタイルをタッチしたと判定する。

ソースコード

開発環境は次の通りです。

PCMacBook Pro(2016年モデル)
IDEAndroid Studio 4.0.1
Android SDKminSdkVersion 16
targetSdkVersion 30
言語Kotlin 1.3.72
package com.sosotata.minesweeper.ui.widgets

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.MotionEvent
import com.sosotata.minesweeper.LOG
import com.sosotata.minesweeper.model.TileController

/**
 * 四角タイルゲーム画面
 */
class SquareTileGameView : SosotataImageView {

    /** タイル描画用ビットマップ */
    private lateinit var mSourceBitmap: Bitmap

    /** タイル描画用キャンバス */
    private lateinit var mRenderCanvas: Canvas

    /** タイル制御 */
    private lateinit var mTile: TileController

    /**
     * コンストラクタ
     */
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}

    /**
     * タイルを描画する
     */
    fun setTileController(tile: TileController) {
        mTile = tile
        mSourceBitmap = Bitmap.createBitmap(
            mTile.tileWidth * mTile.numX, mTile.tileHeight * mTile.numY, Bitmap.Config.ARGB_8888
        )
        mRenderCanvas = Canvas(this.mSourceBitmap)
        for (y in 0 until mTile.numY) {
            for (x in 0 until mTile.numX) {
                mRenderCanvas.drawBitmap(
                    mTile.getTileStateImage(x, y),
                    mTile.tileWidth.toFloat() * x,
                    mTile.tileHeight.toFloat() * y,
                    null
                )
            }
        }
        setImage(mSourceBitmap)
    }

    /**
     * [android.view.View.onTouchEvent]
     */
    override fun onTouchEvent(e: MotionEvent?): Boolean {
        if (e != null) {
            if (e.action == MotionEvent.ACTION_UP) {
                val values = FloatArray(9)
                this.mRenderMatrix.getValues(values)
                val x = ((e.x - values[Matrix.MTRANS_X]) / values[Matrix.MSCALE_X] / mTile.tileWidth).toInt()
                val y = ((e.y - values[Matrix.MTRANS_Y]) / values[Matrix.MSCALE_Y] / mTile.tileHeight).toInt()
                LOG.d("横:${x}番目、縦:${y}番目")
            }
        }
        return super.onTouchEvent(e)
    }
}

解説

タイルを少し拡大したケースを例にタッチしたタイルの場所の判定方法を解説します。

こちらの例も黄色●をタッチすると0オリジンで横3番目、縦1番目だと判定します。

タッチ場所の判定は、タッチイベントハンドラのonTouchEventでタッチアップ(ACTION_UP)時に実施しています。

現在のマトリクス値を取得し、次の計算方法でタッチした場所を算出します。

  • 横何番目 = (タッチX座標 ー マトリクスX座標) / X倍率 / タイル幅
  • 縦何番目 = (タッチY座標 ー マトリクスY座標) / Y倍率 / タイル高さ
val values = FloatArray(9)
this.mRenderMatrix.getValues(values)
val x = ((e.x - values[Matrix.MTRANS_X]) / values[Matrix.MSCALE_X] / mTile.tileWidth).toInt()
val y = ((e.y - values[Matrix.MTRANS_Y]) / values[Matrix.MSCALE_Y] / mTile.tileHeight).toInt()

本ケースでの具体的な値は次の通りです。

タッチ座標Xe.x247.7
タッチ座標Ye.y387.7
マトリクスX座標value[Matrix.MTRANS_X]-131.1
マトリクスY座標value[Matrix.MTRANS_Y]212.6
X倍率values[Matrix.MSCALE_X]1.14
Y倍率values[Matrix.MSCALE_Y]1.14
タイル幅mTile.tileWidth96
タイル高さmTile.tileHeight96

コメント

タイトルとURLをコピーしました