前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go项目开发----2048小游戏(上)

Go项目开发----2048小游戏(上)

作者头像
李海彬
发布2018-03-22 12:02:24
2K0
发布2018-03-22 12:02:24
举报
文章被收录于专栏:Golang语言社区Golang语言社区

刚接触go语言不久,前段时间看到一个2048的项目开发教程,于是就试着练了下手。我的环境采用的是Ubuntu Linux环境。

源码下载:

https://github.com/shiyanlou/golang2048_game.git

http://download.csdn.net/detail/hzy305365977/8067803

项目开发详细教程:

http://www.shiyanlou.com/courses/type/1

一. 2048 游戏设计

《2048》由19岁的意大利人Gabriele Cirulli于2014年3月开发。游戏任务是在一个网格上滑动小方块来进行组合,直到形成一个带有有数字2048的方块。《2048》使用方向键让方块上下左右移动。如果两个带有相同数字的方块在移动中碰撞,则它们会合并为一个方块,且所带数字变为两者之和。每次移动时,会有一个值为2或者4的新方块出现。当值为2048的方块出现时,游戏即胜利。

1. 游戏逻辑设计

2048游戏使用4x4的格子来表示需要移动的数字,这不难想到可以使用一个矩阵来表示这些数字,我们使用type G2048 [4][4]int来表示。每一次使用方向键来移动数字时,对应方向上的数字需要进行移动和合并,也就是移动和合并矩阵中的非零值。当按下不同的方向键时,移动的数字也不同。我们一共会向上、向下、向左、向右四个方向移动数字,可以通过旋转矩阵将向下、向左、向右的移动都转换为向上的移动,这样能一定程度上简化游戏逻辑。大致流程图如下:

2. 界面设计

开发的2048游戏将运行在console下。在console中,我们可以控制每一个字符单元的背景色,以及显示的字符。我们可以根据这一点,在console中绘制中图形,也就是2048游戏的框架:4x4的空白格子,然后每一个格子是4个字符单元,也就是最多能显示四位数字。我们将使用包github.com/nsf/termbox-go进行界面的绘制,termbox-go能很方便的设置字符单元的属性。

三. 2048游戏的实现

2048游戏中的难点有两个地方,一个是矩阵中数字的移动合并,另一个则是矩阵的变换,之所以需要对矩阵进行变换,是为了将2048游戏中向下的移动,向左的移动和向右的移动都转换成向上的移动操作。

1. 矩阵的旋转

矩阵的旋转操作是为了将其他三个方向的移动都转换为向上的移动操作。向下(↓)、向左(←)、向右(→)转换为向上(↑)的操作时,数组需要进行的翻转操作如下所示:

· ↓ → ↑ 此类转换可以有多种方法做到:

o 上下翻转矩阵,然后向上移动合并,再次上下翻转矩阵上下翻转后:martix_new[n-1-x][y]= martix_old[x][y]

o 顺时针翻转180度矩阵,然后向上移动合并,接着逆时针旋转180度此时martix_new[n-1-x]n-1-y]= martix_old[x][y]

· ← → ↑ 此类转换可以将矩阵向右旋转90度后,向上移动合并,接着向左旋转90度完成向右旋转90度后:martix_new[y][n-x-1] = martix_old[x][y] 向左旋转90度后:martix_new[n-y-1][x]= martix_old[x][y]

· → → ↑ 此类转换可以将矩阵向左旋转90度后,向上移动合并,接着向右旋转90度完成

主要代码:

代码语言:javascript
复制
package main
import"fmt"
type g2048 [4][4]int
func (t *g2048)MirrorV() {
    tn := new(g2048)
 for i, line := range t {
 for j, num := range line {
            tn[len(t)-i-1][j] =num
        }
    }
 *t = *tn
}
func (t *g2048)Right90() {
    tn := new(g2048)
 for i, line := range t {
 for j, num := range line {
            tn[j][len(t)-i-1] = num
        }
    }
 *t = *tn
}
func (t *g2048)Left90() {
    tn := new(g2048)
 for i, line := range t {
 for j, num := range line {
            tn[len(line)-j-1][i] =num
        }
    }
 *t = *tn
}
func (g *g2048)R90() {
    tn := new(g2048)
 for x, line := range g {
 for y, _ := range line {
            tn[x][y] = g[len(line)-1-y][x]
        }
    }
 *g = *tn
}
func (t *g2048)Right180() {
    tn := new(g2048)
 for i, line := range t {
 for j, num := range line {
            tn[len(line)-i-1][len(line)-j-1] = num
        }
    }
 *t = *tn
}
func (t *g2048)Print() {
 for _, line := range t {
 for _, number := range line {
            fmt.Printf("%2d ", number)
        }
        fmt.Println()
    }
    fmt.Println()
    tn := g2048{{1, 2, 3, 4}, {5, 8}, {9, 10, 11}, {13, 14, 16}}
 *t = tn
}
func main() {
    fmt.Println("origin")
    t := g2048{{1, 2, 3, 4}, {5, 8}, {9, 10, 11}, {13, 14, 16}}
    t.Print()
    fmt.Println("mirror")
    t.MirrorV()
    t.Print()
    fmt.Println("Left90")
    t.Left90()
    t.Print()
    fmt.Println("Right90")
    t.R90()
    t.Print()
    fmt.Println("Right180")
    t.Right180()
    t.Print()
}
2. 2048的实现
package g2048
import (
 "fmt"
 "github.com/nsf/termbox-go"
 "math/rand"
 "time"
)
var Score int
var step int
//输出字符串
func coverPrintStr(x,y int, str string, fg, bg termbox.Attribute) error {
    xx := x
 for n, c := rangestr {
 if c == '\n' {
            y++
            xx = x - n - 1
        }
        termbox.SetCell(xx+n, y,c, fg, bg)
    }
    termbox.Flush()
 return nil
}
//游戏状态
type Status uint
const (
    Win Status = iota
    Lose
    Add
    Max = 2048
)
//2048游戏中的16个格子使用4x4二维数组表示
type G2048 [4][4]int
//检查游戏是否已经胜利,没有胜利的情况下随机将值为0的元素
//随机设置为2或者4
func (t *G2048)checkWinOrAdd() Status {
 // 判断4x4中是否有元素的值大于(等于)2048,有则获胜利
 for _, x := range t {
 for _, y := range x {
 if y >= Max {
 return Win
            }
        }
    }
 // 开始随机设置零值元素为2或者4
    i := rand.Intn(len(t))
    j := rand.Intn(len(t))
 for x := 0; x < len(t); x++{
 for y := 0; y < len(t); y++{
 if t[i%len(t)][j%len(t)] == 0 {
                t[i%len(t)][j%len(t)] = 2 <<(rand.Uint32() % 2)
 return Add
            }
            j++
        }
        i++
    }
 // 全部元素都不为零(表示已满),则失败
 return Lose
}
//初始化游戏界面
func (t G2048)initialize(ox, oy int) error {
    fg := termbox.ColorYellow
    bg := termbox.ColorBlack
    termbox.Clear(fg, bg)
 str := "      SCORE: " + fmt.Sprint(Score)
 for n, c := rangestr {
        termbox.SetCell(ox+n, oy-1, c, fg, bg)
    }
 str = "ESC:exit" + "Enter:replay"
 for n, c := rangestr {
        termbox.SetCell(ox+n, oy-2, c, fg, bg)
    }
 str = " PLAY withARROW KEY"
 for n, c := rangestr {
        termbox.SetCell(ox+n, oy-3, c, fg, bg)
    }
    fg = termbox.ColorBlack
    bg = termbox.ColorGreen
 for i := 0; i <=len(t); i++{
 for x := 0; x < 5*len(t); x++{
            termbox.SetCell(ox+x,oy+i*2, '-', fg, bg)
        }
 for x := 0; x <=2*len(t); x++{
 if x%2 == 0 {
                termbox.SetCell(ox+i*5, oy+x, '+', fg, bg)
            } else {
                termbox.SetCell(ox+i*5, oy+x, '|', fg, bg)
            }
        }
    }
    fg = termbox.ColorYellow
    bg = termbox.ColorBlack
 for i := range t {
 for j := range t[i] {
 if t[i][j] > 0 {
 str := fmt.Sprint(t[i][j])
 for n, char := rangestr {
                    termbox.SetCell(ox+j*5+1+n, oy+i*2+1, char, fg, bg)
                }
            }
        }
    }
 return termbox.Flush()
}
//翻转二维切片
func (t *G2048)mirrorV() {
    tn := new(G2048)
 for i, line := range t {
 for j, num := range line {
            tn[len(t)-i-1][j] =num
        }
    }
 *t = *tn
}
//向右旋转90度
func (t *G2048)right90() {
    tn := new(G2048)
 for i, line := range t {
 for j, num := range line {
            tn[j][len(t)-i-1] = num
        }
    }
 *t = *tn
}
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2016-07-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 Golang语言社区 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档