Go + C 一款简单的贪吃蛇

2 篇文章 1 订阅

前言

这是一款运行在window上简单贪吃蛇,需要电脑上gcc编译C语言代码,可以参考win10下安装gcc/g++

代码【下载

package main

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

// 全局常量
const (
	WIDTH     = 40  // 地图宽度
	HEIGHT    = 20  // 地图高度
	LENGTH    = 2   // 蛇长度
	DIRECTION = 'R' // 方向
)

// 全局变量
var (
	food  Food                            // 食物
	delay time.Duration = time.Second / 2 // 速度
	score int           = 0               // 分数
)

// 初始化父类坐标
type Position struct {
	X int
	Y int
}

// 初始化蛇子类
type Snake struct {
	len int                      // 长度
	dir int                      // 方向
	pos [WIDTH * HEIGHT]Position // 定义数组,存储每一节蛇的坐标
}

// 初始化食物子类
type Food struct {
	Position
}

// 初始化游戏地图
func MapInit() {
	fmt.Fprintln(os.Stderr, `
                    贪吃蛇
  #----------------------------------------#
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  |                                        |
  #----------------------------------------#
`)
}

// 初始化蛇信息
func (s *Snake) SnakeInit() {
	s.len = LENGTH    // 蛇长度
	s.dir = DIRECTION // 蛇方向

	// 蛇位置
	s.pos[0].X = WIDTH / 2
	s.pos[0].Y = HEIGHT / 2
	s.pos[1].X = WIDTH/2 - 1
	s.pos[1].Y = HEIGHT / 2

	s.snake()    // 绘制蛇
	s.getInput() // 接受键盘输入
}

// 绘制蛇
func (s *Snake) snake() {
	for i := 0; i < s.len; i++ {
		var ch byte
		// 区分蛇头和身体
		if i == 0 {
			ch = '@'
		} else {
			ch = '*'
		}
		Show(s.pos[i].X, s.pos[i].Y, ch)
	}
}

// 接受指定键盘按键输入
func (s *Snake) getInput() {
	go func() {
		for {
			switch Clib.Direction() {
			case 80, 68, 100:
				if s.dir != 'U' {
					s.dir = 'D'
				}
			case 72, 85, 117:
				if s.dir != 'D' {
					s.dir = 'U'
				}
			case 77, 82, 114:
				if s.dir != 'L' {
					s.dir = 'R'
				}
			case 75, 76, 108:
				if s.dir != 'R' {
					s.dir = 'L'
				}
			case 32:
				s.dir = 'P'
			}
		}
	}()
}

// 蛇运动
func (s *Snake) Play() {
	// 游戏流程控制
	for {
	FLAG:
		time.Sleep(delay) // 延迟调用
		if s.dir == 'P' {
			goto FLAG
		}
		if s.check() == false { // 生命检测
			break
		}
		s.eating()      // 享受美食
		s.changeSpeed() // 改变速度
		s.updatePos()   // 更新蛇位置
		s.snake()       // 绘制蛇的UI
	}
}

// 生命检测
func (s *Snake) check() bool {
	// 蛇和墙碰撞
	if s.pos[0].X <= 2 || s.pos[0].X >= WIDTH+3 || s.pos[0].Y <= 2 || s.pos[0].Y >= HEIGHT+3 {
		return false
	}
	// 蛇头和身体碰撞
	for i := 1; i < s.len; i++ {
		if s.pos[0].X == s.pos[i].X && s.pos[0].Y == s.pos[i].Y {
			return false
		}
	}
	return true
}

// 更新位置
func (s *Snake) updatePos() {
	Show(s.pos[s.len-1].X, s.pos[s.len-1].Y, ' ') // 将末尾置空
	// 更新蛇身体坐标
	for i := s.len - 1; i > 0; i-- {
		s.pos[i].X = s.pos[i-1].X
		s.pos[i].Y = s.pos[i-1].Y
		Show(s.pos[i].X, s.pos[i].Y, '*')
	}

	// 根据方向改变蛇头位置
	switch s.dir {
	case 'U':
		s.pos[0].Y += -1
	case 'D':
		s.pos[0].Y += 1
	case 'L':
		s.pos[0].X += -1
	case 'R':
		s.pos[0].X += 1
	}
	Show(s.pos[0].X, s.pos[0].Y, '@') // 绘制蛇头

}

// 享受美食
func (s *Snake) eating() {
	if s.pos[0].X == food.X && s.pos[0].Y == food.Y {
		s.len++        // 身体增加
		s.randomFood() // 创建随机食物
		score ++
		s.showScore() // 显示等分
	}
}

// 根据得分改变速度
func (s *Snake) changeSpeed() {
	delay = time.Second / (time.Duration(score/20) + 3)
}

// 随机食物
func (s *Snake) randomFood() {
	// 随机食物
	for i := 1; i < s.len; i++ {
		food.X = RandInt(3, WIDTH+3)
		food.Y = RandInt(3, HEIGHT+3)
		if food.X == s.pos[i].X && food.Y == s.pos[i].Y {
			continue
		}
	}
	Show(food.X, food.Y, '$') // 显示食物
}

// 显示信息
func Show(X int, Y int, ch byte) {
	Clib.GotoPosition(X, Y)          // 调用C语言代码设置控制光标位置
	fmt.Fprintf(os.Stderr, "%c", ch) // 将字符绘制在界面中
}

// 两者之间随机数 左闭右开
func RandInt(min, max int) int {
	if min >= max || min == 0 || max == 0 {
		return max
	}
	return rand.Intn(max-min) + min
}

// 显示等分
func (s *Snake) showScore() {
	Clib.GotoPosition(2, 24)
	fmt.Fprintf(os.Stderr, "%s", "分数:"+strconv.Itoa(score))
}

// 游戏结束
func (s *Snake) gameOver() {
	// 擦除食物
	Clib.GotoPosition(food.X, food.Y)
	fmt.Fprintf(os.Stderr, "%s", " ")
	// 显示Game Over
	Clib.GotoPosition(18, 10)
	fmt.Fprintf(os.Stderr, "%s", "Game Over")
	// 显示等分
	Clib.GotoPosition(22, 12)
	fmt.Fprintf(os.Stderr, "%s", strconv.Itoa(score))
	// 暂停关闭
	time.Sleep(time.Second * 10)
}

func main() {
	rand.Seed(time.Now().UnixNano()) // 创建随机数种子
	Clib.HideCursor()                // 隐藏控制台光标
	MapInit()                        // 初始化地图
	var s Snake                      // 创建蛇对象
	s.SnakeInit()                    // 初始化蛇信息
	s.randomFood()                   // 随机食物
	s.Play()                         // 开始游戏
	s.gameOver()                     // 游戏结束
}
package Clib

/*
#include<windows.h>
#include<conio.h>
//使用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 GotoPosition(X int, Y int) {
	C.gotoxy(C.int(X), C.int(Y))
}

// 无显示键盘输入字符
func Direction() (key int) {
	key = int(C.direct())
	return
}

// 隐藏鼠标
func HideCursor() {
	C.hideCursor()
}

 

备注:代码学习参考黑马《go语言与区块链精品入门课程视频》视频课程

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值