ゲーム実装で身に付くプログラミング 5

ゲームオーバーでタイトル画面に遷移する

ゲームオーバーでタイトル画面に遷移する

「gameover.go」ファイルを新規作成します。全ての色ブロックがなくなったらゲームオーバー処理します。ゲームオーバー処理と言っても、単純にタイトル画面に戻るだけです。

今回は解説を簡単にするために省略しましたが、ゲームオーバー画像を表示してそれをクリックしたらタイトル画面に戻るように改造すると良いでしょう。

・サンプルコード「mainloop.go」ファイル

package main

import (
(中略)
)

func (g *Game) SetState(s GameState) {
	g.state = s
	// 全消去(背景だけ残す)
	g.root.Objects = []fyne.CanvasObject{g.bg}
	switch s {
	case StateTitle:
		ShowTitle(g)
	case StatePlaying:
		g.startGame()
	case StateGameOver:
		ShowGameOver(g)
	}
	canvas.Refresh(g.root)
}

func (g *Game) startGame() {
(中略)
}

func (g *Game) spawn(i int) {
(中略)
}

func (g *Game) removeSprite(target *Sprite) {
	for i, s := range g.sprites {
		if s == target {
			g.root.Remove(s.obj)
			g.sprites = append(g.sprites[:i], g.sprites[i+1:]...)
			break
		}
	}
	if len(g.sprites) == 0 {
		g.SetState(StateGameOver)
	}
}

func (g *Game) Update() {
(中略)
}

func (g *Game) Start() {
(中略)
}

【サンプルコードの解説】
importでモジュールを読み込みます。
「SetState」メソッドで「StateGameOver」の場合にShowGameOver関数を呼び出します。
「removeSprite」メソッドで「sprites」配列の要素数が0、つまり色ブロックが全てなくなったらゲームオーバー状態にします。

・サンプルコード「gameover.go」ファイル

package main

func ShowGameOver(g *Game) {
	g.SetState(StateTitle)
}

【サンプルコードの解説】
ゲームオーバーのShowGameOver関数は、ゲーム状態を「StateTitle」にするだけです。

ステージクリアーでメインループに遷移する

「stageclear.go」ファイルを新規作成します。色ブロックをクリックして背景色に混色された時、背景色が赤緑青が同じ値になり真っ白になったらステージクリアで、そのまま次のステージに進みます(図4)。

本来ならステージクリア画像を表示して、クリックすると次のステージに進むようにすれば良いので、改造するのであればそうしてみてください。

図4:背景色を反映

・サンプルコード「mainloop.go」ファイル

package main

import (
(中略)
)

func (g *Game) SetState(s GameState) {
	g.state = s
	// 全消去(背景だけ残す)
	g.root.Objects = []fyne.CanvasObject{g.bg}
	switch s {
	case StateTitle:
		ShowTitle(g)
	case StatePlaying:
		g.startGame()
	case StateGameOver:
		ShowGameOver(g)
	case StateStageClear:
		ShowStageClear(g)
	}
	canvas.Refresh(g.root)
}

func (g *Game) startGame() {
	g.rgb = []int{0, 0, 0}
	for g.rgb[0] == g.rgb[1] {
		g.rgb[0] = rand.Intn(g.stage)
		g.rgb[1] = rand.Intn(g.stage)
		g.rgb[2] = rand.Intn(g.stage)
	}
	g.sprites = nil
	g.bg.FillColor = color.White
	g.bg.Refresh()
	for i := 0; i < g.stage*3; i++ {
		g.spawn(i % 3)
	}
}

func (g *Game) spawn(i int) {
	path := "images/" + strconv.Itoa(i) + ".png"
	img := canvas.NewImageFromFile(path)
	img.FillMode = canvas.ImageFillOriginal
	size := img.MinSize()
	img.Resize(size)
	x := rand.Float32() * (width - size.Width)
	y := rand.Float32() * (height - size.Height)
	sprite := &Sprite{
		x:  x,
		y:  y,
		vx: rand.Float32()*2 - 1,
		vy: rand.Float32()*2 - 1,
	}
	btn := widget.NewButton("", func() {
		g.rgb[i]++
		g.removeSprite(sprite)
	})
	btn.Resize(size)
	obj := container.NewStack(btn, img)
	obj.Resize(size)
	obj.Move(fyne.NewPos(x, y))
	sprite.obj = obj
	g.root.Add(obj)
	g.sprites = append(g.sprites, sprite)
}

func (g *Game) removeSprite(target *Sprite) {
(中略)
}

func (g *Game) bgColor() bool {
	idx := []int{0, 1, 2}
	slices.SortFunc(idx, func(i, j int) int {
		return g.rgb[j] - g.rgb[i]
	})
	ratio := 255 / g.rgb[idx[0]]
	red := uint8(g.rgb[0] * ratio)
	green := uint8(g.rgb[1] * ratio)
	blue := uint8(g.rgb[2] * ratio)
	g.bg.FillColor = color.RGBA{red, green, blue, 255}
	g.bg.Refresh()
	if red == green && green == blue {
		return true
	}
	return false
}

func (g *Game) Update() {
	if g.state != StatePlaying {
		return
	}
	if g.bgColor() {
		g.SetState(StateStageClear)
	}
	for i := 0; i < len(g.sprites); i++ {
		s := g.sprites[i]
		s.x += s.vx
		s.y += s.vy
		s.obj.Move(fyne.NewPos(s.x, s.y))
		size := s.obj.Size()
		if s.x < -size.Width || s.x > width || s.y < -size.Height || s.y > height {
			g.removeSprite(s)
			break
		}
	}
}

func (g *Game) Start() {
(中略)
}

【サンプルコードの解説】
「SetState」メソッドのゲーム状態が「StateStageClear」で「ShowStageClear」関数を呼び出します。
「startGame」メソッドで配列「rgb」プロパティの3要素にランダムな整数を代入します。
「spawn」メソッドでボタンがクリックされた時、rgbプロパティのクリックされた色ブロックの色インデックスの要素をインクリメントします。
「bgColor」メソッドでrgb配列の要素が1番大きいインデックスを取得します。255をrgbの1番大きいインデックスの要素で除算した値を「ratio」変数に代入します。
「red」「green」「blue」変数にrgb配列の各要素にratioを乗算した値を代入し、矩形の塗り潰し色(FillColor)にセットします。
背景色のred、green、blue変数が3つとも同じ値ならtrueを返します。
「Update」メソッドでbgColorメソッドを呼び出し、trueが返ったらゲーム状態をStateStageClearにセットします。

・サンプルコード「stageclear.go」ファイル

package main
func ShowStageClear(g *Game) {
    g.stage++
    g.SetState(StatePlaying)
}

【サンプルコードの解説】
「ShowStageClear」はステージクリア時に呼ばれ、stageをインクリメントしてゲーム状態をStatePlayingにセットします。

【コラム】はだかのおうさま

この絵は世界一素晴らしい絵です。お目の高いあなたならお分かりでしょう?と書いて下手くそな絵を描いてコンテストに出しましたが、通用しませんでした…。

おわりに

今回は「Go」言語の「Fyne」モジュールを使ってColorゲームを作りました。今までの言語と似ているようで、コードは全く別のものになりましたね。

この記事をシェアしてください

人気記事トップ10

人気記事ランキングをもっと見る

企画広告も役立つ情報バッチリ! Sponsored