MicroPython-On-ESP8266——8x8LED点阵模块(5)自制贪吃蛇游戏

news2024/11/28 2:43:57

MicroPython-On-ESP8266——8x8LED点阵模块(5)自制贪吃蛇游戏

1. 背景知识

连续折腾了一段时间的8x8点阵屏模块,从基本原理到驱动它显示滚动图案效果,常用的功能都使用到了。系列如下:

MicroPython-On-ESP8266——8x8LED点阵模块(1)驱动原理

MicroPython-On-ESP8266——8x8LED点阵模块(2)使用74HC595驱动

MicroPython-On-ESP8266——8x8LED点阵模块(3)使用MAX7219驱动

MicroPython-On-ESP8266——8x8LED点阵模块(4)基于MAX7219滚动显示字符/图案

由于我手上只有这么一块屏,没有做多屏串接显示的效果。那下一步咱们来继续折腾点啥。就基于MAX7219模块做个贪吃蛇游戏吧(掌机粉、诺基亚粉才懂为什么做这个)

2. 贪吃蛇原始分析

8x8点阵屏有64个led灯珠,从长度2开始,理论上可以贪吃成一条长度为63的小蛇。所以还是有一点可玩性的。

2.1. 游戏规则

  • 地图(点阵屏)上初始有一条长度为2的小蛇,间隔一定时间保持惯性向蛇头方向移动
  • 通过四个方向键可以控制小蛇的移动方向
  • 初始在蛇身之外的地方随机有一个食物,蛇头碰到食物会把食物吃掉,小蛇长度加1,同时食物再随机产生一个
  • 蛇头碰到边界或者自身,游戏结束

2.2. 程序逻辑

先构思一下程序需要实现的基础功能模块:

  • 初始化
  • 惯性移动
  • 创建食物
  • 判断吃到食物
  • 判断撞墙或自杀
  • 小蛇长身体

再根据模块组装一下程序流程:

Created with Raphaël 2.3.0 开始 初始化 获取按健最后确定的方向 惯性移动 吃到食物? 身体加1/创建下个食物 撞墙/自杀? 结束 yes no yes no

2.3. 程序模块分析

基础铺垫:
A.我们基于屏幕坐标的方式来全局进行位置判断和屏幕绘制

在这里插入图片描述

B.用坐标表示食物,用两个数组来表示小蛇的身体

在这里插入图片描述
我们用数组来表示小蛇的身体,且把数组的第一个元素定义为蛇头的位置。基于此,

如果我们要判断吃到食物则用 snake_x[0] == food_x and snake_y[0] == food_y
如果我们判断小蛇撞墙则用snake_x[0] < 0 or snake_x[0] > 7 or snake_y[0] < 0 or snake_y[0] > 7
如果小蛇要长身体则用snake_x.append(...); snake_y.append(...)

这样大体逻辑就出来了。

模块原理拆解

模块原理解释
初始化给小蛇固定一个初始长度(=2)和中间靠左一点点的初始位置 (1,3) 、(2,3)
惯性移动由外部按钮确定方向,初始向右,如果外部按键无操作,就保持当前方向且固定时间间隔地向该方向移动。移动的方法就是从尾巴开始遍历小蛇身体数组,让当前值等于数组的上一个值;而蛇头呢则要根据需要移动的方向去取下个位置的值。
创建食物随机在屏幕范围内找个位置 (x食物, y食物),但不能与小蛇的身体重叠
判断吃到食物这个上面讲到过了,蛇头坐标与食物坐标重合则吃到了
判断撞墙或自杀撞墙是判断蛇头的坐标有没有越界屏幕坐标范围,自杀则是判断蛇头有没有跟任一个身体节点的坐标重合
小蛇长身体先缓存下来蛇尾巴,当小蛇移动一次以后,再把缓存的坐标补到蛇尾巴后面
绘制图案这个会有点绕。每次点亮屏幕前,先把所有位置都当作黑的,再依次把小蛇和食物对应的位置坐标转换为max7219驱动位数据。思路就是这么个思路,具体还是看后面代码慢慢理解吧。

用定时器或者固定间隔的循环来移动小蛇

3. 硬件及接线连接

程序需要不断扫描需要4个按键来确定上下左右四个方向,并保持最后一个按下的方向不变。再有就是使用MAX7219模块来驱动点阵屏。

接线示意图:
在这里插入图片描述
实物连接图:
按键我直接借用的一个焊废的板子上的4个触点按钮,板子斜过来用就是上下左右的布局。
在这里插入图片描述

4. 程序代码

上面已经解析了原理,这里直接整篇代码放上来吧

from machine import Pin
import time
from random import getrandbits


class Button(object):
    '四个按钮,用简化接线方式,按钮线与地线进行判断'

    # def __init__(self, gpio_up=0, gpio_down=5, gpio_left=2, gpio_right=4):
    def __init__(self, gpio_up=0, gpio_down=4, gpio_left=5, gpio_right=2):
        self.btn_up = Pin(gpio_up, Pin.IN, pull=Pin.PULL_UP)
        self.btn_down = Pin(gpio_down, Pin.IN, pull=Pin.PULL_UP)
        self.btn_left = Pin(gpio_left, Pin.IN, pull=Pin.PULL_UP)
        self.btn_right = Pin(gpio_right, Pin.IN, pull=Pin.PULL_UP)
        self.last_press = 'right'
    
    def _check(self, _btn):
        if _btn.value() == 0:
            time.sleep_ms(20)
            if _btn.value() == 0:
                return True
        return False

    def press(self):
        if self._check(self.btn_up): self.last_press = 'up'
        if self._check(self.btn_down): self.last_press = 'down'
        if self._check(self.btn_left): self.last_press = 'left'
        if self._check(self.btn_right): self.last_press = 'right'
        return self.last_press


class Matrix(object):
    '8x8LED点阵屏,MAX7219驱动'

    def __init__(self, gpio_din=13, gpio_clk=14, gpio_cs=15):
        '初始化'
        # 准备数据引脚
        self.pin_clk = Pin(gpio_clk, Pin.OUT, value=1)  #D5,时钟,上升跳变时数据位移锁存
        self.pin_cs  = Pin(gpio_cs,  Pin.OUT, value=1)  #D8,上升跳变时,数据全部推入锁存
        self.pin_din = Pin(gpio_din, Pin.OUT, value=1)  #D7,待移入的数据
        self.model_init()

    def write_byte(self, data):
        "向芯片移入一个字节"
        for i in range(8):
            self.pin_clk.off()
            self.pin_din.value(1 if ((data << i) & 0x80) else 0)  # 从高位开始送数据
            self.pin_clk.on()

    def write_data(self, addr, data):
        "写入地址与值"
        self.pin_cs.off()
        self.write_byte(addr)
        self.write_byte(data)
        time.sleep_us(5)
        self.pin_cs.on()

    def model_init(self):
        "初始化模块"
        self.write_data(0x0c, 0x00)  #关断处于关闭状态 
        self.write_data(0x0f, 0x00)  #不测试
        self.write_data(0x0b, 0x07)  #扫描所有位码
        self.write_data(0x0a, 0x0F)  #亮度0x07,半亮
        self.write_data(0x09, 0x00)  #不译码
        self.write_data(0x0c, 0x01)  #关断处于显示状态 

    def show(self, col_data):
        "亮屏控制,col_data需要为长度为8的数组"
        for line in range(8):
            self.write_data(line+1, col_data[line])


class Snake(object):
    '贪吃蛇'
    def __init__(self):
        '''初始状态
        ........
        ........
        ........
        .00.....  ->
        ........
        ........
        ........
        ........
        '''
        self.direct = 'right'  # 初始移动方向
        self.x = [2, 1]  #范围[0,7],第一个元素是蛇头x,蛇身加长时直接append(self.x[-1])
        self.y = [3, 3]  #范围[0,7],第一个元素是蛇头y,蛇身加长时直接append(self.y[-1])
        self.long = 2
        self.foodx, self.foody = 0, 0
        self.food_create()

    def move(self):
        '移动'
        tmp_x, tmp_y = self.x[-1], self.y[-1]
        # 蛇身向蛇首路过的方向移动
        for i in range(self.long, 1, -1):
            self.x[i-1] = self.x[i-2]
            self.y[i-1] = self.y[i-2]
        # 处理蛇首
        if self.direct=='up':
            self.y[0] = self.y[0]-1
        elif self.direct=='down':
            self.y[0] = self.y[0]+1
        elif self.direct=='left':
            self.x[0] = self.x[0]-1
        else:
            self.x[0] = self.x[0]+1
        # 吃到食物
        if self.food_eat():
            self.x.append(tmp_x)
            self.y.append(tmp_y)
            self.long += 1
            self.food_create()

    def is_dead(self):
        '判断是否撞墙或自杀'
        if self.x[0]<0 or self.x[0]>7:
            return True
        if self.y[0]<0 or self.y[0]>7:
            return True
        for i in range(1, self.long):
            if self.x[0] == self.x[i] and self.y[0] == self.y[i]:
                return True
        return False
    
    def food_create(self):
        '创建食物'
        while True:
            self.foodx = getrandbits(3)
            self.foody = getrandbits(3)
            bad_food = False
            for i in range(self.long):
                if self.x[i] == self.foodx and self.y[i]==self.foody:
                    bad_food = True
                    break
            if not bad_food:
                break

    def food_eat(self):
        '判断吃到食物'
        return self.x[0]==self.foodx and self.y[0]==self.foody

    def drawdata(self):
        '创建绘制图形数据'
        data = [0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]  # 待绘制数据
        # 画蛇
        for i in range(self.long):
            data[self.y[i]] |= (1 << (7-self.x[i]))
        # 画食物
        data[self.foody] |= (1<<(7-self.foodx))
        return data

# 初始各模块
btn = Button()
led = Matrix()
snake = Snake()

led.show(snake.drawdata())
step = 0
while True:
    time.sleep_ms(10)
    step+= 1
    last_press_direct = btn.press()

    if step > 50:
        if last_press_direct != snake.direct:
            snake.direct = last_press_direct  # 方向有变化时才转向
        snake.move()

        if snake.is_dead():
            break
        else:
            led.show(snake.drawdata())

        step = 0

5. 实验效果

8x8LED点阵屏制作贪吃蛇游戏

目前存在的问题与改进方向:

  1. 小蛇的移动是的循环里面判断次数达到就移动一次,间隔不是精准的。可以使用micropython的定时器来改进;
  2. 吃到食物长身体时,那个间隔内小蛇没有移动,只是长了一个节点,可以改进一下;
  3. 撞墙或自杀后程序就卡死了,因为小蛇身体已经越界,使用绘制屏幕去亮屏时报错了,这里也可以改进;
  4. 后续可以增加启动、结束的闪屏效果;
  5. 小蛇的移动速度是固定的,可以改进为随着身体越来越长,移动速度也逐步加快;

就这些吧,然后这些改进我就不费时做了,需要的同(主)学(要)自(是)行(我)研(人)究(懒)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/91922.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

文件下载漏洞详解

今天继续给大家介绍渗透测试相关知识&#xff0c;本文主要内容是文件下载漏洞详解。 免责声明&#xff1a; 本文所介绍的内容仅做学习交流使用&#xff0c;严禁利用文中技术进行非法行为&#xff0c;否则造成一切严重后果自负&#xff01; 再次强调&#xff1a;严禁对未授权设备…

速锐得视角—数字化能源新时代的影响挑战趋势

数字化正在改善能源系统的安全性、生产力、普及率和可持续性&#xff0c;但是同时数字化也引发了新的安全和隐私风险&#xff0c;此外&#xff0c;市场、企业和工作岗位也受数字化的影响&#xff0c;改变工种结构&#xff0c;在数字化新时代来临前&#xff0c;正在发生一些细微…

计算机毕业设计java+springboot+vue学生宿舍管理系统

项目介绍 通篇文章的撰写基础是实际的应用需要,然后在架构系统之前全面复习大学所修习的相关知识以及网络提供的技术应用教程,以学生宿舍管理系统的实际应用需要出发,架构系统来改善现学生宿舍管理系统及出入登记平台工作流程繁琐等问题。不仅如此以操作者的角度来说,该系统的…

数字IC验证快速入门,你想知道的干货都在这里

网上有很多人咨询关于数字IC验证的行情&#xff0c;下面大多数回答都说薪资高、机会多、发展好。 确实&#xff0c;一款芯片从立项到流片生产需要经过层层自测和验证&#xff0c;否则芯片注定是失败。可以说&#xff0c;IC验证是IC设计的关键所在。 验证的重要性 这些年来&a…

020 | 我国河长制运行中的公众协同参与机制研究 | 大学生创新训练项目申请书 | 极致技术工厂

研究目的营造全社会共同关心和保护河湖的良好氛围、拓宽公众参与渠道 公众参与河湖保护具有自身优势。公众是河湖保护的坚实力量&#xff0c;探求河长制中的公众参与机制&#xff0c;营造全社会关心保护环境的良好社会氛围是改善流域生态环境的根本举措。协同治理的发展以社会壮…

为什么要学习rust

一、rust的实现、优点 实现&#xff1a;明确/&#xff08;零成本&#xff09;抽象/赋能优点&#xff1a;兼具高性能/安全性/表达力 明确&#xff1a;rust不像其他的语言&#xff0c;这些编程语言为了照顾初学者&#xff0c;它会把很多基本概念隐藏在基本语法之后&#xff0c;它…

数图互通高校房产管理——公积金补贴管理

数图互通房产管理系统在这方面做得比较全面&#xff1b; 1、公积金管理 1.1 公积金开户申请、审核 新进入学校的职工、博士后(含特别研究助理)公积金开户申请老师登录平台进行公积金开户申请&#xff0c;申请页面先选择人员类型“在职、项目、博士后、特别研究助理”,由房产…

Oracle视图、索引与存储过程

目录 一、视图 二、索引 三、存储函数 (一)存储函数的语法结构 (二)案例 1.输入ID&#xff0c;返回NAME 2.传入数字&#xff0c;能够被2整除就是偶数&#xff0c;不能被2整除的就是奇数 3.对两个数字求和&#xff0c;对和判断奇偶数 4.判断SCOTT用户下&#xff0c;工资…

m基于鱼群优化算法的的三维场景下人员疏散系统matlab仿真

目录 1.算法描述 2.仿真效果预览 3.MATLAB核心程序 4.完整MATLAB 1.算法描述 人工鱼群优化算法&#xff0c;模仿鱼群的行为特点而设计的一种寻优策略。人工鱼群算法(Artificial Fish Swarm Algorithm&#xff0c;AFSA)是Li Xiao-lei在2002年提出的(Yazdani, Toosi, & M…

全网惟一面向软件测试人员的Python基础教程-在Python中怎么干倒字符串?

全网惟一面向软件测试人员的Python基础教程 起点&#xff1a;《python软件测试实战宝典》介绍 第一章 为什么软件测试人员要学习Python 第二章 学Python之前要搞懂的道理 第三章 你知道Python代码是怎样运行的吗&#xff1f; 第四章 Python数据类型中有那些故事呢&#xff1f;…

邂逅Vue3和Vue3开发体验

文章目录01-邂逅Vue3和Vue3开发体验Vue3带来的变化如何使用Vue方式一&#xff1a;CDN引入方式二——下载和引入计数器案例原生实现Vue实现MVVMtemplate写法一写法二datamethod其他属性01-邂逅Vue3和Vue3开发体验 Vue3带来的变化 如何使用Vue 方式一&#xff1a;CDN引入 <d…

Hadoop 综合实训(编写ing)

文章目录一&#xff0c;显示文件内容&#xff08;一&#xff09;启动hadoop服务&#xff08;二&#xff09;创建并上传本地文件&#xff08;1&#xff09;创建students.txt文件&#xff08;2&#xff09;上传文件到HDFS&#xff08;三&#xff09;创建Maven项目&#xff1a;Dis…

windows11执行python没有任何反应或拉起应用商店的解决办法

1 是什么&#xff08;现象&#xff09; 高高兴兴的用上新电脑&#xff0c;系统Windows11&#xff0c;结果发现用power shell执行python姿势不对。 python bioParser.py 点击Enter&#xff0c;结果秒结束&#xff01;而我的python脚本明明有很多打印&#xff01; 如果只执行py…

服务机器人“大战”进入下半场,竞争焦点变了

对于机器人企业而言&#xff0c;“卖出去”是商业本质。 如何“卖出去”&#xff0c;往往是企业之间的竞争焦点&#xff0c;它也许是技术&#xff0c;也许是营销&#xff0c;但随着服务机器人大战进入下半场&#xff0c;服务机器人的竞争焦点正在发生根本上的改变。 竞争焦点…

Docker:基于Docker对中间件进行配置、安装和使用操作合集

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言一、rabbitmq启动rabbitmq设置rabbitmq用户进入rabbitmq容器内部设置外界访问用户二、mongodb安装mongo启动mongodb配置及使用mongodb三、Redis1.安装redis2.启动…

同一台服务器上多版本PHP切换(apache2 php8.2 php7.2)

我们有时会在同一台服务器上搭建多个版本的PHP&#xff0c;用来测试不同的程序。可是如何在多个版本之间切换呢&#xff1f;本文以ubuntu1804Server为例给大家进行讲解示范。 环境 ubuntu1804server 4.15.0-200-genericapache2php 7.4php 8.2 1.安装apche2 apache2的安装非…

【项目管理】项目中的进度管理,你知道多少?

有效实施项目进度计划&#xff0c;是项目成功的重要保障&#xff0c;项目进度管理也是每位项目经理都非常重视的问题。 项目中的进度管理可以帮助您了解项目当前进度&#xff0c;估计项目是否能顺利完成。 项目管理就是通过的对知识、技能、工具的运用对项目活动进行管理&am…

星环数据云平台 TDC 3.1 发布,新增滚动重启、存储回收站等八大核心功能

近日&#xff0c;星环数据云平台 Transwarp Data Cloud &#xff08;以下简称 TDC&#xff09;正式推出 3.1 版本。TDC 是采用云原生技术&#xff0c;融合星环科技全系产品打造的统一 PaaS 平台&#xff0c;可以为企业提供数据流通交易平台、企业湖仓一体数据湖、企业数据中台、…

Redis框架(十四):大众点评项目 基于Redis实现点赞功能实现

大众点评项目 基于Redis的点赞功能实现需求&#xff1a;基于Redis实现点赞功能实现业务实战总体代码展示总结SpringCloud章节复习已经过去&#xff0c;新的章节Redis开始了&#xff0c;这个章节中将会回顾Redis实战项目 大众点评 主要依照以下几个原则 基础实战的Demo和Coding…

解读一个四路组相联cache代码

解读一个四路组相联cache代码 在《计算机组成原理&#xff0c;软硬件接口》中&#xff0c;第五章便是cache的学习。本人初学cache&#xff0c;难免有疏漏之处&#xff0c;源代码github地址&#xff1a;https://github.com/airin711/Verilog-caches 1、四路组相联cache主要特征…