Skip to content

Instantly share code, notes, and snippets.

@Mooan
Last active March 19, 2023 03:13
Show Gist options
  • Save Mooan/f75511b9b702805ddb5feecd3c9643ce to your computer and use it in GitHub Desktop.
Save Mooan/f75511b9b702805ddb5feecd3c9643ce to your computer and use it in GitHub Desktop.
ChatGPT4にEbitenエンジンでゲームを作ってもらった

ChatGPT4にEbitenエンジンでゲームを作ってもらった

ChatGPT4シューティングゲーム作って、とやりとりして以下のコードを書いてもらった。 UnityやUE5ほどメジャーでない(と思う)Ebitengine (v2) を題材にした。

コーディング

以下はChatGPT4と会話している様子 スクリーンショット 2023-03-19 11 23 06

以下はChatGPTが作ってくれたソースコード

// /////////////////////
// 1回目回答
// /////////////////////
package main

import (
	"image/color"
	"log"
	"math"
	"math/rand"
	"strconv"
	"time"

	"github.com/hajimehoshi/ebiten/v2"
	"github.com/hajimehoshi/ebiten/v2/ebitenutil"
	"github.com/hajimehoshi/ebiten/v2/inpututil"
)

const (
	screenWidth  = 640
	screenHeight = 480
	playerSize   = 32
	enemySize    = 16
	bulletSize   = 8
)

type Game struct {
	player  *Player
	enemies []*Enemy
	bullets []*Bullet
	score   int
}

type Player struct {
	x, y float64
}

type Enemy struct {
	x, y float64
}

type Bullet struct {
	x, y float64
}

func (g *Game) Update() error {
	g.player.Update()

	// 弾の生成
	if inpututil.IsKeyJustPressed(ebiten.KeySpace) {
		g.bullets = append(g.bullets, &Bullet{x: g.player.x + playerSize/2, y: g.player.y})
	}

	// 敵と弾の移動
	for _, e := range g.enemies {
		e.y += 2
	}
	for _, b := range g.bullets {
		b.y -= 5
	}

	// 敵機の生成を少し減らす
	if rand.Intn(100) < 5 {
		g.enemies = append(g.enemies, &Enemy{x: float64(rand.Intn(screenWidth - enemySize)), y: -float64(enemySize)})
	}

	// 敵と弾の衝突判定および敵の消滅とスコア加算
	for i := len(g.enemies) - 1; i >= 0; i-- {
		e := g.enemies[i]
		for j := len(g.bullets) - 1; j >= 0; j-- {
			b := g.bullets[j]
			if hit(e, b) {
				g.enemies = append(g.enemies[:i], g.enemies[i+1:]...)
				g.bullets = append(g.bullets[:j], g.bullets[j+1:]...)
				g.score += 100
				break
			}
		}
	}

	// 画面外の敵機を削除
	for i := len(g.enemies) - 1; i >= 0; i-- {
		e := g.enemies[i]
		if e.y > screenHeight {
			g.enemies = append(g.enemies[:i], g.enemies[i+1:]...)
		}
	}

	// 画面外の弾を削除
	for i := len(g.bullets) - 1; i >= 0; i-- {
		b := g.bullets[i]
		if b.y < 0 {
			g.bullets = append(g.bullets[:i], g.bullets[i+1:]...)
		}
	}

	// 自機と敵機の衝突判定およびスコアリセット
	for i := len(g.enemies) - 1; i >= 0; i-- {
		e := g.enemies[i]
		if hitPlayer(g.player, e) {
			g.score = 0
		}
	}

	return nil
}

// hitPlayer関数を追加
func hitPlayer(p *Player, e *Enemy) bool {
	px, py, pr := p.x+playerSize/2, p.y+playerSize/2, float64(playerSize)/2
	ex, ey, er := e.x+enemySize/2, e.y+enemySize/2, float64(enemySize)/2
	return math.Sqrt(math.Pow(px-ex, 2)+math.Pow(py-ey, 2)) < pr+er
}

func hit(a, b interface{}) bool {
	ax, ay, ar := 0.0, 0.0, 0.0
	bx, by, br := 0.0, 0.0, 0.0

	switch at := a.(type) {
	case *Enemy:
		ax, ay, ar = at.x+enemySize/2, at.y+enemySize/2, float64(enemySize)/2
	case *Bullet:
		ax, ay, ar = at.x+bulletSize/2, at.y+bulletSize/2, float64(bulletSize)/2
	}

	switch bt := b.(type) {
	case *Enemy:
		bx, by, br = bt.x+enemySize/2, bt.y+enemySize/2, float64(enemySize)/2
	case *Bullet:
		bx, by, br = bt.x+bulletSize/2, bt.y+bulletSize/2, float64(bulletSize)/2
	}

	return math.Sqrt(math.Pow(ax-bx, 2)+math.Pow(ay-by, 2)) < ar+br
}

func (p *Player) Update() {
	if ebiten.IsKeyPressed(ebiten.KeyLeft) {
		p.x -= 4
	}
	if ebiten.IsKeyPressed(ebiten.KeyRight) {
		p.x += 4
	}
	if ebiten.IsKeyPressed(ebiten.KeyUp) {
		p.y -= 4
	}
	if ebiten.IsKeyPressed(ebiten.KeyDown) {
		p.y += 4
	}

	if p.x < 0 {
		p.x = 0
	}
	if p.x > screenWidth-playerSize {
		p.x = screenWidth - playerSize
	}
	if p.y < 0 {
		p.y = 0
	}
	if p.y > screenHeight-playerSize {
		p.y = screenHeight - playerSize
	}
}

// /////////////////////
// 2回目回答
// /////////////////////
func (g *Game) Draw(screen *ebiten.Image) {
	screen.Fill(color.RGBA{0, 0, 0, 255})

	g.player.Draw(screen)

	for _, e := range g.enemies {
		e.Draw(screen)
	}

	for _, b := range g.bullets {
		b.Draw(screen)
	}
	
    // スコア表示
    scoreString := "Score: " + strconv.Itoa(g.score)
    ebitenutil.DebugPrintAt(screen, scoreString, 10, 30)
}

func (p *Player) Draw(screen *ebiten.Image) {
	rect := ebiten.NewImage(playerSize, playerSize)
	rect.Fill(color.RGBA{0, 0, 255, 255})
	op := &ebiten.DrawImageOptions{}
	op.GeoM.Translate(p.x, p.y)
	screen.DrawImage(rect, op)
}

func (e *Enemy) Draw(screen *ebiten.Image) {
	circle := ebiten.NewImage(enemySize, enemySize)
	circle.Fill(color.RGBA{255, 0, 0, 255})
	op := &ebiten.DrawImageOptions{}
	op.GeoM.Translate(e.x, e.y)
	screen.DrawImage(circle, op)
}

func (b *Bullet) Draw(screen *ebiten.Image) {
	rect := ebiten.NewImage(bulletSize, bulletSize)
	rect.Fill(color.RGBA{255, 255, 255, 255})
	op := &ebiten.DrawImageOptions{}
	op.GeoM.Translate(b.x, b.y)
	screen.DrawImage(rect, op)
}

// /////////////////////
// 3回目回答
// /////////////////////
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
	return screenWidth, screenHeight
}

func main() {
	rand.Seed(time.Now().UnixNano())

	ebiten.SetWindowSize(screenWidth*2, screenHeight*2)
	ebiten.SetWindowTitle("Simple Shooter")
	game := &Game{
		player: &Player{
			x: float64(screenWidth/2 - playerSize/2),
			y: float64(screenHeight - playerSize*2),
		},
		enemies: []*Enemy{},
		bullets: []*Bullet{},
	}
	if err := ebiten.RunGame(game); err != nil {
		log.Fatal(err)
	}
}

Makefileは自分で書いた。 WebAssemblyビルドでブラウザ上で動作するようにした。 これもChatGPT4さんによしなに書いてほしかったが、こっちは会話するより自分で書いた方が速そうだったので。

default: game1.wasm

game1.wasm: main.go
	env GOOS=js GOARCH=wasm go build -o game1.wasm example.com

.PHONY: clean
clean:
	rm game1.wasm

動作確認

結論:普通に動作した。。。

スクリーンショット 2023-03-19 11 35 00

以下のコマンドで動作確認した。 普通にゲームができていてびっくりする。 一体、どこからソースコード取ってきたのだろう。。。

$ make
$ python3 -m http.server 8080

設計書

ついでにUMLで設計書の納品もしてもらった。

スクリーンショット 2023-03-19 11 45 00

クラス図は以下

・オブジェクトクラスのPosition()はどこから出てきたのだろう?   ・ソースコードの全体を添付して、修正を依頼したら正しいクラス図に直してくれた。これは私の依頼の仕方が悪かったと思っている。

スクリーンショット 2023-03-19 11 48 04

シーケンス図は以下

スクリーンショット 2023-03-19 11 48 36

結論

普通に設計・コーディング作業に関しては、使い道がありそう。 (著作権的には大きな懸念があるのだが、、、)

@Mooan
Copy link
Author

Mooan commented Mar 19, 2023

スクリーンショット 2023-03-19 11 23 06

@Mooan
Copy link
Author

Mooan commented Mar 19, 2023

スクリーンショット 2023-03-19 11 35 00

@Mooan
Copy link
Author

Mooan commented Mar 19, 2023

スクリーンショット 2023-03-19 11 45 00

@Mooan
Copy link
Author

Mooan commented Mar 19, 2023

スクリーンショット 2023-03-19 11 48 04

@Mooan
Copy link
Author

Mooan commented Mar 19, 2023

スクリーンショット 2023-03-19 11 48 36

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment