Micropython+合宙Esp32c3+合宙air101LCD完成一个贪吃蛇小游戏

2023-11-06

系列文章目录

手把手使用Micropython+合宙Esp32c3(驱动安装,为合宙Esp32c3安装Micropython固件库,代码上传到ESP32C3中)含Thonny和vscode两种方法

手把手使用Micropython+合宙Esp32c3+合宙air101LCD屏幕绘制,显示图片以及ST7735的详细使用教程



前言

本文介绍如何使用MicroPython编写代码,实现一个简单的贪吃蛇游戏。该游戏利用MicroPython开发板上的TFT显示屏和按键,通过控制贪吃蛇的移动方向,吃掉食物来增加长度,并避免撞到自己或碰到红色矩形。同时,在特定条件下还会生成黄色矩形,使游戏更具挑战性。


流程

准备工作

首先,我们需要准备一块支持MicroPython的开发板,在这里使用的合宙Esp32c3+合宙air101LCD。

1.导入库和设置变量
导入必要的库文件,包括SPI、Pin以及ST7735(驱动TFT显示屏的库)。然后,设置一些变量,如贪吃蛇的初始长度、是否使用帧缓冲区等。

2.初始化TFT显示屏和填充背景
使用SPI和TFT库初始化TFT显示屏,设置背景颜色为白色。

3.按键扫描函数
编写一个函数用于扫描按键状态,判断是否有按键被按下,并记录下按下的按键。

4.重启游戏函数
编写一个函数用于重新开始游戏,当按下按键4时调用该函数。在函数中,重新设置贪吃蛇的初始位置、长度和移动方向,并清空屏幕。

5.游戏主循环
进入游戏主循环,在循环中执行以下操作:
调用按键扫描函数,检测是否有按键被按下,并根据不同的按键改变贪吃蛇的移动方向或重新开始游戏。
清除上一次贪吃蛇尾部的坐标。
根据移动方向更新贪吃蛇的位置,同时进行边界检测。
判断是否与自身身体碰撞,如果碰撞则游戏结束。
更新时间和计数器。
如果计数器达到一定值,生成一个红色矩形,并将其添加到红色矩形位置列表中。
检测是否与黄色矩形碰撞,如果碰撞则游戏结束。
检测是否吃到食物,如果吃到则增加贪吃蛇的长度,并随机生成新的食物位置。
绘制贪吃蛇的身体和食物。
使程序休眠一段时间,控制游戏的速度。

//代码如下:
from machine import SPI, Pin
from ST7735 import TFT, bitSwap
import time
import framebuf
import random

snake_length = 1
USE_FRAME_BUFFER = True

spi = SPI(1, baudrate=40000000, polarity=0, phase=0, sck=Pin(2), mosi=Pin(3), miso=Pin(10))
tft = TFT(spi, '/combined.bin', 6, 10, 7)
tft.init_7735(tft.REDTAB80x160)
tft.fill(TFT.WHITE)

key0 = Pin(13, Pin.IN, Pin.PULL_UP)
key1 = Pin(5, Pin.IN, Pin.PULL_UP)
key2 = Pin(9, Pin.IN, Pin.PULL_UP)
key3 = Pin(8, Pin.IN, Pin.PULL_UP)
key4 = Pin(4, Pin.IN, Pin.PULL_UP)

x, y = 50, 50

def wait_pin_change(pin):
    # 等待引脚值发生改变
    # 需要保持连续 20ms 相同的值
    cur_value = pin.value()
    active = 0
    while active < 20:
        if pin.value() != cur_value:
            active += 1
        else:
            active = 0
        time.sleep_ms(1)

key0_flag = 0
key1_flag = 0
key2_flag = 0
key3_flag = 0
key4_flag = 0
k0 = k1 = k2 = k3 = k4 = 0
last_yellow_rect_score = 0  # 上一次生成黄色矩形时的得分
# 定义贪吃蛇和食物的半径
snake_radius = 4
food_radius = 4
food_x = random.randint(snake_radius, 160 - snake_radius)
food_y = random.randint(snake_radius, 80 - snake_radius)

snake_body = [(x, y)]

# 初始移动方向为向右
direction = "right"

# 定义时间变量和计数器
start_time = time.time()
counter = 0

def key_scan():
    global key0_flag, key1_flag, key2_flag, key3_flag, key4_flag
    global k0, k1, k2, k3, k4
    if key0.value() == 0:
        wait_pin_change(key0)
        k0 += 1
        if k0 >= 1:
            key0_flag = 1
            k0 = 0
    elif key1.value() == 0:
        wait_pin_change(key1)
        k1 += 1
        if k1 >= 1:
            key1_flag = 1
            k1 = 0
    elif key2.value() == 0:
        wait_pin_change(key2)
        k2 += 1
        if k2 >= 1:
            key2_flag = 1
            k2 = 0
    elif key3.value() == 0:
        wait_pin_change(key3)
        k3 += 1
        if k3 >= 1:
            key3_flag = 1
            k3 = 0
    elif key4.value() == 0:
        wait_pin_change(key4)
        k4 += 1
        if k4 >= 1:
            key4_flag = 1
            k4 = 0

def restart_game():
    global snake_body, x, y, snake_length, direction
    snake_body = [(x, y)]
    snake_length = 1
    direction = "right"
    tft.fill(TFT.WHITE)
yellow_rect_positions = []
red_rect_positions = []

while True:
    key_scan()
    if key0_flag == 1:
        direction = "down"
        key0_flag = 0  # 下
    elif key1_flag == 1:
        direction = "left"
        key1_flag = 0  # 左
    elif key2_flag == 1:
        direction = "right"
        key2_flag = 0  # 右
    elif key3_flag == 1:
        direction = "up"
        key3_flag = 0  # 上
    elif key4_flag == 1:
        restart_game()  # 按下按键4,重新开始游戏
        key4_flag = 0  # 重置按键4的状态

    if len(snake_body) > 0:
        tft.fillrect((snake_body[-1][0], snake_body[-1][1]), (snake_radius, snake_radius), TFT.WHITE)  # 清除尾部坐标

    # 保存当前贪吃蛇坐标
    prev_x, prev_y = x, y
    # 根据移动方向更新贪吃蛇位置
    if direction == "down":
        y += 2
    elif direction == "left":
        x -= 2
    elif direction == "right":
        x += 2
    elif direction == "up":
        y -= 2
     # 边界检测与调整
    if y < 0:
        y = 80
    elif y > 80:
        y = 0
    if x < 0:
        x = 160
    elif x > 160:
        x = 0
    # 更新贪吃蛇位置
    snake_body.insert(0, (x, y))  # 将新的头部坐标插入到贪吃蛇身体的第一个位置
    if len(snake_body) > snake_length:
        snake_body.pop()  # 如果贪吃蛇长度超过了限制,删除尾部坐标

    # 检测碰撞
    if (x, y) in snake_body[1:]:
        # 贪吃蛇碰到自己身体,游戏结束
        tft.fill(TFT.WHITE)  # 清空屏幕
        score_text = "Score:" + str(snake_length-1)
        tft.text((80 - len(score_text)*4, 40), score_text, TFT.BLACK)  # 显示得分
        while True:
            key_scan()
            if key4_flag == 1:
                restart_game()  # 按下按键4,重新开始游戏
                key4_flag = 0  # 重置按键4的状态
                break

    # 更新时间和计数器
    current_time = time.time()
    counter += current_time - start_time
    start_time = current_time

    
    if (snake_length-1) % 10 == 0 and snake_length > last_yellow_rect_score and snake_length > 1:
        last_yellow_rect_score = snake_length
        yellow_rect_x = random.randint(food_radius, 160 - food_radius)
        yellow_rect_y = random.randint(food_radius, 80 - food_radius)
        yellow_rect_positions.append((yellow_rect_x, yellow_rect_y))
        tft.fillrect((yellow_rect_x, yellow_rect_y), (food_radius, food_radius), TFT.YELLOW)

    if counter >= 30:
        counter = 0
        rect_x = random.randint(food_radius, 160 - food_radius)
        rect_y = random.randint(food_radius, 80 - food_radius)
        red_rect_positions.append((rect_x, rect_y))
        tft.fillrect((rect_x, rect_y), (food_radius, food_radius), TFT.RED)
    # 检测与黄色矩形碰撞
    for yellow_rect_pos in yellow_rect_positions:
        if x + snake_radius//2 >= yellow_rect_pos[0] - food_radius//2 and x - snake_radius//2 <= yellow_rect_pos[0] + food_radius//2 \
                and y + snake_radius//2 >= yellow_rect_pos[1] - food_radius//2 and y - snake_radius//2 <= yellow_rect_pos[1] + food_radius//2:
            # 发生碰撞,执行相应操作
            tft.fillrect((yellow_rect_pos[0],yellow_rect_pos[1]),(snake_radius,snake_radius),TFT.WHITE)
            print("碰撞到黄色矩形!")
            tft.fill(TFT.WHITE)  # 清空屏幕
            score_text = "Score:" + str(snake_length-1)
            tft.text((80 - len(score_text)*4, 40), score_text, TFT.BLACK)  # 显示得分
            while True:
                key_scan()
                if key4_flag == 1:
                    restart_game()  # 按下按键4,重新开始游戏
                    key4_flag = 0  # 重置按键4的状态
                    yellow_rect_positions = []
                    red_rect_positions = []
                    last_yellow_rect_score = 0
                    break
            # ...
            
    # 检测与红色矩形碰撞
    for red_rect_pos in red_rect_positions:
        if x + snake_radius//2 >= red_rect_pos[0] - food_radius//2 and x - snake_radius//2 <= red_rect_pos[0] + food_radius//2 \
                and y + snake_radius//2 >= red_rect_pos[1] - food_radius//2 and y - snake_radius//2 <= red_rect_pos[1] + food_radius//2:
            # 发生碰撞,执行相应操作
            tft.fillrect((red_rect_pos[0],red_rect_pos[1]),(snake_radius,snake_radius),TFT.WHITE)
            print("碰撞到红色矩形!")
            # 从列表中移除碰撞的红色矩形
            red_rect_positions.remove(red_rect_pos)
            snake_length -= 1

    # 检测是否吃到食物
    if x + snake_radius//2 >= food_x - food_radius//2 and x - snake_radius//2 <= food_x + food_radius//2 \
            and y + snake_radius//2 >= food_y - food_radius//2 and y - snake_radius//2 <= food_y + food_radius//2:
        snake_length += 1
        print(snake_length)
        # 随机生成新的食物位置
        tft.fillrect((food_x, food_y), (food_radius, food_radius), TFT.WHITE)
        food_x = random.randint(snake_radius, 160 - snake_radius)
        food_y = random.randint(snake_radius, 80 - snake_radius)

    # 绘制贪吃蛇身体
    for body_part in snake_body:
        tft.fillrect((body_part[0], body_part[1]), (snake_radius, snake_radius), TFT.BLUE)

    # 绘制食物
    tft.fillrect((food_x, food_y), (food_radius, food_radius), TFT.GREEN)

    time.sleep(0.1)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Micropython+合宙Esp32c3+合宙air101LCD完成一个贪吃蛇小游戏 的相关文章

  • 用于将 cython 中的许多 C++ 类包装到单个共享对象的项目结构

    我在文档 邮件列表和这个问题在这里 https stackoverflow com questions 10300660 cython and distutils 但我想得到一个更直接的答案来解决我的具体情况 我正在通过尝试一点一点地包装我
  • 使用 pythonbrew 编译 Python 3.2 和 2.7 时出现问题

    我正在尝试使用构建多个版本的 python蟒蛇酿造 http pypi python org pypi pythonbrew 0 7 3 但我遇到了一些测试失败 这是在运行的虚拟机上 Ubuntu 8 04 32 位 当我使用时会发生这种情
  • Django 管理员在模型编辑时间歇性返回 404

    我们使用 Django Admin 来维护导出到我们的一些站点的一些数据 有时 当单击标准更改列表视图来获取模型编辑表单而不是路由到正确的页面时 我们会得到 Django 404 页面 模板 它是偶尔发生的 我们可以通过重新加载三次来重现它
  • SQLAlchemy 通过关联对象声明式多对多自连接

    我有一个用户表和一个朋友表 它将用户映射到其他用户 因为每个用户可以有很多朋友 这个关系显然是对称的 如果用户A是用户B的朋友 那么用户B也是用户A的朋友 我只存储这个关系一次 除了两个用户 ID 之外 Friends 表还有其他字段 因此
  • 通过最小元素比较对 5 个元素进行排序

    我必须在 python 中使用元素之间的最小比较次数来建模对 5 个元素的列表进行排序的执行计划 除此之外 复杂性是无关紧要的 结果是一个对的列表 表示在另一时间对列表进行排序所需的比较 我知道有一种算法可以通过 7 次比较 总是在元素之间
  • 如何使用Conda下载python包并随后离线安装?

    我知道通过 pip 我可以使用以下命令下载 Python 包 但 pip install 破坏了我的内部包依赖关系 当我做 pip download
  • 以编程方式停止Python脚本的执行? [复制]

    这个问题在这里已经有答案了 是否可以使用命令在任意行停止执行 python 脚本 Like some code quit quit at this point some more code that s not executed sys e
  • OpenCV 无法从 MacBook Pro iSight 捕获

    几天后 我无法再从 opencv 应用程序内部打开我的 iSight 相机 cap cv2 VideoCapture 0 返回 并且cap isOpened 回报true 然而 cap grab 刚刚返回false 有任何想法吗 示例代码
  • Python 函数可以从作用域之外赋予新属性吗?

    我不知道你可以这样做 def tom print tom s locals locals def dick z print z name z name z guest Harry print z guest z guest print di
  • 如何使用 OpencV 从 Firebase 读取图像?

    有没有使用 OpenCV 从 Firebase 读取图像的想法 或者我必须先下载图片 然后从本地文件夹执行 cv imread 功能 有什么办法我可以使用cv imread link of picture from firebase 您可以
  • AWS EMR Spark Python 日志记录

    我正在 AWS EMR 上运行一个非常简单的 Spark 作业 但似乎无法从我的脚本中获取任何日志输出 我尝试过打印到 stderr from pyspark import SparkContext import sys if name m
  • 绘制方程

    我正在尝试创建一个函数 它将绘制我告诉它的任何公式 import numpy as np import matplotlib pyplot as plt def graph formula x range x np array x rang
  • 如何在ipywidget按钮中显示全文?

    我正在创建一个ipywidget带有一些文本的按钮 但按钮中未显示全文 我使用的代码如下 import ipywidgets as widgets from IPython display import display button wid
  • Pandas:merge_asof() 对多行求和/不重复

    我正在处理两个数据集 每个数据集具有不同的关联日期 我想合并它们 但因为日期不完全匹配 我相信merge asof 是最好的方法 然而 有两件事发生merge asof 不理想的 数字重复 数字丢失 以下代码是一个示例 df a pd Da
  • 解释 Python 中的数字范围

    在 Pylons Web 应用程序中 我需要获取一个字符串 例如 关于如何做到这一点有什么建议吗 我是 Python 新手 我还没有找到任何可以帮助解决此类问题的东西 该列表将是 1 2 3 45 46 48 49 50 51 77 使用
  • 有人用过 Dabo 做过中型项目吗? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我们正处于一个新的 ERP 风格的客户端 服务器应用程序的开始阶段 该应用程序是作为 Python 富客户端开发的 我们目前正在评估 Dabo
  • 使用其构造函数初始化 OrderedDict 以便保留初始数据的顺序的正确方法?

    初始化有序字典 OD 以使其保留初始数据的顺序的正确方法是什么 from collections import OrderedDict Obviously wrong because regular dict loses order d O
  • Python 类继承 - 诡异的动作

    我观察到类继承有一个奇怪的效果 对于我正在处理的项目 我正在创建一个类来充当另一个模块的类的包装器 我正在使用第 3 方 aeidon 模块 用于操作字幕文件 但问题可能不太具体 以下是您通常如何使用该模块 project aeidon P
  • 导入错误:没有名为 site 的模块 - mac

    我已经有这个问题几个月了 每次我想获取一个新的 python 包并使用它时 我都会在终端中收到此错误 ImportError No module named site 我不知道为什么会出现这个错误 实际上 我无法使用任何新软件包 因为每次我
  • Statsmodels.formula.api OLS不显示截距的统计值

    我正在运行以下源代码 import statsmodels formula api as sm Add one column of ones for the intercept term X np append arr np ones 50

随机推荐

  • 使用postman做接口测试实战

    一 准备 1 postman工具 2 搭建被测系统服务 3 fiddler抓包工具 说明 本此实战测试是在完成前台界面开发后进行的 接口是通过fiddler抓包获取的 如果没有完成系统前台开发 以项目组输入的接口为准进行测试也是一样的原理
  • 博世BMA400传感器API (中文说明)

    前言 最近项目中要使用BMA400 sensor 为了以后查找 这里只是对API进行翻译 有些地方翻译可能出错 请指出来一起探讨 谢谢各位看官 BMA 400数据手册 https download csdn net download qq
  • 五种方法,教你如何在Mac上查看文件完整路径

    在MacOS上 Finder显示文件默认是不带路径展示的 你进入某个文件夹只会显示文件夹的名称而已 如下图 那如何获取或者显示文件的完整路径呢 在MacOS中有五种方法可以显示文件完整路径 第一种 使用 终端 Terminal获取文件完整路
  • Numpy 索引

    整数索引 一般形式 arr frist dim index second dim index nth dim index x np array 1 2 3 4 5 6 7 8 print x 2 3 y np array 11 12 13
  • 安卓图片裁剪之Android-Image-Cropper简单使用

    图片裁剪是一个相对用的比较多的功能 正好近期用到了 于是在最新的ChatGPT上询问了一番 两次询问 得到的最优推荐依然是 Android Image Cropper 经过一番研究使用 确实简单好用 直接看代码 首先 你需要引入依赖 dep
  • 吊打面试官系列之:我这样回答 “如何更高效的进行接口测试“,面试官果然跪了。

    高效的进行接口测试 1 引言 2 什么是接口测试 3 为什么要做接口测试 4 接口测试的范围 5 接口测试的重点 6 接口测试原则 6 1 基本原则 6 2 关键原则 6 2 其他原则 6 2 1 系统角度 7 接口测试常用工具 8 总结
  • ECCV2016 paper list (完整版)

    摘自ECCV2016的会议论文 Oral Session 1A Detection Recognition Retrieval Tuesday October 11 09 00 10 00 Chairs Bernt Schiele MPI
  • 牛客网SQL刷题四-电商场景(某东商城)

    SQL13 计算商城中2021年每月的GMV 数据 DROP TABLE IF EXISTS tb order overall CREATE TABLE tb order overall id INT PRIMARY KEY AUTO IN
  • ByteTrack 多目标跟踪 测试笔记

    目录 多目标跟踪2022个人汇总知识 Results on MOT challenge test set ByteTrack 简介 转自知乎 1 Motivation 2 byte原理
  • minicom 没有tx 信号

    在minicom s 的配置中 Serial port setup 选择F Hardware Flow Control No默认是yes 但是没有tx信号输出 改为no 后使用正常
  • 配置Docker本地镜像仓库

    1 需要先创建一个registry ui目录 存放地址随意你自己记得就行 mkdir registry ui 2 在registry ui中创建一个docker compose yml文件 touch docker compose yml
  • 【PTA】谷歌的招聘

    2004 年 7 月 谷歌在硅谷的 101 号公路边竖立了一块巨大的广告牌 如下图 用于招聘 内容超级简单 就是一个以 com 结尾的网址 而前面的网址是一个 10 位素数 这个素数是自然常数 e 中最早出现的 10 位连续数字 能找出这个
  • C语言函数大全-- t 开头的函数

    t 开头的函数 1 tan tanf tanl 1 1 函数说明 1 2 演示示例 1 3 运行结果 2 tanh tanhf tanhl 2 1 函数说明 2 2 演示示例 2 3 运行结果 3 tell 3 1 函数说明 3 2 演示示
  • MyBatis高级

    文章目录 一 动态sql 1 if 2 choose when otherwise 3 where 4 set 5 foreach 6 trim 7 Sql片段 二 分页 1 分页的使用步骤 1 1 导入maven依赖 2 mybatis配
  • sklearn GridSearchCV网格搜索和SVM的两个参数 C 和 gamma

    GridSearchCV 它存在的意义就是自动调参 只要把参数输进去 就能给出最优化的结果和参数 GridSearchCV用于系统地遍历多种参数组合 通过交叉验证确定最佳效果参数 引用自 公众号 写bug的程旭源 个人博客 写bug的程旭源
  • iOS tableView setAccessoryView 导致应用程序卡死问题

    iOS TableView TableViewCell setAccessoryView cell setAccessoryView cell accessoryView xxx iOS 14 使用 cell setAccessoryVie
  • iOS隐藏tableview多余的分割线以及解决cell左边短20px

    解决cell分割线左边短20px 解决cell分割线左边短20px的问题 void tableView UITableView tableView willDisplayCell UITableViewCell cell forRowAtI
  • 网络安全(黑客)自学建议&笔记

    前言 网络安全 顾名思义 无安全 不网络 现如今 安全行业飞速发展 我们呼吁专业化的 就职人员与大学生 而你 认为自己有资格当黑客吗 本文面向所有信息安全领域的初学者和从业人员 给你规划详细的网络安全学习路线 并附上优质的学习资料 让你在越
  • @SpringbootApplication详解和自定义类型过滤器

    spring boot 启动类使用 SpringBootApplication标记 该注解的定义如下 Target ElementType TYPE Retention RetentionPolicy RUNTIME Documented
  • Micropython+合宙Esp32c3+合宙air101LCD完成一个贪吃蛇小游戏

    系列文章目录 手把手使用Micropython 合宙Esp32c3 驱动安装 为合宙Esp32c3安装Micropython固件库 代码上传到ESP32C3中 含Thonny和vscode两种方法 手把手使用Micropython 合宙Es