游戏实现的功能:
1、在游戏界面的左上角初始化生成一条贪吃蛇
贪吃蛇的创建使用列表类型进行存储贪吃蛇每个身体节点的位置信息,通过append()方法在列表的最后添加一个节点来初始化贪吃蛇
2、随机生成多个不同颜色和不同分值的食物
其中食物的所有属性使用字典类型进行存储,食物的位置为key值,食物的类型(食物的分值和颜色)为value值。
食物出现的位置不能为蛇所在的位置。实现思路:先汇总所有的游戏区域的方格位置列表,,所有的位置减去蛇的位置以及已经创建的食物位置,即为可选位置,再使用random.choice()方法从中随机挑选一个位置作为食物出现的位置。(需要注意的是,列表不可相减,但是集合可以相减)
创建多个食物只需重复循环即可。
3、贪吃蛇的移动和吃掉食物和游戏结束
首先判断贪吃蛇的下一个位置是否为食物位置,如果是食物,则只需在蛇头后面增加一个身体节点;如果不是食物,则需对贪吃蛇和游戏界面边缘以及时间进行判断,如在游戏区域内(无撞墙),则需在蛇头后面增加一个身体节点,在蛇尾删除一个身体节点。
如果改变移动方向,则通过pos变量来记录贪吃蛇x和y坐标的变化
吃掉食物后,需要判断存储的食物是否为空,如果为空,则需再调用创建多个食物的方法
如果贪吃蛇的下一个位置不在食物位置,且撞墙或者撞到自己的身体,则游戏结束
4、 贪吃蛇移动速度根据得分进行改变
通过得分,进行速度水平的划分,得分越多,即贪吃蛇越长,移动速度越慢
定义一个speed变量,调用time.time( )函数记录两次移动间距时间,与speed变量进行比较,判断是否达到可以移动时间差,从而实现了通过speed变量控制贪吃蛇移动速度的功能
遇到的问题:
if-elif 和 if-if
elif 和 if 是 一起用的,if-elif 语句中只能按顺序执行其中的某一个,或者都不执行
两个 if 却是具有同样的优先级,因此是可以全部都执行的
当游戏结束即game_over = True 时,按下空格键重新开始游戏,实现这个功能的时候,会遇到下列情形,原因便在于没有清楚的认识到两者的区别
代码1(错误)
while True:
# 事件检测
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key in (pygame.K_w, pygame.K_UP):
pos = (0, -1)
elif event.key in (pygame.K_s, pygame.K_DOWN):
pos = (0, 1)
elif event.key in (pygame.K_a, pygame.K_LEFT):
pos = (-1, 0)
elif event.key in (pygame.K_d, pygame.K_RIGHT):
pos = (1, 0)
elif event.key == pygame.K_SPACE:
if game_begin and game_stop:
game_stop = False
elif game_begin and not game_stop:
game_stop = True
elif not game_begin and not game_stop:
game_begin = True
elif game_over:
main()
代码2(正确)
while True:
# 事件检测
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key in (pygame.K_w, pygame.K_UP):
pos = (0, -1)
elif event.key in (pygame.K_s, pygame.K_DOWN):
pos = (0, 1)
elif event.key in (pygame.K_a, pygame.K_LEFT):
pos = (-1, 0)
elif event.key in (pygame.K_d, pygame.K_RIGHT):
pos = (1, 0)
elif event.key == pygame.K_SPACE:
if game_begin and game_stop and not game_over:
game_stop = False
elif game_begin and not game_stop and not game_over:
game_stop = True
elif not game_begin and not game_stop and not game_over:
game_begin = True
elif game_over:
main()
代码3(正确)
while True:
# 事件检测
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key in (pygame.K_w, pygame.K_UP):
pos = (0, -1)
elif event.key in (pygame.K_s, pygame.K_DOWN):
pos = (0, 1)
elif event.key in (pygame.K_a, pygame.K_LEFT):
pos = (-1, 0)
elif event.key in (pygame.K_d, pygame.K_RIGHT):
pos = (1, 0)
elif event.key == pygame.K_SPACE:
if game_begin and game_stop:
game_stop = False
elif game_begin and not game_stop:
game_stop = True
elif not game_begin and not game_stop:
game_begin = True
if game_over:
main()
完整代码:
import random
import sys
import time
import pygame
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600
SIZE = 30
LINE_WIDTH = 1
BG_COLOR = (0, 0, 0)
PINK = (255, 181, 197)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
FOOD_NUM = 5
def create_snake():
"""创建一条蛇"""
snake = list()
snake.append((2, 2))
snake.append((1, 2))
snake.append((0, 2))
return snake
def create_random_food(snake,foods):
"""随机创建食物"""
# 计算出所有的方格
all_position = [(x,y) for x in range(SCREEN_WIDTH//SIZE) for y in range(2,SCREEN_HEIGHT//SIZE)]
# 计算出可以使用的方格(除去蛇之外的方格)
temp_position = set(all_position) - set(snake)-set(foods)
# 从可以使用的方格中随机出一个位置
return random.choice(list(temp_position))
def create_foods(snake):
"""随机创建多个食物"""
# 食物属性,字典类型,key:食物的位置,value:食物的类型(分值和颜色)
foods_stats = {}
# 所有食物的位置存储在列表中
foods = list(foods_stats.keys())
for i in range(FOOD_NUM+1):
foods = list(foods_stats.keys())
food = create_random_food(snake,foods)
food_style = random.choice([(10, (255, 100, 100)), (20, (100, 255, 100)), (30, (100, 100, 255))])
foods_stats[food] = food_style
return foods,foods_stats
def get_speed(score):
"""获取贪吃蛇的速度"""
if score > 400:
speed_level = 3
speed = 0.3
elif 400 >= score >= 200:
speed_level = 2
speed = 0.2
else:
speed_level = 1
speed = 0.1
return speed_level, speed
def main():
pygame.init()
screen = pygame.display.set_mode((SCREEN_WIDTH,SCREEN_HEIGHT))
pygame.display.set_caption("贪吃蛇游戏")
# 分数、速度的字体
font = pygame.font.Font("STXINGKA.TTF",30)
# 游戏结束和游戏中止和游戏开始的字体
game_font = pygame.font.Font("STCAIYUN.TTF",50)
# 创建蛇
snake = create_snake()
# 随机创建食物
foods,food_style = create_foods(snake)
# 得分
score = 0
# 蛇移动的方向
pos = (1, 0)
# 蛇移动的速度
speed_level, speed = get_speed(score)
# speed值越小,速度越快
last_time = time.time()
# 游戏开始的标记
game_begin = False
# 游戏结束的标记
game_over = False
# 游戏中止的标记
game_stop = False
# 创建计时器(防止while循环过快,占用太多CPU的问题)
clock = pygame.time.Clock()
while True:
# 事件检测
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key in (pygame.K_w, pygame.K_UP):
pos = (0, -1)
elif event.key in (pygame.K_s, pygame.K_DOWN):
pos = (0, 1)
elif event.key in (pygame.K_a, pygame.K_LEFT):
pos = (-1, 0)
elif event.key in (pygame.K_d, pygame.K_RIGHT):
pos = (1, 0)
elif event.key == pygame.K_SPACE:
if game_begin and game_stop and not game_over:
game_stop = False
elif game_begin and not game_stop and not game_over:
game_stop = True
elif not game_begin and not game_stop and not game_over:
game_begin = True
elif game_over:
main()
# 判断事件是否满足,然后移动蛇的位置
if game_begin and not game_over and not game_stop and time.time() - last_time > speed:
last_time = time.time()
# 移动蛇的位置
next_position = (snake[0][0] + pos[0], snake[0][1] + pos[1])
# 判断要移动的位置是否是“食物”的位置
if next_position in foods:
# 将新位置添加到蛇的头
snake.insert(0, next_position)
score += food_style[next_position][0]
foods.remove(next_position)
speed_level, speed = get_speed(score)
if len(foods) == 0:
foods, food_style = create_foods(snake)
else:
if (0 <= next_position[0] and (next_position[0] <= SCREEN_WIDTH // SIZE - 1)
and 2 <= next_position[1] <= SCREEN_HEIGHT // SIZE - 1 and next_position not in snake):
# 将新位置添加到列表的头
snake.insert(0, next_position)
# 移除原列表最后一个元素的位置
snake.pop()
else:
# 游戏结束
game_over = True
# 填充背景色
screen.fill(BG_COLOR)
# 画网格线(竖线)
for x in range(SIZE, SCREEN_WIDTH, SIZE):
pygame.draw.line(screen, WHITE, (x, 2 * SIZE), (x, SCREEN_HEIGHT), LINE_WIDTH)
# 画网格线(横线)
for y in range(2 * SIZE, SCREEN_HEIGHT, SIZE):
pygame.draw.line(screen, WHITE, (0, y), (SCREEN_WIDTH, y), LINE_WIDTH)
# 画蛇
for s in snake:
pygame.draw.rect(screen, PINK,
(s[0] * SIZE + LINE_WIDTH, s[1] * SIZE + LINE_WIDTH, SIZE - LINE_WIDTH * 2,
SIZE - LINE_WIDTH * 2), 0)
# 画食物
for f in foods:
pygame.draw.rect(screen, food_style[f][1], (f[0] * SIZE, f[1] * SIZE, SIZE, SIZE), 0)
# 显示速度、分数
speed_info = font.render("速度:%d" % speed_level, True, (255, 255, 255))
screen.blit(speed_info, (30, 7))
score_info = font.render("得分:%d" % score, True, (255, 255, 255))
screen.blit(score_info, (450, 7))
# 显示游戏未开始的画面
if not game_begin and not game_over:
game_begin_info = game_font.render("按下空格游戏开始", True, (255, 255, 254))
game_font_width, game_font_height = game_font.size("按下空格游戏开始")
screen.blit(game_begin_info, ((SCREEN_WIDTH - game_font_width) / 2, (SCREEN_HEIGHT - game_font_height) / 2))
# 显示游戏中止的画面
if game_begin and game_stop and not game_over:
game_stop_info = game_font.render("游戏暂停(空格继续)", True, (255, 255, 254))
game_font_width, game_font_height = game_font.size("游戏暂停(空格继续)")
screen.blit(game_stop_info, ((SCREEN_WIDTH - game_font_width) / 2, (SCREEN_HEIGHT - game_font_height) / 2))
# 显示游戏结束画面
if game_over:
game_over_info = game_font.render("游戏结束(空格重新开始)", True, (255, 255, 254))
game_font_width, game_font_height = game_font.size("游戏结束(空格重新开始)")
screen.blit(game_over_info, ((SCREEN_WIDTH - game_font_width) / 2, (SCREEN_HEIGHT - game_font_height) / 2))
pygame.display.flip()
# 通过一定的延时,实现每秒钟循环60次
clock.tick(60)
if __name__ == "__main__":
main()