基于Golang編寫貪吃蛇游戲
更新時間:2023年07月28日 16:59:49 作者:LeoForBest
這篇文章主要為大家學習介紹了Golang如何基于終端庫termbox-go做個功能較簡單的貪吃蛇游戲,文中的示例代碼講解詳細,具有一定的學習價值
基于終端庫termbox-go
做了個貪吃蛇游戲, 功能較簡單,代碼約160行左右
一:原理介紹
1. 繪制原理
存儲好蛇身和食物坐標都存儲在Snake結構中
定時300毫秒執(zhí)行移動蛇身/生成食物,然后清空終端再重新根據坐標繪制點●
達到模擬動畫效果
type Location struct { X int Y int } type Snake struct { Body []Location Food Location ...... } func Draw(s *Snake) { termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) for _, location := range s.Body { termbox.SetCell(location.X, location.Y, '●', termbox.ColorGreen, termbox.ColorDefault) } termbox.SetCell(s.Food.X, s.Food.Y, '●', termbox.ColorRed, termbox.ColorDefault) termbox.Flush() }
2.貪吃蛇移動過程
原理很簡單,根據當前行走方向,追加一個點到[]Localtion
如果蛇頭位置不是食物位置,刪除[]Localtion
第一個點, 添加一個點(最后一個點位置+1
)相當于行走了
如果恰好是食物位置,添加一個點(最后一個點位置+1
),再隨機生成食物
// 移動一步, 如果碰壁返回false, 否則返回true func (s *Snake) Move() bool { head := s.GetHead() switch s.Direction { case DIRECTION_UP: s.Body = append(s.Body, Location{head.X, head.Y - 1}) case DIRECTION_DOWN: s.Body = append(s.Body, Location{head.X, head.Y + 1}) case DIRECTION_LEFT: s.Body = append(s.Body, Location{head.X - 1, head.Y}) case DIRECTION_RIGHT: s.Body = append(s.Body, Location{head.X + 1, head.Y}) } head = s.GetHead() // 蛇頭到達食物位置時標記食物已吃,并且追加到蛇尾(s.Body[0]不用剔除, 否則剔除) if head == s.Food { s.FoodEated = true s.RandomFood() s.Score += 10 } else { s.Body = s.Body[1:] } return 0 <= head.X && head.X <= s.MaxX && 0 <= head.Y && head.Y <= s.MaxY }
3.生成食物過程
僅需要注意是否生成在蛇身本身,是的話再生成
// 判斷生成的食物坐標是否在蛇身上 func (s *Snake) isFoodInSnake(location Location) bool { for _, l := range s.Body { if l == location { return true } } return false } // 生成食物 func (s *Snake) RandomFood() { w, h := termbox.Size() // 上下兩邊留點空隙 location := Location{rand.Intn(w-10) + 5, rand.Intn(h-10) + 5} for s.isFoodInSnake(location) { location = Location{rand.Intn(w), rand.Intn(h)} } s.Food = location }
4.效果
二:完整代碼
package main import ( "fmt" "math/rand" "time" "github.com/nsf/termbox-go" ) const ( DIRECTION_LEFT int = iota DIRECTION_RIGHT DIRECTION_UP DIRECTION_DOWN ) type Location struct { X int Y int } type Snake struct { Body []Location Food Location FoodEated bool Direction int MaxX int MaxY int Score int } // 獲取蛇頭位置 func (s *Snake) GetHead() Location { return s.Body[len(s.Body)-1] } // 移動一步, 如果碰壁返回false, 否則返回true func (s *Snake) Move() bool { head := s.GetHead() switch s.Direction { case DIRECTION_UP: s.Body = append(s.Body, Location{head.X, head.Y - 1}) case DIRECTION_DOWN: s.Body = append(s.Body, Location{head.X, head.Y + 1}) case DIRECTION_LEFT: s.Body = append(s.Body, Location{head.X - 1, head.Y}) case DIRECTION_RIGHT: s.Body = append(s.Body, Location{head.X + 1, head.Y}) } head = s.GetHead() // 蛇頭到達食物位置時標記食物已吃,并且追加到蛇尾(s.Body[0]不用剔除, 否則剔除) if head == s.Food { s.FoodEated = true s.RandomFood() s.Score += 10 } else { s.Body = s.Body[1:] } return 0 <= head.X && head.X <= s.MaxX && 0 <= head.Y && head.Y <= s.MaxY } // 判斷生成的食物坐標是否在蛇身上 func (s *Snake) isFoodInSnake(location Location) bool { for _, l := range s.Body { if l == location { return true } } return false } // 生成食物 func (s *Snake) RandomFood() { w, h := termbox.Size() // 上下兩邊留點空隙 location := Location{rand.Intn(w-10) + 5, rand.Intn(h-10) + 5} for s.isFoodInSnake(location) { location = Location{rand.Intn(w), rand.Intn(h)} } s.Food = location } func Draw(s *Snake) { termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) for _, location := range s.Body { termbox.SetCell(location.X, location.Y, '●', termbox.ColorGreen, termbox.ColorDefault) } termbox.SetCell(s.Food.X, s.Food.Y, '●', termbox.ColorRed, termbox.ColorDefault) termbox.Flush() } func main() { err := termbox.Init() if err != nil { panic(err) } defer termbox.Close() w, h := termbox.Size() // 初始給它三個長度吧, 太小不好看 snake := Snake{ Body: []Location{{0, 0}, {1, 0}, {2, 0}}, Direction: DIRECTION_RIGHT, MaxX: w, MaxY: h, FoodEated: false, } snake.RandomFood() Draw(&snake) event_queue := make(chan termbox.Event) go func() { for { event_queue <- termbox.PollEvent() } }() gameFinished := false msgPrinted := false msg := `\n ***************************************** Game Over ! Score: %d Press Esc to exit! ***************************************** ` loop: for { select { case ev := <-event_queue: if ev.Type == termbox.EventKey && ev.Key == termbox.KeyEsc { break loop } else if ev.Type == termbox.EventKey { switch ev.Key { case termbox.KeyArrowUp: snake.Direction = DIRECTION_UP case termbox.KeyArrowDown: snake.Direction = DIRECTION_DOWN case termbox.KeyArrowLeft: snake.Direction = DIRECTION_LEFT case termbox.KeyArrowRight: snake.Direction = DIRECTION_RIGHT } } default: time.Sleep(300 * time.Millisecond) if gameFinished && !msgPrinted { termbox.Clear(termbox.ColorDefault, termbox.ColorDefault) termbox.Flush() fmt.Printf(msg, snake.Score) msgPrinted = true } else { if success := snake.Move(); !success { gameFinished = true } Draw(&snake) } } } }
到此這篇關于基于Golang編寫貪吃蛇游戲的文章就介紹到這了,更多相關Golang貪吃蛇內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!