👾

Ebitengine モバイル : TouchID で座標を取ろう!

2024/06/13に公開

モバイルといえば入力はタッチ!
Ebitengine で TouchID から座標を取得してみました。

公式のサンプルはこちら
https://github.com/hajimehoshi/ebiten/blob/main/examples/touch/

タッチされた最後の座標だけを覚えておくシンプルバージョン

使用するAPI

値を保持する箇所を定義

type Game struct {
    touchIds         []ebiten.TouchID
    touchPositionX   int
    touchPositionY   int
}

座標を取得

func (g *Game) Update() error {
    g.touchIds = ebiten.AppendTouchIDs(g.touchIds[:0]) // タッチされてる箇所を全て取得
    for _, id := range g.touchIds {
        x, y := ebiten.TouchPosition(id) // 順番にIDから座標を取得
        g.touchPositionX = x
        g.touchPositionY = y
    }
}

マルチタッチで複数本の指でタッチしてたりすると、一番最後判定になった座標が touchPositionX, touchPositionY に入る。
指一本でタッチしてる座標を単純に取りたい、のであればこれで良さそう。

デバッグ情報を画面に表示

func (g *Game) Draw(screen *ebiten.Image) {
    msg := fmt.Sprintf("position x=%d,y=%d", g.touchPositionX, g.touchPositionY)
    ebitenutil.DebugPrint(screen, msg)
}

マルチタッチ対応

先ほどのバージョンだと、ループしてるくせに一番最後の値しか保持してないので、TouchID
をキーにした map に保存してみる。
(しれっと言ってるけどここで盛大にハマりました・・)

値を保持する箇所を定義

type Game struct {
    touchIds         []ebiten.TouchID
    touchIdsPosition map[ebiten.TouchID]PositionXY
}

type PositionXY {
    x, y int
}

座標を取得し、map に保存

func (g *Game) Update() error {
    g.touchIds = ebiten.AppendTouchIDs(g.touchIds[:0])
    g.touchIdsPosition = map[ebiten.TouchID]PositionXY{} // ここ重要!
    for _, id := range g.touchIds {
        x, y := ebiten.TouchPosition(id) // 順番にIDから座標を取得
        g.touchIdsPosition[id] = PositionXY{x: x, y: y}
    }
}

↑ここ重要!のコメント箇所が map を初期化してる(はず・・)
これがないと値を入れようとしても何も表示されない。

デバッグ情報を画面に表示

func (g *Game) Draw(screen *ebiten.Image) {
    var msg = "TouchIDs : "
    for _, id := range g.touchIds {
        pos := g.touchIdsPosition[id]
        msg += fmt.Sprintf("ID=%d (%d,%d)", id, pos.x, pos.y)
    }
    ebitenutil.DebugPrint(screen, msg)
}

これがないと値を入れようとしても何も表示されない について

何が起きているのかしっくりこなかったので、A Tour of Go の実行環境で試してみた。

package main

import "fmt"

type Position struct {
	x, y int
}

type Game struct {
	title string
	touchIdPositionMap map[int]Position
}


func main() {
	g := &Game{ title: "New Game" }	
	fmt.Printf("title %s\n", g.title)

	//g.touchIdPositionMap = map[int]Position{} // 大事の行
	g.touchIdPositionMap[0] = Position{x:10,y:20}	
	fmt.Printf("map %q\n", g.touchIdPositionMap)
}

map初期化部分をコメントアウトすると

resultに

title New Game
panic: assignment to entry in nil map

goroutine 1 [running]:
main.main()
	/tmp/sandbox3778988721/prog.go:20 +0xa5

と出てきた。
普通に panic 起きてたのか・・・
Goでビルドした aar を Android プロジェクト側で読み込んでいると、この辺のエラーがどこにも出てこないっぽいので何が起きてるのかわからなかった・・・
なるほどスッキリ!

モバイル組み込みしてたからこその罠という感じがしますね・・
どこかにログ出てくれたらいいんだけど・・

ハートレイルズ

Discussion