Python游戏编程:手把手教你用 Python 制作贪吃蛇游戏

贪吃蛇游戏是有史以来最受欢迎的街机游戏之一。在这个游戏中,玩家的主要目标是在不撞墙或不撞墙的情况下抓住最大数量的水果。在学习 Python 或 Pygame 时,可以将创建蛇游戏视为一项挑战。这是每个新手程序员都应该接受的最好的初学者友好项目之一。学习构建视频游戏是一种有趣而有趣的学习。

贪吃蛇作为一款极其经典且广受欢迎的小游戏,是早期 Windows 电脑和功能手机(特别是诺基亚手机)流行度极高的小游戏,是当时功能手机时代最具代表性的游戏之一。游戏的基本规则和目标十分简单,但却极具吸引力,让人欲罢不能。本博文我们用 Python 编写属于自己的贪吃蛇游戏,一起来体验一下编程的乐趣与成就……

贪吃蛇游戏分析

控制蛇的移动:通过上下左右键,控制一条蛇在游戏区域中移动,最初蛇很短,通常由 1 个方块组成。

吃到食物增长:游戏区域中会随机出现食物(例如一个方块),当蛇头触碰到食物时,代表蛇吃到了食物,蛇身体会增长一节,同时得 1 分。

避免越界或碰撞:游戏中需要避免蛇头撞到游戏区域的边界,或者蛇头碰到自己的身体。

策略性移动:随着游戏的进行蛇身增长,需要巧妙地操控蛇的路径,既要吃到食物,又要避免越界碰撞,这变得越来越具挑战性和趣味性。

游戏分数和结束:游戏过程中,需要记录当前得分(即:蛇吃到食物的数量),游戏结束,展示总得分和重新开始游戏或者退出。

游戏进行中界面

使用库:

import tkinter as tk
from tkinter.messagebox import showinfo
import random

1. 初始化数据:在这里初始化所有的游戏参数包括(窗口大小 颜色,分数,运动速度等…)【可自己修改】:

    def __init__(self):

        self.window = None          # 实例化的窗体
        self.canvas = None          # 实例化的画布
        self.loop = 0               # 暂停标记,1为开启,0为暂停
        self.loop_id = None         # 实例化loop,用来取消循环
        self.game_map = []          # 整个游戏的地图
        self.snake_body = []        # 蛇身的坐标集
        self.food_xy = []           # 食物的坐标
        self.head_x = 0             # 蛇头的X坐标
        self.head_y = 0             # 蛇头的Y坐标
        self.dd = [0]               # 记录按键方向
        self.score = 0              # 记录得分
        self.score_max = 0          # 历史最高得分
        self.len = 3                # 蛇身初始长度(最小设定值为1,不包括蛇头)
        self.body_len = self.len    # 蛇身当前长度
        self.FPS = 100              # 蛇的移动速度(单位毫秒)
        self.row_cells = 27         # 一行多少个单元格(含边框)
        self.col_cells = 27         # 一共多少行单元格(含边框)
        self.canvas_bg = 'white'    # 游戏背景色
        self.cell_size = 20         # 方格单元格大小
        self.cell_gap = 0           # 方格间距
        self.frame_x = 15           # 左右边距
        self.frame_y = 15           # 上下边距
        self.win_w_plus = 120       # 窗口右边额外多出的宽度
        self.wall_list = list()     # 墙体障碍

        self.color_dict = {
            0: 'white',             # 0表示空白
            1: 'red',               # 1代表蛇头
            2: 'black',             # 2代表蛇身
            3: 'red',               # 3代表食物
            4: 'gray'               # 4代表墙
        }

        self.run_game()

2. 窗口的初始化:创建窗口 和 画布 以及 窗口显示文字

    def run_game(self):

        # 游戏窗口
        self.window = tk.Tk()           # 开一个窗口
        self.window.focus_force()       # 主窗口焦点
        self.window.title('贪吃蛇小游戏')

        # 窗体大小
        win_w_size = self.row_cells * self.cell_size + self.frame_x * 2 + self.win_w_plus
        win_h_size = self.col_cells * self.cell_size + self.frame_y * 2
        screenWidth = self.window.winfo_screenwidth()        # 获取显示区域的宽度
        screenHeight = self.window.winfo_screenheight()      # 获取显示区域的高度
        left = (screenWidth - win_w_size) // 2
        top = (screenHeight - win_h_size) // 2
        self.window.geometry("{}x{}+{}+{}".format(win_w_size, win_h_size, left, top))

        # 操作介绍
        txt_lable = tk.Label(self.window, text="操作方式:\n(W)向上\n(S)向下\n(A)向左\n(D)向又\n(空格)STOP", font=('Ya_hei', 15))
        txt_lable.place(x=self.cell_size * self.col_cells + self.cell_size * 2, y=self.cell_size * 10)

        # 创建画布
        canvas_h = win_h_size
        canvas_w = win_w_size - self.win_w_plus
        self.canvas = tk.Canvas(self.window, bg=self.canvas_bg, height=canvas_h, width=canvas_w, highlightthickness=0)
        self.canvas.place(x=0, y=0)
        self.game_start()

3. 创建地图数据,使用二维表的形式存储数据(0为空白, 4为墙壁)

    def create_map(self):
        # 创建地图列表 通过列表存放
        self.game_map = []
        for i in range(0, self.col_cells):
            self.game_map.append([])
        for i in range(0, self.col_cells):
            for j in range(0, self.row_cells):
                self.game_map[i].append(j)
                self.game_map[i][j] = 0
        print("--------------------     地图数据      ---------------------")
        print(self.game_map)
        # 绘制障碍物 可以自己设置
        for i in range(0, self.row_cells - 1):
            self.game_map[0][i] = 4
            self.game_map[self.col_cells - 1][i] = 4

        for i in range(0, self.col_cells - 1):
            self.game_map[i][0] = 4
            self.game_map[i][self.row_cells - 1] = 4
        self.game_map[-1][-1] = 4

        u = 5
        d = 20
        for i in range(5, 10):
            self.wall_list.append([u, i])
            self.game_map[u][i] = 4
            self.wall_list.append([d, i])
            self.game_map[d][i] = 4

        for i in range(17, 22):
            self.wall_list.append([u, i])
            self.game_map[u][i] = 4
            self.wall_list.append([d, i])
            self.game_map[d][i] = 4
        print(self.wall_list)

4. 创建像素格:

    def create_cells(self):
        # 创建单元格 像素点
        for y in range(0, self.col_cells):
            for x in range(0, self.row_cells):
                a = self.frame_x + self.cell_size * x
                b = self.frame_y + self.cell_size * y
                c = self.frame_x + self.cell_size * (x + 1)
                d = self.frame_y + self.cell_size * (y + 1)
                e = self.canvas_bg
                f = self.cell_gap
                g = self.color_dict[self.game_map[y][x]]
                self.canvas.itemconfig(self.canvas.create_rectangle(a, b, c, d, outline=e, width=f, fill=g), fill=g)

5. 初始化 🐍的信息和位置

    def create_snake(self):
        # 蛇头 在边框中间
        self.snake_body = [[self.col_cells // 2, self.row_cells // 2]]
        # 蛇身 蛇头上色,颜色为定义的1
        self.game_map[self.snake_body[0][0]][self.snake_body[0][1]] = 1

6. 食物的随机生成

    def create_food(self):

        # 食物 通过 random 随机生成
        self.food_xy = [0, 0]
        self.food_xy[1] = random.randint(1, self.row_cells - 2)
        self.food_xy[0] = random.randint(1, self.col_cells - 2)
        while self.game_map[self.food_xy[0]][self.food_xy[1]] != 0:
            self.food_xy[0] = random.randint(1, self.row_cells - 2)
            self.food_xy[1] = random.randint(1, self.col_cells - 2)

        self.game_map[self.food_xy[0]][self.food_xy[1]] = 3

7. 读取🐍在地图上的信息

    def snake_xy(self):
        # 读取蛇
        xy = []
        for i in range(0, self.col_cells):
            try:  # 查找数值为1的坐标,没有就返回0。为防止在0列,先加上1,最后再减去。
                x = self.game_map[i].index(1) + 1
            except:
                x = 0
            xy.append(x)
        self.head_x = max(xy)
        self.head_y = xy.index(self.head_x)
        self.head_x = self.head_x - 1

8. 控制🐍的移动

    def move_snake(self, event):

        # 记录按键的方向,a上 b下 c左 d右
        def move_key(a, b, c, d):
            direction = event.keysym

            if self.head_x != self.snake_body[-1][1]:
                if direction == a:
                    self.dd[0] = 1
                if direction == b:
                    self.dd[0] = 2
            else:
                if direction == c:
                    self.dd[0] = 3
                if direction == d:
                    self.dd[0] = 4

            if self.head_y != self.snake_body[-1][0]:
                if direction == c:
                    self.dd[0] = 3
                if direction == d:
                    self.dd[0] = 4
            else:
                if direction == a:
                    self.dd[0] = 1
                if direction == b:
                    self.dd[0] = 2


        def pause_key(key):
            """ 暂停键 """
            direction = event.keysym
            if direction == key:
                self.loop = 0
                showinfo('暂停', '按确定键继续')
                self.loop = 1
                self.window.after(self.FPS, self.game_loop)

        move_key('w', 's', 'a', 'd')
        move_key('W', 'S', 'A', 'D')
        move_key('Up', 'Down', 'Left', 'Right')
        pause_key('space')

9. 判断游戏是否结束

    def game_over(self):

        def over():
            showinfo('游戏结束', '本次得分: {}\n\n再来一局'.format(self.score))
            # 判断分数
            if self.score >= self.score_max:
                self.score_max = self.score
            self.score = 0
            self.body_len = self.len
            self.game_start()

        if [self.head_y, self.head_x] in self.snake_body[0:-2]: over()
        if self.head_x == self.row_cells - 1 or self.head_x == 0: over()
        if self.head_y == self.col_cells - 1 or self.head_y == 0: over()
        if [self.head_y, self.head_x] in self.wall_list: over()

  1. 记录蛇头运行轨迹,生成蛇身
    def snake_record(self):

        # 记录蛇头运行轨迹,生成蛇身
        temp = []
        temp.append(self.head_y)
        temp.append(self.head_x)
        print(self.head_y, self.head_x, self.game_map[self.head_y][self.head_x])
        self.snake_body.append(temp)

        if self.snake_body[-1] == self.snake_body[-2]:
            del self.snake_body[-1]

        # 碰到食物身体加长,并再随机生成一个食物
        if [self.head_y, self.head_x] == self.food_xy:
            self.score += 1
            self.body_len += 1
            self.create_food()
        # 限制蛇身长度,不超过设定值
        elif len(self.snake_body) > self.body_len:
            self.game_map[self.snake_body[0][0]][self.snake_body[0][1]] = 0
            del self.snake_body[0]

        # 在方向 自动前进
        def move(d, x, y):
            if self.dd[0] == d:  # 根据方向值来决定走向
                self.game_map[self.head_y + x][self.head_x + y] = 1
                self.game_map[self.head_y + 0][self.head_x + 0] = 2

        move(1, -1, 0)
        move(2, 1, 0)
        move(3, 0, -1)
        move(4, 0, 1)

  1. 每次吃到食物后🐍会变长,分数会增加 所以吃到一次,画面会刷新一次。
    def game_loop(self):
        # 吃到food 循环 刷新
        self.snake_record()
        self.snake_xy()
        self.canvas.delete('all')  # 清除canvas
        self.create_cells()
        self.game_over()
        if self.loop == 1:
            txt_s = tk.Label(self.window, text="当前得分:\n({})\n\n最高得分:\n({})".format(self.score, self.score_max), font=('Ya_hei', 15))
            txt_s.place(x=self.cell_size * self.col_cells + self.cell_size * 2, y=self.cell_size * 2)
            self.loop_id = self.window.after(self.FPS, self.game_loop)
  1. 游戏的开始 按顺序 初始化函数
    def game_start(self):

        # 游戏开始
        self.loop = 1       # 暂停标记,1为开启,0为暂停
        self.dd = [0]       # 记录按键方向
        self.create_map()
        self.create_snake()
        self.create_food()
        self.window.bind('<Key>', self.move_snake)
        self.snake_xy()
        self.game_loop()

13. 游戏结束关闭窗口

        def close_w():
            self.loop = 0
            self.window.after_cancel(self.loop_id)
            self.window.destroy()

        self.window.protocol('WM_DELETE_WINDOW', close_w)
        self.window.mainloop()

14. 启动main

if __name__ == '__main__':
    Snake()

快速总结——Python 贪吃蛇游戏

其实源码已经都列出来了,不过肯定还有小伙伴想直接拿完整的,需要的可以在评论区留言,暂时还没放在GitHub上,直接放文章里又感觉代码拖得太长了

👉 这份完整版的Python贪吃蛇小游戏已经上传,朋友们如果需要可以扫描下方CSDN官方认证二维码或者点击链接免费领取保证100%免费

读者福利:[CSDN大礼包:《Python小白从入门到精通全套学习资料》免费分享]安全链接免费领取
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值