MicroPython动手做(35)——体验小游戏-Arduino中文社区 - Powered by Discuz!

Arduino中文社区

 找回密码
 立即注册

QQ登录

只需一步,快速开始

楼主: eagler8

MicroPython动手做(35)——体验小游戏

[复制链接]
 楼主| 发表于 2020-6-26 12:20 | 显示全部楼层
Mind+ 实验图形编程2

19.jpg
 楼主| 发表于 2020-6-26 12:27 | 显示全部楼层
25.gif
 楼主| 发表于 2020-6-26 12:40 | 显示全部楼层
4、平衡自行车(shworld)


[mw_shl_code=arduino,true]#MicroPython动手做(35)——小游戏
#平衡自行车

from mpython import *

#自行车BMP图像转字节数据参考
#https://mpython.readthedocs.io/z ... asics/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()[/mw_shl_code]
 楼主| 发表于 2020-6-26 13:45 | 显示全部楼层
#MicroPython动手做(35)——小游戏
#平衡自行车(实验视频)

https://v.youku.com/v_show/id_XN ... oneSokuUgc_1.dtitle



 楼主| 发表于 2020-6-26 13:54 | 显示全部楼层
5、贪吃蛇2
使用三轴传感器控制前后左右


[mw_shl_code=arduino,true]#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 = 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()[/mw_shl_code]
 楼主| 发表于 2020-6-26 14:02 | 显示全部楼层
6、记忆力大比拼(shworld)
产生8位随机键序→累加用户的输入键序→判断键序


[mw_shl_code=arduino,true]#MicroPython动手做(35)——小游戏
#记忆力大比拼

from mpython import *
import time
import random
isStart=False    #是否首次载入,不然游戏中按A键又初始化了
inputKey=''      #键序,统计用户输入的键序,如11112222
inputKey_STR=''  #同键序,文本型,只不过用来显示,当前"当前您已输入AAABBBB"
keyOrder=''      #获取到的8位随机键序,如11112222

#获取随机8位键序
def makeKeyOrder():
    keys=''
    for i in range(8):  #循环8次
        key = random.randrange(1, 3)#获取范围1到2, 1为A键,2位B键
        keys = keys + str(key)
    return keys
keyOrder = makeKeyOrder() #返回获取到的8位键序,如11112222


#覆写oledshow,主要减少重复代码量
def oledshow(str,y=0,isClear=True):
    if isClear==False:
        oled.DispChar(str, 0,y)
        oled.show()
        return
    oled.fill(0)
    oled.DispChar(str, 0,y)
    oled.show()


#倒计时显示3-2-1
def countdownshow():
    j=4
    for i in range(3):
        j = j-1
        oledshow('倒计时:%s'%str(j),0)
        time.sleep(1)

        
#每次用户按键后触发该方法
def checkKey():
    global keyOrder,inputKey,inputKey_STR #引用全局变量,如果不修改变量,不需要申明global
    if len(inputKey)==8:                  #如果当前按键数等于8位才开始进行对比
        if inputKey==keyOrder:            #如果输入的8位键序和生成的8位键序匹配
            oledshow('恭喜您,按对了!...',0)#按键正确,输出内容
        else:
            oledshow('别灰心,再接再厉!...',0)#否则按键失败,输出内容
            
        #重新开始下一轮
        time.sleep(2)   #暂停2秒,避免内容切换过快看不到
        inputKey=''     #清空用户输入的键值,如11112222
        inputKey_STR='' #清空用户输入的键值,文本型,如AAAABBBB
        oledshow('下一题开始:',0)
        time.sleep(2)
        keyOrder = makeKeyOrder() #重新获取8位键序,11112222
        countdownshow()           #倒计时显示3-2-1
        showKey()                 #显示要记忆的键序
        
   
#显示键序
#主要是把数字11112222,转换成对应的AAAABBBB,很好理解,多看看
def showKey():
    global keyOrder  #引用全局变量
    key_str=''   #局部变量
    for key in keyOrder:
        if key=='1':
            key_str=key_str+"A"
        if key=='2':
            key_str=key_str+"B"
    oledshow(key_str,0)
    time.sleep(1)
    oledshow('',0)

        
#按键A触发事件
def on_button_a_down(_):
    time.sleep_ms(100)   #延迟调高点,避免产生2次按键事件
    global isStart,inputKey,inputKey_STR #引用全局变量

    if button_a.value() == 1: return
    if isStart == True:
        inputKey=inputKey+'1'           #统计用户键序
        inputKey_STR=inputKey_STR+'A'   #统计用户键序,文本型,用来显示当前的输入
        oledshow('您输入的是:'+inputKey_STR,0) #显示当前的输入
        checkKey()                      #输入的键序进行校验匹配
        return
    isStart=True
    oledshow('游戏现在开始...',0)
    time.sleep(1)
    countdownshow()
    showKey()
     
#按键B触发事件
def on_button_b_down(_):
    time.sleep_ms(100)  #延迟调高点,避免产生2次按键事件
    global inputKey,inputKey_STR
    if button_b.value() == 1: return
    if isStart == True:
        inputKey=inputKey+'2'            #统计用户键序
        inputKey_STR=inputKey_STR+'B'    #统计用户键序,文本型,用来显示当前的输入
        oledshow('您输入的是:'+inputKey_STR,0) #显示当前的输入
        checkKey()                       #输入的键序进行校验匹配
        return
   
#按键触发监视
button_a.irq(trigger=Pin.IRQ_FALLING, handler=on_button_a_down)
button_b.irq(trigger=Pin.IRQ_FALLING, handler=on_button_b_down)

#游戏启动
oledshow('【记忆力大比拼】',0,False)
oledshow('记忆屏幕出现的键序',16,False)
oledshow('如ABABAA,请依次键入',32,False)
oledshow('按A键自动开始游戏',48,False)[/mw_shl_code]
 楼主| 发表于 2020-6-26 14:16 | 显示全部楼层
记忆力大比拼

32.gif
 楼主| 发表于 2020-6-26 14:32 | 显示全部楼层
7、吃鸡游戏


33.jpg
36.jpg
34.jpg
35.jpg
 楼主| 发表于 2020-6-26 14:35 | 显示全部楼层
[mw_shl_code=arduino,true]#MicroPython动手做(35)——小游戏
#吃鸡游戏

from mpython import *
import time
import random
import music

def zhunxing():
    global grade, zidan, foodstate, yy, diY, xx, diX
    oled.hline((xx - 10), yy, 20, 1)
    oled.vline(xx, (yy - 10), 20, 1)
    oled.circle(xx, yy, 6, 1)

random.seed(time.ticks_cpu())


oled.fill(0)
oled.DispChar("今晚吃鸡?", 32, 26, 1)
oled.show()
time.sleep(3)
xx = 64
yy = 32
foodstate = True
grade = 0
zidan = 10
while True:
    if foodstate:
        diX = random.randint(4, 120)
        diY = random.randint(4, 60)
        foodstate = False
    xx = int(numberMap(accelerometer.get_y(),(-0.5),0.5,2,125))
    yy = int(numberMap(accelerometer.get_x(),0.5,(-0.5),2,61))
    if xx >= 2 and xx <= 125 and yy >= 2 and yy <= 61:
        oled.fill(0)
        oled.fill_circle(diX, diY, 4, 1)
        zhunxing()
        oled.show()
    if button_a.value() == 0 or button_b.value() == 0:
        rgb.fill((int(255), int(0), int(0)))
        rgb.write()
        time.sleep_ms(1)
        music.play('C3:1')
        zidan = zidan + -1
        if diX >= xx - 2 and diX <= xx + 2 and diY >= yy - 2 and diY <= yy + 2:
            foodstate = True
            grade = grade + 1
            if zidan <= 0:
                oled.fill(0)
                oled.DispChar("             游戏结束", 0, 16, 1)
                oled.DispChar(str("              得分:") + str(grade), 0, 32, 1)
                oled.show()
                break
        time.sleep_ms(100)
        rgb.fill( (0, 0, 0) )
        rgb.write()
        time.sleep_ms(1)[/mw_shl_code]
 楼主| 发表于 2020-6-26 14:47 | 显示全部楼层
mPython X 实验图形编程

37.jpg
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|Archiver|手机版|Arduino中文社区

GMT+8, 2024-12-28 01:05 , Processed in 0.081564 second(s), 15 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表