pygame实现俄罗斯方块游戏(基础篇1)


Posted in Python onOctober 29, 2019

本文实例为大家分享了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,0]
 
 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)
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()

效果图

pygame实现俄罗斯方块游戏(基础篇1)

二、方块管理

这里首先想到方块不同种类的可以使用工厂模式,所以先定义一个基类的Block,然后不同种类的方块分别继承自这个Block类,分别有这样七种方块

pygame实现俄罗斯方块游戏(基础篇1)

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),(1,2),(1,3)] if n==0 else [(0,2),(1,2),(2,2),(3,2)]

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


class ZBlock(Block): # 两种形态
 def __init__(self, n=None):
 super(ZBlock, self).__init__()
 if n is None: n=random.randint(0,1)
 self.rect_arr=[(2,0),(2,1),(1,1),(1,2)] if n==0 else [(0,1),(1,1),(1,2),(2,2)]

class SBlock(Block): # 两种形态
 def __init__(self, n=None):
 super(SBlock, self).__init__()
 if n is None: n=random.randint(0,1)
 self.rect_arr=[(1,0),(1,1),(2,1),(2,2)] if n==0 else [(0,2),(1,2),(1,1),(2,1)]

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

class JBlock(Block): # 四种形态
 def __init__(self, n=None):
 super(JBlock, self).__init__()
 if n is None: n=random.randint(0,3)
 if n==0: self.rect_arr=[(1,0),(1,1),(1,2),(0,2)]
 elif n==1: self.rect_arr=[(0,1),(1,1),(2,1),(0,0)]
 elif n==2: self.rect_arr=[(2,0),(1,0),(1,1),(1,2)]
 else: self.rect_arr=[(0,1),(1,1),(2,1),(2,2)]

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

给Panel类加一下当前移动方块的属性,并且修改它的paint方法,将移动方块绘制

class Panel(object): # 用于绘制整个游戏窗口的版面
 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 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._bgcolor,[mid_x,self._y],[mid_x,self._y+self._height],self._width) # 用一个粗线段来填充背景
 
 # 绘制正在落下的方块
 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,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()

当前可以看到方块下落的效果了

pygame实现俄罗斯方块游戏(基础篇1)

四、方块落地的判断

在Block类里增加一个移动判断函数,下面这个这个can_move函数可以判断方块是不是落到底部了

def can_move(self,xdiff,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,[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,bz],1)

现在可以看到方块会落到底部,然后新的方块落下了

pygame实现俄罗斯方块游戏(基础篇1)

贴下目前的完整程序

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

class Panel(object): # 用于绘制整个游戏窗口的版面
 rect_arr=[] # 已经落底下的方块
 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 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): 
  self.moving_block.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._bgcolor,[mid_x,self._y],[mid_x,self._y+self._height],self._width) # 用一个粗线段来填充背景
 
 # 绘制已经落底下的方块
 bz=self._block_size
 for rect in self.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,bz],1)
 
 # 绘制正在落下的方块
 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,bz],1)


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

 def can_move(self,xdiff,ydiff):
 for x,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,0),(1,1),(1,2),(1,3)] if n==0 else [(0,2),(1,2),(2,2),(3,2)]

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


class ZBlock(Block): # 两种形态
 def __init__(self, n=None):
 super(ZBlock, self).__init__()
 if n is None: n=random.randint(0,1)
 self.rect_arr=[(2,0),(2,1),(1,1),(1,2)] if n==0 else [(0,1),(1,1),(1,2),(2,2)]

class SBlock(Block): # 两种形态
 def __init__(self, n=None):
 super(SBlock, self).__init__()
 if n is None: n=random.randint(0,1)
 self.rect_arr=[(1,0),(1,1),(2,1),(2,2)] if n==0 else [(0,2),(1,2),(1,1),(2,1)]

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

class JBlock(Block): # 四种形态
 def __init__(self, n=None):
 super(JBlock, self).__init__()
 if n is None: n=random.randint(0,3)
 if n==0: self.rect_arr=[(1,0),(1,1),(1,2),(0,2)]
 elif n==1: self.rect_arr=[(0,1),(1,1),(2,1),(0,0)]
 elif n==2: self.rect_arr=[(2,0),(1,0),(1,1),(1,2)]
 else: self.rect_arr=[(0,1),(1,1),(2,1),(2,2)]

class TBlock(Block): # 四种形态
 def __init__(self, n=None):
 super(TBlock, self).__init__()
 if n is None: n=random.randint(0,3)
 if n==0: self.rect_arr=[(0,1),(1,1),(2,1),(1,2)]
 elif n==1: self.rect_arr=[(1,0),(1,1),(1,2),(0,1)]
 elif n==2: self.rect_arr=[(0,1),(1,1),(2,1),(1,0)]
 else: self.rect_arr=[(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)) #设置窗口长宽
 main_panel=Panel(screen,main_block_size,[space,space,main_panel_width,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,100)) # 将界面设置为灰色
 main_panel.paint() # 主面盘绘制

 pygame.display.update() # 必须调用update才能看到绘图显示

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

run()

这章先写到这,下章继续

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
python paramiko实现ssh远程访问的方法
Dec 03 Python
Python中if __name__ == &quot;__main__&quot;详细解释
Oct 21 Python
python 计算数组中每个数字出现多少次--“Bucket”桶的思想
Dec 19 Python
利用python将json数据转换为csv格式的方法
Mar 22 Python
基于Python批量生成指定尺寸缩略图代码实例
Nov 20 Python
python中设置超时跳过,超时退出的方式
Dec 13 Python
django xadmin action兼容自定义model权限教程
Mar 30 Python
Python如何实现线程间通信
Jul 30 Python
pandas取dataframe特定行列的实现方法
May 24 Python
Python集合set()使用的方法详解
Mar 18 Python
Python中三种花式打印的示例详解
Mar 19 Python
Python+Tkinter制作专属图形化界面
Apr 01 Python
pygame实现五子棋游戏
Oct 29 #Python
python多线程案例之多任务copy文件完整实例
Oct 29 #Python
jenkins配置python脚本定时任务过程图解
Oct 29 #Python
pygame实现成语填空游戏
Oct 29 #Python
Python多线程及其基本使用方法实例分析
Oct 29 #Python
基于python的itchat库实现微信聊天机器人(推荐)
Oct 29 #Python
pygame实现非图片按钮效果
Oct 29 #Python
You might like
php strlen mb_strlen计算中英文混排字符串长度
2009/07/10 PHP
PHP判断远程图片或文件是否存在的实现代码
2014/02/20 PHP
PHP 面向对象程序设计(oop)学习笔记(三) - 单例模式和工厂模式
2014/06/12 PHP
php写入、删除与复制文件的方法
2015/06/20 PHP
微信公众号判断用户是否已关注php代码解析
2016/06/24 PHP
利用Laravel生成Gravatar头像地址的优雅方法
2017/12/30 PHP
PHP获取星期几的常用方法小结
2018/12/18 PHP
document 和 document.all 分别什么时候用
2006/06/22 Javascript
(JS实现)MapBar中坐标的加密和解密的脚本
2007/05/16 Javascript
jQuery第三课 修改元素属性及内容的代码
2010/03/14 Javascript
JavaScript 学习笔记二 字符串拼接
2010/03/28 Javascript
Jquery 表单验证类介绍与实例
2013/06/09 Javascript
jquery插件推荐 jquery.cookie
2014/11/09 Javascript
Js 正则表达式知识汇总
2014/12/02 Javascript
使用原生JS实现弹出层特效
2014/12/22 Javascript
js实现简单的左右两边固定广告效果实例
2015/04/10 Javascript
PHP+jQuery实现随意拖动层并即时保存拖动位置
2015/04/30 Javascript
JS/jQ实现免费获取手机验证码倒计时效果
2016/06/13 Javascript
javascript实现将数字转成千分位的方法小结【5种方式】
2016/12/11 Javascript
JavaScript生成.xls文件的代码
2016/12/22 Javascript
Kindeditor单独调用单图上传增加预览功能的实例
2017/07/31 Javascript
angular2路由切换改变页面title的示例代码
2017/08/23 Javascript
详解Vue 的异常处理机制
2020/11/30 Vue.js
python添加模块搜索路径和包的导入方法
2019/01/19 Python
Python底层封装实现方法详解
2020/01/22 Python
浅谈keras中Dropout在预测过程中是否仍要起作用
2020/07/09 Python
俄罗斯皮肤健康中心:Pharmacosmetica.ru
2020/02/22 全球购物
中专生职业生涯规划书范文
2014/01/10 职场文书
教堂婚礼主持词
2014/03/14 职场文书
竞选学生会主席演讲稿
2014/04/24 职场文书
优秀班主任主要事迹材料
2014/12/16 职场文书
中班下学期个人工作总结
2015/02/12 职场文书
辞职书格式样本
2015/02/26 职场文书
2015年爱牙日活动总结
2015/03/23 职场文书
2016年会领导致辞稿
2015/07/29 职场文书
python脚本框架webpy模板控制结构
2021/11/20 Python