從上圖和遊戲玩法可以得出以下兩點:
1,方塊位置十分有規律
2,兩類方塊(上面移動的,下方固定的 都比較有特點)
方塊的大小都是固定的,只需要操心位置的問題,下面建座標系
下一步,
座標的儲存方式記錄方式有兩種:
1,橫縱座標做一個二元元組,再用一個列表裝著一堆二元元組
例如:[(20,1),(20,2),(20,3),(20,4)]代表第20行的1~4列的四個方塊
2,二維數組,一行是一個列表,用兩個索引代表橫縱座標,值為1就代表有方塊,0就是沒有方塊
補充:座標轉換
鍵盤到圖像(本質:鍵盤到核心變量)
下面簡略列出需要的函數
首先,方塊移動的難點在“旋轉”上
Q:為什麼不先考慮左右移動
A:旋轉的問題的有些複雜,需要變更“核心變量”
核心變量一但變更 其它相關函數都得改寫
所以為了省心,優先考慮可能涉及“核心變量”的事情
解決思路:
1,為每個形狀建立一個“狀態庫”,手寫出每個姿態,旋轉時再讀取
2,旋轉前後存在明確的數學關係
選那個沒有懸念
追加一個變量,記錄旋轉中心座標
旋轉時依照方程轉換座標
公式很簡單吧
如果旋轉在原點,將會更簡單
PS:注意座標系,公式不能直接抄
所以,從記錄“絕對座標”變更為“中心座標+相對座標”
PS:繪製函數需要做相應的調整
旋轉過程 ( x , y ) --> (-y , x)
重要的細節:移動是有限制的
方塊在邊界處,就得限制向外的移動,如果移動後與已有的方塊重疊,也得限制移動
旋轉的
def rotate(): x, y = centre l = [(-j, i) for i, j in active] for i, j in l: i += x j += y if j < 0 or j > 9 or background[i][j]: break else: active.clear() active.extend(l)
PS:因為旋轉的機制很簡陋,會有田字形方塊的也能旋轉的奇怪現象發生。
講道理下落並不難,關鍵是下落結束後會有很多後事要處理
1,檢查是否落到底部,是:繼續,否:跳出
2,active的信息轉到background,
3,檢查background是否有“行”被填滿 是:繼續,否:跳至5
4,清掉滿行,補上空行,計分
5,生成新的active,檢查其位置是否被佔(被佔<=>方塊被堆至頂部<=>game over)
那就開始擼代碼
def move_down(): x, y = centre x -= 1 for i, j in active: i += x j += y if background[i][j]: break else: centre.clear() centre.extend([x, y]) return # 如果新位置未被佔用 通過return結束 # 如果新位置被佔用則繼續向下執行 x, y = centre for i, j in active: background[x + i][y + j] = 1 l = [] for i in range(1, 20): if 0 not in background[i]: l.append(i) # l裝 行號,鑑於刪去後,部分索引變化,對其降序排列,倒著刪除 l.sort(reverse=True) for i in l: background.pop(i) background.append([0 for j in range(10)]) # 隨刪隨補 score[0] += len(l) pygame.display.set_caption("分數:%d" % (score[0])) active.clear() active.extend(list(random.choice(all_block))) # all_block保存7種形狀的信息,手打出來的 centre.clear() centre.extend([20, 4]) x, y = centre for i, j in active: i += x j += y if background[i][j]: break else: return alive.append(1)
控制結構
下一步組裝
因為核心變量發生變化,new_draw重寫
def new_draw(): screen.fill(white) for i in range(1, 21): for j in range(10): bolck = background[i][j] if bolck: pygame.draw.rect(screen, blue, (j * 25 + 1, 500 - i * 25 + 1, 23, 23)) x, y = centre for i, j in active: i += x j += y pygame.draw.rect(screen, blue, (j * 25 + 1, 500 - i * 25 + 1, 23, 23)) pygame.display.update()
核心變量定義
all_block = (((0, 0), (0, -1), (0, 1), (0, 2)), ((0, 0), (0, 1), (-1, 0), (-1, 1)), ((0, 0), (0, -1), (-1, 0), (-1, 1)), ((0, 0), (0, 1), (-1, -1), (-1, 0)), ((0, 0), (0, 1), (1, 0), (0, -1)), ((0, 0), (1, 0), (-1, 0), (1, -1)), ((0, 0), (1, 0), (-1, 0), (1, 1)))background = [[0 for i in range(10)] for j in range(24)]background[0] = [1 for i in range(10)]active = list(random.choice(all_block))centre = [20, 4]score = [0] for i in range(1, 20): if 0 not in background[i]: l.append(i)
這個部分是從第1行才開始檢查的(~ ̄▽ ̄)~
3,我懶,不想傳參,所以 老套路
pygame固定結構,控制結構,控制變量,龍套變量
pygame.init()screen = pygame.display.set_mode((250, 500))pygame.display.set_caption("俄羅斯方塊")fclock = pygame.time.Clock()black = 0, 0, 0white = 255, 255, 255blue = 0, 0, 255times = 0alive = []press = Falsewhile True: for event in pygame.event.get(): if event.type == pygame.QUIT: sys.exit() elif event.type == pygame.KEYDOWN: if event.key == pygame.K_LEFT: move_LR(-1) elif event.key == pygame.K_RIGHT: move_LR(1) elif event.key == pygame.K_UP: rotate() elif event.key == pygame.K_DOWN: press = True elif event.type == pygame.KEYUP: if event.key == pygame.K_DOWN: press = False if press: times += 10 if times >= 50: move_down() times = 0 else: times += 1 if alive: pygame.display.set_caption("over分數:%d" % (score[0])) time.sleep(3) break new_draw() fclock.tick(100)
說明:
1,原來按一次“下”,方塊只會移動一格。。。。
所以修正了一下,支持 長按,為此加了一個變量press
2,times用於計時
3,遊戲結束的有點突兀,直接就brake啦
最後發現漏了一行沒拷上來
閱讀更多 繁華落盡and曲終人散 的文章