基于M5StickC Plus实现小游戏《接住掉落物》
使用M5StickC Plus,利用六轴IMU (SH200Q/MPU6886)姿态传感器控制移动,接住随机掉落的目标获得分数的小游戏A键开始游戏,B键重新开始
标签
嵌入式系统
显示
M5StickC Plus
2022暑期在家一起练(2)
UIFlow
listeningsnow
更新2022-09-02
燕山大学里仁学院
740

硬禾学堂2022暑假在家练(2)-使用M5StickC Plus实现小游戏《接住掉落物》

一 项目简介:

该项目是使用M5StickC Plus实现小游戏《接住掉落物》,掉落物在屏幕上由上至下掉落,控制“小人儿”接住掉落物,每接一个得一分。使用UIFlow开发平台开发。

实现的功能和大致方法如下:

  • 利用姿态传感器传出的俯仰角的数据来控制“小人儿”移动,A键开始游戏,B键返回开始界面
  • 俯仰角越大“小人儿”移动速度越大。
  • 显示图形方面,UIFlow对M5StickC Plus有专门的图形控制程序,直接控制横纵坐标变化即可使目标移动。

二 设计思路:

  • “小人儿”的移动:判断姿态传感器传出的俯仰角的数据,设定合适移动的阈值。再利用俯仰角大小来对“小人儿”横坐标进行加减,以达到控制“小人儿”的移动和移动速度。
  • 目标物的生成与移动:UIFlow自带图形编辑系统,可以使目标物显示(show)和隐藏(hide),设置了五个关键纵坐标标号来确定”掉落物“的五个轨迹。利用随机抽取列表[1,2,3,4,5]中的数来随机掉落五个目标物其中一个。
  • 得分检测: 在设计”掉落物“和“小人儿”移动时有意保留了各自横纵坐标值,只需检测是否符合得分范围即可

三 软件流程图:

Fo2r1QKNA2c4HexlRb1_qycLZHa4

四 简单的硬件介绍

  • ESP32(240MHz dual core, 600 DMIPS, 520KB SRAM, Wi-Fi)
  • 4MB Flash
  • 屏幕:0.96 inch, 80*160 Colorful TFT LCD, ST7735SV
  • SPM1423麦克风
  • 一个红外发射管
  • MEMS:MPU6886
  • 2.4G 3D天线
  • 蜂鸣器

五 实现的功能及图片展示:

  • 开始界面如下,按A开始游戏,按B返回开始界面

Fuy9EhuBCKIlwo_19DyQY-4kYTCx

  • 利用姿态传感器传回俯仰角数值判断左右移动以及移动速度

FizEDLL0LIqJX2zGlhlHZnEogr5vFgNPpAoWKHFHsay9EnKa-freODDm

  • 当“小人儿”接住"掉落物"时,下方分数显示分数加一

FvVf_49QgYkYcP_RXoyVg_AFk8XC

六 主要代码片段及说明:

  • 对应标号的KEY(E1_KEY---E5_KEY,默认为0)来更为方便的控制各个"掉落物"的是否运动以及显现,随机值取自数字1到5的列表。

 

# 五个“掉落物”随机生成,取目标物标号列表里1-5标号,使对应标号的显示&移动开关为开
def choice():
  global e1, x, a, X_M1, score, e2, AAA, main_loca, e3, E1_KEY, Main_loca, e4, E2_KEY, b, e5, E3_KEY, E4_KEY, E5_KEY
  x = lists_remove_random_item(X_M1)
  if x == 1:
    E1_KEY = 1
  if x == 2:
    E2_KEY = 1
  if x == 3:
    E3_KEY = 1
  if x == 4:
    E4_KEY = 1
  if x == 5:
    E5_KEY = 1
  • 当某个"掉落物"到达设定的最低端时,KEY值变回0,”掉落物“隐藏,并将取出的相应数字标识返回到列表。
  # e1---e5边界设定,到达边界返回初始值
  if e1 >= 176:
    e1 = -20
    E1_KEY = 0
    R1.hide()
    # 返回标号到目标物别号列表,防止出现空列表(下同)
    X_M1.append(1)
  if e2 >= 176:
    e2 = -20
    E2_KEY = 0
    R2.hide()
    X_M1.append(2)
  if e3 >= 176:
    e3 = -20
    E3_KEY = 0
    R3.hide()
    X_M1.append(3)
  if e4 >= 176:
    e4 = -20
    E4_KEY = 0
    R4.hide()
    X_M1.append(4)
  if e5 >= 176:
    e5 = -20
    E5_KEY = 0
    R5.hide()
    X_M1.append(5)
  • 判定“掉落物”是否移动。当KEY等于1时对相应“掉落物”的纵坐标累加,使“掉落物”向下“掉落“。
# 五个“掉落物”的移动、显示和隐藏
def E_MOVE():
  global e1, x, a, X_M1, score, e2, AAA, main_loca, e3, E1_KEY, Main_loca, e4, E2_KEY, b, e5, E3_KEY, E4_KEY, E5_KEY
  # (e1---e5)显示开关为1时开始移动
  if E1_KEY == 1:
    # 目标移动速度
    e1 = e1 + random.randint(4, 8)
    R1.setPosition(y=e1)
  if E2_KEY == 1:
    e2 = e2 + random.randint(4, 8)
    R2.setPosition(y=e2)
  if E3_KEY == 1:
    e3 = e3 + random.randint(4, 8)
    R3.setPosition(y=e3)
  if E4_KEY == 1:
    e4 = e4 + random.randint(4, 8)
    R4.setPosition(y=e4)
  if E5_KEY == 1:
    e5 = e5 + random.randint(4, 8)
    R5.setPosition(y=e5)
  • “小人儿”的移动:获取姿态传感器俯仰角数值,大于5横坐标加运算,小于5减运算,加减数值与俯仰角数值正相关,以此达到控制速度的目的。
# 控制“小人儿”左右移动
def MOVE():
  global x, e1, a, X_M1, score, e2, AAA, main_loca, E1_KEY, e3, Main_loca, E2_KEY, e4, b, E3_KEY, e5, E4_KEY, E5_KEY
  a = round(imu0.ypr[2])
  AAA = [a, b]
  Main_loca = [main_loca]
  # b为a的绝对值
  if a >= 0:
    b = a
  else:
    b = 0 - a
  # 使移动速度与俯仰角数值有关
  if a >= 5:
    main_loca = main_loca + round(b * 4 / 10)
    rectangle2.setPosition(x=Main_loca[0])
  if a <= -5:
    main_loca = main_loca - round(b * 4 / 10)
    rectangle2.setPosition(x=Main_loca[0])
  # 移动边界
  if main_loca <= 0:
    main_loca = 0
  if main_loca >= 109:
    main_loca = 109
  # 左右检测
  if a >= 10:
    label2.setText('R')
    label2.show()
  else:
    label2.hide()
  if a <= -10:
    label1.setText('L')
    label1.show()
  else:
    label1.hide()
  • 判定是否得分:利用5个”掉落物“(e1---e5)的纵坐标和“小人儿”的横纵坐标,检测是否得分。
# 利用5个”掉落物“(e1---e5)的纵坐标和“小人儿”的横纵坐标,检测是否得分
def SCORE1():
  global x, e1, a, X_M1, score, e2, AAA, main_loca, E1_KEY, e3, Main_loca, E2_KEY, e4, b, E3_KEY, e5, E4_KEY, E5_KEY
  if e1 > 170 and e1 < 190 and main_loca + 12 >= 0 and main_loca <= 20:
    score = score + 1
  if e2 > 170 and e2 < 190 and main_loca + 12 > 24 and main_loca < 40:
    score = score + 1
  if e3 > 170 and e3 < 190 and main_loca + 12 > 53 and main_loca < 77:
    score = score + 1
  if e4 > 170 and e4 < 190 and main_loca + 12 > 82 and main_loca < 106:
    score = score + 1
  if e5 > 170 and e5 < 190 and main_loca + 12 >= 111 and main_loca <= 135:
    score = score + 1

七 遇到的主要难题及解决方法:

  • “掉落物”的掉落,起初很久没找到很好的方法:

    解决过程:先是利用RTC来对各个掉落物纵坐标进行累加,最后发现不能独立控制某个”掉落物“,然后我想利用随机取出列表里的数的方法来对他们独立管控,但最后还是不尽人意。之后想到开关的方法,赋值给KEY=0or1。当为1时,显现掉落物并且纵坐标累加,当到达底部边界时,使KEY为0时,隐藏掉落物,并且初始化“掉落物”。

  • “小人儿”的左右移动不是很顺滑,而且不能控制速度:

   解决方法:将其横坐标累加值与俯仰角相关联,俯仰角越大,累加的值就越大,让其移动的速度就更快。

八 未来计划:

  • 由于对ESP 32 的编程不熟悉,我这次开发用的是图形化编程平台,也是M5官方的平台,对没有编程基础的人很友好,但是对于更高级的需求可能完成不了,因此我仍然需要学习。
  • 这个项目的其他任务我也想尝试,迫于本人实力有限,将来对嵌入式开发更加熟练时一定实时其他各种玩法。
#完整代码,本人承诺以下代码均为本人编写

from m5stack import *
from m5ui import *
from uiflow import *
import imu

setScreenColor(0x000000)


x = None
e1 = None
a = None
X_M1 = None
score = None
e2 = None
AAA = None
main_loca = None
E1_KEY = None
e3 = None
Main_loca = None
E2_KEY = None
e4 = None
b = None
E3_KEY = None
e5 = None
E4_KEY = None
E5_KEY = None

imu0 = imu.IMU()

rectangle2 = M5Rect(54, 198, 24, 24, 0xFFFFFF, 0xFFFFFF)
R1 = M5Rect(0, 0, 20, 20, 0xFFFFFF, 0xFFFFFF)
R2 = M5Rect(28, 0, 20, 20, 0xFFFFFF, 0xFFFFFF)
R3 = M5Rect(57, 0, 20, 20, 0xFFFFFF, 0xFFFFFF)
R4 = M5Rect(86, 0, 20, 20, 0xFFFFFF, 0xFFFFFF)
R5 = M5Rect(115, 0, 20, 20, 0xFFFFFF, 0xFFFFFF)
l1 = M5TextBox(54, 225, "0", lcd.FONT_Default, 0xFFFFFF, rotate=0)
label0 = M5TextBox(17, 77, "Press A to play", lcd.FONT_Default, 0xFFFFFF, rotate=0)
label3 = M5TextBox(23, 101, "B to try again", lcd.FONT_Default, 0xFFFFFF, rotate=0)
label1 = M5TextBox(0, 225, "L", lcd.FONT_Default, 0xffffff, rotate=0)
label2 = M5TextBox(124, 225, "R", lcd.FONT_Default, 0xffffff, rotate=0)
rectangle0 = M5Rect(0, 222, 135, 2, 0xFFFFFF, 0xff0000)

import random
import math


def lists_remove_random_item(myList):
  x = int(random.random() * len(myList))
  return myList.pop(x)

# 五个”掉落物“随机生成,取“掉落物”标号列表里1-5标号,使对应标号的显示&移动开关为开
def choice():
  global x, e1, a, X_M1, score, e2, AAA, main_loca, E1_KEY, e3, Main_loca, E2_KEY, e4, b, E3_KEY, e5, E4_KEY, E5_KEY
  x = lists_remove_random_item(X_M1)
  if x == 1:
    E1_KEY = 1
  if x == 2:
    E2_KEY = 1
  if x == 3:
    E3_KEY = 1
  if x == 4:
    E4_KEY = 1
  if x == 5:
    E5_KEY = 1

# 利用5个”掉落物“(e1---e5)的纵坐标和“小人儿”的横纵坐标,检测是否得分
def SCORE1():
  global x, e1, a, X_M1, score, e2, AAA, main_loca, E1_KEY, e3, Main_loca, E2_KEY, e4, b, E3_KEY, e5, E4_KEY, E5_KEY
  if e1 > 170 and e1 < 190 and main_loca + 12 >= 0 and main_loca <= 20:
    score = score + 1
  if e2 > 170 and e2 < 190 and main_loca + 12 > 24 and main_loca < 40:
    score = score + 1
  if e3 > 170 and e3 < 190 and main_loca + 12 > 53 and main_loca < 77:
    score = score + 1
  if e4 > 170 and e4 < 190 and main_loca + 12 > 82 and main_loca < 106:
    score = score + 1
  if e5 > 170 and e5 < 190 and main_loca + 12 >= 111 and main_loca <= 135:
    score = score + 1

# 各变量的初始化
def INT_E():
  global x, e1, a, X_M1, score, e2, AAA, main_loca, E1_KEY, e3, Main_loca, E2_KEY, e4, b, E3_KEY, e5, E4_KEY, E5_KEY
  e1 = -20
  e2 = -20
  e3 = -20
  e4 = -20
  e5 = -20
  # E1的show与hide开关
  E1_KEY = 0
  E2_KEY = 0
  E3_KEY = 0
  E4_KEY = 0
  E5_KEY = 0
  R1.hide()
  R2.hide()
  R3.hide()
  R4.hide()
  R5.hide()

# 控制“小人儿”左右移动
def MOVE():
  global x, e1, a, X_M1, score, e2, AAA, main_loca, E1_KEY, e3, Main_loca, E2_KEY, e4, b, E3_KEY, e5, E4_KEY, E5_KEY
  a = round(imu0.ypr[2])
  AAA = [a, b]
  Main_loca = [main_loca]
  # b为a的绝对值
  if a >= 0:
    b = a
  else:
    b = 0 - a
  # 使移动速度与俯仰角数值有关
  if a >= 5:
    main_loca = main_loca + round(b * 4 / 10)
    rectangle2.setPosition(x=Main_loca[0])
  if a <= -5:
    main_loca = main_loca - round(b * 4 / 10)
    rectangle2.setPosition(x=Main_loca[0])
  # 移动边界
  if main_loca <= 0:
    main_loca = 0
  if main_loca >= 109:
    main_loca = 109
  # 左右检测
  if a >= 10:
    label2.setText('R')
    label2.show()
  else:
    label2.hide()
  if a <= -10:
    label1.setText('L')
    label1.show()
  else:
    label1.hide()

# 五个“掉落物”的移动、显示和隐藏
def E_MOVE():
  global x, e1, a, X_M1, score, e2, AAA, main_loca, E1_KEY, e3, Main_loca, E2_KEY, e4, b, E3_KEY, e5, E4_KEY, E5_KEY
  # (e1---e5)显示开关为1时开始移动
  if E1_KEY == 1:
    # 目标移动速度
    e1 = e1 + random.randint(4, 8)
    R1.setPosition(y=e1)
  if E2_KEY == 1:
    e2 = e2 + random.randint(4, 8)
    R2.setPosition(y=e2)
  if E3_KEY == 1:
    e3 = e3 + random.randint(4, 8)
    R3.setPosition(y=e3)
  if E4_KEY == 1:
    e4 = e4 + random.randint(4, 8)
    R4.setPosition(y=e4)
  if E5_KEY == 1:
    e5 = e5 + random.randint(4, 8)
    R5.setPosition(y=e5)
  # e1---e5边界设定,到达边界返回初始值
  if e1 >= 176:
    e1 = -20
    E1_KEY = 0
    R1.hide()
    # 返回标号到目标物别号列表,防止出现空列表(下同)
    X_M1.append(1)
  if e2 >= 176:
    e2 = -20
    E2_KEY = 0
    R2.hide()
    X_M1.append(2)
  if e3 >= 176:
    e3 = -20
    E3_KEY = 0
    R3.hide()
    X_M1.append(3)
  if e4 >= 176:
    e4 = -20
    E4_KEY = 0
    R4.hide()
    X_M1.append(4)
  if e5 >= 176:
    e5 = -20
    E5_KEY = 0
    R5.hide()
    X_M1.append(5)


def buttonA_wasPressed():
  global x, e1, a, X_M1, score, e2, AAA, main_loca, E1_KEY, e3, Main_loca, E2_KEY, e4, b, E3_KEY, e5, E4_KEY, E5_KEY
  timerSch.run('timer', 1000, 0x00)
  label0.hide()
  label3.hide()
  pass
btnA.wasPressed(buttonA_wasPressed)

def buttonB_wasPressed():
  global x, e1, a, X_M1, score, e2, AAA, main_loca, E1_KEY, e3, Main_loca, E2_KEY, e4, b, E3_KEY, e5, E4_KEY, E5_KEY
  timerSch.stop('timer')
  score = 0
  label0.show()
  label3.show()
  pass
btnB.wasPressed(buttonB_wasPressed)

@timerSch.event('timer')
def ttimer():
  global x, e1, a, X_M1, score, e2, AAA, main_loca, E1_KEY, e3, Main_loca, E2_KEY, e4, b, E3_KEY, e5, E4_KEY, E5_KEY
  choice()
  pass


# 5个目标物的标号
X_M1 = [1, 2, 3, 4, 5]
# 控制物的初始横位置
main_loca = 54
# 得分
score = 0
INT_E()
while True:
  MOVE()
  E_MOVE()
  SCORE1()
  # 显示得分
  l1.setText(str(score))
  wait_ms(2)
附件下载
my-game.m5f
my_game.py
团队介绍
团队成员
listeningsnow
评论
0 / 100
查看更多
目录
硬禾服务号
关注最新动态
0512-67862536
info@eetree.cn
江苏省苏州市苏州工业园区新平街388号腾飞创新园A2幢815室
苏州硬禾信息科技有限公司
Copyright © 2023 苏州硬禾信息科技有限公司 All Rights Reserved 苏ICP备19040198号