##
我們先搭建一個程序大致的框架,繪制一個游戲窗口。
導入程序所必要的模塊,因為要隨機產生一個方塊,所以用到隨機數模塊random,time庫是時間函數用來延時。
```python
import random, time, pygame, sys
from pygame.locals import *
```
## 設置俄羅斯方塊使用的常量。
``` python
FPS = 25 # 設置屏幕刷新率
WINDOW_WIDTH = 640 # 設置窗口寬度
WINDOW_HEIGHT = 480 # 設置窗口高度
BOX_SIZE = 20 # 方格大小
# 放置俄羅斯方塊窗口的大小
BOARD_WIDTH = 10
BOARD_HEIGHT = 20
BLANK = '.' # 代表空的形狀
MOVESIDEWAYSFREQ = 0.15 # 若一直按下方向左鍵或右鍵那么每0.15秒方塊才會繼續移動
MOVEDOWNFREQ = 0.1 # 向下的頻率
XMARGIN = int((WINDOWWIDTH - BOARDWIDTH * BOXSIZE) / 2)
# x方向的邊距
TOPMARGIN = WINDOWHEIGHT - (BOARDHEIGHT * BOXSIZE) - 5
# 距離窗口頂部的邊距
```
<div align="center"><img src="images/screenshot_1561344446084.png"/></div>
## 定義顏色
```python
# add color
WHITE = (255, 255, 255)
GRAY = (185, 185, 185)
BLACK = ( 0, 0, 0)
RED = (155, 0, 0)
LIGHTRED = (175, 20, 20)
GREEN = ( 0, 155, 0)
LIGHTGREEN = ( 20, 175, 20)
BLUE = ( 0, 0, 155)
LIGHTBLUE = ( 20, 20, 175)
YELLOW = (155, 155, 0)
LIGHTYELLOW = (175, 175, 20)
BORDERCOLOR = BLUE
BGCOLOR = BLACK
TEXTCOLOR = WHITE
TEXTSHADOWCOLOR = GRAY
COLORS = ( BLUE, GREEN, RED, YELLOW)
LIGHTCOLORS = (LIGHTBLUE, LIGHTGREEN, LIGHTRED, LIGHTYELLOW)
assert len(COLORS) == len(LIGHTCOLORS) # each color must have light color
```
每個下落的俄羅斯方塊隨機有四種顏色:藍色、綠色、紅色和黃色。當我們繪制小方塊的時候,會在邊緣增加一個較淺的顏色,使方塊看起來更有立體感。
## 定義方塊
方塊的基本形狀一共有以下七種:
<div align="center"><img src="images/screenshot_1561102081007.png"/></div>
每種方塊都能夠旋轉,所謂旋轉,即是把方塊順時針旋轉90°。我們創建數組來存儲這些方塊,像下面這樣,“.”表示空白,“O”表示小方格。
例如:<br>
['.....', <br>
'.....', <br>
'..00.',<br>
'.00..',<br>
'.....']<br>
上面就是繪制的一個如下圖的S型方塊,:
<div align="center"><img src="images/screenshot_1561359412952.png"/></div>
我們再將方塊順時針旋轉90°,然后繪制其圖形,寫入數組中。下面的數組列出了所有寫形狀。
```python
T_SHAPE = [['.....', '..O..', '.OOO.', '.....', '.....'],
['.....', '..O..', '..OO.', '..O..', '.....'],
['.....', '.....', '.OOO.', '..O..', '.....'],
['.....', '..O..', '.OO..', '..O..', ''.....]]
S_SHAPE = [['.....', '..... ', '..OO.', '.OO..', '.....'],
['.....', '..O..', '..OO.', '.....']]
Z_SHAPE = ['.....', '.....', '.OO..', '..OO.', '.....'],
['.....', '..O..', '.OO..', '.O...', '.....']]
J_SHAPE = [['.....', '.O...', '.OOO.', '.....', '.....'],
['.....', '..OO.', '..O..', '..O..’, '.....'],
['.....', '.....', '.OOO.', '...O.', '.....'],
['.....', '.....', '.OOO.', '...O.', '.....'],
['.....', '..O..', '..O..', '.OO..', '.....']]
L_SHAPE = [['.....', '...O.', '.OOO.', '.....', '.....'],
['.....', '...O.', '.OOO.', '.....', '.....'],
['.....', '.....', '.OOO.', '.O...', '.....'],
['.....', '.OO..', '..O..', '..O..', '.....']]
I_SHAPE = [['..O..', '..O..', '..O..', '..O..', '.....'],
['.....', '.....', 'OOOO.', '.....', '.....']]
O_SHAPE = [['.....', '.....', '.OO..', '.OO..', '.....']]
PIECES = { # 定義一個數據結構存儲對應的形狀
'T' : T_SHAPE,
'S' : S_SHAPE,
'Z' : Z_SHAPE,
'J' : J_SHAPE,
'L' : L_SHAPE,
'I' : I_SHAPE,
'O' : O_SHAPE
}
```
## main()方法
主函數中主要創建一寫全局變量和游戲開始前顯示一個開始畫面,之后是游戲循環,循環中首先播放背景音樂,然后調用runGame()運行游戲,當游戲失敗,runGame()就會返回到main()函數,這是會停止背景音樂并顯示游戲失敗的畫面。當游戲這按下任意鍵,顯示游戲失敗的showTextScreen()函數就會返回到main()函數,游戲循環會再次開始然后繼續下一次游戲。
```python
def main():
global FPSLOCK, DISPLAYSURF, BASICFONT, BIGFONT # 定義全局變量
pygame.init() # 初始化pygame
FPSCLOCK = pygame.time.Clock() # 獲得pygame時鐘
DISPLAYSURF = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT)) # 設置窗口
BASICFONT = pygame.font.Font('freesansbold.ttf', 18) # 設置基礎的字體
BIGFONT = pygame.font.Font('freesansbold.ttf', 100) # 設置大字體
pygame.display.set_caption('My Tetris') # 窗口標題
showTextScreen('Tetris') # 顯示開始畫面
while True: # 游戲主循環
pygame.mixer.music.load('tetrisb.mid')
pygame.mixer.music.play(-1, 0.0)
runGame() # 運行游戲
pygame.mixer.music.stop() # 退出游戲后,結束播放音樂
showTextScreen('Game Over') # 顯示結束畫面
```
main函數主要創建游戲的窗口和設置播放背景音樂。然后調用runGame()函數開始游戲,當玩家游戲結束時,返回到main()中,然后打印游戲結束信息。
## 基本模塊
定義一個退出方法,以便需要的時候退出游戲。
```python
# 退出
def terminate():
pygame.quit()
sys.exit()
```
定義一個檢測是否有按鍵被按下的方法,當處于開始、結束、暫停畫面時,可以調用該方法,以便程序退出當前畫面。
```python
# 檢查是否有按鍵被按下
def checkForKeyPress():
# 通過事件隊列尋找KEYUP事件
# 從事件隊列刪除KEYDOWN事件
checkForQuit()
for event in pygame.event.get([KEYDOWN, KEYUP]):
if event.type == KEYDOWN:
continue
return event.key
return None
```
考慮到我們需要在屏幕上顯示文字,不妨直接創建相關方法,以便程序復用。此程序接收三個參數:要顯示的文字、要顯示文字的字體、要顯示文字的顏色,它會返回相應的文本對象,以便使用。
```python
# 創建文本繪制對象
def makeTextObjs(text, font, color):
surf = font.render(text, True, color)
return surf, surf.get_rect()
```
游戲開始畫面、游戲結束畫面以及游戲暫停畫面可用一個方法來實現,以及游戲暫停畫面可以用一個方法來實現,同時在循環中調用之前的checkForKeyPress()方法,以檢測是否有按鍵被按下,從而實現是否從當前畫面退出。
```python
# 顯示開始、暫停、結束畫面
def showTextScreen(text):
# 這個函數用于在屏幕中央顯示大文本,直到按下任意鍵
# 繪制文字陰影
titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTSHADOWCOLOR)
titleRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2))
DISPLAYSURF.blit(titleSurf, titleRect)
# 繪制文字
titleSurf, titleRect = makeTextObjs(text, BIGFONT, TEXTCOLOR)
titleRect.center = (int(WINDOWWIDTH / 2) - 3, int(WINDOWHEIGHT / 2) - 3)
DISPLAYSURF.blit(titleSurf, titleRect)
# 繪制額外的"Press a key to play."文字
pressKeySurf, pressKeyRect = makeTextObjs('Press a key to play.', BASICFONT, TEXTCOLOR)
pressKeyRect.center = (int(WINDOWWIDTH / 2), int(WINDOWHEIGHT / 2) + 100)
DISPLAYSURF.blit(pressKeySurf, pressKeyRect)
while checkForKeyPress() == None:
pygame.display.update()
FPSCLOCK.tick()
```
在游戲開始之前,我們需要一個空的Board框,我們用一個二維列表表示Board框,列表中的每一項都為BLANK:
```python
# 清空Board
def getBlankBoard():
board = []
for i in range(BOARDWIDTH):
board.append([BLANK] * BOARDHEIGHT)
return board
```
游戲運行時,每次都會有一個新的Piece從頂部落下,我們用一個字典來表示Piece,字典中的鍵包括Shape、相應Shape的方向、起始位置、以及顏色,獲得新Piece的方法如下:
```python
# 隨機獲得一個新的Piece(形狀,方向,顏色)
def getNewPiece():
shape = random.choice(list(PIECES.keys()))
newPiece = {'shape': shape,
'rotation': random.randint(0, len(PIECES[shape]) - 1),
'x': int(BOARDWIDTH / 2) - int(TEMPLATEWIDTH / 2), # x居中
'y': -2, # y在屏幕的上方,小于0
'color': random.randint(0, len(COLORS)-1)}
return newPiece
```
獲取新Piece之后,就要將它添加到Board框中,添加的原理就是將Board框中對應坐標的Box繪制成相應Piece的顏色:
```python
# 將一個Piece添加到Board中
def addToBoard(board, piece):
for x in range(TEMPLATEWIDTH):
for y in range(TEMPLATEHEIGHT):
if PIECES[piece['shape']][piece['rotation']][y][x] != BLANK:
board[x + piece['x']][y + piece['y']] = piece['color']
```
當Piece著陸之后在Board外時,游戲結束,因此我們需要一個判斷Board邊界的方法:
```python
# Board邊界
def isOnBoard(x, y):
return x >= 0 and x < BOARDWIDTH and y < BOARDHEIGHT
```
剛剛那種判斷游戲結束的方法,我們可以將其抽象出來,看成是檢查Piece的當前位置是否合法,因為不光是在判斷游戲結束時調用它,在調整Piece形狀時也需要調用,判斷調整形狀后的Piece在當前位置中是否容得下。
```python
# Piece在當前的Board里是否是一個合法可用的位置
def isValidPosition(board, piece, adjX=0, adjY=0):
# 若Piece在Board內并且無碰撞,則返回True
for x in range(TEMPLATEWIDTH):
for y in range(TEMPLATEHEIGHT):
isAboveBoard = y + piece['y'] + adjY < 0
if isAboveBoard or PIECES[piece['shape']][piece['rotation']][y][x] == BLANK:
continue
if not isOnBoard(x + piece['x'] + adjX, y + piece['y'] + adjY):
return False
if board[x + piece['x'] + adjX][y + piece['y'] + adjY] != BLANK:
return False
return True
```
此外,當游戲中某一行被填滿時,我們將移除這一行,因此我們需要一個判斷某行是否填滿的方法,判斷的原理就是看相應的這一行列表中的項是否為BLANK:
```python
# 判斷當前的這行是否被全部填滿
def isCompleteLine(board, y): for x in range(BOARDWIDTH): if board\[x\]\[y\] == BLANK: return False return True
```
還需要一個移除某行的方法,也就是將這一行上面的每一行都下降一行,同時還應該返回完成填滿的總行數,這個值將作為玩家的分值,也就是說每成功移除一行,玩家分數加1:
```python
# 檢查每一行,移除完成填滿的一行,將這一行上面的所有的都下降一行,返回完成填滿的總行數
def removeCompleteLines(board):
numLinesRemoved = 0
# 從-1開始從下往上檢查每一行
y = BOARDHEIGHT - 1
while y >= 0:
if isCompleteLine(board, y):
for pullDownY in range(y, 0, -1):
for x in range(BOARDWIDTH):
board[x][pullDownY] = board[x][pullDownY-1]
for x in range(BOARDWIDTH):
board[x][0] = BLANK
numLinesRemoved += 1
else:
y -= 1
return numLinesRemoved
```
隨著游戲分數的越來越大,相應的等級也應越來越大,等級是當前消除行數除以10,我們假設剛開始時等級為1,隨著等級的不斷增大,下落頻率應相應的減小,如下所示:
```python
# 根據分數來計算等級和下落的頻率
def calculateLevelAndFallFreq(score):
level = int(score / 10) + 1
fallFreq = 0.27 - (level * 0.02)
return level, fallFreq
```
## runGame()方法
在游戲開始和Piece掉落之前,我們需要初始化一些跟游戲開始相關的變量。fallingPiece變量被賦值成當前掉落的變量,nextPiece變量被賦值成游戲者可以在屏幕NEXT區域看見的下一個Piece。 游戲主循環中,fallingPiece變量在Piece著陸后被設置成None。這意味著nextPiece變量中的下一個Piece應該被賦值給fallingPiece變量,然后一個隨機的Piece又會被賦值給nextPiece變量。lastFallTime變量也被賦值成當前時間,這樣我們就可以通過fallFreq變量控制Piece下落的頻率。 事件循環主要處理當翻轉方塊、移動方塊時或者暫停游戲時的一些事情。若游戲暫停,我們應該隱藏掉游戲界面以防止游戲者作弊(否則游戲者會看著畫面思考怎么處理方塊),用DISPLAYSURF.fill(BGCOLOR)就可以實現這個效果。停止按下方向鍵或ASD鍵會把movingLeft,movingRight,movingDown變量設置為False,表明游戲者不再想要在此方向上移動方塊。當左方向鍵按下(而且往左移動是有效的,通過調用isVaildPosition()函數知道的),那么我們應該改變一個方塊的位置使其向左移動一格。 如果方向鍵上或W鍵被按下,那么就會翻轉方塊,就是將儲存在fallingPiece字典中的‘rotation’鍵的鍵值加1,然而,當增加的'rotation'鍵值大于所有當前類型方塊的形狀的數目的話(此變量儲存在len(SHAPES[fallingPiece['shape']])變量中),那么它翻轉到最初的形狀。如果翻轉后的形狀因為其中的一些小方塊已經超過邊框的范圍而無效,那么我們就要把它變回原來的形狀通過將fallingPiece['rotation'])減去1,同理,按Q鍵執行反向翻轉時則是加1。 當游戲者按下空格鍵,方塊將會迅速的下落至著陸。程序首先需要找出到它著陸需要下降個多少個格子,其中有關moving的三個變量都要被設置為False(保證程序后面部分的代碼知道游戲者已經停止了按下所有的方向鍵)。 方塊自然下落的速率由lastFallTime變量決定。如果自從上個Piece掉落了一個格子后過去了足夠的時間,那么我們就會再讓Piece移動一個格子。
```python
# 運行游戲
def runGame():
# 在游戲開始前初始化變量
# 獲得一個空的board
board = getBlankBoard()
lastMoveDownTime = time.time()
# 最后向下移動的時刻
lastMoveSidewaysTime = time.time()
#最后側向移動的時刻
lastFallTime = time.time()
# 最后的下降時間
# 是否可以 向下,向左,向右
# 注意:這里沒有向上可用
movingDown = False
movingLeft = False
movingRight = False
score = 0
# 分數
level, fallFreq = calculateLevelAndFallFreq(score)
# 根據分數計算等級和下降的頻率
fallingPiece = getNewPiece()
# 獲得新的形狀(當前的形狀)
nextPiece = getNewPiece()
# 獲得下一個形狀
while True:
# 游戲循環體
if fallingPiece == None:
# 當前沒有下降的形狀
# 重新獲得新的形狀和下一個形狀
fallingPiece = nextPiece
nextPiece = getNewPiece()
lastFallTime = time.time()
# 重置最后下降的時間
if not isValidPosition(board, fallingPiece):
# 判斷界面上是否還有空位(方塊是否到頂),沒有則結束游戲
return
checkForQuit()
# 檢查是否有退出事件
for event in pygame.event.get():
# 事件處理循環
if event.type == KEYUP:
# KEYUP事件處理
if (event.key == K_p):
# 用戶按P鍵暫停
DISPLAYSURF.fill(BGCOLOR)
pygame.mixer.music.stop()
#停止音樂
showTextScreen('Paused')
# 顯示暫停界面,直到按任意鍵繼續
pygame.mixer.music.play(-1, 0.0)
# 繼續循環音樂
# 重置各種時間
lastFallTime = time.time()
lastMoveDownTime = time.time()
lastMoveSidewaysTime = time.time()
elif (event.key == K_LEFT or event.key == K_a):
movingLeft = False
elif (event.key == K_RIGHT or event.key == K_d):
movingRight = False
elif (event.key == K_DOWN or event.key == K_s):
movingDown = False
elif event.type == KEYDOWN:
# KEYDOWN事件處理
# 左右移動piece
if (event.key == K_LEFT or event.key == K_a) and isValidPosition(board, fallingPiece, adjX=-1):
fallingPiece['x'] -= 1
movingLeft = True
movingRight = False
lastMoveSidewaysTime = time.time()
elif (event.key == K_RIGHT or event.key == K_d) and isValidPosition(board, fallingPiece, adjX=1):
fallingPiece['x'] += 1
movingRight = True
movingLeft = False
lastMoveSidewaysTime = time.time()
# UP或W鍵 旋轉piece (在有空間旋轉的前提下)
# 正向旋轉
elif (event.key == K_UP or event.key == K_w):
fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']])
if not isValidPosition(board, fallingPiece):
fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']])
# Q鍵,反向旋轉
elif (event.key == K_q):
fallingPiece['rotation'] = (fallingPiece['rotation'] - 1) % len(PIECES[fallingPiece['shape']])
if not isValidPosition(board, fallingPiece):
fallingPiece['rotation'] = (fallingPiece['rotation'] + 1) % len(PIECES[fallingPiece['shape']])
# DOWN或S鍵 使piece下降得更快
elif (event.key == K_DOWN or event.key == K_s):
movingDown = True
if isValidPosition(board, fallingPiece, adjY=1):
fallingPiece['y'] += 1
lastMoveDownTime = time.time()
# 空格鍵,直接下降到最下面且可用的地方
elif event.key == K_SPACE:
movingDown = False
movingLeft = False
movingRight = False
for i in range(1, BOARDHEIGHT):
if not isValidPosition(board, fallingPiece, adjY=i):
break
fallingPiece['y'] += i - 1
# 根據記錄的用戶輸入方向的變量來移動piece
if (movingLeft or movingRight) and time.time() - lastMoveSidewaysTime > MOVESIDEWAYSFREQ:
if movingLeft and isValidPosition(board, fallingPiece, adjX=-1):
fallingPiece['x'] -= 1
elif movingRight and isValidPosition(board, fallingPiece, adjX=1):
fallingPiece['x'] += 1
lastMoveSidewaysTime = time.time()
if movingDown and time.time() - lastMoveDownTime > MOVEDOWNFREQ and isValidPosition(board, fallingPiece, adjY=1):
fallingPiece['y'] += 1
lastMoveDownTime = time.time()
# 自動下降piece
if time.time() - lastFallTime > fallFreq:
if not isValidPosition(board, fallingPiece, adjY=1):
addToBoard(board, fallingPiece)
score += removeCompleteLines(board)
level, fallFreq = calculateLevelAndFallFreq(score)
fallingPiece = None
else:
fallingPiece['y'] += 1
lastFallTime = time.time()
# 繪制屏幕上的所有東西
DISPLAYSURF.fill(BGCOLOR)
drawBoard(board)
drawStatus(score, level)
drawNextPiece(nextPiece)
if fallingPiece != None:
drawPiece(fallingPiece)
pygame.display.update()
FPSCLOCK.tick(FPS)
```
## 繪制屏幕
之前的編程,為了簡化操作,我們使用的是Board的坐標,在繪制圖形之前,我們需要把Box的坐標轉換為相應的像素坐標:
```python
# 根據Board的坐標轉化成像素坐標
def convertToPixelCoords(boxx, boxy):
return (XMARGIN + (boxx * BOXSIZE)), (TOPMARGIN + (boxy * BOXSIZE))
```
繪制Box:
```python
# 繪制Box
def drawBox(boxx, boxy, color, pixelx=None, pixely=None):
# 使用Board的坐標繪制單個Box(一個Piece含有4個Box),若像素坐標pixelx、pixely被指定,則直接使用像素坐標(用于NextPiece區域)
if color == BLANK:
return
if pixelx == None and pixely == None:
pixelx, pixely = convertToPixelCoords(boxx, boxy)
pygame.draw.rect(DISPLAYSURF, COLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 1, BOXSIZE - 1))
pygame.draw.rect(DISPLAYSURF, LIGHTCOLORS[color], (pixelx + 1, pixely + 1, BOXSIZE - 4, BOXSIZE - 4))
```
繪制Board主要包括繪制Board邊框、繪制Board背景以及繪制Board中的Box:
```python# 繪制Board
def drawBoard(board):
# 繪制Board邊框
pygame.draw.rect(DISPLAYSURF, BORDERCOLOR, (XMARGIN - 3, TOPMARGIN - 7, (BOARDWIDTH * BOXSIZE) + 8, (BOARDHEIGHT * BOXSIZE) + 8), 5)
# 繪制Board背景
pygame.draw.rect(DISPLAYSURF, BGCOLOR, (XMARGIN, TOPMARGIN, BOXSIZE * BOARDWIDTH, BOXSIZE * BOARDHEIGHT))
# 繪制Board中的Box
for x in range(BOARDWIDTH):
for y in range(BOARDHEIGHT):
drawBox(x, y, board[x][y])
```
繪制分數、等級等狀態信息:
```python
\# 繪制游戲分數、等級信息 def drawStatus(score, level): # 繪制分數文本 scoreSurf = BASICFONT.render('Score: %s' % score, True, TEXTCOLOR) scoreRect = scoreSurf.get\_rect() scoreRect.topleft = (WINDOWWIDTH - 150, 20) DISPLAYSURF.blit(scoreSurf, scoreRect) # 繪制等級文本 levelSurf = BASICFONT.render('Level: %s' % level, True, TEXTCOLOR) levelRect = levelSurf.get\_rect() levelRect.topleft = (WINDOWWIDTH - 150, 50) DISPLAYSURF.blit(levelSurf, levelRect)
```
繪制Piece:
```python
# 繪制各種形狀Piece(S,Z,I,O,J,L,T)
def drawPiece(piece, pixelx=None, pixely=None):
shapeToDraw = PIECES[piece['shape']][piece['rotation']]
if pixelx == None and pixely == None:
# 若pixelx、pixely沒有被指定,則使用piece數據結構中存儲的位置
pixelx, pixely = convertToPixelCoords(piece['x'], piece['y'])
# 繪制組成Piece的每個Box
for x in range(TEMPLATEWIDTH):
for y in range(TEMPLATEHEIGHT):
if shapeToDraw[y][x] != BLANK:
drawBox(None, None, piece['color'], pixelx + (x * BOXSIZE), pixely + (y * BOXSIZE))
```
繪制NextPiece區域顯示的內容:
```python
# 繪制提示信息,下一個Piece
def drawNextPiece(piece):
# 繪制"Next"文本
nextSurf = BASICFONT.render('Next:', True, TEXTCOLOR)
nextRect = nextSurf.get_rect()
nextRect.topleft = (WINDOWWIDTH - 120, 80)
DISPLAYSURF.blit(nextSurf, nextRect)
# 繪制NextPiece
drawPiece(piece, pixelx=WINDOWWIDTH-120, pixely=100)
```
## 嘗試運行代碼
```python
if __name__ == "__main__":
main()
```
## 執行程序
```
sudo python tetris.py
```
- 前言
- 第一章 樹莓派快速入門
- 1. 初識樹莓派3B+
- 2. 燒錄系統
- 3. 樹莓派連接鍵盤鼠標和顯示器
- 4. 啟動樹莓派
- 5.樹莓派連接網絡
- 6. Windows遠程訪問樹莓派
- 7. 終端通過raspi-config配置樹莓派
- 第二章 樹莓派編程
- 1. Linux入門操作
- 常用的linux命令
- 重要的快捷鍵
- 通過命令安裝軟件
- 樹莓派關機/重啟
- 2. 創建、編輯和保存文件
- 3. 創建并運行Python程序
- 4. 使用樹莓派的GPIO口
- 第三章 樹莓派套件應用
- 樹莓派3B+ IO擴展板介紹
- 家居系統
- 會呼吸的RGB燈
- 樹莓派控制家電
- 制作一個環境檢測儀
- 樹莓派攝像頭做遠程監控
- 攝像頭使用
- socket通信
- PiCamera + socket遠程監控
- AI語音
- 配置snowboy
- 自定義響應
- 采集語音和語音播放
- 語音機器人
- 圖靈機器人
- 俄羅斯方塊小游戲
- pygame基本使用
- ADKeyboard使用
- 俄羅斯方塊實現原理
- 俄羅斯方塊代碼講解
- 手勢控制的樹莓派相冊
- 模塊介紹
- 爬取圖片
- 電子相冊
- 附錄
- 網址