系列文章目录
手把手使用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)