知识点:什么是掌控板?
掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片,支持WiFi和蓝牙双模通信,可作为物联网节点,实现物联网应用。同时掌控板上集成了OLED显示屏、RGB灯、加速度计、麦克风、光线传感器、蜂鸣器、按键开关、触摸开关、金手指外部拓展接口,支持图形化及MicroPython代码编程,可实现智能机器人、创客智造作品等智能控制类应用。
掌控板硬件特性:
ESP-32主控
处理器:Tensilica LX6双核处理器(一核处理高速连接;一核独立应用开发)
主频:高达240MHz的时钟频率
SRAM:520KB
Flash:8MB
Wi-Fi标准:FCC/CE/TELEC/KCC
Wi-Fi协议:802.11 b/g/n/d/e/i/k/r (802.11n,速度高达150 Mbps),A-MPDU和A-MSDU聚合,支持0.4us防护间隔
频率范围:2.4~2.5 GHz
蓝牙协议:符合蓝牙v4.2 BR/EDR和BLE标准
蓝牙音频:CVSD和SBC音频低功耗:10uA
供电方式:Micro USB供电
工作电压:3.3V
最大工作电流:200mA
最大负载电流:1000mA
掌控板载
三轴加速度计MSA300,测量范围:±2/4/8/16G
地磁传感器MMC5983MA,测量范围:±8 Gauss;精度0.4mGz,电子罗盘误差±0.5°
光线传感器
麦克风
3 颗全彩ws2812灯珠
1.3英寸OLED显示屏,支持16*16字符显示,分辨率128x64
无源蜂鸣器
支持2个物理按键(A/B)、6个触摸按键
支持1路鳄鱼夹接口,可方便接入各种阻性传感器
拓展接口
20通道数字I/O, (其中支持12路PWM,6路触摸输入)
5通道12bit模拟输入ADC,P0~P4
1路的外部输入鳄鱼夹接口:EXT/GND
支持I2C、UART、SPI通讯协议
小游戏 (体积较小、玩法简单的游戏)
小游戏是一个较模糊的概念,它是相对于体积庞大的单机游戏及网络游戏而言的,泛指所有体积较小、玩法简单的游戏,通常这类游戏以休闲益智类为主,有单机版有网页版,在网页上嵌入的多为FLASH格式。当下小游戏主要是指在线玩的flash版本游戏,统称小游戏,其实小游戏还包含单机游戏,小型游戏机等。一般游戏大小小于10m的游戏都统称为小游戏,一些街机类小游戏。因其游戏安装简便,耐玩性强,无依赖性而广受白领及小朋友的喜爱。
“小游戏”这个词的型含义其实很简单,它不是一些大的游戏,不必花费更多的时间和精力。小游戏是原始的游戏娱乐方式,小游戏本身是为了叫人们在工作,学习后的一种娱乐、休闲的一种方式,不是为了叫玩家为之花费金钱、花费精力,更不是叫玩家为他痴迷。小游戏也可以理解为“Flash游戏”,是以SWF为后缀的游戏的总称.这些游戏是通过Flash软件和 Flash 编程语言 Flash ActionScript 制作而成。由于Flash是矢量软件,所以小游戏放大后几乎不影响画面效果。Flash小游戏是一种新兴起的游戏形式,以游戏简单,操作方便,绿色,无需安装,文件体积小等优点渐渐被广大网友喜爱。
Mind+ 实验图形编程
Mind+ 实验图形编程2
贪吃蛇
4、平衡自行车(shworld)
#MicroPython动手做(35)——小游戏
#平衡自行车
from mpython import *
#自行车BMP图像转字节数据参考
#https://mpython.readthedocs.io/zh/master/tutorials/basics/oled.html#id4
bmp = bytearray([\
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X7F,0X00,0X0F,0XF8,0X00,0X00,
0X00,0X00,0X18,0X00,0X0C,0X0C,0X00,0X00,0X00,0X00,0X08,0X00,0X04,0X04,0X00,0X00,
0X00,0X00,0X04,0X00,0X02,0X38,0X00,0X00,0X00,0X00,0X07,0XFF,0XFF,0X00,0X00,0X00,
0X00,0X00,0X07,0X00,0X07,0X00,0X00,0X00,0X00,0X00,0X09,0X00,0X04,0X80,0X00,0X00,
0X00,0X00,0X11,0X80,0X0C,0XC0,0X00,0X00,0X00,0XFF,0X30,0X80,0X18,0X7F,0XE0,0X00,
0X03,0X80,0XE0,0XC0,0X30,0X70,0X38,0X00,0X06,0X00,0XF0,0X60,0X21,0XB0,0X06,0X00,
0X08,0X00,0X88,0X20,0X43,0X10,0X03,0X00,0X10,0X01,0X04,0X30,0X86,0X08,0X01,0X00,
0X30,0X03,0X0E,0XFF,0X84,0X0C,0X00,0X80,0X20,0X1F,0XFF,0X31,0X8C,0X04,0X00,0XC0,
0X60,0X32,0X02,0X20,0X8C,0X00,0X00,0XC0,0X60,0X22,0X02,0X24,0XC8,0X00,0X00,0XC0,
0X60,0X1F,0X02,0X3C,0X8C,0X00,0X00,0XC0,0X30,0X0F,0XFF,0XFF,0X04,0X00,0X00,0X80,
0X10,0X00,0X04,0X18,0X04,0X00,0X01,0X80,0X18,0X00,0X0C,0X08,0X02,0X00,0X03,0X00,
0X0C,0X00,0X18,0X00,0X01,0X00,0X06,0X00,0X07,0X00,0X70,0X00,0X00,0XC0,0X0C,0X00,
0X01,0XFF,0XC0,0X00,0X00,0X3F,0XF0,0X00,0X00,0X3E,0X00,0X00,0X00,0X0F,0XC0,0X00,
0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,0X00,
])
#无限循环
while True:
bikeWidth=60 #自行车图片宽度
bikeHeight=30 #自行车图片高度
bikeInitX=34 #初始化自行车的X中央点,屏幕宽度128/2-补偿自行车宽度30=34
bikeInitY=35 #初始化自行车的Y点,手动测量调为35即可
y=accelerometer.get_y() #如官方说明图所示,y轴和x轴是相反的,所以这里获取的是y轴加速度
if y<=1 and y>=-1: #定界,其实不定也行。用于下面设定变量转换
offsetX=int(numberMap(y,1,-1,-60,128)) #-60=最小宽度0-自行车宽度,128为屏幕最大宽度
#offsetX主要把y轴的加速度转换成屏幕的宽度分辨率
#numberMap变量转换说明
#numberMap(输入值,需映射的最小值,需映射的最大值,映射出的最小值,映射出的最大值)
#比如numberMap(i,1,2,10000,20000)
#即i是变量,范围在1~2之间,通过numberMap函数你可以得到转换后的范围,在10000-2000之间
#如i是1.5则返回15000,i是1.8返回18000,以此类推
move_x=offsetX #移动的坐标
#清除
oled.fill(0)
#填充图形
oled.Bitmap(move_x,bikeInitY, bmp, bikeWidth , bikeHeight, 1)
#填充左侧钉子,手绘坐标
oled.line(0,64,2,58,1)
oled.line(2,58,4,64,1)
#填充右侧钉子,手绘坐标
oled.line(127,64,125,58,1)
oled.line(125,58,123,64,1)
#判断是否碰到左右钉子边界,并填充文字提示
if move_x+bikeWidth >=125:
oled.DispChar('老铁,扎前胎了!', 60-14, 0)
if move_x+bikeWidth<=58:
oled.DispChar('老铁,扎后胎了!',0,0)
#显示图形文字
oled.show()
#MicroPython动手做(35)——小游戏
#平衡自行车(实验视频)
https://v.youku.com/v_show/id_XNDcyNzY3NTUzMg==.html?spm=a2h0c.8166622.PhoneSokuUgc_1.dtitle
5、贪吃蛇2
使用三轴传感器控制前后左右
#MicroPython动手做(35)——小游戏
#贪吃蛇2
from mpython import *
import random, time
WIDTH, HEIGHT = 127, 63
class Direction():
"""
贪吃蛇方向,含上下左右
"""
UP = 0
DOWN = 1
LEFT = 2
RIGHT = 3
class GameState():
"""
游戏状态
"""
PLAYING = 0
PAUSE = 1
WIN = 2
FAIL = 3
class Snake():
"""
贪吃蛇
构建snake
:param cube(int): 网格大小默认4
"""
def __init__(self, cube=4):
self.cube_width = cube
self.grid_width_num, self.grid_height_num = WIDTH // self.cube_width, HEIGHT // self.cube_width
self.snake_body = []
self.snake_body.append((int(self.grid_width_num // 2 * self.cube_width),
int(self.grid_height_num // 2 * self.cube_width))) # 添加贪吃蛇的“头”
self.food_pos = self.generate_food()
self.direction = Direction.LEFT
def draw_grids(self):
"""
绘制网格
"""
for i in range(self.grid_width_num + 1):
oled.vline(self.cube_width * i, 0, HEIGHT, 1)
for i in range(self.grid_height_num + 1):
oled.hline(0, self.cube_width * i, WIDTH, 1)
def draw_body(self):
"""
绘制snake
"""
for sb in self.snake_body:
# pygame.draw.rect(screen, WHITE, (sb[0], sb[1], CUBE_WIDTH, CUBE_WIDTH))
oled.fill_rect(sb[0], sb[1], self.cube_width, self.cube_width, 1)
def generate_food(self):
"""
随机产生一个食物
"""
self.food_pos = (random.randint(0, self.cube_width - 1), random.randint(0, self.grid_height_num - 1))
return self.food_pos
def draw_food(self):
"""
绘制食物
"""
oled.fill_rect(self.food_pos[0] * self.cube_width, self.food_pos[1] * self.cube_width, self.cube_width,
self.cube_width, 1)
def grow(self):
"""
判断贪吃蛇是否吃到了事物,如果吃到了我们就加长小蛇的身体
"""
if self.snake_body[0][0] == self.food_pos[0] * self.cube_width and \
self.snake_body[0][1] == self.food_pos[1] * self.cube_width:
return True
return False
def refresh(self):
"""
更新小蛇身体的位置
"""
for i in range(len(self.snake_body) - 1, 0, -1):
self.snake_body[i] = self.snake_body[i - 1]
def move(self):
"""
移动snake身体
"""
if self.direction == Direction.UP:
self.snake_body[0] = (self.snake_body[0][0], self.snake_body[0][1] - self.cube_width)
elif self.direction == Direction.DOWN:
self.snake_body[0] = (self.snake_body[0][0], self.snake_body[0][1] + self.cube_width)
# top += cube_width
elif self.direction == Direction.LEFT:
self.snake_body[0] = (self.snake_body[0][0] - self.cube_width, self.snake_body[0][1])
# left -= cube_width
elif self.direction == Direction.RIGHT:
self.snake_body[0] = (self.snake_body[0][0] + self.cube_width, self.snake_body[0][1])
class Game():
"""
snake游戏控制
"""
def __init__(self, fps=8):
self.snake = Snake()
self.get_body = self.snake.snake_body
self.state = None
self.fps = fps
self.handles_cb = None
def is_win(self):
"""
判断是否赢
"""
return len(self.get_body) == WIDTH * HEIGHT - 1
def is_fail(self):
"""
判断是否输
"""
if not 0 <= self.get_body[0][0] < WIDTH or not 0 <= self.get_body[0][1] < HEIGHT:
return True
return False
@property
def score(self):
"""
游戏分数
"""
return len(self.get_body) - 1
def handles_accele(self, threshold=0.2):
"""
掌控板加速度控制
"""
x = accelerometer.get_x()
y = accelerometer.get_y()
if y <= 1 and y >= -1:
if abs(y) > threshold:
if y > 0:
self.snake.direction = Direction.LEFT
else:
self.snake.direction = Direction.RIGHT
if x <= 1 and x >= -1:
if abs(x) > threshold:
if x > 0:
self.snake.direction = Direction.DOWN
else:
self.snake.direction = Direction.UP
def handles_callback(self, f):
"""
游戏控制回调函数,可外部自定义控制方式
"""
self.handles_cb = f
def run(self):
"""
游戏运行
"""
self.state = GameState.PLAYING
update_time = time.ticks_ms()
while self.state == GameState.PLAYING: # 游戏状态为PLAYING
self.handles_cb() # 游戏控制回调函数
# 显示帧刷新,刷新方块位置
if time.ticks_diff(time.ticks_ms(), update_time) > (1000 // self.fps):
last_pos = self.get_body[-1] # 这里需要保存一下尾部的位置,如果小蛇迟到了食物,需要在尾部增长
self.snake.refresh() # 更新小蛇身体的位置
self.snake.move() # 改变头部的位置
if self.snake.grow(): # 判断小蛇是否吃到了事物,吃到了就成长,如果吃到了事物我们就产生一个新的食物
self.snake.generate_food()
self.get_body.append(last_pos)
oled.fill(0) # 清屏
self.snake.draw_body() # 画小蛇的身体
self.snake.draw_food() # 画出食物
oled.show() # 显示生效
update_time = time.ticks_ms() # 刷新帧时间
if self.is_fail(): # 判断if输
self.state = GameState.FAIL
break
if self.is_win(): # 判断if赢
self.state = GameState.WIN
break
if self.state == GameState.FAIL: # 输了,显示分数
oled.fill(0)
oled.text('Game over!', 25, 20)
oled.text('Score:%d' % self.score, 25, 32)
oled.show()
if self.state == GameState.WIN: # 赢了!
oled.fill(0)
oled.text('You win!', 25, 20)
oled.show()
if __name__ == '__main__':
game = Game(fps=8)
game.handles_callback(game.handles_accele)
game.run()