pygame實(shí)現(xiàn)俄羅斯方塊游戲(基礎(chǔ)篇3)
上一章請(qǐng)點(diǎn)擊查看:pygame實(shí)現(xiàn)俄羅斯方塊游戲(基礎(chǔ)篇2)
現(xiàn)在繼續(xù)
一、給每個(gè)方塊設(shè)置不同的顏色
根據(jù)代碼這里可以判斷正在下落的方塊在那些Block子類里加一個(gè)屬性最合適,而已經(jīng)落下的方塊顏色管理最合適的地方應(yīng)該是修改在Panel類里的rect_arr
Block子類里的修改比較簡(jiǎn)單,以TBlock類為例,在__init__函數(shù)加一行
self.color=(255,0,0)
在Panel的paint函數(shù)里將代碼
# 繪制正在落下的方塊 if self.move_block: for rect in self.moving_block.get_rect_arr(): x,y=rect pygame.draw.line(self._bg,[0,0,255],[self._x+x*bz+bz/2,self._y+y*bz],[self._x+x*bz+bz/2,self._y+(y+1)*bz],bz) pygame.draw.rect(self._bg,[255,255,255],[self._x+x*bz,self._y+y*bz,bz+1,bz+1],1)
中的
pygame.draw.line(self._bg,[0,0,255],[self._x+x*bz+bz/2,self._y+y*bz],[self._x+x*bz+bz/2,self._y+(y+1)*bz],bz)
改成
pygame.draw.line(self._bg,self.moving_block.color,[self._x+x*bz+bz/2,self._y+y*bz],[self._x+x*bz+bz/2,self._y+(y+1)*bz],bz)
已經(jīng)下落的方塊修改會(huì)麻煩一點(diǎn),原來存在rect_arr里的是x,y,現(xiàn)在要增加一個(gè)顏色,直接改也是可以的,不過考慮到以后的擴(kuò)展性,果斷定義一個(gè)RectInfo類
class RectInfo(object): def __init__(self, x, y, color): self.x = x self.y = y self.color = color
將存入rect_arr時(shí)的代碼修改為
def add_block(self,block): for x,y in block.get_rect_arr(): self.rect_arr.append(RectInfo(x,y, block.color))
并將設(shè)計(jì)rect_arr做下修改即可

貼下目前的完整代碼
# -*- coding=utf-8 -*-
import random
import pygame
from pygame.locals import KEYDOWN,K_LEFT,K_RIGHT,K_UP,K_DOWN,K_SPACE
class RectInfo(object):
def __init__(self, x, y, color):
self.x = x
self.y = y
self.color = color
class Panel(object): # 用于繪制整個(gè)游戲窗口的版面
rect_arr=[] # 已經(jīng)落底下的方塊
moving_block=None # 正在落下的方塊
def __init__(self,bg, block_size, position):
self._bg=bg;
self._x,self._y,self._width,self._height=position
self._block_size=block_size
self._bgcolor=[0,0,0]
def add_block(self,block):
for x,y in block.get_rect_arr():
self.rect_arr.append(RectInfo(x,y, block.color))
def create_move_block(self):
block = create_block()
block.move(5-2,-2) # 方塊挪到中間
self.moving_block=block
def check_overlap(self, diffx, diffy, check_arr=None):
if check_arr is None: check_arr = self.moving_block.get_rect_arr()
for x,y in check_arr:
for rect_info in self.rect_arr:
if x+diffx==rect_info.x and y+diffy==rect_info.y:
return True
return False
def control_block(self, diffx, diffy):
if self.moving_block.can_move(diffx,diffy) and not self.check_overlap(diffx, diffy):
self.moving_block.move(diffx,diffy)
def change_block(self):
if self.moving_block:
new_arr = self.moving_block.change()
if new_arr and not self.check_overlap(0, 0, check_arr=new_arr): # 變形不能造成方塊重疊
self.moving_block.rect_arr=new_arr
def move_block(self):
if self.moving_block is None: create_move_block()
if self.moving_block.can_move(0,1) and not self.check_overlap(0,1):
self.moving_block.move(0,1)
return 1
else:
self.add_block(self.moving_block)
self.check_clear()
for rect_info in self.rect_arr:
if rect_info.y<0: return 9 # 游戲失敗
self.create_move_block()
return 2
def check_clear(self):
tmp_arr = [[] for i in range(20)]
# 先將方塊按行存入數(shù)組
for rect_info in self.rect_arr:
if rect_info.y<0: return
tmp_arr[rect_info.y].append(rect_info)
clear_num=0
clear_lines=set([])
y_clear_diff_arr=[[] for i in range(20)]
# 從下往上計(jì)算可以消除的行,并記錄消除行后其他行的向下偏移數(shù)量
for y in range(19,-1,-1):
if len(tmp_arr[y])==10:
clear_lines.add(y)
clear_num += 1
y_clear_diff_arr[y] = clear_num
if clear_num>0:
new_arr=[]
# 跳過移除行,并將其他行做偏移
for y in range(19,-1,-1):
if y in clear_lines: continue
tmp_row = tmp_arr[y]
y_clear_diff=y_clear_diff_arr[y]
for rect_info in tmp_row:
#new_arr.append([x,y+y_clear_diff])
new_arr.append(RectInfo(rect_info.x, rect_info.y+y_clear_diff, rect_info.color))
self.rect_arr = new_arr
def paint(self):
mid_x=self._x+self._width/2
pygame.draw.line(self._bg,self._bgcolor,[mid_x,self._y],[mid_x,self._y+self._height],self._width) # 用一個(gè)粗線段來填充背景
# 繪制已經(jīng)落底下的方塊
bz=self._block_size
for rect_info in self.rect_arr:
x=rect_info.x
y=rect_info.y
pygame.draw.line(self._bg,rect_info.color,[self._x+x*bz+bz/2,self._y+y*bz],[self._x+x*bz+bz/2,self._y+(y+1)*bz],bz)
pygame.draw.rect(self._bg,[255,255,255],[self._x+x*bz,self._y+y*bz,bz+1,bz+1],1)
# 繪制正在落下的方塊
if self.move_block:
for rect in self.moving_block.get_rect_arr():
x,y=rect
pygame.draw.line(self._bg,self.moving_block.color,[self._x+x*bz+bz/2,self._y+y*bz],[self._x+x*bz+bz/2,self._y+(y+1)*bz],bz)
pygame.draw.rect(self._bg,[255,255,255],[self._x+x*bz,self._y+y*bz,bz+1,bz+1],1)
class Block(object):
sx=0
sy=0
def __init__(self):
self.rect_arr=[]
def get_rect_arr(self): # 用于獲取方塊種的四個(gè)矩形列表
return self.rect_arr
def move(self,xdiff,ydiff): # 用于移動(dòng)方塊的方法
self.sx+=xdiff
self.sy+=ydiff
self.new_rect_arr=[]
for x,y in self.rect_arr:
self.new_rect_arr.append((x+xdiff,y+ydiff))
self.rect_arr=self.new_rect_arr
def can_move(self,xdiff,ydiff):
for x,y in self.rect_arr:
if y+ydiff>=20: return False
if x+xdiff<0 or x+xdiff>=10: return False
return True
def change(self):
self.shape_id+=1 # 下一形態(tài)
if self.shape_id >= self.shape_num:
self.shape_id=0
arr = self.get_shape()
new_arr = []
for x,y in arr:
if x+self.sx<0 or x+self.sx>=10: # 變形不能超出左右邊界
self.shape_id -= 1
if self.shape_id < 0: self.shape_id = self.shape_num - 1
return None
new_arr.append([x+self.sx,y+self.sy])
return new_arr
class LongBlock(Block):
shape_id=0
shape_num=2
def __init__(self, n=None): # 兩種形態(tài)
super(LongBlock, self).__init__()
if n is None: n=random.randint(0,1)
self.shape_id=n
self.rect_arr=self.get_shape()
self.color=(50,180,50)
def get_shape(self):
return [(1,0),(1,1),(1,2),(1,3)] if self.shape_id==0 else [(0,2),(1,2),(2,2),(3,2)]
class SquareBlock(Block): # 一種形態(tài)
shape_id=0
shape_num=1
def __init__(self, n=None):
super(SquareBlock, self).__init__()
self.rect_arr=self.get_shape()
self.color=(0,0,255)
def get_shape(self):
return [(1,1),(1,2),(2,1),(2,2)]
class ZBlock(Block): # 兩種形態(tài)
shape_id=0
shape_num=2
def __init__(self, n=None):
super(ZBlock, self).__init__()
if n is None: n=random.randint(0,1)
self.shape_id=n
self.rect_arr=self.get_shape()
self.color=(30,200,200)
def get_shape(self):
return [(2,0),(2,1),(1,1),(1,2)] if self.shape_id==0 else [(0,1),(1,1),(1,2),(2,2)]
class SBlock(Block): # 兩種形態(tài)
shape_id=0
shape_num=2
def __init__(self, n=None):
super(SBlock, self).__init__()
if n is None: n=random.randint(0,1)
self.shape_id=n
self.rect_arr=self.get_shape()
self.color=(255,30,255)
def get_shape(self):
return [(1,0),(1,1),(2,1),(2,2)] if self.shape_id==0 else [(0,2),(1,2),(1,1),(2,1)]
class LBlock(Block): # 四種形態(tài)
shape_id=0
shape_num=4
def __init__(self, n=None):
super(LBlock, self).__init__()
if n is None: n=random.randint(0,3)
self.shape_id=n
self.rect_arr=self.get_shape()
self.color=(200,200,30)
def get_shape(self):
if self.shape_id==0: return [(1,0),(1,1),(1,2),(2,2)]
elif self.shape_id==1: return [(0,1),(1,1),(2,1),(0,2)]
elif self.shape_id==2: return [(0,0),(1,0),(1,1),(1,2)]
else: return [(0,1),(1,1),(2,1),(2,0)]
class JBlock(Block): # 四種形態(tài)
shape_id=0
shape_num=4
def __init__(self, n=None):
super(JBlock, self).__init__()
if n is None: n=random.randint(0,3)
self.shape_id=n
self.rect_arr=self.get_shape()
self.color=(200,100,0)
def get_shape(self):
if self.shape_id==0: return [(1,0),(1,1),(1,2),(0,2)]
elif self.shape_id==1: return [(0,1),(1,1),(2,1),(0,0)]
elif self.shape_id==2: return [(2,0),(1,0),(1,1),(1,2)]
else: return [(0,1),(1,1),(2,1),(2,2)]
class TBlock(Block): # 四種形態(tài)
shape_id=0
shape_num=4
def __init__(self, n=None):
super(TBlock, self).__init__()
if n is None: n=random.randint(0,3)
self.shape_id=n
self.rect_arr=self.get_shape()
self.color=(255,0,0)
def get_shape(self):
if self.shape_id==0: return [(0,1),(1,1),(2,1),(1,2)]
elif self.shape_id==1: return [(1,0),(1,1),(1,2),(0,1)]
elif self.shape_id==2: return [(0,1),(1,1),(2,1),(1,0)]
else: return [(1,0),(1,1),(1,2),(2,1)]
def create_block():
n = random.randint(0,19)
if n==0: return SquareBlock(n=0)
elif n==1 or n==2: return LongBlock(n=n-1)
elif n==3 or n==4: return ZBlock(n=n-3)
elif n==5 or n==6: return SBlock(n=n-5)
elif n>=7 and n<=10: return LBlock(n=n-7)
elif n>=11 and n<=14: return JBlock(n=n-11)
else: return TBlock(n=n-15)
def run():
pygame.init()
space=30
main_block_size=30
main_panel_width=main_block_size*10
main_panel_height=main_block_size*20
screencaption = pygame.display.set_caption('Tetris')
screen = pygame.display.set_mode((main_panel_width+160+space*3,main_panel_height+space*2)) #設(shè)置窗口長(zhǎng)寬
main_panel=Panel(screen,main_block_size,[space,space,main_panel_width,main_panel_height])
pygame.key.set_repeat(200, 30)
main_panel.create_move_block()
diff_ticks = 300 # 移動(dòng)一次蛇頭的事件,單位毫秒
ticks = pygame.time.get_ticks() + diff_ticks
game_state = 1 # 游戲狀態(tài)1.表示正常 2.表示失敗
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == KEYDOWN:
if event.key == K_LEFT: main_panel.control_block(-1,0)
if event.key == K_RIGHT: main_panel.control_block(1,0)
if event.key == K_UP: main_panel.change_block()
if event.key == K_DOWN: main_panel.control_block(0,1)
if event.key == K_SPACE:
flag = main_panel.move_block()
while flag==1:
flag = main_panel.move_block()
if flag == 9: game_state = 2
screen.fill((100,100,100)) # 將界面設(shè)置為灰色
main_panel.paint() # 主面盤繪制
if game_state == 2:
myfont = pygame.font.Font(None,30)
white = 255,255,255
textImage = myfont.render("Game over", True, white)
screen.blit(textImage, (160,190))
pygame.display.update() # 必須調(diào)用update才能看到繪圖顯示
if game_state == 1 and pygame.time.get_ticks() >= ticks:
ticks+=diff_ticks
if main_panel.move_block()==9: game_state = 2 # 游戲結(jié)束
run()
二、下一個(gè)方塊
為便于下一方塊的提示窗的繪制,我們定義一個(gè)類HintBox,用于管理下一方塊和界面的繪制
class HintBox(object): next_block=None def __init__(self, bg, block_size, position): self._bg=bg; self._x,self._y,self._width,self._height=position self._block_size=block_size self._bgcolor=[0,0,0] def take_block(self): block = self.next_block if block is None: # 如果還沒有方塊,先產(chǎn)生一個(gè) block = create_block() self.next_block = create_block() # 產(chǎn)生下一個(gè)方塊 return block def paint(self): mid_x=self._x+self._width/2 pygame.draw.line(self._bg,self._bgcolor,[mid_x,self._y],[mid_x,self._y+self._height],self._width) bz=self._block_size # 繪制正在落下的方塊 if self.next_block: arr = self.next_block.get_rect_arr() minx,miny=arr[0] maxx,maxy=arr[0] for x,y in arr: if x<minx: minx=x if x>maxx: maxx=x if y<miny: miny=y if y>maxy: maxy=y w=(maxx-minx)*bz h=(maxy-miny)*bz # 計(jì)算使方塊繪制在提示窗中心位置所需要的偏移像素 cx=self._width/2-w/2-minx*bz-bz/2 cy=self._height/2-h/2-miny*bz-bz/2 for rect in arr: x,y=rect pygame.draw.line(self._bg,self.next_block.color,[self._x+x*bz+cx+bz/2,self._y+cy+y*bz],[self._x+x*bz+cx+bz/2,self._y+cy+(y+1)*bz],bz) pygame.draw.rect(self._bg,[255,255,255],[self._x+x*bz+cx,self._y+y*bz+cy,bz+1,bz+1],1)
在Panel類里面增加一個(gè)屬性
hint_box=None
將Panel類里面的
def create_move_block(self): block = create_block() block.move(5-2,-2) # 方塊挪到中間 self.moving_block=block
產(chǎn)生方塊的方式,改為由hint_box產(chǎn)生
def create_move_block(self): block = self.hint_box.take_block() block.move(5-2,-2) # 方塊挪到中間 self.moving_block=block
在run函數(shù)里增加初始化hint_box和設(shè)置main_panel的程序
hint_box=HintBox(screen,main_block_size,[main_panel_width+space+space,space,160,160]) main_panel.hint_box=hint_box
在游戲主循環(huán)增加下一方塊提示窗的繪制
hint_box.paint() # 繪制下一個(gè)方塊的提示窗
現(xiàn)在可以正常顯示下一方塊提示了

三、分?jǐn)?shù)的計(jì)算
消除分?jǐn)?shù)的計(jì)算方式為
1行 100分
2行 300分
3行 800分
4行 1600分
類似下一方塊提示窗的設(shè)計(jì),我們可以增加一個(gè)ScoreBox類
class ScoreBox(object):
total_score = 0
def __init__(self, bg, block_size, position):
self._bg=bg;
self._x,self._y,self._width,self._height=position
self._block_size=block_size
self._bgcolor=[0,0,0]
def paint(self):
myfont = pygame.font.Font(None,36)
white = 255,255,255
textImage = myfont.render('Score:%06d'%(self.total_score), True, white)
self._bg.blit(textImage, (self._x,self._y))
然后在Panel增加score_box屬性
score_box=None
定義一個(gè)全局的SCORE_MAP
SCORE_MAP=(100,300,800,1600)
在check_clear函數(shù)中,如果有方塊消除,則執(zhí)行
score = SCORE_MAP[clear_num-1] self.score_box.total_score += score
在run主函數(shù)初始化score_box
score_box=ScoreBox(screen,main_block_size,[main_panel_width+space+space,160+space*2,160,160]) main_panel.score_box=score_box
并在游戲循環(huán)繪制score_box
score_box.paint() # 繪制總分

四、歷史最高分
準(zhǔn)備在當(dāng)前目錄用一個(gè)tetris.db的pickle文件保存
所以首先
import pickle,os
由于最高分可以借用ScoreBox在繪制當(dāng)前分?jǐn)?shù)時(shí)一起繪制,所以直接在ScoreBox增加一個(gè)最高分的屬性和一個(gè)文件的定義
high_score = 0 db_file = 'tetris.db'
在ScoreBox的初始化函數(shù)里增加pickle的加載
if os.path.exists(self.db_file): self.high_score = pickle.load(open(self.db_file,'rb'))
在paint里增加下最高分的繪制
def paint(self):
myfont = pygame.font.Font(None,36)
white = 255,255,255
textImage = myfont.render('High: %06d'%(self.high_score), True, white)
self._bg.blit(textImage, (self._x,self._y))
textImage = myfont.render('Score:%06d'%(self.total_score), True, white)
self._bg.blit(textImage, (self._x,self._y+40))
將之前直接對(duì)ScoreBox的score的修改改為封裝一個(gè)add_score的函數(shù)
def add_score(self, score): self.total_score += score if self.total_score > self.high_score: self.high_score=self.total_score pickle.dump(self.high_score, open(self.db_file,'wb+'))
在add_score函數(shù)里進(jìn)行score的修改并做是否超過最高分的判斷,如果超過則保存分?jǐn)?shù)(當(dāng)然也可以在游戲結(jié)束或關(guān)閉界面時(shí)判斷和保存最高分,減少磁盤io)
看下效果圖

貼下完整的程序
# -*- coding=utf-8 -*-
import random
import pygame
from pygame.locals import KEYDOWN,K_LEFT,K_RIGHT,K_UP,K_DOWN,K_SPACE
import pickle,os
SCORE_MAP=(100,300,800,1600)
class RectInfo(object):
def __init__(self, x, y, color):
self.x = x
self.y = y
self.color = color
class HintBox(object):
next_block=None
def __init__(self, bg, block_size, position):
self._bg=bg;
self._x,self._y,self._width,self._height=position
self._block_size=block_size
self._bgcolor=[0,0,0]
def take_block(self):
block = self.next_block
if block is None: # 如果還沒有方塊,先產(chǎn)生一個(gè)
block = create_block()
self.next_block = create_block() # 產(chǎn)生下一個(gè)方塊
return block
def paint(self):
mid_x=self._x+self._width/2
pygame.draw.line(self._bg,self._bgcolor,[mid_x,self._y],[mid_x,self._y+self._height],self._width)
bz=self._block_size
# 繪制正在落下的方塊
if self.next_block:
arr = self.next_block.get_rect_arr()
minx,miny=arr[0]
maxx,maxy=arr[0]
for x,y in arr:
if x<minx: minx=x
if x>maxx: maxx=x
if y<miny: miny=y
if y>maxy: maxy=y
w=(maxx-minx)*bz
h=(maxy-miny)*bz
# 計(jì)算使方塊繪制在提示窗中心位置所需要的偏移像素
cx=self._width/2-w/2-minx*bz-bz/2
cy=self._height/2-h/2-miny*bz-bz/2
for rect in arr:
x,y=rect
pygame.draw.line(self._bg,self.next_block.color,[self._x+x*bz+cx+bz/2,self._y+cy+y*bz],[self._x+x*bz+cx+bz/2,self._y+cy+(y+1)*bz],bz)
pygame.draw.rect(self._bg,[255,255,255],[self._x+x*bz+cx,self._y+y*bz+cy,bz+1,bz+1],1)
class ScoreBox(object):
total_score = 0
high_score = 0
db_file = 'tetris.db'
def __init__(self, bg, block_size, position):
self._bg=bg;
self._x,self._y,self._width,self._height=position
self._block_size=block_size
self._bgcolor=[0,0,0]
if os.path.exists(self.db_file): self.high_score = pickle.load(open(self.db_file,'rb'))
def paint(self):
myfont = pygame.font.Font(None,36)
white = 255,255,255
textImage = myfont.render('High: %06d'%(self.high_score), True, white)
self._bg.blit(textImage, (self._x,self._y))
textImage = myfont.render('Score:%06d'%(self.total_score), True, white)
self._bg.blit(textImage, (self._x,self._y+40))
def add_score(self, score):
self.total_score += score
if self.total_score > self.high_score:
self.high_score=self.total_score
pickle.dump(self.high_score, open(self.db_file,'wb+'))
class Panel(object): # 用于繪制整個(gè)游戲窗口的版面
rect_arr=[] # 已經(jīng)落底下的方塊
moving_block=None # 正在落下的方塊
hint_box=None
score_box=None
def __init__(self,bg, block_size, position):
self._bg=bg;
self._x,self._y,self._width,self._height=position
self._block_size=block_size
self._bgcolor=[0,0,0]
def add_block(self,block):
for x,y in block.get_rect_arr():
self.rect_arr.append(RectInfo(x,y, block.color))
def create_move_block(self):
block = self.hint_box.take_block()
#block = create_block()
block.move(5-2,-2) # 方塊挪到中間
self.moving_block=block
def check_overlap(self, diffx, diffy, check_arr=None):
if check_arr is None: check_arr = self.moving_block.get_rect_arr()
for x,y in check_arr:
for rect_info in self.rect_arr:
if x+diffx==rect_info.x and y+diffy==rect_info.y:
return True
return False
def control_block(self, diffx, diffy):
if self.moving_block.can_move(diffx,diffy) and not self.check_overlap(diffx, diffy):
self.moving_block.move(diffx,diffy)
def change_block(self):
if self.moving_block:
new_arr = self.moving_block.change()
if new_arr and not self.check_overlap(0, 0, check_arr=new_arr): # 變形不能造成方塊重疊
self.moving_block.rect_arr=new_arr
def move_block(self):
if self.moving_block is None: create_move_block()
if self.moving_block.can_move(0,1) and not self.check_overlap(0,1):
self.moving_block.move(0,1)
return 1
else:
self.add_block(self.moving_block)
self.check_clear()
for rect_info in self.rect_arr:
if rect_info.y<0: return 9 # 游戲失敗
self.create_move_block()
return 2
def check_clear(self):
tmp_arr = [[] for i in range(20)]
# 先將方塊按行存入數(shù)組
for rect_info in self.rect_arr:
if rect_info.y<0: return
tmp_arr[rect_info.y].append(rect_info)
clear_num=0
clear_lines=set([])
y_clear_diff_arr=[[] for i in range(20)]
# 從下往上計(jì)算可以消除的行,并記錄消除行后其他行的向下偏移數(shù)量
for y in range(19,-1,-1):
if len(tmp_arr[y])==10:
clear_lines.add(y)
clear_num += 1
y_clear_diff_arr[y] = clear_num
if clear_num>0:
new_arr=[]
# 跳過移除行,并將其他行做偏移
for y in range(19,-1,-1):
if y in clear_lines: continue
tmp_row = tmp_arr[y]
y_clear_diff=y_clear_diff_arr[y]
for rect_info in tmp_row:
#new_arr.append([x,y+y_clear_diff])
new_arr.append(RectInfo(rect_info.x, rect_info.y+y_clear_diff, rect_info.color))
self.rect_arr = new_arr
score = SCORE_MAP[clear_num-1]
self.score_box.add_score(score)
def paint(self):
mid_x=self._x+self._width/2
pygame.draw.line(self._bg,self._bgcolor,[mid_x,self._y],[mid_x,self._y+self._height],self._width) # 用一個(gè)粗線段來填充背景
# 繪制已經(jīng)落底下的方塊
bz=self._block_size
for rect_info in self.rect_arr:
x=rect_info.x
y=rect_info.y
pygame.draw.line(self._bg,rect_info.color,[self._x+x*bz+bz/2,self._y+y*bz],[self._x+x*bz+bz/2,self._y+(y+1)*bz],bz)
pygame.draw.rect(self._bg,[255,255,255],[self._x+x*bz,self._y+y*bz,bz+1,bz+1],1)
# 繪制正在落下的方塊
if self.move_block:
for rect in self.moving_block.get_rect_arr():
x,y=rect
pygame.draw.line(self._bg,self.moving_block.color,[self._x+x*bz+bz/2,self._y+y*bz],[self._x+x*bz+bz/2,self._y+(y+1)*bz],bz)
pygame.draw.rect(self._bg,[255,255,255],[self._x+x*bz,self._y+y*bz,bz+1,bz+1],1)
class Block(object):
sx=0
sy=0
def __init__(self):
self.rect_arr=[]
def get_rect_arr(self): # 用于獲取方塊種的四個(gè)矩形列表
return self.rect_arr
def move(self,xdiff,ydiff): # 用于移動(dòng)方塊的方法
self.sx+=xdiff
self.sy+=ydiff
self.new_rect_arr=[]
for x,y in self.rect_arr:
self.new_rect_arr.append((x+xdiff,y+ydiff))
self.rect_arr=self.new_rect_arr
def can_move(self,xdiff,ydiff):
for x,y in self.rect_arr:
if y+ydiff>=20: return False
if x+xdiff<0 or x+xdiff>=10: return False
return True
def change(self):
self.shape_id+=1 # 下一形態(tài)
if self.shape_id >= self.shape_num:
self.shape_id=0
arr = self.get_shape()
new_arr = []
for x,y in arr:
if x+self.sx<0 or x+self.sx>=10: # 變形不能超出左右邊界
self.shape_id -= 1
if self.shape_id < 0: self.shape_id = self.shape_num - 1
return None
new_arr.append([x+self.sx,y+self.sy])
return new_arr
class LongBlock(Block):
shape_id=0
shape_num=2
def __init__(self, n=None): # 兩種形態(tài)
super(LongBlock, self).__init__()
if n is None: n=random.randint(0,1)
self.shape_id=n
self.rect_arr=self.get_shape()
self.color=(50,180,50)
def get_shape(self):
return [(1,0),(1,1),(1,2),(1,3)] if self.shape_id==0 else [(0,2),(1,2),(2,2),(3,2)]
class SquareBlock(Block): # 一種形態(tài)
shape_id=0
shape_num=1
def __init__(self, n=None):
super(SquareBlock, self).__init__()
self.rect_arr=self.get_shape()
self.color=(0,0,255)
def get_shape(self):
return [(1,1),(1,2),(2,1),(2,2)]
class ZBlock(Block): # 兩種形態(tài)
shape_id=0
shape_num=2
def __init__(self, n=None):
super(ZBlock, self).__init__()
if n is None: n=random.randint(0,1)
self.shape_id=n
self.rect_arr=self.get_shape()
self.color=(30,200,200)
def get_shape(self):
return [(2,0),(2,1),(1,1),(1,2)] if self.shape_id==0 else [(0,1),(1,1),(1,2),(2,2)]
class SBlock(Block): # 兩種形態(tài)
shape_id=0
shape_num=2
def __init__(self, n=None):
super(SBlock, self).__init__()
if n is None: n=random.randint(0,1)
self.shape_id=n
self.rect_arr=self.get_shape()
self.color=(255,30,255)
def get_shape(self):
return [(1,0),(1,1),(2,1),(2,2)] if self.shape_id==0 else [(0,2),(1,2),(1,1),(2,1)]
class LBlock(Block): # 四種形態(tài)
shape_id=0
shape_num=4
def __init__(self, n=None):
super(LBlock, self).__init__()
if n is None: n=random.randint(0,3)
self.shape_id=n
self.rect_arr=self.get_shape()
self.color=(200,200,30)
def get_shape(self):
if self.shape_id==0: return [(1,0),(1,1),(1,2),(2,2)]
elif self.shape_id==1: return [(0,1),(1,1),(2,1),(0,2)]
elif self.shape_id==2: return [(0,0),(1,0),(1,1),(1,2)]
else: return [(0,1),(1,1),(2,1),(2,0)]
class JBlock(Block): # 四種形態(tài)
shape_id=0
shape_num=4
def __init__(self, n=None):
super(JBlock, self).__init__()
if n is None: n=random.randint(0,3)
self.shape_id=n
self.rect_arr=self.get_shape()
self.color=(200,100,0)
def get_shape(self):
if self.shape_id==0: return [(1,0),(1,1),(1,2),(0,2)]
elif self.shape_id==1: return [(0,1),(1,1),(2,1),(0,0)]
elif self.shape_id==2: return [(2,0),(1,0),(1,1),(1,2)]
else: return [(0,1),(1,1),(2,1),(2,2)]
class TBlock(Block): # 四種形態(tài)
shape_id=0
shape_num=4
def __init__(self, n=None):
super(TBlock, self).__init__()
if n is None: n=random.randint(0,3)
self.shape_id=n
self.rect_arr=self.get_shape()
self.color=(255,0,0)
def get_shape(self):
if self.shape_id==0: return [(0,1),(1,1),(2,1),(1,2)]
elif self.shape_id==1: return [(1,0),(1,1),(1,2),(0,1)]
elif self.shape_id==2: return [(0,1),(1,1),(2,1),(1,0)]
else: return [(1,0),(1,1),(1,2),(2,1)]
def create_block():
n = random.randint(0,19)
if n==0: return SquareBlock(n=0)
elif n==1 or n==2: return LongBlock(n=n-1)
elif n==3 or n==4: return ZBlock(n=n-3)
elif n==5 or n==6: return SBlock(n=n-5)
elif n>=7 and n<=10: return LBlock(n=n-7)
elif n>=11 and n<=14: return JBlock(n=n-11)
else: return TBlock(n=n-15)
def run():
pygame.init()
space=30
main_block_size=30
main_panel_width=main_block_size*10
main_panel_height=main_block_size*20
screencaption = pygame.display.set_caption('Tetris')
screen = pygame.display.set_mode((main_panel_width+160+space*3,main_panel_height+space*2)) #設(shè)置窗口長(zhǎng)寬
main_panel=Panel(screen,main_block_size,[space,space,main_panel_width,main_panel_height])
hint_box=HintBox(screen,main_block_size,[main_panel_width+space+space,space,160,160])
score_box=ScoreBox(screen,main_block_size,[main_panel_width+space+space,160+space*2,160,160])
main_panel.hint_box=hint_box
main_panel.score_box=score_box
pygame.key.set_repeat(200, 30)
main_panel.create_move_block()
diff_ticks = 300 # 移動(dòng)一次蛇頭的事件,單位毫秒
ticks = pygame.time.get_ticks() + diff_ticks
game_state = 1 # 游戲狀態(tài)1.表示正常 2.表示失敗
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if event.type == KEYDOWN:
if event.key == K_LEFT: main_panel.control_block(-1,0)
if event.key == K_RIGHT: main_panel.control_block(1,0)
if event.key == K_UP: main_panel.change_block()
if event.key == K_DOWN: main_panel.control_block(0,1)
if event.key == K_SPACE:
flag = main_panel.move_block()
while flag==1:
flag = main_panel.move_block()
if flag == 9: game_state = 2
screen.fill((100,100,100)) # 將界面設(shè)置為灰色
main_panel.paint() # 主面盤繪制
hint_box.paint() # 繪制下一個(gè)方塊的提示窗
score_box.paint() # 繪制總分
if game_state == 2:
myfont = pygame.font.Font(None,30)
white = 255,255,255
textImage = myfont.render("Game over", True, white)
screen.blit(textImage, (160,190))
pygame.display.update() # 必須調(diào)用update才能看到繪圖顯示
if game_state == 1 and pygame.time.get_ticks() >= ticks:
ticks+=diff_ticks
if main_panel.move_block()==9: game_state = 2 # 游戲結(jié)束
run()
也許有人會(huì)想右下角空那么大一塊是做什么用的?
那塊區(qū)域我是準(zhǔn)備做對(duì)戰(zhàn)顯示用的,這里基礎(chǔ)篇差不多算收尾了,下一篇準(zhǔn)備寫AI篇。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
- pygame實(shí)現(xiàn)俄羅斯方塊游戲(對(duì)戰(zhàn)篇1)
- pygame實(shí)現(xiàn)俄羅斯方塊游戲(AI篇2)
- pygame實(shí)現(xiàn)俄羅斯方塊游戲(AI篇1)
- pygame實(shí)現(xiàn)俄羅斯方塊游戲(基礎(chǔ)篇2)
- pygame實(shí)現(xiàn)俄羅斯方塊游戲(基礎(chǔ)篇1)
- pygame實(shí)現(xiàn)俄羅斯方塊游戲
- python和pygame實(shí)現(xiàn)簡(jiǎn)單俄羅斯方塊游戲
- Python使用pygame模塊編寫俄羅斯方塊游戲的代碼實(shí)例
- pygame庫實(shí)現(xiàn)俄羅斯方塊小游戲
相關(guān)文章
python?Copula?實(shí)現(xiàn)繪制散點(diǎn)模型
這篇文章主要介紹了python?Copula實(shí)現(xiàn)繪制散點(diǎn)模型,文章圍繞主題展開詳細(xì)的內(nèi)容介紹,具有一定的參考價(jià)值,需要的朋友可以參考一下2022-07-07
利用Python內(nèi)置庫實(shí)現(xiàn)創(chuàng)建命令行應(yīng)用程序
Python?有一個(gè)叫做argparse的內(nèi)置庫,可以用它來創(chuàng)建一個(gè)命令行界面。本文將詳解如何利用argparse實(shí)現(xiàn)創(chuàng)建一個(gè)命令行應(yīng)用程序,需要的可以參考一下2022-06-06
python利用winreg生成桌面路徑及實(shí)現(xiàn)掃描二維碼圖片返回相關(guān)信息
這篇文章主要介紹了python生成桌面路徑及實(shí)現(xiàn)掃描二維碼圖片返回相關(guān)信息,winreg是python的一個(gè)標(biāo)準(zhǔn)庫,用來對(duì)windows注冊(cè)表的操作,更多相關(guān)內(nèi)容需要的小伙伴可以參考一下2022-06-06
Python中的Request請(qǐng)求重試機(jī)制
這篇文章主要介紹了Python中的Request請(qǐng)求重試機(jī)制,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-06-06
Python全局變量與global關(guān)鍵字常見錯(cuò)誤解決方案
這篇文章主要介紹了Python全局變量與global關(guān)鍵字常見錯(cuò)誤解決方案,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10
python和shell監(jiān)控linux服務(wù)器的詳細(xì)代碼
這篇文章主要為大家介紹了使用python和shell監(jiān)控linux服務(wù)器的詳細(xì)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06
python?包實(shí)現(xiàn)?urllib?網(wǎng)絡(luò)請(qǐng)求操作
這篇文章主要介紹了python包實(shí)現(xiàn)urllib網(wǎng)絡(luò)請(qǐng)求操作,urllib?是?Python?標(biāo)準(zhǔn)庫中用于網(wǎng)絡(luò)請(qǐng)求的庫,下面urllib的相關(guān)資料介紹,需要的小伙伴可以參考一下2022-04-04

