はじめに
前回は画面上でボールが動くだけの処理について記載しましたが、
ボールが動くのであれば、昔懐かしのpongのようなホッケーゲームができると思い作成しました。
以下はソースについて記載します。
必要なパッケージのインポート
import (
"image/color" // 色を扱うためのパッケージ
"log" // ロギングを行うためのパッケージ
"github.com/hajimehoshi/ebiten/v2" // Ebitenのパッケージ
"github.com/hajimehoshi/ebiten/v2/ebitenutil" // Ebitenのユーティリティパッケージ
)
定数の定義
const (
screenWidth, screenHeight = 640, 480 // 画面の幅と高さ
paddleWidth, paddleHeight = 20, 80 // パドルの幅と高さ
ballSize = 20 // ボールの大きさ
paddleSpeed = 4 // パドルの速度
)
Game構造体の定義
type Game struct {
ballPositionX, ballPositionY float64 // ボールの位置
ballDX, ballDY float64 // ボールの移動量
paddle1Y, paddle2Y float64 // 両パドルの位置
}
Game構造体はゲームの状態を保持します。ボールの位置と移動量、そしてパドルの位置が含まれます。
Updateメソッド
func (g *Game) Update() error {
g.ballPositionX += g.ballDX // ボールのX座標を更新
g.ballPositionY += g.ballDY // ボールのY座標を更新
// ボールが画面の左右端に触れたら反射
if g.ballPositionX < 0 {
g.ballDX = -g.ballDX
g.ballPositionX = 0
} else if g.ballPositionX > screenWidth-ballSize {
g.ballDX = -g.ballDX
g.ballPositionX = screenWidth - ballSize
}
// ボールが画面の上下端に触れたら反射
if g.ballPositionY < 0 {
g.ballDY = -g.ballDY
g.ballPositionY = 0
} else if g.ballPositionY > screenHeight-ballSize {
g.ballDY = -g.ballDY
g.ballPositionY = screenHeight - ballSize
}
// パドルの移動
if ebiten.IsKeyPressed(ebiten.KeyW) {
g.paddle1Y -= paddleSpeed // Wキーでパドル1を上に移動
}
if ebiten.IsKeyPressed(ebiten.KeyS) {
g.paddle1Y += paddleSpeed // Sキーでパドル1を下に移動
}
if ebiten.IsKeyPressed(ebiten.KeyUp) {
g.paddle2Y -= paddleSpeed // 上矢印キーでパドル2を上に移動
}
if ebiten.IsKeyPressed(ebiten.KeyDown) {
g.paddle2Y += paddleSpeed // 下矢印キーでパドル2を下に移動
}
// ボールがパドルに当たったら反射
if (g.ballPositionX < paddleWidth && g.ballPositionY+ballSize > g.paddle1Y && g.ballPositionY < g.paddle1Y+paddleHeight) ||
(g.ballPositionX+ballSize > screenWidth-paddleWidth && g.ballPositionY+ballSize > g.paddle2Y && g.ballPositionY < g.paddle2Y+paddleHeight) {
g.ballDX = -g.ballDX
}
return nil
}
Updateメソッドでは、ゲームの状態を更新します。ここではボールの位置、ボールの反射、パドルの移動、そしてボールとパドルの衝突を処理しています。
Drawメソッド
func (g *Game) Draw(screen *ebiten.Image) {
ebitenutil.DrawRect(screen, 10, g.paddle1Y, paddleWidth, paddleHeight, color.White) // パドル1を描画
ebitenutil.DrawRect(screen, screenWidth-30, g.paddle2Y, paddleWidth, paddleHeight, color.White) // パドル2を描画
ebitenutil.DrawRect(screen, g.ballPositionX, g.ballPositionY, ballSize, ballSize, color.White) // ボールを描画
}
Drawメソッドでは、ゲームの状態に基づいて画面を描画します。ここではパドルとボールを描画しています。
Layoutメソッド
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
return screenWidth, screenHeight
}
Layoutメソッドでは、ゲーム画面のサイズを設定します。
main関数
func main() {
g := &Game{
ballPositionX: screenWidth / 2,
ballPositionY: screenHeight / 2,
ballDX: 2,
ballDY: 2,
paddle1Y: screenHeight/2 - paddleHeight/2,
paddle2Y: screenHeight/2 - paddleHeight/2,
}
ebiten.SetWindowSize(screenWidth, screenHeight) // ウィンドウの大きさを設定
ebiten.SetWindowTitle("Pong") // ウィンドウのタイトルを設定
if err := ebiten.RunGame(g); err != nil {
log.Fatal(err) // エラーハンドリング
}
}
main関数では、ゲームの初期化と実行を行います。ゲームの状態を表すGame構造体を初期化し、ウィンドウの大きさとタイトルを設定した後、ゲームを実行します。
現状は、パドルに当たり判定を付け,ただ永遠とはじくだけではありますが、
今後、pongと同じような機能を追加していこうと思います。
以上
前回