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 相关文章推荐
浅谈编码,解码,乱码的问题
Dec 30 Python
python实现读取并显示图片的两种方法
Jan 13 Python
Python代码缩进和测试模块示例详解
May 07 Python
python 猴子补丁(monkey patch)
Jun 26 Python
python requests使用socks5的例子
Jul 25 Python
python读取Excel表格文件的方法
Sep 02 Python
python给指定csv表格中的联系人群发邮件(带附件的邮件)
Dec 31 Python
python GUI库图形界面开发之PyQt5图片显示控件QPixmap详细使用方法与实例
Feb 27 Python
基于Tensorflow的MNIST手写数字识别分类
Jun 17 Python
python json.dumps() json.dump()的区别详解
Jul 14 Python
Python3安装模块报错Microsoft Visual C++ 14.0 is required的解决方法
Jul 28 Python
python3.8动态人脸识别的实现示例
Sep 21 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的范围解析操作符(::)的含义分析说明
2011/07/03 PHP
解析php中heredoc的使用方法
2013/06/17 PHP
PHP函数超时处理方法
2016/02/14 PHP
javascript 火狐(firefox)不显示本地图片问题解决
2008/07/05 Javascript
JQuery与Ajax常用代码实现对比
2009/10/03 Javascript
Javascript中的this绑定介绍
2011/09/22 Javascript
如何书写高质量jQuery代码(使用jquery性能问题)
2014/06/30 Javascript
node+express+jade制作简单网站指南
2014/11/26 Javascript
Javascript中3个需要注意的运算符
2015/04/02 Javascript
js将滚动条滚动到指定位置的简单实现方法
2016/06/25 Javascript
深入浅析knockout源码分析之订阅
2016/07/12 Javascript
javascript深拷贝和浅拷贝详解
2017/02/14 Javascript
jQuery插件HighCharts绘制2D柱状图、折线图的组合双轴图效果示例【附demo源码下载】
2017/03/09 Javascript
JS实现简单拖拽效果
2017/06/21 Javascript
ECMAscript 变量作用域总结概括
2017/08/18 Javascript
使用vue制作FullPage页面滚动效果
2017/08/21 Javascript
react学习笔记之state以及setState的使用
2017/12/07 Javascript
浅谈python配置与使用OpenCV踩的一些坑
2018/04/02 Python
Python3 操作 MySQL 插入一条数据并返回主键 id的实例
2020/03/02 Python
python新手学习使用库
2020/06/11 Python
Python 中如何写注释
2020/08/28 Python
Python编写单元测试代码实例
2020/09/10 Python
python3爬虫GIL修改多线程实例讲解
2020/11/24 Python
html5应用缓存_动力节点Java学院整理
2017/07/13 HTML / CSS
Amara德国:家居饰品、设计师品牌和豪华礼品
2019/05/20 全球购物
写出一个方法实现冒泡排序
2016/07/08 面试题
董事长职责范文
2013/11/08 职场文书
会计学自我鉴定
2014/02/06 职场文书
《特殊的葬礼》教学反思
2014/04/27 职场文书
工商局领导班子存在的问题整改措施思想汇报
2014/10/05 职场文书
2015清明节祭奠英烈寄语大全
2015/03/04 职场文书
外出考察学习心得体会
2016/01/18 职场文书
创业计划书之酒店
2019/08/30 职场文书
JavaScript利用html5新方法操作元素类名详解
2021/11/27 Javascript
Python可视化学习之seaborn调色盘
2022/02/24 Python
详解Python中__new__方法的作用
2022/03/31 Python