通过构建2D蛇游戏来学习Golang:完整的指南
#go #gamedev

学习一种新的编程语言可能是一项艰巨的任务,但是从事一个有趣的项目(例如构建游戏)可以使过程变得愉快而有效。在本教程中,我们将通过创建一个简单的蛇游戏来学习Golang。 Golang或Go是一种由Google设计的开源编程语言,它易于构建简单,可靠和高效的软件。

在本教程结束时,您将对GO及其核心概念(例如变量,功能,循环和结构和结构)以及有效的蛇游戏有一个基本的理解,以展示您的新技能。


设置您的GO环境

在开始构建游戏之前,您需要设置GO环境。您可以从https://golang.org/dl/的官方网站下载Go。安装后,请确保设置gopath并正确配置环境变量。


Ebiten简介

用于构建2D游戏,我们将使用Ebiten软件包。 Ebiten是GO的2D游戏库,可以轻松开发跨平台游戏。 Ebiten提供了必不可少的游戏功能,例如绘制图像和处理用户输入。要开始使用Ebiten,请通过运行以下命令安装库:

go get -u github.com/hajimehoshi/ebiten/v2

设置游戏环境

首先创建一个新的go文件并导入所需的软件包,例如 fmt log Math/rand/rand 时间 github.com/hajimehoshi/ebiten/v2 。接下来,为屏幕宽度和高度创建常数。

const (
    screenWidth  = 320
    screenHeight = 240
    tileSize     = 5
)

主要功能应初始化游戏状态并致电ebiten.RunGame()开始游戏循环。

func main() {
    rand.Seed(time.Now().UnixNano())
    game := &Game{
        snake:    NewSnake(),
        food:     NewFood(),
        gameOver: false,
        ticks:    0,
        speed:    10,
    }
    ebiten.SetWindowSize(screenWidth*2, screenHeight*2)
    ebiten.SetWindowTitle("Snake Game")
    if err := ebiten.RunGame(game); err != nil {
        log.Fatal(err)
    }
}

此代码设置一个基本的Ebiten游戏窗口,大小为640ã480像素。

创建蛇结构

创建一个Point struct代表x和y坐标,以及一个代表蛇的身体,方向和生长计数器的Snake结构。

type Point struct {
    X int
    Y int
}

type Snake struct {
    Body        []Point
    Direction   Point
    GrowCounter int
}

现在实现NewSnake()函数来创建新的蛇实例和Move()方法,以根据其方向更新蛇的位置。 Move()方法还应通过根据GrowCounter保留或去除尾部细分来处理蛇的生长。

func NewSnake() *Snake {
    return &Snake{
        Body: []Point{
            {X: screenWidth / tileSize / 2, Y: screenHeight / tileSize / 2},
        },
        Direction: Point{X: 1, Y: 0},
    }
}

func (s *Snake) Move() {
    newHead := Point{
        X: s.Body[0].X + s.Direction.X,
        Y: s.Body[0].Y + s.Direction.Y,
    }
    s.Body = append([]Point{newHead}, s.Body...)

    if s.GrowCounter > 0 {
        s.GrowCounter--
    } else {
        s.Body = s.Body[:len(s.Body)-1]
    }
}

NewSnake函数在屏幕中心的单个身体部位初始化蛇,并将初始方向设置为右侧。

Move函数根据当前头部位置和方向计算新的头部位置。然后,除非蛇生长,否则它将新的头部添加到身体上并卸下尾巴。

实施食物

现在创建一个Food结构来表示食品的位置和NewFood()功能,以创建一个新的食物实例,并在游戏屏幕上随机位置。

type Food struct {
    Position Point
}

func NewFood() *Food {
    return &Food{
        Position: Point{
            X: rand.Intn(screenWidth / tileSize),
            Y: rand.Intn(screenHeight / tileSize),
        },
    }
}

处理用户输入和游戏更新

创建一个Game struct来表示游戏状态,包括snakefoodscorespeedgame over flag。

type Game struct {
    snake         *Snake
    food          *Food
    score         int
    gameOver      bool
    ticks         int
    updateCounter int
    speed         int
}

Game结构实施Update()方法来处理用户输入,更新蛇的位置,检查碰撞并处理食物的蛇。如果蛇吃食物,请增加分数并更新食物位置。

func (g *Game) Update() error {
    if g.gameOver {
        if inpututil.IsKeyJustPressed(ebiten.KeyR) {
            g.restart()
        }
        return nil
    }

    g.updateCounter++
    if g.updateCounter < g.speed {
        return nil
    }
    g.updateCounter = 0

    // Update the snake's position
    g.snake.Move()

    if ebiten.IsKeyPressed(ebiten.KeyLeft) && g.snake.Direction.X == 0 {
        g.snake.Direction = Point{X: -1, Y: 0}
    } else if ebiten.IsKeyPressed(ebiten.KeyRight) && g.snake.Direction.X == 0 {
        g.snake.Direction = Point{X: 1, Y: 0}
    } else if ebiten.IsKeyPressed(ebiten.KeyUp) && g.snake.Direction.Y == 0 {
        g.snake.Direction = Point{X: 0, Y: -1}
    } else if ebiten.IsKeyPressed(ebiten.KeyDown) && g.snake.Direction.Y == 0 {
        g.snake.Direction = Point{X: 0, Y: 1}
    }

    head := g.snake.Body[0]
    if head.X < 0 || head.Y < 0 || head.X >= screenWidth/tileSize || head.Y >= screenHeight/tileSize {
        g.gameOver = true
        g.speed = 10
    }

    for _, part := range g.snake.Body[1:] {
        if head.X == part.X && head.Y == part.Y {
            g.gameOver = true
            g.speed = 10
        }
    }

    if head.X == g.food.Position.X && head.Y == g.food.Position.Y {
        g.score++
        g.snake.GrowCounter += 1
        g.food = NewFood()
        g.score++
        g.food = NewFood()
        g.snake.GrowCounter = 1

        // Decrease speed (with a lower limit)
        if g.speed > 2 {
            g.speed--
        }
    }

    return nil
}

在更新功能中,我们正在处理,通过逻辑,速度,用户输入和重新启动游戏功能进行游戏。

绘制游戏对象

Game结构实现Draw()方法,以渲染游戏对象,例如蛇,食物和游戏。使用Ebiten的绘图功能,例如DrawRect(),将蛇和食物绘制为矩形和text.Draw()功能以显示分数和游戏。

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

    // Draw snake
    for _, p := range g.snake.Body {
        ebitenutil.DrawRect(screen, float64(p.X*tileSize), float64(p.Y*tileSize), tileSize, tileSize, color.RGBA{0, 255, 0, 255})
    }

    // Draw food
    ebitenutil.DrawRect(screen, float64(g.food.Position.X*tileSize), float64(g.food.Position.Y*tileSize), tileSize, tileSize, color.RGBA{255, 0, 0, 255})

    // Create a font.Face
    face := basicfont.Face7x13

    // Draw game over text
    if g.gameOver {
        text.Draw(screen, "Game Over", face, screenWidth/2-40, screenHeight/2, color.White)
        text.Draw(screen, "Press 'R' to restart", face, screenWidth/2-60, screenHeight/2+16, color.White)
    }

    // Draw score
    scoreText := fmt.Sprintf("Score: %d", g.score)
    text.Draw(screen, scoreText, face, 5, screenHeight-5, color.White)
}

重新启动游戏

终于实现了游戏结构的重新启动()方法,以重置游戏后的玩家在游戏结束后按“ R”。

func (g *Game) restart() {
    g.snake = NewSnake()
    g.score = 0
    g.gameOver = false
    g.food = NewFood()
    g.speed = 10
}

此代码检查游戏结束时是否按下R键,如果是,则通过调用restart方法重新启动游戏。 restart方法重置游戏状态,包括snakescoregameOver flag。

跑步游戏

Golang Snake Game

twitter上关注我,并给我发消息,我会立即向您发送完整的工作代码。

结论

恭喜!您现在使用Golang和Ebiten Library构建了一个简单的蛇游戏。在此过程中,您了解了Golang的基础知识,包括变量,功能,循环和结构,以及如何处理游戏中的用户输入和碰撞。

您可以通过添加更多功能,例如不同的级别,障碍或电力来进一步增强该游戏。可能性是无穷无尽的,现在您可以通过游戏开发来学习golang,可以建立坚实的基础。愉快的编码!

如果您有兴趣了解有关编程和相关主题的更多信息,我们邀请您查看我们的网站programmingeeksclub.com。我们提供宝贵的资源和见解。

您可以在TwitterFacebook上找到我们。

下载我的第一本关于掌握宣传的电子书,从这里:Download,评论和建议非常感谢。