最近闲来无事,做了一个2048类似的小游戏。其中的算法思想,如果有的话,都是本人花了一点点时间想出来的,完全没有参考任何教程,所以可能(其实是肯定)使用的方法比较傻一些,算是抛砖引玉了。
为了制作这个游戏,我先下载了一个2048小游戏来玩,以便学习规则。根据20分钟的游玩体验,我总结的规则大致如下:
- 4*4方格。
- 游戏开始时出现2个2。
- 然后每移动一次出现新的2,如果某个方向无法移动,则不会增加新的2。
- 只有相同的数字才能够相加。
- 新增的只会出现2
- 相加时,只会加一次,不会累加。不知道为啥。
- 游戏结束检查没有空位且任意数字周围都没有相同数字,如果都没有,则游戏结束。
- 敏感的察觉到不需要外部图片素材,只需要画框还有画数字即可。
- 动画过程应该最麻烦,pygame画动画我是没什么信心。
因为之前做了好多这种类似的棋盘类型的游戏,比如扫雷,五子连珠(有机会一并写出来),所以画2048的棋盘部分格外容易,难点在配色,好在我是不在乎颜色好看与否,所以直接开始弄。
首先依然是基础的pygame配置代码,涉及到各种初始化配置,颜色代码等等,边距一大堆,基本基本上棋盘游戏我都是通用的,修改一下就可以用了。
import pygame
import sys
import random
from pygame.locals import *
board_width = 4
board_height = 4
tile_size = 80
screen_width = 640
screen_height = 480
fps = 30
white = (255, 255, 255)
bright_blue = 'sky blue'
dark_turquoise = (250, 234, 211)
green = 'green'
bg_color = (107, 81, 82)
tile_color = bright_blue
text_color = (144, 59, 28)
border_color = bright_blue
basic_font_size = 30
message_color = white
x_margin = int((screen_width-(tile_size*board_width + (board_width-1)))/2)
y_margin = int((screen_height-(tile_size*board_height + (board_height - 1)))/2)
up = 'up'
down = 'down'
left = 'left'
right = 'right'
# 四个方向
directions = [(0, 1), (0, -1), (-1, 0), (1, 0)]
来一个主函数,把pygame框架搭起来
if __name__ == '__main__':
pygame.init()
fps_clock = pygame.time.Clock()
display = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('2048')
basic_font = pygame.font.Font('freesansbold.ttf', basic_font_size)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
pygame.display.update()
fps_clock.tick(fps)
运行后的样子
接下来编写一个生成二维列表的函数,生成的二维列表即对应了游戏界面,直接对应游戏界面。比如说二维列表长这样
[
[0, 2, 0, 2],
[0, 0, 0, ],
[0, 0, 0, 0],
[0, 0, 0, 0]
]
那么我们使用pygame绘制的时候所有0的位置都是空白的小块,而有数字的地方则会直接绘制数字,并且位置与二维列表位置一一对应。即二维列表[0][0]对应左上角第一个小块,[3][3]对应右下角最后一个小块。这样对应的好处是直观,劣势是我们需要计算小块的横纵坐标也就是在pygame界面中的位置时,第一个下标是用来计算y值即纵向位置,第二个下标用来计算x数值即横向位置,这与一般认知相矛盾,这是容易搞错的地方。
现在来写生成二维列表的函数,比较简单,先生成一个数值全为None的列表,然后,在随机位置生成两个数值2。然后返回这个二维列表的值。
def get_starting_board():
counter = 2
board = [[None for _ in range(board_width)] for _ in range(board_height)]
while counter > 0:
random_x = random.randint(0, board_height-1)
random_y = random.randint(0, board_width-1)
if board[random_x][random_y] is None:
board[random_x][random_y] = 2
counter -= 1
return board
这样我们生成了一个二维列表并且随机生成了数字2所在位置。接下来还不能直接开始绘制小块,我们还需要一个函数把二维列表的下标转换成实际在pygmae中的位置。
x_margin = int((screen_width-(tile_size*board_width + (board_width-1)))/2)
y_margin = int((screen_height-(tile_size*board_height + (board_height - 1)))/2)
这是已经定义好的横纵方向的间距,利用这个间距以及计算得出二维列表每一个元素在pygame游戏界面即棋盘中的位置。
# 将board[x][y]转为游戏屏幕对应的坐标点
def get_left_top_of_tile(x, y):
left = x_margin + y * tile_size + (y - 1)
top = y_margin + x * tile_size + (x - 1)
return left, top
终于可以开始编写绘制函数了,该函数根据二维列表的数据内容绘制相应的图形到指定位置。
# 绘制游戏背景面板,此处开始根据board中的内容绘制游戏主界面了,一开始绘制的是已经完成好的界面
def draw_board(board, message):
# 填充背景
display.fill(bg_color)
# 如果有信息,则将信息写在左上角
if message:
text_surf, text_rect = make_text(message, message_color, bg_color, 0, 0)
display.blit(text_surf, text_rect)
# 遍历二维列表中所有内容,绘图
for x in range(board_width):
for y in range(board_height):
if board[x][y]:
# 如果有数字则绘制数字
draw_tile(x, y, board[x][y])
else:
# 否则仅绘制小块
draw_tile(x, y, '')
# 绘制游戏边框
left, top = get_left_top_of_tile(0, 0)
width = board_width * tile_size
height = board_height * tile_size
# 边框不要和滑片重合,所以稍微往四周挪动一点距离
pygame.draw.rect(display, border_color, (left-11, top-11, width+16, height+16), 4)
接下来最底层的绘制图形函数
#绘制游戏界面上的小滑片,其中adj_x,y偏移量是用来后期做动#画用的
def draw_tile(board_x, board_y, number, adj_x=0, adj_y=0):
#获取实际位置
left, top = get_left_top_of_tile(board_x, board_y)
# 画出滑片的背景色,即一个填充了颜色的矩形
# 在同样的位置显示滑片对应的数字,即board[x][y]中对应的数字
# 画数字时修改了一下位置,看起来更合适一些
if number:
pygame.draw.rect(display, dark_turquoise, (left + adj_x, top + adj_y, tile_size - 10, tile_size - 10))
text_surf = basic_font.render(str(number), True, text_color)
text_rect = text_surf.get_rect()
text_rect.center = left + int((tile_size-10)/2) + adj_x, top + int((tile_size-10)/2) + adj_y
# text_rect.center = left + adj_x, top + adj_y
display.blit(text_surf, text_rect)
else:
pygame.draw.rect(display, bright_blue, (left + adj_x, top + adj_y, tile_size - 10, tile_size - 10))
然后在定义一个综合的生成游戏界面的函数
# 创建新游戏谜题
def generate_new_puzzle():
board = get_starting_board()
draw_board(board, '')
pygame.display.update()
pygame.time.wait(500)
last_move = None
return board
在主函数中调用并获得二维列表
if __name__ == '__main__':
pygame.init()
fps_clock = pygame.time.Clock()
display = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption('2048')
basic_font = pygame.font.Font('freesansbold.ttf', basic_font_size)
# 配置三个按键位置以及颜色,大小
# reset_surf, reset_rect = make_text('Reset', text_color, tile_color, screen_width - 120, screen_height - 90)
main_board = generate_new_puzzle()
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
pygame.display.update()
fps_clock.tick(fps)
运行程序,开始有点意思了
待续…