运行结果
游戏规则
1. ↑ ↓ ← → 来控制蛇的移动方向
2. 蛇吃到自己身体的任意一部分游戏结束, 自动退出窗口
3. 蛇的速度会随游戏时间增长越来越快, 与吃食物的多少 (分数) 无关
4. 蛇可以穿过边界到达另一边
5. 场上食物同时只会存在一个, 颜色随机, 但每个颜色的所得分数不同, 生存概率也不同
实现思路
此段介绍代码逻辑, 比较简单, 可以直接跳过, 最后有全部代码
1. 棋盘实现
棋盘采用最简单的方法来实现, 即一个grid[][]二元列表来表示棋盘, 下标表示棋盘的位置
例如: grid[5][4]表示第5行第4列的一格
1) None表示该一格为空, 即蛇可以安全通过
2) 颜色例如(0, 0, 0)为该一格有食物
3) True表示该一格是蛇的身体
SIZE = 30 SIDE = HEIGHT // SIZE grid = [[None for _ in range(SIDE)] for _ in range(SIDE)]
2. 蛇的实现
用双端队列表示蛇, 这样尾部和头部的更新时间复杂度都为O(1).
蛇初始长度为3, 方向向右
1). 蛇的动态实现
根据蛇的前进速度, 每前进一格, 若没有吃到食物, 则删除尾部一格, 添加头部一格, 并更新棋盘的值; 若吃到食物, 则头部添加一格, 尾部不会删除, 即实现了蛇的长度增加一格
2). 蛇的方向改变
在按上下左右来改变蛇的方向时, 为了防止蛇反向移动吃掉自己, 需要获取蛇此时的移动方向
例如: 蛇此时往右移动, 那么按"左"时蛇的移动方向不会发生改变, 否则会立即吃到自己结束游戏
若成功改变移动方向, 则根据DIR变量来改变移动方向
snake = collections.deque() # 蛇的实现 DIR = ((-1, 0), (1, 0), (0, -1), (0, 1)) # 上下左右 dir = DIR[3] # 初始方向右 speed = 0.12 # 蛇初始有三格 snake.append((0, 0)) snake.append((0, 1)) snake.append((0, 2)) grid[0][0], grid[0][1], grid[0][2] = True, True, True . . . # 蛇的速度随时间非线性增长 if game_t >= 10 * up: speed /= 1.2 up += 1 s -= F if s <= 0: # 移动一次 x, y = snake[-1][0] + dir[0], snake[-1][1] + dir[1] # 下一步的坐标 x, y = x % SIDE, y % SIDE # 过墙穿到另一边 if grid[x][y] == True: # 吃到自己, 游戏结束 pygame.quit() exit() elif grid[x][y]: # 吃到食物, 加分, 重新生成食物 score += SCORE[grid[x][y]] create_food() # 重新生成 else: # 无事发生, 前进一格 xp, yp = snake.popleft() grid[xp][yp] = None snake.append((x, y)) grid[x][y] = True s = speed for e in pygame.event.get(): if e.type == QUIT: pygame.quit() exit() if e.type == KEYDOWN: if e.key == K_UP and dir != DIR[1]: dir = DIR[0] elif e.key == K_DOWN and dir != DIR[0]: dir = DIR[1] elif e.key == K_LEFT and dir != DIR[3]: dir = DIR[2] elif e.key == K_RIGHT and dir != DIR[2]: dir = DIR[3]
3. 食物生成
食物采用随机生成在棋盘任意位置的方式, 但不能直接生成在蛇的身上.
这里为了避免食物一直生成在蛇身上, 然后导致程序卡在一个循环里, 我们设置最大循环次数为100, 若100次循环后还没找到位置生成食物, 就会遍历棋盘直接寻找空位, 没有空位则不生成食物 (你的蛇铺满了整个棋盘, 好耶)
食物得分: 绿色:2分, 蓝色: 3分, 白色: 1分
食物生成概率: 绿色25%, 蓝色 12.5%, 白色62.5%
SCORE = {GREEN: 2, LIGHTBLUE: 3, WHITE: 1} RCOL = (GREEN, GREEN, LIGHTBLUE, WHITE, WHITE, WHITE, WHITE, WHITE) score = 0 # 得分 # 生成食物 def create_food(): i, j = random.randint(0, SIDE-1), random.randint(0, SIDE-1) c = 0 # 重置次数 while grid[i][j] and c <= 100: i, j = random.randint(0, SIDE-1), random.randint(0, SIDE-1) c += 1 if c <= 100: grid[i][j] = (random.choice(RCOL)) return for i in range(SIDE): for j in range(SIDE): if not grid[i][j]: grid[i][j] = (random.choice(RCOL)) return . . . create_food()
全部代码:
# 游戏规则: ↑ ↓ ← →控制蛇的移动方向 # 可以穿过边界 # 蛇的速度每10s增长一次, 不随分数增长 import pygame, random, collections from pygame.locals import * pygame.init() WIDTH, HEIGHT = 750, 600 sur = pygame.display.set_mode((WIDTH, HEIGHT)) FPS = 200 fpsClock = pygame.time.Clock() # 颜色变量 WHITE = (255, 255, 255) RED = (255, 0, 0) GREEN = (0, 255, 0) BLUE = (0, 0, 255) BLACK = (0, 0, 0) YELLOW = (255, 255, 0) SILVER = (192, 192, 192) GRAY = (169, 169, 169) PURPLE = (127, 0, 255) PINK = (255, 51, 153) ORANGE = (255, 128, 0) BROWN = (102, 51, 0) LIGHTBLUE = (137, 207, 240) WOOD = (222, 184, 135) # 游戏变量 SIZE = 30 SIDE = HEIGHT // SIZE snake = collections.deque() grid = [[None for _ in range(SIDE)] for _ in range(SIDE)] DIR = ((-1, 0), (1, 0), (0, -1), (0, 1)) # 上下左右 dir = DIR[3] # 初始方向右 SCORE = {GREEN: 2, LIGHTBLUE: 3, WHITE: 1} RCOL = (GREEN, GREEN, LIGHTBLUE, WHITE, WHITE, WHITE, WHITE, WHITE) score = 0 # 得分 speed = 0.12 # 写入文本 def write(x, y, text, color, size): font = pygame.font.SysFont('SimHei', size) Text = font.render(text, True, color) sur.blit(Text, (x, y)) # 生成食物 def create_food(): i, j = random.randint(0, SIDE-1), random.randint(0, SIDE-1) c = 0 # 重置次数 while grid[i][j] and c <= 100: i, j = random.randint(0, SIDE-1), random.randint(0, SIDE-1) c += 1 if c <= 100: grid[i][j] = (random.choice(RCOL)) return for i in range(SIDE): for j in range(SIDE): if not grid[i][j]: grid[i][j] = (random.choice(RCOL)) return def main(): global speed, dir, score # 蛇初始有三格 snake.append((0, 0)) snake.append((0, 1)) snake.append((0, 2)) grid[0][0], grid[0][1], grid[0][2] = True, True, True create_food() F = 1/FPS game_t = 0 s = speed up = 0 while True: sur.fill(BLACK) sur.fill(GRAY, (WIDTH-150, 0, 200, HEIGHT)) game_t += F # 右侧信息栏 write(620, 80, '时间:'+str(int(game_t)), BLACK, 25) write(620, 20, '分数:'+str(score), BLACK, 25) write(620, 140, '速度:'+str(int(1/speed)), BLACK, 25) # 画蛇和食物 for i in range(SIDE): for j in range(SIDE): if grid[i][j] == True: pygame.draw.rect(sur, PINK, (j*SIZE, i*SIZE, SIZE, SIZE)) elif grid[i][j]: pygame.draw.rect(sur, grid[i][j], (j*SIZE, i*SIZE, SIZE, SIZE)) # 画棋盘的线 for i in range(0, WIDTH-149, SIZE): pygame.draw.line(sur, BLUE, (i, 0), (i, HEIGHT), 1) for j in range(0, HEIGHT+1, SIZE): pygame.draw.line(sur, BLUE, (0, j), (WIDTH-150, j), 1) # 蛇的速度随时间非线性增长 if game_t >= 10*up: speed /= 1.2 up += 1 s -= F if s <= 0: # 移动一次 x, y = snake[-1][0]+dir[0], snake[-1][1]+dir[1] # 下一步的坐标 x, y = x % SIDE, y % SIDE # 过墙穿到另一边 if grid[x][y] == True: # 吃到自己, 游戏结束 pygame.quit() exit() elif grid[x][y]: # 吃到食物, 加分, 重新生成食物 score += SCORE[grid[x][y]] create_food() # 重新生成 else: # 无事发生, 前进一格 xp, yp = snake.popleft() grid[xp][yp] = None snake.append((x, y)) grid[x][y] = True s = speed for e in pygame.event.get(): if e.type == QUIT: pygame.quit() exit() if e.type == KEYDOWN: if e.key == K_UP and dir != DIR[1]: dir = DIR[0] elif e.key == K_DOWN and dir != DIR[0]: dir = DIR[1] elif e.key == K_LEFT and dir != DIR[3]: dir = DIR[2] elif e.key == K_RIGHT and dir != DIR[2]: dir = DIR[3] pygame.display.update() fpsClock.tick(FPS) main()
最后
请勿用于商业用途, 若有问题或bug, 感谢各位大佬及时指出!
标签:Python,小游戏,grid,食物,贪吃蛇,GREEN,WHITE,SIDE,255 From: https://www.cnblogs.com/xanderChou/p/18242363