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完成一个贪吃蛇小游戏 的相关文章

随机推荐

  • 使用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