之前撸了一个控制台的贪吃蛇,分享出来一下

jan-bar · · 1028 次点击 · 开始浏览    置顶
这是一个创建于 的主题,其中的信息可能已经有所发展或是发生改变。

[码云地址](https://gitee.com/janbar/GluttonousSnake) 下面是源码: ```go package main import ( "container/list" "fmt" "math/rand" "time" "github.com/jan-bar/golibs" ) const ( LengthX = 20 /* 矩阵行数 */ LengthY = 40 /* 矩阵列数 */ NoneFlag = 0 /* 空白标识 */ FoodFlag = 1 /* 食物标识 */ BodyFlag = 2 /* 蛇身标识 */ ) var ( MatrixData [LengthX][LengthY]byte /* 0:表示空位,1表示食物,2表示蛇 */ api *golibs.Win32Api ) /** * 初始化 **/ func init() { api = golibs.NewWin32Api() api.Clear() /* 清屏 */ rand.Seed(time.Now().UnixNano()) /* 初始化随机数种子 */ api.SetWindowText("贪吃蛇") /* 设置标题 */ api.CenterWindowOnScreen(550, 400) /* 居中显示,并设置窗口大小 */ api.ShowHideCursor(false) /* 隐藏光标 */ var i int api.GotoXY(1, 0) for i = 0; i < LengthY; i++ { fmt.Print("-") /* 画顶部横线 */ } api.GotoXY(1, LengthX+1) for i = 0; i < LengthY; i++ { fmt.Print("-") /* 画底部横线 */ } for i = 1; i <= LengthX; i++ { api.GotoXY(0, i) fmt.Print("|") /* 画左边竖线 */ api.GotoXY(LengthY+1, i) fmt.Print("|") /* 画右边竖线 */ } } /** * 主程序 **/ func main() { var ( headPos = golibs.Coord{LengthX / 2, LengthY / 2} dirNew int32 = golibs.KeyUp dirOld int32 = golibs.KeyUp direction = make(chan int32) tLoop = time.NewTimer(time.Second) Snake = list.New() /* 创建蛇身链表 */ score = 0 /* 吃一个食物加1分 */ ) DrawSnake(headPos, BodyFlag) Snake.PushFront(headPos) /* 链表存储蛇头位置 */ RandFood() /* 初始一个食物 */ PrintScore(score) /* 打印初始分数 */ go func() { for { /* 此处只往通道丢获取的按键值 */ direction <- golibs.WaitKeyBoard() } }() for { headPos = Snake.Front().Value.(golibs.Coord) /* 每次取蛇头位置 */ select { case dir, ok := <-direction: tLoop.Stop() /* 避免改变方向时定时的循环也移动一下蛇身 */ if ok { dirNew = dir /* 得到新的方向 */ } case <-tLoop.C: /* 这里,每秒刷新游戏 */ } tLoop.Reset(time.Second) /* 重置间隔时间 */ switch dirNew { case golibs.KeyUp: /* 新方向朝上 */ if dirOld == golibs.KeyDown { dirNew = golibs.KeyDown headPos.X++ /* 旧方向如果朝下,则继续向下走 */ } else { /* 旧方向为: 左右上 */ dirOld = golibs.KeyUp headPos.X-- } case golibs.KeyDown: if dirOld == golibs.KeyUp { dirNew = golibs.KeyUp headPos.X-- /* 旧方向如果朝上,则继续向上走 */ } else { /* 旧方向为: 左右下 */ dirOld = golibs.KeyDown headPos.X++ } case golibs.KeyLeft: if dirOld == golibs.KeyRight { dirNew = golibs.KeyRight headPos.Y++ /* 旧方向如果朝右,则继续向右走 */ } else { /* 旧方向为: 上下左 */ dirOld = golibs.KeyLeft headPos.Y-- } case golibs.KeyRight: if dirOld == golibs.KeyLeft { dirNew = golibs.KeyLeft headPos.Y-- /* 旧方向如果朝左,则继续向左走 */ } else { /* 旧方向为: 上下右 */ dirOld = golibs.KeyRight headPos.Y++ } } if headPos.X < 0 || headPos.Y < 0 || headPos.X >= LengthX || headPos.Y >= LengthY || MatrixData[headPos.X][headPos.Y] == BodyFlag { api.GotoXY(LengthY+3, 7) fmt.Print("你输了,按回车退出!") break /* 越界了,这个位置是蛇身,游戏结束 */ } if MatrixData[headPos.X][headPos.Y] == NoneFlag { var end = Snake.Back() /* 如果头部为空白,则尾部也要去掉一个 */ DrawSnake(end.Value.(golibs.Coord), NoneFlag) /* 将蛇尾置位为空白 */ Snake.Remove(end) /* 下一步是空白,尾部删除一个蛇尾 */ } else { /* 吃到一个食物,则需要再初始化一个食物 */ score++ /* 吃一个食物加1分 */ PrintScore(score) RandFood() } Snake.PushFront(headPos) /* 头部加入链表 */ DrawSnake(headPos, BodyFlag) } fmt.Scanln() /* 避免一闪而逝 */ } /** * 打印分数 **/ func PrintScore(score int) { api.GotoXY(LengthY+3, 5) fmt.Print("分数:", score) } /** * 在指定位置画整个界面数据 * 包括空白,蛇,食物 **/ func DrawSnake(pos golibs.Coord, dType byte) { MatrixData[pos.X][pos.Y] = dType /* 标记这个位置的类型 */ api.GotoXY(pos.Y+1, pos.X+1) switch dType { case NoneFlag: fmt.Print(" ") case BodyFlag: fmt.Print("#") case FoodFlag: fmt.Print("+") } } /** * 在空白位置 * 随机画一个食物 **/ func RandFood() { var i, j int for { i = rand.Intn(LengthX) /* 随机一个X值 */ j = rand.Intn(LengthY) /* 随机一个Y值 */ if NoneFlag == MatrixData[i][j] { DrawSnake(golibs.Coord{i, j}, FoodFlag) break /* 空白位置画一个食物 */ } } } /** 下面是对链表库的解释 func (e *Element) Next() *Element //返回该元素的下一个元素,如果没有下一个元素则返回nil func (e *Element) Prev() *Element//返回该元素的前一个元素,如果没有前一个元素则返回nil。 func New() *List //返回一个初始化的list func (l *List) Back() *Element //获取list l的最后一个元素 func (l *List) Front() *Element //获取list l的第一个元素 func (l *List) Init() *List //list l初始化或者清除list l func (l *List) InsertAfter(v interface{}, mark *Element) *Element //在list l中元素mark之后插入一个值为v的元素,并返回该元素,如果mark不是list中元素,则list不改变。 func (l *List) InsertBefore(v interface{}, mark *Element) *Element//在list l中元素mark之前插入一个值为v的元素,并返回该元素,如果mark不是list中元素,则list不改变。 func (l *List) Len() int //获取list l的长度 func (l *List) MoveAfter(e, mark *Element) //将元素e移动到元素mark之后,如果元素e或者mark不属于list l,或者e==mark,则list l不改变。 func (l *List) MoveBefore(e, mark *Element)//将元素e移动到元素mark之前,如果元素e或者mark不属于list l,或者e==mark,则list l不改变。 func (l *List) MoveToBack(e *Element)//将元素e移动到list l的末尾,如果e不属于list l,则list不改变。 func (l *List) MoveToFront(e *Element)//将元素e移动到list l的首部,如果e不属于list l,则list不改变。 func (l *List) PushBack(v interface{}) *Element//在list l的末尾插入值为v的元素,并返回该元素。 func (l *List) PushBackList(other *List)//在list l的尾部插入另外一个list,其中l和other可以相等。 func (l *List) PushFront(v interface{}) *Element//在list l的首部插入值为v的元素,并返回该元素。 func (l *List) PushFrontList(other *List)//在list l的首部插入另外一个list,其中l和other可以相等。 func (l *List) Remove(e *Element) interface{}//如果元素e属于list l,将其从list中删除,并返回元素e的值。 **/ ``` ![Snake.gif](https://static.studygolang.com/190926/a8e776caa9a8177e20884b4f39c581c1.gif) 上面是效果图,里面win32api也是我参照另一个开源项目写的。

有疑问加站长微信联系(非本文作者)

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

1028 次点击  ∙  2 赞  
加入收藏 微博
暂无回复
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传