游戏简介
2048是一款比较流行的数字游戏。游戏规则:每次可按上、下、左、右方向键滑动数字,每滑动一次,所有数字都会往滑动方向靠拢,同时在空白位置随机出现一个数字,相同数字在靠拢时会相加。不断叠加最终拼出2048这个数字算成功。
2048最早于2014年3月20日发行。原版2048首先在GitHub上发布,原作者是Gabriele Cirulli,后被移植到各个平台。
本例难度为初级,适合具有Python基础和Tkinter组件编程知识的用户学习。
用户可以下载完整示例代码,作为参照对比进行学习。
设计原理
这个游戏的本质是二位数组,就以4*4的二位数组来分析关键的逻辑以及实现。二位数组如图1。
图1 图2 图3
所有的操作都是对这个二维数组的数据的操作。分为上下左右四个方向。先说向左的方向(如图2)。向左操作的结果如图3;当向左的方向是,所有的数据沿着水平方向向左跑。
水平说明操作的是二维数组的一行,而垂直操作的则是二位数组的一列。这样就可以将二维数组的操作变成遍历后对一维数组的操作。向左说明数据的优先考虑的位置是从左开始的。这样就确定了一维数组的遍历开始的位置。
图2中共四行,每一个行都能得到一个数组。
arr1:[0,0,2,0] arr2:[0,4,2,0] arr3:[0,0,4,4] arr4:[2,0,2,0]
这样一来向左的方向就变成。从上到下获得每一行的数组,方向向左。参数(row,left)。
其他的三个方向在开始的时候记住是怎样获得以为数组的,等操作完才放回去这样就能实现了。
示例效果
示例源码
import random import sys import pygame from pygame.locals import * PIXEL = 150 SCORE_PIXEL = 100 SIZE = 4 # 地图的类 class Map: def __init__(self, size): self.size = size self.score = 0 self.map = [[0 for i in range(size)] for i in range(size)] self.add() self.add() # 新增2或4,有1/4概率产生4 def add(self): while True: p = random.randint(0, self.size * self.size - 1) if self.map[int(p / self.size)][int(p % self.size)] == 0: x = random.randint(0, 3) > 0 and 2 or 4 self.map[int(p / self.size)][int(p % self.size)] = x self.score += x break # 地图向左靠拢,其他方向的靠拢可以通过适当旋转实现,返回地图是否更新 def adjust(self): changed = False for a in self.map: b = [] last = 0 for v in a: if v != 0: if v == last: b.append(b.pop() << 1) last = 0 else: b.append(v) last = v b += [0] * (self.size - len(b)) for i in range(self.size): if a[i] != b[i]: changed = True a[:] = b return changed # 逆时针旋转地图90度 def rotate90(self): self.map = [[self.map[c][r] for c in range(self.size)] for r in reversed(range(self.size))] # 判断游戏结束 def over(self): for r in range(self.size): for c in range(self.size): if self.map[r][c] == 0: return False for r in range(self.size): for c in range(self.size - 1): if self.map[r][c] == self.map[r][c + 1]: return False for r in range(self.size - 1): for c in range(self.size): if self.map[r][c] == self.map[r + 1][c]: return False return True def moveUp(self): self.rotate90() if self.adjust(): self.add() self.rotate90() self.rotate90() self.rotate90() def moveRight(self): self.rotate90() self.rotate90() if self.adjust(): self.add() self.rotate90() self.rotate90() def moveDown(self): self.rotate90() self.rotate90() self.rotate90() if self.adjust(): self.add() self.rotate90() def moveLeft(self): if self.adjust(): self.add() # 更新屏幕 def show(map): for i in range(SIZE): for j in range(SIZE): # 背景颜色块 screen.blit(map.map[i][j] == 0 and block[(i + j) % 2] or block[2 + (i + j) % 2], (PIXEL * j, PIXEL * i)) # 数值显示 if map.map[i][j] != 0: map_text = map_font.render( str(map.map[i][j]), True, (106, 90, 205)) text_rect = map_text.get_rect() text_rect.center = (PIXEL * j + PIXEL / 2, PIXEL * i + PIXEL / 2) screen.blit(map_text, text_rect) # 分数显示 screen.blit(score_block, (0, PIXEL * SIZE)) score_text = score_font.render((map.over( ) and "Game over with score " or "Score: ") + str(map.score), True, (106, 90, 205)) score_rect = score_text.get_rect() score_rect.center = (PIXEL * SIZE / 2, PIXEL * SIZE + SCORE_PIXEL / 2) screen.blit(score_text, score_rect) pygame.display.update() map = Map(SIZE) pygame.init() screen = pygame.display.set_mode((PIXEL * SIZE, PIXEL * SIZE + SCORE_PIXEL)) pygame.display.set_caption("2048") block = [pygame.Surface((PIXEL, PIXEL)) for i in range(4)] # 设置颜色 block[0].fill((152, 251, 152)) block[1].fill((240, 255, 255)) block[2].fill((0, 255, 127)) block[3].fill((225, 255, 255)) score_block = pygame.Surface((PIXEL * SIZE, SCORE_PIXEL)) score_block.fill((245, 245, 245)) # 设置字体 map_font = pygame.font.Font(None, int(PIXEL * 2 / 3)) score_font = pygame.font.Font(None, int(SCORE_PIXEL * 2 / 3)) clock = pygame.time.Clock() show(map) while not map.over(): # 12为实验参数 clock.tick(12) for event in pygame.event.get(): if event.type == QUIT: sys.exit() # 接收玩家操作 pressed_keys = pygame.key.get_pressed() if pressed_keys[K_w] or pressed_keys[K_UP]: map.moveUp() elif pressed_keys[K_s] or pressed_keys[K_DOWN]: map.moveDown() elif pressed_keys[K_a] or pressed_keys[K_LEFT]: map.moveLeft() elif pressed_keys[K_d] or pressed_keys[K_RIGHT]: map.moveRight() show(map) # 游戏结束 pygame.time.delay(3000)