GROUP14.pptx

코드

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)
	}
}