灵感来源
PinPong板集成Arduino,同时支持WIFI功能,并且可用通过PinPong库进行Python程序的编写。集成MPU6050, 6050能够获取xyz的加速度和角速度,我们可以利用这个特点,使用板子的倾斜角度来控制游戏角色的移动,同时,板子上集成按钮,可以控制游戏角色的行为,通过wifi无线通信,摆脱线的束缚,完全可以做一个互动功能的无线手柄,再加上一个震动传感器,感觉就更棒了。
编程环境
针对小学生使用的Python编程环境,mu-editor算是一个比较友好的,界面简洁,集成度高,可以使用纯Python编程、pyzero、还支持micro:bit和esp32,非常容易被小学生掌握,因此很多老师都会用它来教学,基于PinPong板的互动手柄,就尝试使用该编程环境来完成本次项目。
材料清单
- PinPong X1
- 震动传感器 X2 链接
步骤1 下载并安装好mu-editor后,选择模式为pyzero,接着就是安装PinPong库,点击右下角的齿轮图标:
选择“ThirdPart Packages”
在输入框里输入包的名称,这里输入“pinpong”,如果需要安装多个包,每一行写一个包名就行了。如果不清楚完整的包名,可以先去https://pypi.org/ 进行搜索,比如搜索 PinPong,会显示详细的包版本信息,如下图所示:
步骤2 导入一个游戏项目,这里使用一个简化版的“飞机大战”游戏项目,在代码中导入PinPong库。
from pinpong.board import Board,Pin
from pinpong.libs.dfrobot_mpu6050 import MPU6050
import random, time,math
WIDTH = 480 # 屏幕宽度
HEIGHT = 680 # 屏幕高度
backgrounds = [] # 背景图像列表
backgrounds.append(Actor("warplanes_background", topleft=(0, 0)))
backgrounds.append(Actor("warplanes_background", bottomleft=(0, 0)))
hero = Actor("warplanes_hero1", midbottom=(WIDTH // 2, HEIGHT - 50))
hero.speed = 5 # 战机移动速度
hero.animcount = 0 # 战机动画计数
hero.power = False # 子弹增强标记
hero.live = 5 # 生命值
hero.unattack = False # 无敌状态标记
hero.ukcount = 0 # 无敌状态计数
hero.score = 0 # 游戏积分
gameover = False # 游戏结束标记
enemies = [] # 敌机列表
bullets = [] # 子弹列表
powers = [] # 增强道具列表
K1 =0.05 # 对加速度计取值的权重
dt=20*0.001 #注意:dt的取值为滤波器采样时间
angle=0.0
# 缓动类型列表
tweens = ["linear", "accelerate", "decelerate","accel_decel", \
"in_elastic", "out_elastic", "in_out_elastic", \
"bounce_end", "bounce_start", "bounce_start_end"]
#初始化,选择板型和端口号,不输入端口号则进行自动识别
Board("PinPong Board").begin()
accelgyro = MPU6050()
#初始化
#引脚初始化为电平输入,作为发射子弹的按钮
btn = Pin(Pin.D8, Pin.IN)
accelgyro.init()
if accelgyro.connection():
print("MPU6050 connection successful")
else:
print("MPU6050 connection failed")
# 创建敌机
def spawn_enemy():
origin_x = random.randint(50, WIDTH)
target_x = random.randint(50, WIDTH)
tn = random.choice(tweens)
dn = random.randint(3, 6)
enemy = Actor("warplanes_enemy1", bottomright=(origin_x, 0))
if random.randint(1, 100) < 20:
enemy.image = "warplanes_enemy2"
enemies.append(enemy)
# 根据指定的缓动类型来执行缓动操作
animate(enemy, tween=tn, duration=dn, topright=(target_x, HEIGHT))
# 周期性生成敌机(每1秒调用一次创建敌机函数)
clock.schedule_interval(spawn_enemy, 1.0)
music.play("warplanes")
# 更新游戏逻辑
def update():
if gameover:
clock.unschedule(spawn_enemy) # 停止自动生成敌机
return
update_background()
update_hero()
update_bullets()
update_powerup()
update_enemy()
# 绘制游戏场景和角色
def draw():
if gameover:
screen.blit("warplanes_gameover", (0, 0))
return
for backimgae in backgrounds:
backimgae.draw()
for enemy in enemies:
enemy.draw()
for powerup in powers:
powerup.draw()
for bullet in bullets:
bullet.draw()
draw_hud()
draw_hero()
# 更新游戏场景
def update_background():
for backimage in backgrounds:
backimage.y += 2
if backimage.top > HEIGHT:
backimage.bottom = 0
# 更新战机
def update_hero():
move_hero()
# 播放战机飞行动画
hero.animcount = (hero.animcount + 1) % 20
if hero.animcount == 0:
hero.image = "warplanes_hero1"
elif hero.animcount == 10:
hero.image = "warplanes_hero2"
# 无敌状态计数
if hero.unattack:
hero.ukcount -= 1
if hero.ukcount <= 0:
hero.unattack = False
hero.ukcount = 100
# 移动战机
def move_hero():
#通过PinPong板来移动战机
buf = accelgyro.get_motion6()
ax = buf[0]
az = buf[2]
gy = buf[4]
#加速度计算角度,
angle_ax = math.atan2(ax,az)*180/3.1415926
#陀螺仪角速度
gyro_gy = -gy/131.00
#一阶互补滤波
angle = 0.0
angle = K1 * angle_ax +(1-K1) * (angle +gyro_gy * dt)
#控制战机的左右移动
hero.x += angle * 10
#控制战机的上下移动
if keyboard.down:
hero.y += hero.speed
elif keyboard.up:
hero.y -= hero.speed
#读取引脚电平,控制子弹发射
if btn.read_digital():
clock.schedule_unique(shoot, 0.1) # 射击冻结时间为0.1秒
if hero.left < 0:
hero.left = 0
elif hero.right > WIDTH:
hero.right = WIDTH
if hero.top < 0:
hero.top = 0
elif hero.bottom > HEIGHT:
hero.bottom = HEIGHT
# 子弹射击
def shoot():
sounds.bullet.play()
bullets.append(Actor("warplanes_bullet", midbottom=(hero.x, hero.top)))
# 如果获得增强道具则额外添加两枚子弹
if hero.power:
leftbullet = Actor("warplanes_bullet", midbottom=(hero.x, hero.top))
leftbullet.angle = 15
bullets.append(leftbullet)
rightbullet = Actor("warplanes_bullet", midbottom=(hero.x, hero.top))
rightbullet.angle = -15
bullets.append(rightbullet)
# 更新子弹
def update_bullets():
for bullet in bullets:
theta = math.radians(bullet.angle + 90)
bullet.x += 10 * math.cos(theta)
bullet.y -= 10 * math.sin(theta)
if bullet.bottom < 0:
bullets.remove(bullet)
# 更新增强道具
def update_powerup():
for powerup in powers:
powerup.y += 2
if powerup.top > HEIGHT:
powers.remove(powerup)
elif powerup.colliderect(hero):
powers.remove(powerup)
hero.power = True
clock.schedule(powerdown, 5.0) # 5秒钟后取消增强效果
if hero.power or len(powers) != 0:
return
# 随机生成增强道具
if random.randint(1, 1000) < 5:
x = random.randint(50, WIDTH)
powerup = Actor("warplanes_powerup", bottomright=(x, 0))
powers.append(powerup)
# 取消子弹增强效果
def powerdown():
hero.power = False
# 更新敌机
def update_enemy():
global gameover
for enemy in enemies:
if enemy.top >= HEIGHT:
enemies.remove(enemy)
continue
# 检测是否碰被子弹击中
n = enemy.collidelist(bullets)
if n != -1:
enemies.remove(enemy)
bullets.remove(bullets[n])
sounds.shooted.play()
hero.score += 200 if enemy.image == "warplanes_enemy2" else 100
# 检测是否碰撞到战机
elif enemy.colliderect(hero) and not hero.unattack:
hero.live -= 1
if hero.live > 0:
hero.unattack = True
hero.ukcount = 100
enemies.remove(enemy)
sounds.shooted.play()
else:
sounds.gameover.play()
gameover = True
music.stop()
time.sleep(0.5)
# 绘制战机
def draw_hero():
if hero.unattack:
if hero.ukcount % 5 == 0:
return
hero.draw()
# 绘制生命值图像和游戏积分
def draw_hud():
for i in range(hero.live):
screen.blit("warplanes_live", (i * 35, HEIGHT - 35))
screen.draw.text(str(hero.score), topleft=(20, 20),
fontname="marker_felt", fontsize=25)
这里还没有加入震动传感和无线功能,先看下初步效果
虾虾^0^2021.08.11
好
犹有橘2021.05.30
材料清单是不是不全
天明zzb2021.05.16
能把整个项目压缩上🚢吗?