The previous chapter was written at https://blog.csdn.net/zhangenter/article/details/89304707.
Continue now
1. Set different colors for each square.
According to the code, it can be judged that it is most appropriate to add an attribute to the falling blocks in those Block subclasses, and the most appropriate place for the color management of the falling blocks should be to modify rect_arr in the Panel class.
The modification in the Block subclass is relatively simple. Take the TBlock class as an example, add a line to the _init__function.
self.color=(255,0,0)
In Panel's paint function, the code will be
# Draw falling squares 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)
Medium
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) //Change to 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)
It's a bit more troublesome to modify the fallen square. The original rect_arr is x,y. Now it's possible to add a color and change it directly, but considering the future extensibility, it's decisive to define a RectInfo class.
class RectInfo(object): def __init__(self, x, y, color): self.x = x self.y = y self.color = color
Modify the code stored in rect_arr to
def add_block(self,block): for x,y in block.get_rect_arr(): self.rect_arr.append(RectInfo(x,y, block.color))
And the design rect_arr can be modified
Paste down the current complete code
# -*- 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): # Layout for drawing the entire game window rect_arr=[] # The bottomed square moving_block=None # Falling square 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) # Move the box to the middle 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): # Deformation does not cause overlap of squares 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 # Game failure self.create_move_block() return 2 def check_clear(self): tmp_arr = [[] for i in range(20)] # Save the box in an array by line first 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)] # Calculate rows that can be eliminated from bottom to top and record the number of downward offsets of other rows after elimination 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=[] # Skip removed rows and offset other rows 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) # Fill in the background with a thick line segment # Draw bottomed squares 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) # Draw falling squares 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): # Four Rectangular Lists for Getting Block Species return self.rect_arr def move(self,xdiff,ydiff): # A Method for Moving Blocks 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 # Next form 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: # Deformation cannot exceed left and right boundary 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): # Two forms 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): # A form 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): # Two forms 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): # Two forms 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): # Four forms 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): # Four forms 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): # Four forms 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)) #Setting window length and width 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 # Moving a snakehead event in milliseconds ticks = pygame.time.get_ticks() + diff_ticks game_state = 1 # Game Status 1. Represents Normal 2. Represents Failure 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)) # Set the interface to grey main_panel.paint() # Main panel drawing 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() # You must call update to see the drawing display if game_state == 1 and pygame.time.get_ticks() >= ticks: ticks+=diff_ticks if main_panel.move_block()==9: game_state = 2 # Game over run()
2. Next box
To facilitate the drawing of the next box's prompt window, we define a HintBox class to manage the drawing of the next box and interface.
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: # If there are no squares, create one first block = create_block() self.next_block = create_block() # Generate the next box 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 # Draw falling squares 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 # Calculate the offset pixels needed to render the block at the center of the prompt window 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)
Add an attribute to the Panel class
hint_box=None
Inside the Panel class
def create_move_block(self): block = create_block() block.move(5-2,-2) # Move the box to the middle self.moving_block=block
The way the box is generated is changed to hint_box
def create_move_block(self): block = self.hint_box.take_block() block.move(5-2,-2) # Move the box to the middle self.moving_block=block
Increase the program of initializing hint_box and setting main_panel in run function
hint_box=HintBox(screen,main_block_size,[main_panel_width+space+space,space,160,160]) main_panel.hint_box=hint_box
Add the drawing of the next cube prompt window in the main loop of the game
hint_box.paint() # Draw the next box's prompt window
Now you can display the next box prompt properly.
3. The Calculation of Scores
The method of calculating the elimination score is as follows:
1 elements and 100 points
2 elements and 300 points
3 elements and 800 points
4 elements and 1600 points
Similar to the design of the next box prompt window, we can add a ScoreBox class
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))
Then add the score_box attribute to Panel
score_box=None
Define a global SCORE_MAP
SCORE_MAP=(100,300,800,1600)
In the check_clear function, if there is a block elimination, it executes
score = SCORE_MAP[clear_num-1] self.score_box.total_score += score
Initialize score_box in run main function
score_box=ScoreBox(screen,main_block_size,[main_panel_width+space+space,160+space*2,160,160]) main_panel.score_box=score_box
And draw score_box in the game loop
score_box.paint() # Draw total score
IV. HISTORICAL HIGH SCORE
Prepare to save in the current directory with a pickle file of tetris.db
So first
import pickle,os
Since the highest score can be drawn with ScoreBox when drawing the current score, add a attribute of the highest score and a definition of a file directly to the ScoreBox.
high_score = 0 db_file = 'tetris.db'
Adding pickle load to the initialization function of CoreBox
if os.path.exists(self.db_file): self.high_score = pickle.load(open(self.db_file,'rb'))
Drawing with the highest score added to 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))
Change the previous direct modification to ScoreBox's score to encapsulate a function of add_score
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+'))
Modify the score in the add_score function and decide whether it exceeds the maximum score. If it exceeds, save the score (of course, you can also judge and save the maximum score at the end of the game or close the interface, reducing disk io)
Look at the picture.
Put down the complete procedure
# -*- 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: # If there are no squares, create one first block = create_block() self.next_block = create_block() # Generate the next box 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 # Draw falling squares 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 # Calculate the offset pixels needed to render the block at the center of the prompt window 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): # Layout for drawing the entire game window rect_arr=[] # The bottomed square moving_block=None # Falling square 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) # Move the square to the center 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): # Deformation does not cause overlap of squares 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 # Game failure self.create_move_block() return 2 def check_clear(self): tmp_arr = [[] for i in range(20)] # Save the box in an array by line first 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)] # Calculate rows that can be eliminated from bottom to top and record the number of downward offsets of other rows after elimination 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=[] # Skip removed rows and offset other rows 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) # Fill in the background with a thick line segment # Draw bottomed squares 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) # Draw falling squares 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): # Four Rectangular Lists for Getting Block Species return self.rect_arr def move(self,xdiff,ydiff): # A Method for Moving Blocks 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 # Next form 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: # Deformation cannot exceed left and right boundary 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): # Two forms 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): # A form 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): # Two forms 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): # Two forms 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): # Four forms 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): # Four forms 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): # Four forms 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)) #Setting window length and width 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 # Moving a snakehead event in milliseconds ticks = pygame.time.get_ticks() + diff_ticks game_state = 1 # Game Status 1. Represents Normal 2. Represents Failure 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)) # Set the interface to grey main_panel.paint() # Main panel drawing hint_box.paint() # Draw the next box's prompt window score_box.paint() # Draw total score 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() # You must call update to see the drawing display if game_state == 1 and pygame.time.get_ticks() >= ticks: ticks+=diff_ticks if main_panel.move_block()==9: game_state = 2 # Game over run()
Maybe someone would wonder what the big space in the lower right corner is for?
I'm going to do battle display in that area. The basic article here is almost the end. The next one is going to write AI.