作者:湯阿嬤
前言
嗨大家好我是阿嬤,今天一樣是在講樣是在python的一些程式,這一次的如圖上所看到的,
程式碼
import pygame
import randompygame.font.init()
首先起出的程式,就會先要有前面的設定,因為這一次的程式是屬於遊戲,我們必須輸入python遊戲,還必須輸入隨機數,也對未來的字體做出預設。
s_width = 800
s_height = 700
play_width = 300
play_height = 600
block_size = 30
因為我們也必須設定俄羅斯方塊的大小和畫面與遊戲視窗,具體來講就是把他的長寬都預設出來
s_width = 整個視窗的寬(800)
s_height = 整個視窗的高(700)
play_width = 遊戲視窗的寬(300)
play_height =遊戲視窗的高(600)
block_size = 方塊大小(30)
top_left_x = (s_width — play_width) // 2
top_left_y = s_height — play_height
那接下來就跟上面的有關係,我們直接和上面的對照,從第一行那我們可以簡單推斷出說 top_left_x = 整個視窗的寬 — 遊戲視窗的寬 除以二(不包含於數)
那麼算式就是 (800–300)//2,答案則是250,那我們則會知道
那我們便可得知,上面黃色圈起來的,就會是250。
S = [['.....',
'.....',
'..00.',
'.00..',
'.....'],
['.....',
'..0..',
'..00.',
'...0.',
'.....']]Z = [['.....',
'.....',
'.00..',
'..00.',
'.....'],
['.....',
'..0..',
'.00..',
'.0...',
'.....']]I = [['..0..',
'..0..',
'..0..',
'..0..',
'.....'],
['.....',
'0000.',
'.....',
'.....',
'.....']]O = [['.....',
'.....',
'.00..',
'.00..',
'.....']]J = [['.....',
'.....',
'.0...',
'.000..',
'.....'],
['.....',
'..00.',
'..0..',
'..0..',
'.....'],
['.....',
'.....',
'.000.',
'...0.',
'.....'],
['.....',
'..0..',
'..0..',
'.00..',
'.....']]L = [['.....',
'.....',
'...0.',
'.000.',
'.....'],
['.....',
'..0..',
'..0..',
'..00.',
'.....'],
['.....',
'.....',
'.000.',
'.0...',
'.....'],
['.....',
'.00..',
'..0..',
'..0..',
'.....']]T = [['.....',
'.....',
'..0..',
'.000..',
'.....'],
['.....',
'..0..',
'..00.',
'..0..',
'.....'],
['.....',
'.....',
'.000.',
'..0..',
'.....'],
['.....',
'..0..',
'.00..',
'..0..',
'.....']]
這邊的形狀大家一定有些熟悉,這個的話用矩陣(Matrix)的方式,簡單來講Matrix就是一個清單,然後就用這方式,把所有的方塊的轉動都顯示出來,方便後續的程式,就簡單給電腦看說到時候的轉動方式。
shapes = [S, Z, I, O, J, L, T]
shape_colors = [(0, 255, 0), (255, 0, 0), (0, 255, 255), (255, 255, 0), (255, 165, 0), (0, 0, 255), (128, 0 ,128)]
那相對的,除了設定他的轉動的話,還要設定他的顏色,之前也教過RGB的用法,紅色(red)綠色(green)藍色(blue),那也就對應上面的方塊顏色,舉例來講S的話就是(0, 255, 0)這樣以此類推。
Class Piece(object):
def __init__(self, x, y, shape):
self.x = x
self.y = y
self.shape = shape
self.color = shape_colors[shapes.index(shape)]
self.rotation = 0
那接下來就是把所設定的變數轉換為一個代數,舉例來講,把self.x轉換代數的話就是x,那剛剛也有說到設定轉換方塊的設定那一行中的零,就有用到這邊我們再看self.rotation就可得知,就是他在轉的時候的設定,就是這個零。
def create_grid(locked_pos={}):
grid = [[(0,0,0) for _ in range(10)] for _ in range(20)]for i in range(len(grid)):
for j in range(len(grid[i])):
if (j, i) in locked_pos:
c = locked_pos[(j, i)]
grid[i][j] = c
return grid
在這遊戲的主要重點在於方塊的掉落,可獲得分數,那這邊的話一個一個慢慢講,手先,我們先創一個grid,就是Matrix(平面矩陣),那下一行就是在設定這平面矩陣的東西,先看第一個括號,踏就是創造一個平面的東西以三個零重複十次,例:
grid = [[(0,0,0) for _ in range(2)] for _ in range(3)]
首先一樣先看第一個括號,把三個零重複兩次
[(0,0,0), (0,0,0)]
那接下來下一個,再複製一次重複三次
[[(0,0,0), (0,0,0)],
[(0,0,0), (0,0,0)],
[(0,0,0), (0,0,0)]],
這樣能懂吧。
def create_grid(locked_pos={}):
grid = [[(0,0,0) for _ in range(10)] for _ in range(20)]for i in range(len(grid)):
for j in range(len(grid[i])):
if (j, i) in locked_pos:
c = locked_pos[(j,i)]
grid[i][j] = c
return grid
再來,回去看第二行,這樣我們大概就能知道說,三個零重複十次,再重複二十次就可以了,這就是玩遊戲畫面的程式
在下方的程式,就是固定住這遊戲畫面,怎麼說?例如例如原本說完全沒有任何一個方塊,當一個方塊落下到底時,那落下來的方塊的定位就要被固定住,無法再放任何一個方塊。
def convert_shape_format(shape):
positions = []
format = shape.shape[shape.rotation % len(shape.shape)]for i, line in enumerate(format):
row = list(line)
for j, column in enumerate(row):
if column == '0':
positions.append((shape.x + j, shape.y + i))for i, pos in enumerate(positions):
positions[i] = (pos[0] - 2, pos[1] - 4)return positions
那麼就是轉方塊的程式,若是我們不去看下面的程式話,大概可以推測,當方塊旋轉的時,在網格座標上適合不合理的,不管有沒有旋轉,都必須改變自己的定位,更何況是在邊緣選轉時,有要有一個定位才合理。
def valid_space(shape, grid):
accepted_pos = [[(j, i) for j in range(10) if grid[i][j] == (0,0,0)]for i in range(20)]
accepted_pos = [j for sub in accepted_pos for j in sub]formatted = convert_shape_format(shape)for pos in formatted:
if pos not in accepted_pos:
if pos[1] > -1:
return False
return True
這邊就是驗證說當方塊落到另一個方塊時,要去確認剛剛講的上一個程式裡,是否還能繼續轉動,若是有的話,就停止落下、旋轉,那以此類推,若是沒有的話,就繼續讓方塊落下去。
def check_lost(positions):
for pos in positions:
x, y = pos
if y < 1:
return Truereturn False
每一次遊戲中,都要確認說是否有方塊已經到遊戲畫面的最高點,有的話,遊戲結束,沒有的話,繼續遊戲。
def get_shape():
return Piece(5, 0, random.choice(shapes))
遊戲中的方塊,在每五個中其中選一個當落下去的方塊。
def draw_text_middle(surface, text, size, color):
font = pygame.font.SysFont("comicsans", size, bold=True)
label = font.render(text, 1, color)surface.blit(label, (top_left_x + play_width /2 - (label.get_width()/2), top_left_y + play_height/2 - label.get_height()/2))
這一個函式為了要在畫面的中間,擺上致中的文子的座標換算。
def draw_grid(surface, grid):
sx = top_left_x
sy = top_left_yfor i in range(len(grid)):
pygame.draw.line(surface, (128,128,128), (sx, sy + i*block_size), (sx+play_width, sy+ i*block_size))
for j in range(len(grid[i])):
pygame.draw.line(surface, (128, 128, 128), (sx + j*block_size, sy),(sx + j*block_size, sy + play_height))
雖然說這程式看似複雜,但老實說就是把所有的遊戲面畫在python的頁面上。
def clear_rows(grid, locked):inc = 0
for i in range(len(grid)-1, -1, -1):
row = grid[i]
if (0,0,0) not in row:
inc += 1
ind = i
for j in range(len(row)):
try:
del locked[(j,i)]
except:
continueif inc > 0:
for key in sorted(list(locked), key=lambda x: x[1])[::-1]:
x, y = key
if y < ind:
newKey = (x, y + inc)
locked[newkey] = locked.pop(key)
當如果有一排的座標是滿的時候,將其消失,並且分數加一分。
def draw_next_shape(shape, surface):
font = pygame.font.SysFont('conicsans', 30)
label = font.render('Next Shape', 1, (255,255,255))sx = top_left_x + play_width + 50
sy = top_left_y + play_height/2 - 100
format = shape.shape[shape.rotation % len(shape.shape)]for i, line in enumerate(format):
row = list(line)
for j, column in enumerate(row):
if column == '0':
pygame.draw.rect(surface,shape.color, (sx + j*block_size, sy + i*block_size, block_size, block_size), 0)
這裡是呼叫新的方塊時的程式,與剛剛有個函式相似,確認說下一個方塊的函式之後,當放下原本的方塊時,下一個便會落下。
20210207 待補