golang实现贪吃蛇(go面向对象版)

贪吃蛇几乎每个人都玩过,而对于程序员来说,这也是每个程序员成长路上的必经之路,一个小小的里程碑,那么如何在go语言中利用面向对象编程的方法实现贪吃蛇呢,别急,我们先整理一下大致思路。

1、蛇结构体创建
长度
[]坐标
方向
2、食物结构体创建
坐标
3、蛇初始化
设置蛇长度 2节
设置蛇的坐标
蛇头方向
4、界面初始化
游戏界面
食物初始化
键盘输入
5、开始游戏
程序流程控制
程序更新周期 time.Sleep()

6、蛇头和墙的碰撞
蛇头和身体的碰撞
游戏结束

7、蛇头和食物碰撞
长度增长
分数增长
随机新食物(不能出现在墙 障碍物 蛇身体)

8、根据方向改变蛇的位置
更新蛇的坐标
身体坐标
蛇头坐标

9、绘制食物 蛇头和身体

10、计算分数
下面让我们跟着已经理好的思路进行编程吧

package main

import (
    "fmt"
    "os"
    "math/rand"
    "Clib"
    "time"
)

//游戏界面大小
const WIDE int = 20
const HIGH int = 20

//食物坐标
var food Food
//分数
var score int = 0
//蛇的移动偏移值
var dx int = 0
var dy int = 0

//坐标父类
type Postion struct {
    X int
    Y int
}

//蛇子类
type Snake struct {
    pos  [WIDE * HIGH]Postion //坐标位置
    size int                  //长度
    dir  byte                 //方向
}

//食物子类
type Food struct {
    Postion
}

//绘制界面
func DrawUI(p Postion, ch byte) {

    //通过C函数更改控制台光标
    Clib.GotoPostion(p.X*2+4, p.Y+2)
    fmt.Fprintf(os.Stderr, "%c", ch)

}

//蛇初始化方法
func (s *Snake) Init() {
    //初始化蛇的长度
    s.size = 2
    //初始化蛇的坐标位置
    s.pos[0].X = WIDE / 2
    s.pos[0].Y = HIGH / 2

    s.pos[1].X = WIDE/2 - 1
    s.pos[1].Y = HIGH / 2

    //初始化蛇的方向
    //U 上 L 左 R 右 D 下 P 暂停
    s.dir = 'R'

    // 输出初始画面
    fmt.Fprintln(os.Stderr,
        `
  #-----------------------------------------#
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  |                                         |
  #-----------------------------------------#
`)

    //食物初始化
    food = Food{Postion{rand.Intn(WIDE), rand.Intn(HIGH)}}
    //判断  食物和蛇 障碍物重合(需完善)
    DrawUI(food.Postion, '#')
    //Clib.Direction()
    //调用C函数Direction()通过键盘控制方向
    //go独立程序 用来接收键盘输入的值 非阻塞式调用
    go func() {
        for {
            switch Clib.Direction() {
            //方向上  W|w|↑
            case 72, 87, 119:
                s.dir = 'U'
                //方向左
            case 65, 97, 75:
                s.dir = 'L'
                //方向右
            case 100, 68, 77:
                s.dir = 'R'
                //方向下
            case 83, 115, 80:
                s.dir = 'D'
                //暂停  空格键
            case 32:
                s.dir = 'P'
            }
        }
    }()
}

//开始游戏
func (s *Snake) PlayGame() {
    for {
        //程序更新周期  333毫秒  3可以表示等级 (在关卡中 表示蛇的速度 需要完善)
        time.Sleep(time.Second / 3)
        //time.Sleep(time.Millisecond * 300)

        //暂停
        if s.dir == 'P' {
            continue
        }

        //蛇头和墙的碰撞判断
        if s.pos[0].X < 0 || s.pos[0].X >= WIDE || s.pos[0].Y < 0 || s.pos[0].Y >= HIGH {
            //将游戏光标设置在末尾
            Clib.GotoPostion(0, 23)
            return
        }

        //蛇头和身体碰撞
        for i := 1; i < s.size; i++ {
            if s.pos[0].X == s.pos[i].X && s.pos[0].Y == s.pos[i].Y {
                //将游戏光标设置在末尾
                Clib.GotoPostion(0, 23)
                return
            }
        }

        //蛇和食物的碰撞
        if s.pos[0].X == food.X && s.pos[0].Y == food.Y {
            //蛇身体增加
            s.size++
            //分数增加
            score++
            //生成新的食物
            food = Food{Postion{rand.Intn(WIDE), rand.Intn(HIGH)}}
            DrawUI(food.Postion, '#')
        }

        //方向控制
        switch s.dir {
        case 'U':
            dx = 0
            dy = -1
        case 'L':
            dx = -1
            dy = 0
        case 'R':
            dx = 1
            dy = 0
        case 'D':
            dx = 0
            dy = 1

        }
        //记录最后一节坐标
        lp := s.pos[s.size-1] //Postion
        //顺序为每一节蛇坐标赋值
        for i := s.size - 1; i > 0; i-- {
            //用前一节坐标位当前节赋值
            s.pos[i] = s.pos[i-1]
            DrawUI(s.pos[i], '*')
        }
        //将蛇移动过的位置 设为空格
        DrawUI(lp, ' ')

        //更新蛇头坐标
        s.pos[0].X += dx
        s.pos[0].Y += dy
        DrawUI(s.pos[0], '@')
    }
}

func main() {

    //创建随机数种子
    rand.Seed(time.Now().UnixNano())
    //去掉控制台光标
    Clib.HideCursor()

    var s Snake
    //蛇的初始化
    s.Init()

    //开始游戏
    s.PlayGame()
    fmt.Println("分数:",score)

    //20秒后自动关闭界面
    time.Sleep(time.Second*20)
    //fmt.Scan(&score)

}

注意:go和c可以实现混合编程,所以需要创建一个clib包引入c中的控制台程序,编码如下:

package Clib


#include 
#include 

// 使用了WinAPI来移动控制台的光标
void gotoxy(int x,int y)
{
    COORD c;
    c.X=x,c.Y=y;
    SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),c);
}

// 从键盘获取一次按键,但不显示到控制台
int direct()
{
    return _getch();
}
//去掉控制台光标
void hideCursor()
{
    CONSOLE_CURSOR_INFO  cci;
    cci.bVisible = FALSE;
    cci.dwSize = sizeof(cci);
    SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cci);
}

import "C" // go中可以嵌入C语言的函数

//设置控制台光标位置
func GotoPostion(X int, Y int) {
    //调用C语言函数
    C.gotoxy(C.int(X), C.int(Y))
}
//无显获取键盘输入的字符
func Direction() (key int) {
    key = int(C.direct())
    return
}
//设置控制台光标隐藏
func HideCursor() {
    C.hideCursor()
}

以上就是简易的贪吃蛇小程序了,其中还存在不少不完善的地方,小伙伴们还可以思考一下如何精进这个程序。可以加入排名系统,加入AI蛇与之pk,也可以做成双人贪吃蛇,欢迎一起讨论

你可能感兴趣的:(golang)