go语言实现推箱子游戏

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yang731227/article/details/88914718

title: go语言实现推箱子游戏
tags: go


相信大家都玩过推箱子这个游戏,本文我们就将用go语言实现一个推箱子游戏。

地图构建

首先我随便找了一个推箱子的关卡,并且用坐标的方式展现出来。

我们可以看到其实这个地图就是个二维数组。因此我们先声明一个二维数组。

	const (
		W = 10
		H = 7
	)
 var GameMap = [H][W]int{}

我们用二维数组存储的内容来表示不同的物体,用0 表示空地,用1表示墙,用2表示小人,用3表示箱子,用4表示箱子推放的地点。现在我们来对刚刚到数组初始化下。

	var GameMap = [H][W]int{
		{0, 0, 0, 1, 1, 1, 1, 1, 1, 0},
		{0, 1, 1, 1, 0, 0, 0, 0, 1, 0},
		{1, 1, 4, 0, 3, 1, 1, 0, 1, 1},
		{1, 4, 4, 3, 0, 3, 0, 0, 2, 1},
		{1, 4, 4, 0, 3, 0, 3, 0, 1, 1},
		{1, 1, 1, 1, 1, 1, 0, 0, 1, 0},
		{0, 0, 0, 0, 0, 1, 1, 1, 1, 0},
	}

地图显示

地图构建好了,我们现在再来设置地图的显示,我们通过二维数组遍历的方法,来打印地图。

	func initMap() {

		for i := 0; i < H; i++ {
			for j := 0; j < W; j++ {

				switch (GameMap[i][j]) {
				case 0:
					fmt.Printf(" ")//空地
				case 1:
					fmt.Printf("▒") //墙
				case 2:
					fmt.Printf("♘") //人
				case 3:
					fmt.Printf("✩") //箱子
				case 4:
					fmt.Printf("⊙") //箱子推放的终点
				case 6:
					fmt.Printf("♞") //人物走到箱子存放点显示
				case 7:
					fmt.Printf("✭") //箱子推到存放点显示
				}
			}
			fmt.Println()
		}
	}

1 2 3 4 的内容没什么好说的,我们具体的说下6和7, 就是当人物和箱子和4(箱子存放点)重叠的时候,起到变色效果。

接收键盘事件

因为go语言没有像c语言一样,给我们提供无缓冲输入getch。所以我们需要借助一个开源包来帮我实现键盘接收功能。
使用下面的命令安装库:

go get github.com/nsf/termbox-go

扫描二维码关注公众号,回复: 5843418 查看本文章

有一点需要注意一下,使用go run 直接在控制台中会编译错误。最好使用go build 打包后运行。

我们需要在main函数中添加这个初始化代码

		for true {
			err := termbox.Init()
			if err != nil {
				panic(err)
			}
			defer termbox.Close()
func control() {


		/******键盘事件代码*******/
		switch ev := termbox.PollEvent(); ev.Type {
		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyArrowUp: //小键盘向上
			
			case termbox.KeyArrowDown://小键盘向下
			
			case termbox.KeyArrowLeft://小键盘向左
			
			case termbox.KeyArrowRight://小键盘向右
			
			case termbox.KeyF5://F5 用来重置地图
			
			}
		}

逻辑判断

我们首先设置小人向上移动,我们之前说过,地图其实就是个二维数组,我们想要向上移动,只需要把小人的纵坐标减一个单位就行。
我们的地图只有小人和箱子可以移动,但是箱子的移动又是依靠小人的推动。所以我们的给小人的位置设置成2个变量。

var col, row int // col row 是人物所在坐标变量

我们简单说下人物向上的逻辑:

  • 想要人物向上移动,就需要先判断人物上一个坐标是不是空地,能不能走;
  • 人物向上移动的时候,我们需要把人物原来所在地位置变为空地,然后把上面的空地变成人物;
  • 如果人物的上面是箱子,并且箱子的上面是空地,那么我们就以人物现在的位置为参照点,把人物移动一个单位长度,把箱子移动2个单位长度;
  • 箱子跟人物一样都想要重新设置位置,把原来箱子的位置设置为小人,然后把箱子上面的空地重新设置为箱子;
  • 当我走错想要重新开始的时候,只需要把GameMap重新初始化就行

然后其他的键盘事件,如向下、向左、向右事件都是类似的,都是参考小人的当前坐标来的。

  • 小人向下 纵坐标加1
  • 小人向左 横坐标减1
  • 小人向右 横坐标加1
func control() {
		var col, row int // col row 是人物所在坐标变量
		for i := 0; i < H; i++ {
			for j := 0; j < W; j++ {
				if GameMap[i][j] == 2 || GameMap[i][j] == 6 {
					col = i
					row = j
				}
			}
		}
		//ch, _ := getch.Getch()
		switch ev := termbox.PollEvent(); ev.Type {
		case termbox.EventKey:
			switch ev.Key {
			case termbox.KeyArrowUp:
				if GameMap[col-1][row] == 0 || GameMap[col-1][row] == 4 { //col-1 就是 Y坐标-1 就是往上
					GameMap[col][row] -= 2;   //因为要移动人物,所以我们要在移动人物的时候 把人物原来的位置重新绘图
					GameMap[col-1][row] += 2; // 让上一个坐标的位置 等于2  绘制出 人物
					//  如果往上是箱子
				} else if GameMap[col-1][row] == 3 || GameMap[col-1][row] == 7 {
					if GameMap[col-2][row] == 0 || GameMap[col-2][row] == 4 { //因为人要推箱子,所以Y坐标-2,如果箱子上面是空地
						GameMap[col][row] -= 2;   // 重新绘图人物 col =1  row =5
						GameMap[col-1][row] -= 1; // 往上再减1 就是 1-1 =0  5-1 =4   设置箱子原来位置为空地
						GameMap[col-2][row] += 3; // 重新设置箱子的位置
					}
				}

			case termbox.KeyArrowDown:
				if GameMap[col+1][row] == 0 || GameMap[col+1][row] == 4 {
					GameMap[col][row] -= 2;
					GameMap[col+1][row] += 2;
				} else if GameMap[col+2][row] == 0 || GameMap[col+2][row] == 4 {
					if GameMap[col+1][row] == 3 || GameMap[col+1][row] == 7 {
						GameMap[col][row] -= 2;
						GameMap[col+1][row] -= 1;
						GameMap[col+2][row] += 3;
					}
				}
			case termbox.KeyArrowLeft:
				if (GameMap[col][row-1] == 0 || GameMap[col][row-1] == 4) {
					GameMap[col][row] -= 2;
					GameMap[col][row-1] += 2;
				} else if (GameMap[col][row-2] == 0 || GameMap[col][row-2] == 4) {
					if (GameMap[col][row-1] == 3 || GameMap[col][row-1] == 7) {
						GameMap[col][row] -= 2;
						GameMap[col][row-1] -= 1;
						GameMap[col][row-2] += 3;
					}
				}
			case termbox.KeyArrowRight:
				if (GameMap[col][row+1] == 0 || GameMap[col][row+1] == 4) {
					GameMap[col][row] -= 2;
					GameMap[col][row+1] += 2;
				} else if (GameMap[col][row+2] == 0 || GameMap[col][row+2] == 4) {
					if (GameMap[col][row+1] == 3 || GameMap[col][row+1] == 7) {
						GameMap[col][row] -= 2;
						GameMap[col][row+1] -= 1;
						GameMap[col][row+2] += 3;
					}
				}
			case termbox.KeyF5:
			GameMap = [H][W]int{
					{0, 0, 0, 1, 1, 1, 1, 1, 1, 0},
					{0, 1, 1, 1, 0, 0, 0, 0, 1, 0},
					{1, 1, 4, 0, 3, 1, 1, 0, 1, 1},
					{1, 4, 4, 3, 0, 3, 0, 0, 2, 1},
					{1, 4, 4, 0, 3, 0, 3, 0, 1, 1},
					{1, 1, 1, 1, 1, 1, 0, 0, 1, 0},
					{0, 0, 0, 0, 0, 1, 1, 1, 1, 0},
				}
			}
		}

	}

有一点需要注意,需要设置小人坐标越界处理。 比如说小人一直向左走,横坐标会一直减-1,如果超出二维数组的范围,就会产生数组越界。

打印处理

因为我们的游戏是通过控制台循环打印来实现的,这种方法如果不做一些处理,屏幕会不断的下滚,打印N次,因此我们需要每次打印前都清空下控制台。使用控制台打印还存在一个问题,如果我们不设置下打印时间等待,就会造成游戏一直闪烁。

	func main() {
	
		for true {
			err := termbox.Init()
			if err != nil {
				panic(err)
			}
			defer termbox.Close()
		 //清空控制台。
			cmd := exec.Command("clear") //mac的清屏命令
			//exec.Command("cmd", "/c", "cls") //如果是win使用该调命令
			cmd.Stdout = os.Stdout
			cmd.Run()
			initMap()
			control()
			time.Sleep(100)

		}

	}

通关判断

没有推到存放点的箱子,我们是通过二维数组值为3来定义的,存放倒终点的箱子是通过7来定义的。我们可以遍历数组,当二维数组中的值没有3,那说明箱子已经全部存放倒终点,说明过关。

总结

我们已经实现的推箱子的基本功能,你可以再次基础上添加背景音乐,多重关卡,步数显示等功能。

猜你喜欢

转载自blog.csdn.net/yang731227/article/details/88914718