esp32C3 micropython oled 恐龙快跑游戏
目录
简介
效果展示
源代码
main.py
ssd1306.py
实现思路
血量值
分数
恐龙
障碍物
得分与血量值的计算
简介
使用合宙esp32c3模块,基于micropython平台开发的一款oled小游戏,恐龙快跑,所有代码已经给出,将两个py文件放进esp32c3里即可运行,使用的是硬件i2c,这个ssd1306.py文件是我优化过的,许多用法可查看源码即可推敲,只支持128*64的I2C oled一定要用我提供的ssd1306驱动。
效果展示
esp32 micropython oled恐龙快跑
源代码
main.py
from ssd1306 import SSD1306_I2C
from machine import Pin,I2C,ADC
import time
import randomi2c=I2C(0,scl=Pin(5),sda=Pin(4))
oled=SSD1306_I2C(i2c)ps2x=ADC(Pin(2))
ps2x.atten(ADC.ATTN_11DB)
#生命值的绘制
live_list=[0x30,0x4C,0x42,0x21,0x21,0x42,0x4C,0x30]
#绘制恐龙
dinosaur=[0x03,0x01,0x00,0x00,0x00,0x00,0x01,0x03,0x07,0x7F,0xFF,0x8F,0xAF,0x8D,0xF9,0x78,
0xC0,0xE0,0xF0,0x78,0x7F,0xFD,0xF0,0xFC,0xFF,0xF9,0xF0,0xE0,0xC0,0x00,0x80,0x00]
#初始化屏幕
oled.fill(0)
oled.p8(live_list,0,0)
oled.p8(live_list,9,0)
oled.p8(live_list,18,0)
oled.text('0',120,0)
oled.p16(dinosaur,0,48)
oled.rect(117,53,10,10,True)
oled.show()
#设定游戏参数,一次跳跃用12帧数据处理
jump = 0
jump_num = [48,34,23,15,10,8]#根据恐龙的跳跃位置和自由落体运动规律得到的每帧绘制恐龙的位置
fall = False#降落标志
score = 0#分数
x = 0
live=3#生命值为3
#障碍物随机坐标
box1 = random.randint(40,120)
box2 = random.randint(40,120) + box1
speed = 3#初始游戏速度while True:#如果还有生命值if live:#当摇杆推动且恐龙在地平线上才触发跳动if ps2x.read()>2500 and jump == 0:jump = 1#一直升高直到最高点if jump != 0:jump += 1 if not fall else -1#降落到地面if jump == 0:fall = Falsescore += 1if jump == 5:fall = True#跳到最高点下落x += speedspeed = 3 + score//10#速度随积分增加#刷新屏幕oled.fill(0)#显示血量值for i in range(live):oled.p8(live_list,i*9,0)#更新分数oled.text(str(score),120,0)#画小恐龙的外形oled.p16(dinosaur,0,jump_num[jump])#画障碍物oled.rect(box1-x,55,4,8,True)oled.rect(box2-x,55,4,8,True)#判断当前障碍物过了屏幕,就把它变最后一个if box1+4-x <= 0:box1 = box2 box2 = box1 + random.randint(40,120)#判断是否碰到障碍物if 15 > box1-x > 12 and 48-jump_num[jump] < 14:live-=1score-=1time.sleep_ms(20)elif 0<=box1-x<4 and 48-jump_num[jump] < 14:live-=1#生命值为0,恐龙挂掉了else:oled.text('GAME_OVER',29,30)oled.show()
ssd1306.py
import framebuf
# 寄存器定义
SET_CONTRAST = const(0x81)
SET_ENTIRE_ON = const(0xa4)
SET_NORM_INV = const(0xa6)
SET_MEM_ADDR = const(0x20)
SET_COL_ADDR = const(0x21)
SET_PAGE_ADDR = const(0x22)
SET_DISP_START_LINE = const(0x40)
SET_DISP = const(0xae)
SET_SEG_REMAP = const(0xa0)
SET_MUX_RATIO = const(0xa8)
SET_COM_OUT_DIR = const(0xc0)
SET_DISP_OFFSET = const(0xd3)
SET_COM_PIN_CFG = const(0xda)
SET_DISP_CLK_DIV = const(0xd5)
SET_PRECHARGE = const(0xd9)
SET_VCOM_DESEL = const(0xdb)
SET_CHARGE_PUMP = const(0x8d)class SSD1306:def __init__(self,external_vcc):self.width = 128self.height = 64self.external_vcc = external_vccself.pages = 8self.init_display()def init_display(self):for cmd in (SET_DISP | 0x00, #熄屏SET_MEM_ADDR, 0x00, #水平寻址SET_DISP_START_LINE | 0x00,#显示起始行地址SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0SET_MUX_RATIO, 63,SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0SET_DISP_OFFSET, 0x00,SET_COM_PIN_CFG, 0x12,# timing and driving schemeSET_DISP_CLK_DIV, 0x80,SET_PRECHARGE, 0x22 if self.external_vcc else 0xf1,SET_VCOM_DESEL, 0x30, # 0.83*Vcc# displaySET_CONTRAST, 0xff, # maximumSET_ENTIRE_ON, # output follows RAM contentsSET_NORM_INV, # not inverted# charge pumpSET_CHARGE_PUMP, 0x10 if self.external_vcc else 0x14,0x2e, # 禁止滚动0xae | 0x01): #开屏self.write_cmd(cmd)self.fill(0)self.show()def v_scroll(self, d=1): self.write_cmd(0x2e) # 关闭滚动if d:self.write_cmd(0x26) # 向左self.write_cmd(0x00)self.write_cmd(0x07) # 起始页self.write_cmd(0x00) # 滚动帧率self.write_cmd(0x00) # 结束页else:self.write_cmd(0x27) # 向左self.write_cmd(0x00)self.write_cmd(0x00) # 起始页self.write_cmd(0x00) # 滚动帧率self.write_cmd(0x07) # 结束页self.write_cmd(0x00)self.write_cmd(0xff)self.write_cmd(0x2f) # 开启滚动def poweroff(self):self.write_cmd(const(0xae) | 0x00)#熄屏def contrast(self, contrast):self.write_cmd(SET_CONTRAST)self.write_cmd(contrast)def invert(self, invert):self.write_cmd(SET_NORM_INV | (invert & 1))def show(self):self.write_cmd(SET_COL_ADDR)self.write_cmd(0)self.write_cmd(127)self.write_cmd(SET_PAGE_ADDR)self.write_cmd(0)self.write_cmd(63)self.write_framebuf()def fill(self, c):self.framebuf.fill(c)def pixel(self, x, y, c):self.framebuf.pixel(x, y, c)def text(self, string, x, y, c=1):self.framebuf.text(string, x, y, c)def hline(self,x,y,w,c=1):self.framebuf.hline(x,y,w,c)def vline(self,x,y,h,c=1):self.framebuf.vline(x,y,h,c)def line(self,x1,y1,x2,y2,c=1):self.framebuf.line(x1,y1,x2,y2,c)def rect(self,x,y,w,h,c=1,f=False):self.framebuf.rect(x,y,w,h,c,f)def ellipse(self,x,y,xr,yr,c,f=False,m=15):self.framebuf.ellipse(x,y,xr,yr,c,f,m)def cube(self,x,y,l):self.rect(x,y,l,l)self.rect(x+int(0.5*l),int(y-0.5*l),l,l)self.line(x,y,int(x+0.5*l),int(y-0.5*l),1)self.line(x+l,y,int(x+1.5*l),int(y-0.5*l),1)self.line(x,y+l,int(x+0.5*l),int(y+0.5*l),1)self.line(x+l,y+l,int(x+1.5*l),int(y+0.5*l),1)def p8(self,page,x,y):for e in range(8):byte=bin(page[e]).replace('0b','')while len(byte)<8:byte='0'+bytefor i in range(8):if byte[i]=='1':self.pixel(x+e,y+i,int(byte[i]))def p16(self,page,x,y):for e in range(32):byte=bin(page[e]).replace('0b','')while len(byte)<8:byte='0'+bytefor i in range(8):if byte[i] and e<16:self.pixel(x+e,y+i,int(byte[i]))elif byte[i] and e>=16:self.pixel(x-16+e,y+8+i,int(byte[i]))def p32(self,page,x,y):for e in range(128):byte=bin(page[e]).replace('0b','')while len(byte)<8:byte='0'+bytefor i in range(8):if byte[i] and e<32:self.pixel(x+e,y+i,int(byte[i]))elif byte[i] and 32<=e<64:self.pixel(x+e-32,y+8+i,int(byte[i]))elif byte[i] and 64<=e<96:self.pixel(x+e-64,y+16+i,int(byte[i]))elif byte[i] and 96<=e<128:self.pixel(x+e-96,y+24+i,int(byte[i]))class SSD1306_I2C(SSD1306):def __init__(self,i2c, addr=0x3c, external_vcc=False):self.i2c = i2cself.addr = addrself.temp = bytearray(2)# buffer需要8 * 128的显示字节加1字节命令self.buffer = bytearray(8 * 128 + 1)self.buffer[0] = 0x40 # Co=0, D/C=1self.framebuf = framebuf.FrameBuffer1(memoryview(self.buffer)[1:], 128, 64)super().__init__(external_vcc)def write_cmd(self, cmd):self.temp[0] = 0x80 # Co=1, D/C#=0self.temp[1] = cmdself.i2c.writeto(self.addr, self.temp)def write_framebuf(self):self.i2c.writeto(self.addr, self.buffer)
实现思路
在python框架下开发游戏,思路很重要
血量值
用了8*8的矩形取模,是一个小爱心,代表血量值,在oled的左上角展示
分数
设置了游戏奖励分数,位于oled右上角
恐龙
拥有跳跃功能,符合自由落体运动规律,采用16*16取模方式构建,在oled左下角。恐龙跳起来分为6帧,落地也分为6帧,就是恐龙从地面跳到最高点时,刷新6次,用6个图像展示动态过程。根据自由落体运动规律,6帧平均每帧时间相同,由于恐龙只在y轴上运动,帧与帧之间的距离为1:3:5:7:9,用一个列表来记录这个规律,计算每一帧恐龙y坐标的位置,从最高点向下运动也是一样的。
障碍物
用4*8的矩形表示,设置两个并排的矩形,分别用随机数将其位置初始化,由于矩形只在x轴上移动,只需不停的移动矩形,改变矩形的x坐标即可,由于在恐龙的处理设置了12帧,不妨将障碍物一起嵌入这12帧中,在每一帧减小矩形的x坐标,每一帧减小的数量关系到矩形的移动速度。为了设置难度,把矩形移动速度与积分挂钩,积分越多,移动速度越大,难度越大,游戏越有意思,当然也可以用随机数处理,忽快忽慢,也很有意思。定义了两个矩形,(也可以根据个人感觉多定义几个),分别编号1,2,接近恐龙的为1号,可以实时计算矩形的坐标来检查矩形是否出界。分别用随机数表示两个矩形出现的位置,并把2号矩形加在1号矩形的后面,以随机数为它们之间的距离,由于不断减小矩形的坐标,并刷新,视觉上就看到了向左滚动的矩形,当第一个矩形出界后,就把2号矩形转为1号,同时新定义1个2号矩形,以一个随机数为距离加在1号矩形的后面,以此类推,就形成了一个迭代效果,源源不断的矩形滚动。
得分与血量值的计算
我把得分加在落地的瞬间,只要落地就加1分,产生了一种很奇妙的效果,玩家为了多得分,就要多跳,又不能碰到障碍物,无形中加了难度和趣味。
由于恐龙只在y轴上移动,矩形只在x轴移动,它们交叉的区域就是碰撞区域,可以计算损失血量,但是程序是在一个循环里的,esp32c3运行速度很快,如果把0-15的区域都设为碰撞区,会导致一次碰撞损失很多血量,我想要一次碰撞损失1滴血,就把碰撞区域缩小到两边,对应跳起和降落碰到障碍物两种情况。同时加了一定的延时使游戏感更好。
对于碰撞的判断,就相当于车祸双方,双方有交叉区域才能判定发生碰撞,当障碍物处于交叉区域,恐龙的跳跃高度没有跳出障碍区时,就判断发生碰撞,血量值减1。
当血量值为0时,游戏结束。
如果你有更好的想法,大家一起交流
相关文章:

esp32C3 micropython oled 恐龙快跑游戏
目录 简介 效果展示 源代码 main.py ssd1306.py 实现思路 血量值 分数 恐龙 障碍物 得分与血量值的计算 简介 使用合宙esp32c3模块,基于micropython平台开发的一款oled小游戏,恐龙快跑,所有代码已经给出,将两个py文件…...

53.Linux day03 文件查看命令,vi/vim常用命令
今天进行了新的学习。 目录 1.cat a.查看单个文件的内容: b.查看多个文件的内容: c.将多个文件的内容连接并输出到一个新文件: d.显示带有行号的文件内容: 2.more 3.less 4.head 5.tail 6.命令模式 7.插入模式 8.图…...

YOLOv8改进后效果
数据集 自建铁路障碍数据集-包含路障,人等少数标签。其中百分之八十作为训练集,百分之二十作为测试集 第一次部署 版本:YOLOv5 训练50epoch后精度可达0.94 mAP可达0.95.此时未包含任何改进操作 第二次部署 版本:YOLOv8改进版本 首…...

小程序的数据绑定和事件绑定
小程序的数据绑定 1.需要渲染的数据放在index.js中的data里 Page({data: {info:HELLO WORLD,imgSrc:/images/1.jpg,randomNum:Math.random()*10,randomNum1:Math.random().toFixed(2)}, }) 2.在WXML中通过{{}}获取数据 <view>{{info}}</view><image src"{{…...

第四章MyBatis核心配置文件
environments与environment标签 environments主要用来配置环境,属性default表示默认环境,值为environment的idenvironment为具体环境,属性id表示环境唯一标识environments可以有多个environment 加载默认环境 sqlSessionFactory sqlSessi…...

⛳ Docker - Centos 安装配置
目录 ⛳ Docker - Centos 安装配置🏭 Docker 安装:📢 一、安装依赖包💬 二、添加 Docker 下载源地址🐾 三、更新yum缓存👣 四、安装Docker💻 五、启动Docker🎁 六、查看Docker状态和…...
Python web实战之Django 的跨站点请求伪造(CSRF)保护详解
关键词:Python、Web、Django、跨站请求伪造、CSRF 大家好,今天我将分享web关于安全的话题:Django 的跨站点请求伪造(CSRF)保护,介绍 CSRF 的概念、原理和保护方法. 1. CSRF 是什么? CSRF&#…...

ARM(汇编指令)
.global _start _start:/*mov r0,#0x5mov r1,#0x6 bl LoopLoop:cmp r0,r1beq stopsubhi r0,r0,r1subcc r1,r1,r0mov pc,lr*/ mov r0,#0x1mov r1,#0x0mov r2,#0x64bl Loop Loop:cmp r0,r2bhi stopadd r1,r1,r0add r0,r0,#0x01mov pc,lr stop:B stop.end...

神经网络基础-神经网络补充概念-01-二分分类
概念 二分分类是一种常见的机器学习任务,其目标是将一组数据点分成两个不同的类别。在二分分类中,每个数据点都有一个与之关联的标签,通常是“正类”或“负类”。算法的任务是根据数据点的特征来学习一个模型,以便能够准确地将新…...

Linux16(1) 线程同步
目录 1、概念 2、线程的实现: 3、线程同步: 4、使用信号量: 5、使用信号量实现进程同步: 6、使用互斥锁 7、使用互斥锁实现线程同步 8、读写锁 9、使用读写锁 10、使用读写锁实现进程同步 1、概念 线程:进程…...

深入探讨lowess算法:纯C++实现与局部加权多项式回归的数据平滑技术
引言 在统计学和数据科学中,有时我们面对的数据是嘈杂的、充满噪声的。为了更好地揭示数据的潜在趋势和结构,数据平滑技术成为了一个重要工具。lowess或称为局部加权多项式回归是其中的一种流行方法,它对每一个点给予一个权重,根…...

Sui安全篇|详解零知识证明 (ZKP) Groth16的可塑性
Sui Move允许用户使用Groth16进行高效验证任何非确定性多项式时间(Non-deterministic Polynomial time ,NP)状态。Groth16是一种高效且广泛使用的零知识简洁非交互知识证明(Zero-Knowledge Succinct Non-interactive Argument of …...

记录--webpack和vite原理
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前言 每次用vite创建项目秒建好,前几天用vue-cli创建了一个项目,足足等了我一分钟,那为什么用 vite 比 webpack 要快呢,这篇文章带你梳理清楚它们的原理…...

Windows系统中使用bat脚本启动git bash 并运行指定命令 - 懒人一键git更新
目标 双击"autoGitPull.bat",自动打开git bash,并cd到项目,逐个git pull,保留git bash窗口展示进度。 脚本 start "" "D:\Program Files\Git\git-bash.exe" -c "echo autoGitPull &&…...

elementui form组件出现英文提示
今天让解决一个bug,是表单组件提示词会出现英文。 问题情景如下: 有时会出现中文,有时会出现英文。 解决方法: 经查看,代码采用的是elementui的form组件,在el-form-item中使用了required属性,同…...

使用windows Api简单验证ISO9660文件格式,以及装载和卸载镜像文件
使用IIsoImageManager接口简单验证ISO镜像文件正确性,使用AttachVirtualDisk装载ISO镜像文件,和使用DetachVirtualDisk卸载,(只支持windows 8及以上系统) 导读 IIsoImageManager 验证ISO文件正确性AttachVirtualDisk 装载镜像文件DetachVirtualDisk 卸载镜像文件其他相关函…...

iPhone 15受益:骁龙8 Gen 3可能缺席部分安卓旗舰机
明年一批领先的安卓手机的性能可能与今年的机型非常相似。硅成本的上涨可能是原因。 你可以想象,2024年许多最好的手机都会在Snapdragon 8 Gen 3上运行,这是高通公司针对移动设备的顶级芯片系统的更新,尚未宣布。然而,来自中国的…...

理解持续测试,才算理解DevOps
软件产品的成功与否,在很大程度上取决于对市场需求的及时把控,采用DevOps可以加快产品交付速度,改善用户体验,从而有助于保持领先于竞争对手的优势。 作为敏捷开发方法论的一种扩展,DevOps强调开发、测试和运维不同团…...

使用OpenCV与深度学习从视频和图像中精准识别人脸: Python实践指南
第一部分: 引言与背景 人脸识别已经成为了当代技术领域中最热门和广泛应用的话题之一。从智能手机的解锁功能到机场的安全检查,人脸识别技术无处不在。在这篇文章中,我们将使用Python中的OpenCV库和深度学习模型,深入探讨如何从视频和图像中…...

面试之快速学习C++11-完美转发,nullptr, shared_ptr,unique_ptr,weak_ptr,shared_from_this
完美转发及其实现 函数模版可以将自己的参数完美地转发给内部调用的其他函数。所谓完美,即不仅能准确地转发参数的值,还能保证被转发参数的左右值属性不变引用折叠:如果任一引用为左值引用,则结果为左值引用,否则为右…...

android resoure资源图片颜色值错乱
最近androidstudio开发,添加一些颜色值或者drawable资源文件时,运行app,颜色值或者图片对应不上,暂时找不到原因,望告知。 暂时解决方法:...

leetcode第 357/358 场周赛
2817. 限制条件下元素之间的最小绝对差 可能别人有更好的解法,我这写法是不断往线段树中插入数值,每次先插入nums[i-x],然后搜索(1到i)中的最大值和(i到max)中的最小值去更新ans。 class Solution { public:struct node{int mx,…...
Jmeter 分布式性能测试避坑指南
在做后端服务器性能测试中,我们会经常听到分布式。那你,是否了解分布式呢?今天,我们就来给大家讲讲,在企业实战中,如何使用分布式进行性能测试,实战过程中,又有哪些地方要特别注意&a…...

基于SpringCloud的会议室预约系统Java基于微服务的会议室报修系统【源码+lw】
💕💕作者:计算机源码社 💕💕个人简介:本人七年开发经验,擅长Java、微信小程序、Python、Android、大数据等,大家有这一块的问题可以一起交流! 💕💕…...

idea设置忽略大小写
1.点击file 2.点击settings 3.点击Editor选项 4.点击general选项 5.点击code completion 6.点击左上角match case...

re学习(35)攻防世界-no-strings-attached(动调)
参考文章:re学习笔记(28)攻防世界-re-no-strings-attached_Forgo7ten的博客-CSDN博客 攻防世界逆向入门题之no-strings-attached_攻防世界 no-strings-attached_沐一 林的博客-CSDN博客 本人题解: 扔入Exepeinfo中查壳和其他信息…...

STM32 F103C8T6学习笔记8:0.96寸单色OLED显示屏显示字符
使用STM32F103 C8T6 驱动0.96寸单色OLED显示屏: OLED显示屏的驱动,在设计开发中OLED显示屏十分常见,因此今日学习一下。一篇文章从程序到显示都讲通。 文章提供源码、原理解释、测试工程下载,测试效果图展示。 目录 OLED驱动原理—IIC通信…...

vscode的配置和使用
1.侧边栏调整大小 放大:View -> Appearance -> Zoom in(快捷键Ctrl ) 缩小:View -> Appearance -> Zoom out(快捷键Ctrl -) 侧边栏字体调整到合适大小后,可以按下一步调整代码区…...

SpringBoot统⼀功能处理
前言🍭 ❤️❤️❤️SSM专栏更新中,各位大佬觉得写得不错,支持一下,感谢了!❤️❤️❤️ Spring Spring MVC MyBatis_冷兮雪的博客-CSDN博客 本章是讲Spring Boot 统⼀功能处理模块,也是 AOP 的实战环节&…...

LeetCode 每日一题 2023/8/14-2023/8/20
记录了初步解题思路 以及本地实现代码;并不一定为最优 也希望大家能一起探讨 一起进步 目录 8/14 617. 合并二叉树8/15 833. 字符串中的查找与替换8/16 2682. 找出转圈游戏输家8/17 1444. 切披萨的方案数8/18 1388. 3n 块披萨8/19 2235. 两整数相加8/20 8/14 617. 合…...