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時,游戲結束。

如果你有更好的想法,大家一起交流

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/42933.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/42933.shtml
英文地址,請注明出處:http://en.pswp.cn/news/42933.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【Maven教程】(一)入門介紹篇:Maven基礎概念與其他構建工具:理解構建過程與Maven的多重作用,以及與敏捷開發的關系 ~

Maven入門介紹篇 1?? 基礎概念1.1 構建1.2 maven對構建的支持1.3 Maven的其他作用 2?? 其他構建工具2.1 IDE2.2 Make2.3 Ant2.4 Jenkins 3?? Maven與敏捷開發&#x1f33e; 總結 1?? 基礎概念 "Maven"可以翻譯為 “知識的積累者” 或 “專家”。這個詞源于波…

Qt應用開發(基礎篇)——MDI窗口 QMdiArea QMdiSubWindow

一、前言 QMdiArea類繼承于QAbstractScrollArea&#xff0c;QAbstractScrollArea繼承于QFrame&#xff0c;是Qt用來顯示MDI窗口的部件。 滾屏區域基類 QAbstractScrollAreahttps://blog.csdn.net/u014491932/article/details/132245486 框架類 QFramehttps://blog.csdn.net/u01…

面試算法編程題

面試算法編程題記錄 題目 : 羊圈里的狼 題目背景 : 一到了晚上&#xff0c;草原牧民的羊就會被趕進羊圈里。這時&#xff0c;野外的狼群就會打羊羔的主意。為了保護羊羔&#xff0c;牧民需要將羊圈里的狼趕走或殺死。由于來的狼很多&#xff0c;他需要快速甄別哪些狼在羊圈里面…

FANUC機器人加減速倍率指令ACC的使用方法說明

FANUC機器人加減速倍率指令ACC的使用方法說明 單位有一臺FANUC機器人(型號:M-900iB 360kg),偶爾會在啟動的瞬間會報SRVO-050碰撞檢測報警,而事實上機器人并沒有開始移動或和其他工件產生碰撞,一直查了很長時間,也沒有查到具體的原因,也嘗試過重新進行負載推算,但是偶爾…

恒運資本:CPO概念發力走高,兆龍互聯漲超10%,華是科技再創新高

CPO概念15日盤中發力走高&#xff0c;截至發稿&#xff0c;華是科技漲超15%再創新高&#xff0c;兆龍互聯漲逾11%&#xff0c;中貝通訊漲停&#xff0c;永鼎股份、太辰光漲超5%&#xff0c;天孚通訊漲逾4%。 消息面上&#xff0c;光通訊聞名咨詢機構LightCounting近日發布的202…

國產之光:訊飛星火最新大模型V2.0

大家好&#xff0c;我是herosunly。985院校碩士畢業&#xff0c;現擔任算法研究員一職&#xff0c;熱衷于機器學習算法研究與應用。曾獲得阿里云天池比賽第一名&#xff0c;CCF比賽第二名&#xff0c;科大訊飛比賽第三名。擁有多項發明專利。對機器學習和深度學習擁有自己獨到的…

每天一道leetcode:1466. 重新規劃路線(圖論中等廣度優先遍歷)

今日份題目&#xff1a; n 座城市&#xff0c;從 0 到 n-1 編號&#xff0c;其間共有 n-1 條路線。因此&#xff0c;要想在兩座不同城市之間旅行只有唯一一條路線可供選擇&#xff08;路線網形成一顆樹&#xff09;。去年&#xff0c;交通運輸部決定重新規劃路線&#xff0c;以…

OpenCV-Python中的圖像處理-視頻分析

OpenCV-Python中的圖像處理-視頻分析 視頻分析Meanshift算法Camshift算法光流Lucas-Kanade Optical FlowDense Optical Flow 視頻分析 學習使用 Meanshift 和 Camshift 算法在視頻中找到并跟蹤目標對象: Meanshift算法 Meanshift 算法的基本原理是和很簡單的。假設我們有一堆…

Failed to init API, possibly an invalid tessdata path: ./ ubuntu

1、問題描述 Failed to init API, possibly an invalid tessdata path: ./2、解決方案&#xff1a; 添加“TESSDATA_PREFIX”到系統環境變量中&#xff0c;值為testdata的父路徑&#xff08;一般就是 Tesseract-OCR 的安裝路徑&#xff09;亦可解決。在~/.bashrc中添加 expo…

【學習日記】【FreeRTOS】空閑任務與阻塞延時

寫在前面 本文是基于野火 RTOS 教程對空閑任務和阻塞延時的詳解。 一、什么是任務中的阻塞延時 說到阻塞延時&#xff0c;筆者的第一反應就是在單片機的 while 循環中&#xff0c;使用一個 for 循環不斷遞減一個大數&#xff0c;通過 CPU 不斷執行一條指令的耗時進行延時。這…

python優雅地爬蟲!

背景 我需要獲得新聞&#xff0c;然后tts&#xff0c;在每天上班的路上可以聽一下。具體的方案后期我也會做一次分享。先看我喜歡的萬能的老路&#xff1a;獲得html內容-> python的工具庫解析&#xff0c;獲得元素中的內容&#xff0c;完成。 好家伙&#xff0c;我知道我爬…

視頻云存儲/安防監控/視頻匯聚EasyCVR平臺新增設備經緯度選取

視頻云存儲/安防監控EasyCVR視頻匯聚平臺基于云邊端智能協同&#xff0c;支持海量視頻的輕量化接入與匯聚、轉碼與處理、全網智能分發、視頻集中存儲等。音視頻流媒體視頻平臺EasyCVR拓展性強&#xff0c;視頻能力豐富&#xff0c;具體可實現視頻監控直播、視頻輪播、視頻錄像、…

公網遠程連接Redis數據庫「內網穿透」

文章目錄 1. Linux(centos8)安裝redis數據庫2. 配置redis數據庫3. 內網穿透3.1 安裝cpolar內網穿透3.2 創建隧道映射本地端口 4. 配置固定TCP端口地址4.1 保留一個固定tcp地址4.2 配置固定TCP地址4.3 使用固定的tcp地址連接 前言 潔潔的個人主頁 我就問你有沒有發揮&#xff0…

藍牙資訊|蘋果Apple Watch可手勢操控Mac和Apple TV等設備

根據美國商標和專利局&#xff08;USPTO&#xff09;公示的清單&#xff0c;蘋果公司近日獲得了一項技術專利&#xff0c;概述了未來的 Apple Watch 手表&#xff0c;使用手勢等操控 Mac 和 Apple TV 等設備。 該專利描述未來 Apple Watch 可以交互實現編輯圖像、繪圖、處理文…

02:STM32--EXTI外部中斷

目錄 一:中斷 1:簡歷 2:AFIO 3:EXTI ?編輯 4:NVIC基本結構 5:使用步驟 二:中斷的應用 A:對外式紅外傳感計數器 1:連接圖?編輯 2:函數介紹 3:硬件介紹 4:計數代碼 B;旋轉編碼計數器 1:連接圖 2:硬件介紹 3:旋轉編碼器代碼: 一:中斷 1:簡歷 中斷&#xff1a;在主程…

Flutter 測試小結

Flutter 項目結構 pubspec.yaml 類似于 RN 的 package.json&#xff0c;該文件分別在最外層及 example 中有&#xff0c;更新該文件后&#xff0c;需要執行的 Pub get lib 目錄下的 dart 文件為 Flutter 插件封裝后的接口源碼&#xff0c;方便在其他 dart 文件中調用 example 目…

python通過S7協議讀取西門子200smart數據

發現網上很多關于python通過s7協議控制200smart的代碼都失敗&#xff0c;我猜應該是版本的問題。自己搗鼓了半天&#xff0c;終于測試成功 from snap7 import util,clientmy_plc client.Client() #建立一個客戶端對象 my_plc.set_connection_type(3) #如果是200smart,必須有此…

Flink流批一體計算(14):PyFlink Tabel API之SQL查詢

舉個例子 查詢 source 表&#xff0c;同時執行計算 # 通過 Table API 創建一張表&#xff1a; source_table table_env.from_path("datagen") # 或者通過 SQL 查詢語句創建一張表&#xff1a; source_table table_env.sql_query("SELECT * FROM datagen&quo…

QT實現天氣預報

1. MainWindow類設計的成員變量和方法 public: MainWindow(QWidget* parent nullptr); ~MainWindow(); protected: 形成文本菜單來用來右鍵關閉窗口 void contextMenuEvent(QContextMenuEvent* event); 鼠標被點擊之后此事件被調用 void mousePressEvent(QMouseEv…

Leetcode每日一題:1444. 切披薩的方案數(2023.8.17 C++)

目錄 1444. 切披薩的方案數 題目描述&#xff1a; 實現代碼與解析&#xff1a; 二維后綴和 動態規劃 原理思路&#xff1a; 1444. 切披薩的方案數 題目描述&#xff1a; 給你一個 rows x cols 大小的矩形披薩和一個整數 k &#xff0c;矩形包含兩種字符&#xff1a; A …