编程语言
首页 > 编程语言> > python讲座2—贪吃蛇

python讲座2—贪吃蛇

作者:互联网

这次讲座讲了一下用pygame库写贪吃蛇的小游戏:

总览

首先贴出全部代码:


# 导入所需的模块
import enum
import sys
import pygame as pg
import random

WIDTH, HEIGHT = 400, 400
ROW_NUM = 20  # 行数
COL_NUM = 20  # 列数
BLOCK_WIDTH, BLOCK_HEIGHT = WIDTH / COL_NUM, HEIGHT / ROW_NUM

# R(Red) G(Green) B(Blue)
BODY_COLOR = (0, 255, 0)
HEAD_COLOR = (255, 0, 0)
FOOD_COLOR = (0, 0, 255)

# 使用pg之前必须初始化
pg.init()

# 设置主屏窗口
screen = pg.display.set_mode((WIDTH, HEIGHT))

# 设置窗口的标题,即游戏名称
pg.display.set_caption('贪吃蛇')


class Direction(enum.Enum):
    Left = 0
    Up = 1
    Right = 3
    Down = 2


class GameState(enum.Enum):
    Die = 0
    Playing = 1
    Preparing = 2


# 初始化这条蛇
snakes = []
blocks = []
direction: Direction = Direction.Up
game_state: GameState = GameState.Playing
difficulty = 3
food = (10*BLOCK_WIDTH, 10*BLOCK_HEIGHT)
score = 0
max_score = 0


def init():
    snakes.clear()
    snakes.append((5*BLOCK_WIDTH, 5*BLOCK_HEIGHT))
    snakes.append((5*BLOCK_WIDTH, 6*BLOCK_HEIGHT))
    snakes.append((5*BLOCK_WIDTH, 7*BLOCK_HEIGHT))
    global direction, game_state, difficulty, score, max_score
    direction = Direction.Up
    game_state = GameState.Playing
    difficulty = 3
    generate_food()
    score = 0


def set_direction(d: Direction):
    global direction
    if(d.value + direction.value == 3):
        return
    direction = d


def generate_food():
    global food
    while True:
        x = random.randint(0, COL_NUM-1) * BLOCK_WIDTH
        y = random.randint(0, ROW_NUM-1) * BLOCK_HEIGHT
        if (x, y) not in snakes and (x, y) not in blocks:
            food = (x, y)
            break


def move():
    global game_state
    cur_head: tuple[int, int] = snakes[0]
    match direction:
        case Direction.Left:
            snakes.insert(0, (cur_head[0]-BLOCK_WIDTH, cur_head[1]))
        case Direction.Right:
            snakes.insert(0, (cur_head[0]+BLOCK_WIDTH, cur_head[1]))
        case Direction.Down:
            snakes.insert(0, (cur_head[0], cur_head[1]+BLOCK_HEIGHT))
        case Direction.Up:
            snakes.insert(0, (cur_head[0], cur_head[1]-BLOCK_HEIGHT))
    if (head := snakes[0]) != food:
        if head in snakes[1:] or head[0] < 0 or head[0] >= WIDTH or head[1] < 0 or head[1] >= HEIGHT:
            game_state = GameState.Die
        else:
            snakes.pop()
    else:
        global difficulty, score, max_score
        difficulty *= 1.0
        score += 100
        generate_food()


def draw_text(s: str, center, font_size=50, font_color=(255, 0, 0), back_color=(255, 255, 255)):
    f = pg.font.Font('C:/Windows/Fonts/simhei.ttf', font_size)
    # 生成文本信息,第一个参数文本内容;第二个参数,字体是否平滑;
    # 第三个参数,RGB模式的字体颜色;第四个参数,RGB模式字体背景颜色;
    text = f.render(s, True, font_color, back_color)
    # 获得显示对象的rect区域坐标
    textRect = text.get_rect()
    # 设置显示对象居中
    textRect.center = center
    # 将准备好的文本信息,绘制到主屏幕 Screen 上。
    screen.blit(text, textRect)


init()
clock = pg.time.Clock()
# 固定代码段,实现点击"X"号退出界面的功能,几乎所有的pg都会使用该段代码
while True:
    clock.tick(2 * difficulty)
    # 循环获取事件,监听事件状态
    for event in pg.event.get():
        # 判断用户是否点了"X"关闭按钮,并执行if代码段
        match event.type:
            case pg.QUIT:
                pg.quit()
                sys.exit()
            case pg.MOUSEBUTTONDOWN:
                #print("click")
                if game_state == GameState.Die:
                    game_state = GameState.Playing
                    init()
            case pg.KEYDOWN:
                match event.key:
                    case pg.K_LEFT:
                        set_direction(Direction.Left)
                    case pg.K_RIGHT:
                        set_direction(Direction.Right)
                    case pg.K_UP:
                        set_direction(Direction.Up)
                    case pg.K_DOWN:
                        set_direction(Direction.Down)
                    case pg.K_0:
                         if game_state == GameState.Die:
                           game_state = GameState.Playing
                           init()

    move()
    screen.fill((255, 255, 255))
    if game_state == GameState.Playing:
        for i, block in enumerate(snakes):
            if i == 0:
                pg.draw.rect(screen, HEAD_COLOR,
                             (block[0], block[1], BLOCK_WIDTH, BLOCK_HEIGHT))
            else:
                pg.draw.rect(screen, BODY_COLOR,
                             (block[0], block[1], BLOCK_WIDTH, BLOCK_HEIGHT))
        pg.draw.rect(screen, FOOD_COLOR,
                     (food[0], food[1], BLOCK_WIDTH, BLOCK_HEIGHT))
        if score >= max_score:
            max_score = score
            draw_text(f"最高分数:{max_score}!", (60, 100), 18, (255, 0, 0))
        else:
            draw_text(f"最高分数:{max_score}", (60, 100), 18, (0, 0, 0))
        draw_text(f"分数:{score}", (60, 50), 18, (0, 0, 0))
    else:
        draw_text("你输了!", (200, 200))

    pg.display.flip()  # 更新屏幕内容

模块导入:

把需要用的库都引用一下,一般有这几个:

import enum
import sys
import pygame as pg
import random

import ... as ...就是将库重命名了一下

设置一些常数

WIDTH, HEIGHT = 400, 400
ROW_NUM = 20  # 行数
COL_NUM = 20  # 列数
BLOCK_WIDTH, BLOCK_HEIGHT = WIDTH / COL_NUM, HEIGHT / ROW_NUM

# R(Red) G(Green) B(Blue)
BODY_COLOR = (0, 255, 0)
HEAD_COLOR = (255, 0, 0)
FOOD_COLOR = (0, 0, 255)

使用了RGB颜色

初始化窗口:

# 使用pg之前必须初始化
pg.init()

# 设置主屏窗口
screen = pg.display.set_mode((WIDTH, HEIGHT))

# 设置窗口的标题,即游戏名称
pg.display.set_caption('贪吃蛇')


class Direction(enum.Enum):
    Left = 0
    Up = 1
    Right = 3
    Down = 2


class GameState(enum.Enum):
    Die = 0
    Playing = 1
    Preparing = 2

创建的两个类Direction和GameState继承了enum库,enum就是一个枚举,意思是这个类里面只存在Class里面枚举的键值对,其他都会报错,用于加强鲁棒性。

初始化参数:

snakes = []
blocks = []
direction: Direction = Direction.Up
game_state: GameState = GameState.Playing
difficulty = 3
food = (10*BLOCK_WIDTH, 10*BLOCK_HEIGHT)
score = 0
max_score = 0

这里采用元组的形式来建立蛇

定义主要函数:

初始化函数

def init():
    snakes.clear()
    snakes.append((5*BLOCK_WIDTH, 5*BLOCK_HEIGHT))
    snakes.append((5*BLOCK_WIDTH, 6*BLOCK_HEIGHT))
    snakes.append((5*BLOCK_WIDTH, 7*BLOCK_HEIGHT))
    global direction, game_state, difficulty, score, max_score
    direction = Direction.Up
    game_state = GameState.Playing
    difficulty = 3
    generate_food()
    score = 0

global + 变量名:将变量声明为全局变量,
在函数里面如果不加global,就像c语言中的形参一样,对于变量本身没有影响。
初始时蛇长定为3

定向函数:

def set_direction(d: Direction):
    global direction
    if(d.value + direction.value == 3):
        return
    direction = d

d.value + direction.value != 3是为了保证转向后不会向反方向走(其他方向都有可能)

产生食物:

def generate_food():
    global food
    while True:
        x = random.randint(0, COL_NUM-1) * BLOCK_WIDTH
        y = random.randint(0, ROW_NUM-1) * BLOCK_HEIGHT
        if (x, y) not in snakes and (x, y) not in blocks:
            food = (x, y)
            break

食物随机产生,但不能生成在蛇身上和墙上。

蛇的抽抽:

def move():
    global game_state
    cur_head: tuple[int, int] = snakes[0]
    match direction:
        case Direction.Left:
            snakes.insert(0, (cur_head[0]-BLOCK_WIDTH, cur_head[1]))
        case Direction.Right:
            snakes.insert(0, (cur_head[0]+BLOCK_WIDTH, cur_head[1]))
        case Direction.Down:
            snakes.insert(0, (cur_head[0], cur_head[1]+BLOCK_HEIGHT))
        case Direction.Up:
            snakes.insert(0, (cur_head[0], cur_head[1]-BLOCK_HEIGHT))
    if (head := snakes[0]) != food:
        if head in snakes[1:] or head[0] < 0 or head[0] >= WIDTH or head[1] < 0 or head[1] >= HEIGHT:
            game_state = GameState.Die
        else:
            snakes.pop()
    else:
        global difficulty, score, max_score
        difficulty *= 1.0
        score += 100
        generate_food()

产生文本:

def draw_text(s: str, center, font_size=50, font_color=(255, 0, 0), back_color=(255, 255, 255)):
    f = pg.font.Font('C:/Windows/Fonts/simhei.ttf', font_size)
    # 生成文本信息,第一个参数文本内容;第二个参数,字体是否平滑;
    # 第三个参数,RGB模式的字体颜色;第四个参数,RGB模式字体背景颜色;
    text = f.render(s, True, font_color, back_color)
    # 获得显示对象的rect区域坐标
    textRect = text.get_rect()
    # 设置显示对象居中
    textRect.center = center
    # 将准备好的文本信息,绘制到主屏幕 Screen 上。
    screen.blit(text, textRect)

设置font对象,渲染font对象,设置文本位置。

主循环:

init()
clock = pg.time.Clock()
# 固定代码段,实现点击"X"号退出界面的功能,几乎所有的pg都会使用该段代码
while True:
    clock.tick(2 * difficulty)
    # 循环获取事件,监听事件状态
    for event in pg.event.get():
        # 判断用户是否点了"X"关闭按钮,并执行if代码段
        match event.type:
            case pg.QUIT:
                pg.quit()
                sys.exit()
            case pg.MOUSEBUTTONDOWN:
                #print("click")
                if game_state == GameState.Die:
                    game_state = GameState.Playing
                    init()
            case pg.KEYDOWN:
                match event.key:
                    case pg.K_LEFT:
                        set_direction(Direction.Left)
                    case pg.K_RIGHT:
                        set_direction(Direction.Right)
                    case pg.K_UP:
                        set_direction(Direction.Up)
                    case pg.K_DOWN:
                        set_direction(Direction.Down)
                    case pg.K_0:
                         if game_state == GameState.Die:
                           game_state = GameState.Playing
                           init()

    move()
    screen.fill((255, 255, 255))
    if game_state == GameState.Playing:
        for i, block in enumerate(snakes):
            if i == 0:
                pg.draw.rect(screen, HEAD_COLOR,
                             (block[0], block[1], BLOCK_WIDTH, BLOCK_HEIGHT))
            else:
                pg.draw.rect(screen, BODY_COLOR,
                             (block[0], block[1], BLOCK_WIDTH, BLOCK_HEIGHT))
        pg.draw.rect(screen, FOOD_COLOR,
                     (food[0], food[1], BLOCK_WIDTH, BLOCK_HEIGHT))
        if score >= max_score:
            max_score = score
            draw_text(f"最高分数:{max_score}!", (60, 100), 18, (255, 0, 0))
        else:
            draw_text(f"最高分数:{max_score}", (60, 100), 18, (0, 0, 0))
        draw_text(f"分数:{score}", (60, 50), 18, (0, 0, 0))
    else:
        draw_text("你输了!", (200, 200))

    pg.display.flip()  # 更新屏幕内容

标签:head,snakes,python,WIDTH,讲座,pg,贪吃蛇,score,BLOCK
来源: https://www.cnblogs.com/misasteria/p/16290637.html