코드
package main
import (
"fmt"
"image"
"image/color"
"image/draw"
"log"
"math/rand"
"pj/font"
"time"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
)
const (
screenWidth = 800
screenHeight = 600
gravity = 0.6
baseLift = -6
maxLift = -12
planeSize = 32
obstacleWidth = 30
obstacleGap = 150
obstacleSpeed = 4
)
var (
planeImage *ebiten.Image
)
type Plane struct {
x, y float64
dy float64
}
type Obstacle struct {
x, yTop, yBottom float64
}
type Game struct {
plane Plane
obstacles []Obstacle
tick int
spacePressed int
score int
isGameStarted bool
isGameOver bool
rng *rand.Rand
}
func init() {
img, _, err := ebitenutil.NewImageFromFile("plane.jpg")
if err != nil {
log.Fatal(err)
}
planeImage = img
}
func (g *Game) Update() error {
if !g.isGameStarted {
if ebiten.IsKeyPressed(ebiten.KeySpace) {
g.isGameStarted = true
g.isGameOver = false
g.score = 0
g.plane = Plane{x: 100, y: screenHeight / 2}
g.obstacles = []Obstacle{}
}
return nil
}
if g.isGameOver {
if ebiten.IsKeyPressed(ebiten.KeySpace) {
g.isGameStarted = false
}
return nil
}
if ebiten.IsKeyPressed(ebiten.KeySpace) {
g.spacePressed++
lift := baseLift - float64(g.spacePressed)/10
if lift < maxLift {
lift = maxLift
}
g.plane.dy = lift
} else {
g.spacePressed = 0
}
g.plane.dy += gravity
g.plane.y += g.plane.dy
if g.plane.y < 0 {
g.plane.y = 0
g.plane.dy = 0
} else if g.plane.y > screenHeight-planeSize {
g.plane.y = screenHeight - planeSize
g.plane.dy = 0
}
if g.tick%90 == 0 {
gapY := g.rng.Float64() * (screenHeight - obstacleGap)
g.obstacles = append(g.obstacles, Obstacle{
x: screenWidth, yTop: gapY, yBottom: gapY + obstacleGap,
})
}
for i := 0; i < len(g.obstacles); i++ {
g.obstacles[i].x -= obstacleSpeed
if g.obstacles[i].x+obstacleWidth < 0 {
g.obstacles = append(g.obstacles[:i], g.obstacles[i+1:]...)
i--
g.score++
}
}
for _, obs := range g.obstacles {
if g.plane.x+planeSize > obs.x && g.plane.x < obs.x+obstacleWidth &&
(g.plane.y < obs.yTop || g.plane.y+planeSize > obs.yBottom) {
g.isGameOver = true
break
}
}
g.tick++
return nil
}
func (g *Game) DrawRect(screen *ebiten.Image, x, y, w, h int, clr color.Color) {
rect := image.Rect(0, 0, w, h)
img := image.NewRGBA(rect)
draw.Draw(img, rect, &image.Uniform{clr}, image.Point{}, draw.Src)
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(float64(x), float64(y))
screen.DrawImage(ebiten.NewImageFromImage(img), op)
}
func (g *Game) DrawPlane(screen *ebiten.Image, x, y, w, h int, clr color.Color) {
op := &ebiten.DrawImageOptions{}
op.GeoM.Scale(float64(planeSize)/float64(planeImage.Bounds().Dx()), float64(planeSize)/float64(planeImage.Bounds().Dy()))
op.GeoM.Translate(float64(x), float64(y))
screen.DrawImage(planeImage, op)
}
func (g *Game) Draw(screen *ebiten.Image) {
screen.Fill(color.RGBA{135, 206, 235, 255})
if !g.isGameStarted {
font.DrawText(screenWidth/2, screenHeight/2-20, "Game Start", 48, color.White, screen)
font.DrawText(screenWidth/2, screenHeight/2+20, "-Press Space-", 24, color.White, screen)
return
}
g.DrawRect(screen, int(g.plane.x), int(g.plane.y), planeSize, planeSize, color.RGBA{255, 255, 255, 255})
g.DrawPlane(screen, int(g.plane.x), int(g.plane.y), planeSize, planeSize, color.RGBA{255, 255, 255, 255})
for _, obs := range g.obstacles {
g.DrawRect(screen, int(obs.x), 0, obstacleWidth, int(obs.yTop), color.RGBA{255, 255, 255, 255})
g.DrawRect(screen, int(obs.x), int(obs.yBottom), obstacleWidth, screenHeight-int(obs.yBottom), color.RGBA{255, 255, 255, 255})
}
font.DrawText(50, 20, "Score: "+fmt.Sprintf("%d", g.score), 24, color.White, screen)
if g.isGameOver {
font.DrawText(screenWidth/2, screenHeight/2, "Game Over", 48, color.Black, screen)
font.DrawText(screenWidth/2, screenHeight/2+40, "-Press Space to Restart-", 24, color.Black, screen)
}
}
func (g *Game) Layout(outsideWidth, outsideHeight int) (int, int) {
return screenWidth, screenHeight
}
func main() {
rng := rand.New(rand.NewSource(time.Now().UnixNano()))
game := &Game{
plane: Plane{x: 100, y: screenHeight / 2},
rng: rng,
}
ebiten.SetWindowSize(screenWidth, screenHeight)
ebiten.SetWindowTitle("Group Project 14")
if err := ebiten.RunGame(game); err != nil {
log.Fatal(err)
}
}