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 相关文章推荐
使用Pyrex来扩展和加速Python程序的教程
Apr 13 Python
Ruby使用eventmachine为HTTP服务器添加文件下载功能
Apr 20 Python
详解python中requirements.txt的一切
Mar 03 Python
基于Python os模块常用命令介绍
Nov 03 Python
Pycharm导入Python包,模块的图文教程
Jun 13 Python
详解Python 协程的详细用法使用和例子
Jun 15 Python
解决python写入带有中文的字符到文件错误的问题
Jan 31 Python
通过案例解析python鸭子类型相关原理
Oct 10 Python
在pycharm中使用pipenv创建虚拟环境和安装django的详细教程
Nov 30 Python
基于Python-Pycharm实现的猴子摘桃小游戏(源代码)
Feb 20 Python
Python使用sql语句对mysql数据库多条件模糊查询的思路详解
Apr 12 Python
Python可视化动图组件ipyvizzu绘制惊艳的可视化动图
Apr 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读取数据库信息的几种方法
2008/05/24 PHP
php中可能用来加密字符串的函数[base64_encode、urlencode、sha1]
2012/01/16 PHP
PHP设计模式之调解者模式的深入解析
2013/06/13 PHP
关于php操作mysql执行数据库查询的一些常用操作汇总
2013/06/24 PHP
php微信公众开发之获取周边酒店信息的方法
2014/12/22 PHP
php实现的二分查找算法示例
2017/06/20 PHP
php反射学习之不用new方法实例化类操作示例
2019/06/14 PHP
PHP中echo与print区别点整理
2021/03/09 PHP
JavaScript中令你抓狂的魔术变量
2006/11/30 Javascript
利用onresize使得div可以随着屏幕大小而自适应的代码
2010/01/15 Javascript
jquery对单选框,多选框,文本框等常见操作小结
2014/01/08 Javascript
用Jquery.load载入页面实现局部刷新
2014/01/22 Javascript
JavaScript日期时间与时间戳的转换函数分享
2015/01/31 Javascript
javascript字符串函数汇总
2015/12/06 Javascript
分享一个原生的JavaScript拖动方法
2016/09/25 Javascript
nodejs操作mysql实现增删改查的实例
2017/05/28 NodeJs
对存在JavaScript隐式类型转换的四种情况的总结(必看篇)
2017/08/31 Javascript
JavaScript实现AOP详解(面向切面编程,装饰者模式)
2017/12/19 Javascript
vue数据操作之点击事件实现num加减功能示例
2019/01/19 Javascript
详解javascript 变量提升(Hoisting)
2019/03/12 Javascript
vue项目中运用webpack动态配置打包多种环境域名的方法
2019/06/24 Javascript
JavaScript中this的学习笔记及用法整理
2020/02/17 Javascript
关于vue 项目中浏览器跨域的配置问题
2020/11/10 Javascript
python实现简单温度转换的方法
2015/03/13 Python
Python实现简单的HttpServer服务器示例
2017/09/25 Python
flask 框架操作MySQL数据库简单示例
2020/02/02 Python
Python3和PyCharm安装与环境配置【图文教程】
2020/02/14 Python
python实现拼接图片
2020/03/23 Python
如何在windows下安装配置python工具Ulipad
2020/10/27 Python
Python爬取酷狗MP3音频的步骤
2021/02/26 Python
HTML5时代CSS设置漂亮字体取代图片
2014/09/04 HTML / CSS
美国在线医疗分销商:MedEx Supply
2020/02/04 全球购物
硕士研究生自我鉴定
2013/11/08 职场文书
表彰大会主持词
2014/03/26 职场文书
演讲比赛主持词
2015/06/29 职场文书
JavaScript实现栈结构详细过程
2021/12/06 Javascript