問題的提出: 俄羅斯方塊允許90度的坡,是不是有點不夠科學#(滑稽) 想辦法加一種會“滑坡”的方塊 本文兩大部分: 詳細的描繪是怎樣的“流動” 寫代碼,並整合進游戲 本文基於我寫的 俄羅斯方塊(一):簡版 事先上兩個動圖, 說明下我想做什麼 第一部分 首先是假象圖 這是一個長條逐漸“癱軟”的過程 歸 ...
問題的提出:
俄羅斯方塊允許90度的坡,是不是有點不夠科學#(滑稽)
想辦法加一種會“滑坡”的方塊
本文兩大部分:
詳細的描繪是怎樣的“流動”
寫代碼,並整合進游戲
本文基於我寫的
事先上兩個動圖, 說明下我想做什麼
第一部分
首先是假象圖
這是一個長條逐漸“癱軟”的過程
歸納規律,其實只有兩種移動
1下方沒有方塊時:向下方滑落
2下方有方塊時:向左下或者右下滑落
但是這兩條是不夠的
下麵展示一種例外
左邊的比右邊“更科學”
顯然,需要再加一條規則“規則三:下方的方塊先行動”
但是,這個規則還不夠,我又找到兩個“不科學的”例子
左邊的比右邊“更科學”
不同行之間需要區分次序,同一行的也要區分次序!!!
行內從左向右,和從右向左都無法從根本解決問題,那就只能調整兩種移動的優先順序
再加一條規則“規則四:同一行的,下落移動的優先”
接下來還有一個“不科學”
進去了。。。這是最不科學的一個。。
添加一條斜向移動的限制“左右有方塊不可斜向移動”
然後我發現,規則四沒用了!!!
說明:1號方塊的斜向移動被2號阻止了,上面的情況變成“不可能發生”
它們解決的是同一個問題,水平相鄰方塊之間的次序問題
只是限制斜向移動的方法更為徹底!
規則彙總:
1下方沒有方塊時:向下方滑落
2下方有方塊且左下右下為空時且無阻礙時:向左下或者右下滑落
3多個方塊,行數小的方塊先行動
我已經儘力的考慮每一種“例外”了,如有疏漏歡迎指出
第二部分
代碼的問題無非兩個:
怎麼寫
什麼時候執行
先說第二個問題
什麼時候執行
講流程,原來的“方塊落地-->清算分數-->下一個方塊” 新的 "方塊落地-->開始流動-->清算分數-->下一個方塊"
可是一次流動結束就太沒趣了 一次只流動一步
之前的下落過程的流程圖
新的
代碼重整
# flows list 全局變數 儲存"正在流動的方塊" # block_type list 全局變數 決定活動方塊能否流動 def move_down(): if flows:
# ---------流動過程--------- pass # ========================== else: # 下麵是常規的流程 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 # ----------落地後------- # 如果方塊狀態 為 流動 則寫入flows if block_type[0] == 2: x, y = centre for i, j in active: flows.append((x + i, y + j)) # === 將方塊信息 轉入 待流動列表 active.clear() return # 結束函數,防止進入下方"清算環節"
# - 否則走常規流程 else: 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.sort(reverse=True) for i in l: background.pop(i) background.append([0 for j in range(10)]) score[0] += scores_f(len(l)) pygame.display.set_caption("分數:%d" % (score[0])) active.clear() new = list(random.choice(all_block)) if random.randint(1, 10) >= 4 else list(random.choice(all_block_plus)) active.extend(new) block_type[0] = 1 if random.randint(1, 10) >= 5 else 2 # 取個隨機數,決定下個方塊的類型 1為普通方塊 2為流動方塊 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)
下麵是流動的詳細內容:
PS:從流動列表移除的同時 , 應該寫入 background "固化"成為背景
流動過程代碼(在最後有 紅色代碼額外的說明)
# 基於"遍歷過程中避免修改遍歷對象"的原則 # 故遍歷 flows的 拷貝 flows_copy = flows.copy() # - 流動原則三,行數小的先動, 故遍歷前先排序 flows_copy.sort() for i, j in flows_copy: flows.remove((i, j)) # 1 # '抹去'舊方塊位置信息 if background[i - 1][j] or ((i - 1, j) in flows): # 如果下方有方塊(背景方塊,流動中的方塊都算) # 2 num = 0 # 如果左側沒有方塊(背景方塊,流動中的方塊都算)num += 1 if j >= 1 and (not background[i][j - 1]) and (not background[i - 1][j - 1]) \ and ((i, j - 1) not in flows) and ((i - 1, j - 1) not in flows): # (3) num += 1 # 如果右側沒有方塊(背景方塊,流動中的方塊都算)num += 2 if j <= 8 and (not background[i][j + 1]) and (not background[i - 1][j + 1]) \ and ((i, j + 1) not in flows) and ((i - 1, j + 1) not in flows): num += 2 #num可能的情況 0 1 2 3 #對應 左右均不通 僅通左路 僅通右路 左右均通 #如果左右均通 左右兩路隨機選一個 if num == 3: num = random.randint(1, 2) # 根據num取值 做出相應的移動 if num == 0: # 這裡與 流程圖 不一致 後面會說明原因 (4) if (background[i - 1][j]) and (j <= 0 or background[i][j - 1] or background[i - 1][j - 1]) and \ (j >= 9 or background[i][j + 1] or background[i - 1][j + 1]): background[i][j] = 3 #如果 三個方向 被背景方塊 堵死 #就"固化/停止流動/移出flows/寫入background" else: flows.append((i, j)) elif num == 1: flows.append((i - 1, j - 1)) elif num == 2: flows.append((i - 1, j + 1)) else: # 否則就將算出 下方的坐標 添回flows flows.append((i - 1, j)) # 如果flows仍有方塊存在 # return 結束函數, 防止 if flows: return
額外的說明:
1, 移動就是, 從flows除去舊的位置,添入新位置,,,為避免代碼重覆出現,迴圈第一步就移除舊位置
2,至此,方塊有兩種,background的背景方塊 flows的流動方塊 一個位置是否有方塊 需要查閱兩次 另外畫面繪製部分需要 遍歷 flows 繪製方塊
3,為避免 越界錯誤 ,索引background前 加個判斷
4流程圖未考慮到一個特殊情況
理想狀態下 兩個流動方塊應該 填上洞 但是按流程圖 1 號方塊三路堵死 固化
所以 因流動方塊 阻礙 造成的"假死"不用固化 / 單純被 背景堵死 才固化
完整代碼
import pygame, sys, random, time 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, colors[bolck], (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, colors[block_type[0]], (j * 25 + 1, 500 - i * 25 + 1, 23, 23)) for i, j in flows: pygame.draw.rect(screen, yellow, (j * 25 + 1, 500 - i * 25 + 1, 23, 23)) pygame.display.update() def move_LR(n): """n=-1代表向左,n=1代表向右""" x, y = centre y += n for i, j in active: i += x j += y if j < 0 or j > 9 or background[i][j]: break else: centre.clear() centre.extend([x, y]) 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) def move_down(): if flows: flows_copy = flows.copy() flows_copy.sort() for i, j in flows_copy: flows.remove((i, j)) if background[i - 1][j] or ((i - 1, j) in flows): num = 0 if j >= 1 and (not background[i][j - 1]) and (not background[i - 1][j - 1]) \ and ((i, j - 1) not in flows) and ((i - 1, j - 1) not in flows): num += 1 if j <= 8 and (not background[i][j + 1]) and (not background[i - 1][j + 1]) \ and ((i, j + 1) not in flows) and ((i - 1, j + 1) not in flows): num += 2 if num == 3: num = random.randint(1, 2) if num == 0: if (background[i - 1][j]) and (j <= 0 or background[i][j - 1] or background[i - 1][j - 1]) and \ (j >= 9 or background[i][j + 1] or background[i - 1][j + 1]): background[i][j] = 3 else: flows.append((i, j)) if num == 1: flows.append((i - 1, j - 1)) if num == 2: flows.append((i - 1, j + 1)) else: flows.append((i - 1, j)) if flows: return else: 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 if block_type[0] == 2: x, y = centre for i, j in active: flows.append((x + i, y + j)) active.clear() return else: 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.sort(reverse=True) for i in l: background.pop(i) background.append([0 for j in range(10)]) score[0] += scores_f(len(l)) pygame.display.set_caption("分數:%d" % (score[0])) active.clear() new = list(random.choice(all_block)) if random.randint(1, 10) >= 4 else list(random.choice(all_block_plus)) active.extend(new) block_type[0] = 1 if random.randint(1, 10) >= 5 else 2 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) def scores_f(n): if n in scores: return scores[n] else: return scores_f(n-4) pygame.init() screen = pygame.display.set_mode((250, 500)) pygame.display.set_caption("俄羅斯方塊") fclock = pygame.time.Clock() 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))) all_block_plus = (((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 0), (0, 1), (1, -1), (1, 0), (1, 1),), ((-1, 0), (0, -1), (0, 0), (0, 1), (1, 0)), ((-1, 0), (0, -1), (0, 0), (0, 1), (1, 0), (-2, 0)), ((0, -1), (0, 0), (0, 1), (1, -1), (1, 1)), ((-1, 1), (0, -1), (0, 0), (0, 1), (1, -1)), ((-1, -1), (0, -1), (0, 0), (0, 1), (1, 1)), ((-1, -1), (-1, 1), (0, 0), (1, -1), (1, 1)), ((-1, -1), (-1, 1), (0, -1), (0, 0), (0, 1), (1, -1), (1, 1)), ((-1, -1), (0, -1), (0, 0), (0, 1), (1, -1)) ) '''3x3,十,十,凹,2,5,X,H,T''' scores = {0: 0, 1: 1, 2: 3, 3: 6, 4: 10}
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] flows = [] block_type = [1] black = 0, 0, 0 white = 255, 255, 255 blue = 0, 0, 255 yellow = 255, 215, 0 colors = {1: blue, 2: yellow, 3: (139, 105, 20)} times = 0 alive = [] press = False while 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 += 20 if times >= 100: 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)
PS : 標紅的是一些細枝末節 有需要的話我再解釋
流動方塊降低了難度,,所以加入了一些 特殊形狀的 方塊增加難度
這篇急於發表 畢竟寫了一個月了...有問題有空再更新
#