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操作mysql中文显示乱码的解决方法
Oct 11 Python
用Python进行一些简单的自然语言处理的教程
Mar 31 Python
Python获取某一天是星期几的方法示例
Jan 17 Python
简单了解什么是神经网络
Dec 23 Python
Tensorflow 训练自己的数据集将数据直接导入到内存
Jun 19 Python
Python3获取电脑IP、主机名、Mac地址的方法示例
Apr 11 Python
python 搜索大文件的实例代码
Jul 08 Python
Python代码使用 Pyftpdlib实现FTP服务器功能
Jul 22 Python
python 设置xlabel,ylabel 坐标轴字体大小,字体类型
Jul 23 Python
pytorch中的自定义数据处理详解
Jan 06 Python
python实现的Iou与Giou代码
Jan 18 Python
Python使用Pyqt5实现简易浏览器(最新版本测试过)
Apr 27 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
一个图形显示IP的PHP程序代码
2007/10/19 PHP
优化网页之快速的呈现我们的网页
2007/06/29 Javascript
菜鸟javascript基础资料整理2
2010/12/06 Javascript
cookie中的path与domain属性详解
2013/12/18 Javascript
采用call方式实现js继承
2014/05/20 Javascript
jQuery实现Meizu魅族官方网站的导航菜单效果
2015/09/14 Javascript
基于JavaScript实现百叶窗动画效果不只单纯flas可以实现
2016/02/29 Javascript
javascript断点调试心得分享
2016/04/23 Javascript
总结JavaScript设计模式编程中的享元模式使用
2016/05/21 Javascript
javascript正则表达式之分组概念与用法实例
2016/06/16 Javascript
JS实现类似百叶窗下拉菜单效果
2016/12/30 Javascript
关于JS与jQuery中的文档加载问题
2017/08/22 jQuery
什么是Vue.js框架 为什么选择它?
2017/10/17 Javascript
vue3.0 搭建项目总结(详细步骤)
2019/05/20 Javascript
Vue-CLI与Vuex使用方法实例分析
2020/01/06 Javascript
Python数据分析中Groupby用法之通过字典或Series进行分组的实例
2017/12/08 Python
python创建列表和向列表添加元素的实现方法
2017/12/25 Python
Python中getpass模块无回显输入源码解析
2018/01/11 Python
python如何定义带参数的装饰器
2018/03/20 Python
Pytorch入门之mnist分类实例
2018/04/14 Python
Python3.6实现连接mysql或mariadb的方法分析
2018/05/18 Python
对tf.reduce_sum tensorflow维度上的操作详解
2018/07/26 Python
对python遍历文件夹中的所有jpg文件的实例详解
2018/12/08 Python
Python之指数与E记法的区别详解
2019/11/21 Python
python3.x 生成3维随机数组实例
2019/11/28 Python
在 Python 中接管键盘中断信号的实现方法
2020/02/04 Python
django实现HttpResponse返回json数据为中文
2020/03/27 Python
Python 利用OpenCV给照片换底色的示例代码
2020/08/03 Python
如何向scrapy中的spider传递参数的几种方法
2020/11/18 Python
uniapp+Html5端实现PC端适配
2020/07/15 HTML / CSS
物流管理专业求职信
2014/05/29 职场文书
优秀教师申报材料
2014/12/16 职场文书
店铺转让协议书
2015/01/29 职场文书
清明节扫墓活动总结
2015/02/09 职场文书
刑事附带民事代理词
2015/05/25 职场文书
八年级作文之我的母亲
2019/12/10 职场文书