俄罗斯方块游戏
1.python代码实现
import sys
import random,copy
import pygame as pg
from pygame.locals import *
EMPTY_CELL=0
FALLING_BLOCK=1
STATIC_BLOCK=2
defaultFont=None
screen=None
backSurface=None
score=0
clearLineScore=0
level=1
clock=None
nowBlock=None
nextBlock=None
fallSpeed=10
beginFallSpeed=fallSpeed
speedBuff=0
keyBuff=None
maxBlockWidth=10
maxBlockHeight=18
blockWidth=30
blockHeight=30
blocks=[]
stage=[]
gameOver=False
pause=False
def printTxt(content,x,y,font,screen,color=(255,255,255)):
imgTxt=font.render(content,True,color)
screen.blit(imgTxt,(x,y))
class point(object):
def __init__(self,x,y):
self.__x=x
self.__y=y
def getx(self):
return self.__x
def setx(self,x):
self.__x=x
x=property(getx,setx)
def gety(self):
return self.__y
def sety(self,y):
self.__y=y
y=property(gety,sety)
def __str__(self):
return "{x:"+"{:.0f}".format(self.__x)+",y:"+"{:.0f}".format(self.__y)+"}"
class blockSprite(object):
def __init__(self,shape,direction,xy):
self.shape=shape
self.direction=direction
self.xy=xy
def chgDirection(self,direction):
dirNumb=len(blocks[self.shape])-1
if direction==1:
self.direction+=1
if self.direction>dirNumb:
self.direction=0
else:
self.direction-=1
if self.direction<0:
self.direction=dirNumb
def clone(self):
return blockSprite(self.shape,self.direction,point(self.xy.x,self.xy.y))
def _getBlock(self):
return blocks[self.shape][self.direction]
block = property(_getBlock)
def getConf(fileName):
global blocks
with open(fileName,'rt') as fp:
for temp in fp.readlines():
blocks.append([])
blocksNumb=len(blocks)-1
blocks[blocksNumb]=[]
blocks[blocksNumb].append([])
row=temp.split(";")
for r in range(len(row)):
col=[]
ct=row[r].split(",")
for c in range(len(ct)):
if ct[c]!="1":
col.append(0)
else:
col.append(1)
for c in range(len(ct)-1,3):
col.append(0)
blocks[blocksNumb][0].append(col)
for r in range(len(row)-1,3):
blocks[blocksNumb][0].append([0,0,0,0])
blocks[blocksNumb][0]=formatBlock(blocks[blocksNumb][0])
def sysInit():
global defaultFont,screen,backSurface,clock,blocks,stage,gameOver,fallSpeed,beginFallSpeed,nowBlock,nextBlock,score,level,clearLineScore,pause
pg.init()
screen=pg.display.set_mode((500,550))
backSurface=pg.Surface((screen.get_rect().width,screen.get_rect().height))
pg.display.set_caption("block")
clock=pg.time.Clock()
pg.mouse.set_visible(False)
defaultFont=pg.font.Font("res/font/yh.ttf",16)
nowBlock=None
nextBlock=None
gameOver=False
pause=False
score=0
level=1
clearLineScore=0
beginFallSpeed=20
fallSpeed=beginFallSpeed-level*2
stage=[]
for y in range(maxBlockHeight):
stage.append([])
for x in range(maxBlockWidth):
stage[y].append(EMPTY_CELL)
for x in range(len(blocks)):
if len(blocks[x])<2:
t=blocks[x][0]
for i in range(3):
t=transform(t,1)
blocks[x].append(formatBlock(t))
def transform(block,direction=0):
result=[]
for y in range(4):
result.append([])
for x in range(4):
if direction==0:
result[y].append(block[x][3-y])
else:
result[y].append(block[3-x][y])
return result
def removeTopBlank(block):
result=copy.deepcopy(block)
blankNumb=0
while sum(result[0])<1 and blankNumb<4:
del result[0]
result.append([0,0,0,0])
blankNumb+=1
return result
def formatBlock(block):
result=removeTopBlank(block)
result=transform(result, 1)
result=removeTopBlank(result)
result=transform(result,0)
return result
def checkDeany(sprite):
topX=sprite.xy.x
topY=sprite.xy.y
for y in range(len(sprite.block)):
for x in range(len(sprite.block[y])):
if sprite.block[y][x]==1:
yInStage=topY+y
xInStage=topX+x
if yInStage>maxBlockHeight-1 or yInStage<0:
return True
if xInStage>maxBlockWidth-1 or xInStage<0:
return True
if stage[yInStage][xInStage]==STATIC_BLOCK:
return True
return False
def checkLine():
global stage
clearCount=0
tmpStage=[]
for y in stage:
if sum(y)>=maxBlockWidth*2:
tmpStage.insert(0,maxBlockWidth*[0])
clearCount+=1
else:
tmpStage.append(y)
if clearCount>0:
stage=tmpStage
updateScore(clearCount)
return clearCount
def updateStage(sprite,updateType=1):
global stage
topX=sprite.xy.x
topY=sprite.xy.y
for y in range(len(sprite.block)):
for x in range(len(sprite.block[y])):
if sprite.block[y][x]==1:
if updateType==0:
if stage[topY+y][topX+x]==FALLING_BLOCK:
stage[topY+y][topX+x]=EMPTY_CELL
elif updateType==1:
if stage[topY+y][topX+x]==EMPTY_CELL:
stage[topY+y][topX+x]=FALLING_BLOCK
else:
stage[topY+y][topX+x]=STATIC_BLOCK
def updateScore(clearCount):
global score,fallSpeed,level,clearLineScore
prizePoint=0
if clearCount>1:
if clearCount<4:
prizePoint=clearCount**clearCount
else:
prizePoint=clearCount*5
score+=(clearCount+prizePoint)*level
if score>99999999:
score=0
clearLineScore+=clearCount
if clearLineScore>100:
clearLineScore=0
level+=1
if level>(beginFallSpeed/2):
level=1
fallSpeed=beginFallSpeed
fallSpeed=beginFallSpeed-level*2
return score
def drawStage(drawScreen):
staticColor=30,102,76
activeColor=255,239,0
fontColor=200,10,120
baseRect=0,0,blockWidth*maxBlockWidth+1,blockHeight*maxBlockHeight+1
drawScreen.fill((180,200,170))
pg.draw.rect(drawScreen, staticColor, baseRect,1)
for y in range(len(stage)):
for x in range(len(stage[y])):
baseRect=x*blockWidth,y*blockHeight,blockWidth,blockHeight
if stage[y][x]==2:
pg.draw.rect(drawScreen, staticColor, baseRect)
elif stage[y][x]==1:
pg.draw.rect(drawScreen, activeColor, baseRect)
printTxt("Next:",320,350,defaultFont,backSurface,fontColor)
if nextBlock!=None:
for y in range(len(nextBlock.block)):
for x in range(len(nextBlock.block[y])):
baseRect=320+x*blockWidth,380+y*blockHeight,blockWidth,blockHeight
if nextBlock.block[y][x]==1:
pg.draw.rect(drawScreen, activeColor, baseRect)
printTxt("Level:%d" % level,320,40,defaultFont,backSurface,fontColor)
printTxt("Score:%d" % score,320,70,defaultFont,backSurface,fontColor)
printTxt("Clear:%d" % clearLineScore,320,100,defaultFont,backSurface,fontColor)
if gameOver:
printTxt("GAME OVER",230,200,defaultFont,backSurface,fontColor)
printTxt("<PRESS RETURN TO REPLAY>",200,260,defaultFont,backSurface,fontColor)
if pause:
printTxt("Game pausing",230,200,defaultFont,backSurface,fontColor)
printTxt("<PRESS RETURN TO CONTINUE>",200,260,defaultFont,backSurface,fontColor)
def process():
global gameOver,nowBlock,nextBlock,speedBuff,backSurface,keyBuff,pause
if nextBlock is None:
nextBlock=blockSprite(random.randint(0,len(blocks)-1),random.randint(0,3),point(maxBlockWidth+4,maxBlockHeight))
if nowBlock is None:
nowBlock=nextBlock.clone()
nowBlock.xy=point(maxBlockWidth//2,0)
nextBlock=blockSprite(random.randint(0,len(blocks)-1),random.randint(0,3),point(maxBlockWidth+4,maxBlockHeight))
gameOver=checkDeany(nowBlock)
if gameOver:
updateStage(nowBlock,2)
tmpBlock=nowBlock.clone()
for event in pg.event.get():
if event.type== pg.QUIT:
sys.exit()
pg.quit()
elif event.type==pg.KEYDOWN:
if event.key==pg.K_ESCAPE:
sys.exit()
pg.quit()
elif event.key==pg.K_RETURN:
if gameOver:
sysInit()
return
elif pause:
pause=False
else:
pause=True
return
elif not gameOver and not pause:
if event.key==pg.K_SPACE:
tmpBlock.chgDirection(1)
elif event.key==pg.K_UP:
tmpBlock.chgDirection(0)
if not gameOver and not pause:
keys=pg.key.get_pressed()
if keys[K_DOWN]:
tmpBlock.xy=point(tmpBlock.xy.x,tmpBlock.xy.y+1)
keyBuff=None
elif keys[K_LEFT]:
if keyBuff!=pg.K_LEFT:
tmpBlock.xy=point(tmpBlock.xy.x-1,tmpBlock.xy.y)
keyBuff=pg.K_LEFT
else:
keyBuff=None
elif keys[K_RIGHT]:
if keyBuff!=pg.K_RIGHT:
tmpBlock.xy=point(tmpBlock.xy.x+1,tmpBlock.xy.y)
keyBuff=pg.K_RIGHT
else:
keyBuff=None
if not checkDeany(tmpBlock):
updateStage(nowBlock,0)
nowBlock=tmpBlock.clone()
speedBuff+=1
if speedBuff>=fallSpeed:
speedBuff=0
tmpBlock=nowBlock.clone()
tmpBlock.xy=point(nowBlock.xy.x,nowBlock.xy.y+1)
if not checkDeany(tmpBlock):
updateStage(nowBlock,0)
nowBlock=tmpBlock.clone()
updateStage(nowBlock,1)
else:
updateStage(nowBlock,2)
checkLine()
nowBlock=None
else:
updateStage(nowBlock,1)
drawStage(backSurface)
screen.blit(backSurface,(0,0))
pg.display.update()
clock.tick(40)
def main():
sysInit()
while True:
process()
if __name__ == "__main__":
main()
源代码出自https://www.cnblogs.com/lykyl/p/5946102.html
在此基础上进行了一些细节上的小优化,让游戏体验感更好一点。
2.
![](https://img2020.cnblogs.com/blog/2166610/202011/2166610-20201129220256320-900992373.jpg)