1. 程式人生 > 程式設計 >pygame實現俄羅斯方塊遊戲(基礎篇1)

pygame實現俄羅斯方塊遊戲(基礎篇1)

本文例項為大家分享了pygame實現俄羅斯方塊遊戲的具體程式碼,基礎的第一篇,供大家參考,具體內容如下

一、初始介面

之前的遊戲都比較簡單,所以程式碼都是面向過程的寫法,這次遊戲後面可能會寫比較複雜(比如人機對戰、聯機對戰、使用道具對戰等),這次面向物件一點來寫這個專案。

遊戲的視窗設計一個專門的Panel類便於負責單個遊戲視窗的管理控制。
遊戲主視窗按每個方塊30畫素,那麼寬3010=300,高是3020=600

# -*- coding=utf-8 -*-
import random
import pygame
class Panel(object): # 用於繪製整個遊戲視窗的版面
 def __init__(self,bg,position):
 self._bg=bg;
 self._x,self._y,self._width,self._height=position
 self._bgcolor=[0,0]
 
 def paint(self):
 mid_x=self._x+self._width/2
 pygame.draw.line(self._bg,self._bgcolor,[mid_x,self._y],self._y+self._height],self._width)
def run():
 pygame.init()
 space=40
 main_panel_width=300
 main_panel_height=main_panel_width*2
 screencaption = pygame.display.set_caption('Tetris')
 screen = pygame.display.set_mode((main_panel_width+160+space*3,main_panel_height+space*2)) #設定視窗長寬
 main_panel=Panel(screen,[space,space,main_panel_width,main_panel_height])
 while True:
 for event in pygame.event.get():
  if event.type == pygame.QUIT:
   pygame.quit()
   exit()
 
 screen.fill((100,100,100)) # 將介面設定為灰色
 main_panel.paint() # 主面盤繪製
 pygame.display.update() # 必須呼叫update才能看到繪圖顯示
run()

效果圖

二、方塊管理

這裡首先想到方塊不同種類的可以使用工廠模式,所以先定義一個基類的Block,然後不同種類的方塊分別繼承自這個Block類,分別有這樣七種方塊

class Block(object):
 def __init__(self):
 self.rect_arr=[]

 def get_rect_arr(self): # 用於獲取方塊種的四個矩形列表
 return self.rect_arr

 def move(self,xdiff,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

class LongBlock(Block):
 def __init__(self,n=None): # 兩種形態
 super(LongBlock,self).__init__()
 if n is None: n=random.randint(0,1)
 self.rect_arr=[(1,0),(1,1),2),3)] if n==0 else [(0,(2,(3,2)]

class SquareBlock(Block): # 一種形態
 def __init__(self,n=None):
 super(SquareBlock,self).__init__()
 self.rect_arr=[(1,2)]


class ZBlock(Block): # 兩種形態
 def __init__(self,n=None):
 super(ZBlock,1)
 self.rect_arr=[(2,2)] if n==0 else [(0,2)]

class SBlock(Block): # 兩種形態
 def __init__(self,n=None):
 super(SBlock,1)]

class LBlock(Block): # 四種形態
 def __init__(self,n=None):
 super(LBlock,3)
 if n==0: self.rect_arr=[(1,2)]
 elif n==1: self.rect_arr=[(0,(0,2)]
 elif n==2: self.rect_arr=[(0,2)]
 else: self.rect_arr=[(0,0)]

class JBlock(Block): # 四種形態
 def __init__(self,n=None):
 super(JBlock,0)]
 elif n==2: self.rect_arr=[(2,2)]

class TBlock(Block): # 四種形態
 def __init__(self,n=None):
 super(TBlock,3)
 if n==0: self.rect_arr=[(0,2)]
 elif n==1: self.rect_arr=[(1,1)]
 elif n==2: self.rect_arr=[(0,0)]
 else: self.rect_arr=[(1,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)

給Panel類加一下當前移動方塊的屬性,並且修改它的paint方法,將移動方塊繪製

class Panel(object): # 用於繪製整個遊戲視窗的版面
 moving_block=None # 正在落下的方塊
 def __init__(self,block_size,position):
  self._bg=bg;
  self._x,self._height=position
  self._block_size=block_size
  self._bgcolor=[0,0]
  
 def create_move_block(self):
  block = create_block()
  block.move(5-2,-2) # 方塊挪到中間 
  self.moving_block=block

 def move_block(self):
  self.moving_block.move(0,1)

 def paint(self):
  mid_x=self._x+self._width/2
  pygame.draw.line(self._bg,self._width) # 用一個粗線段來填充背景
  
  # 繪製正在落下的方塊
  if self.move_block:
   for rect in self.moving_block.get_rect_arr():
    x,y=rect
    pygame.draw.line(self._bg,[0,255],[self._x+x*bz+bz/2,self._y+y*bz],self._y+(y+1)*bz],bz)
    pygame.draw.rect(self._bg,[255,255,[self._x+x*bz,self._y+y*bz,bz,bz],1)

主迴圈中建立方塊並將方塊調整到下落的起始位置

main_panel.create_move_block()

設定位置重新整理時間

diff_ticks = 300 # 移動一次蛇頭的事件,單位毫秒
 ticks = pygame.time.get_ticks() + diff_ticks

在主迴圈中重新整理當前移動方塊的位置

if pygame.time.get_ticks() >= ticks:
 ticks+=diff_ticks
 main_panel.move_block()

當前可以看到方塊下落的效果了

四、方塊落地的判斷

在Block類裡增加一個移動判斷函式,下面這個這個can_move函式可以判斷方塊是不是落到底部了

def can_move(self,ydiff):
  for x,y in self.rect_arr:
   if y+ydiff>=20: return False
  return True

修改Panel的move函式,改為

def move_block(self):
  if self.moving_block is None: create_move_block()
  if self.moving_block.can_move(0,1): 
   self.moving_block.move(0,1)
  else:
   self.add_block(self.moving_block)
   self.create_move_block()

這裡增加了一個add_block函式,用於將已經落地的方塊存起來,所以Panel另外做了三處改動

1.增加一個存已落下方塊的陣列變數

rect_arr=[] # 已經落底下的方塊

2.定義add_block函式

def add_block(self,block):
  for rect in block.get_rect_arr():
   self.rect_arr.append(rect)

3.在paint裡進行self.rect_arr的繪製

# 繪製已經落底下的方塊
bz=self._block_size
 for rect in self.rect_arr:
 x,y=rect
 pygame.draw.line(self._bg,bz)
 pygame.draw.rect(self._bg,1)

現在可以看到方塊會落到底部,然後新的方塊落下了

貼下目前的完整程式

# -*- coding=utf-8 -*-
import random
import pygame

class Panel(object): # 用於繪製整個遊戲視窗的版面
 rect_arr=[] # 已經落底下的方塊
 moving_block=None # 正在落下的方塊
 def __init__(self,0]
 
 def add_block(self,block):
  for rect in block.get_rect_arr():
   self.rect_arr.append(rect)

 def create_move_block(self):
  block = create_block()
  block.move(5-2,-2) # 方塊挪到中間 
  self.moving_block=block

 def move_block(self):
  if self.moving_block is None: create_move_block()
  if self.moving_block.can_move(0,1)
  else:
   self.add_block(self.moving_block)
   self.create_move_block()

 def paint(self):
  mid_x=self._x+self._width/2
  pygame.draw.line(self._bg,self._width) # 用一個粗線段來填充背景
  
  # 繪製已經落底下的方塊
  bz=self._block_size
  for rect in self.rect_arr:
   x,y=rect
   pygame.draw.line(self._bg,bz)
   pygame.draw.rect(self._bg,1)
  
  # 繪製正在落下的方塊
  if self.move_block:
   for rect in self.moving_block.get_rect_arr():
    x,1)


class Block(object):
 def __init__(self):
  self.rect_arr=[]

 def get_rect_arr(self): # 用於獲取方塊種的四個矩形列表
  return self.rect_arr

 def move(self,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,y in self.rect_arr:
   if y+ydiff>=20: return False
  return True

class LongBlock(Block):
 def __init__(self,n=None): # 兩種形態
  super(LongBlock,self).__init__()
  if n is None: n=random.randint(0,1)
  self.rect_arr=[(1,n=None):
  super(SquareBlock,self).__init__()
  self.rect_arr=[(1,n=None):
  super(ZBlock,1)
  self.rect_arr=[(2,n=None):
  super(SBlock,n=None):
  super(LBlock,3)
  if n==0: self.rect_arr=[(1,2)]
  elif n==1: self.rect_arr=[(0,2)]
  elif n==2: self.rect_arr=[(0,2)]
  else: self.rect_arr=[(0,n=None):
  super(JBlock,0)]
  elif n==2: self.rect_arr=[(2,n=None):
  super(TBlock,3)
  if n==0: self.rect_arr=[(0,2)]
  elif n==1: self.rect_arr=[(1,1)]
  elif n==2: self.rect_arr=[(0,0)]
  else: self.rect_arr=[(1,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_block_size,main_panel_height])

 
 main_panel.create_move_block()

 diff_ticks = 300 # 移動一次蛇頭的事件,單位毫秒
 ticks = pygame.time.get_ticks() + diff_ticks

 while True:
  for event in pygame.event.get():
    if event.type == pygame.QUIT:
     pygame.quit()
     exit()
  
  screen.fill((100,100)) # 將介面設定為灰色
  main_panel.paint() # 主面盤繪製

  pygame.display.update() # 必須呼叫update才能看到繪圖顯示

  if pygame.time.get_ticks() >= ticks:
   ticks+=diff_ticks
   main_panel.move_block()

run()

這章先寫到這,下章繼續

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。