python实现俄罗斯方块

网上搜到一个Pygame写的俄罗斯方块(tetris),大部分看懂的前提下增加了注释,Fedora19下运行OK的

主程序:

#coding:utf8
#! /usr/bin/env python
# 注释说明:shape表示一个俄罗斯方块形状 cell表示一个小方块
import sys
from random import choice
import pygame
from pygame.locals import *
from block import O, I, S, Z, L, J, T

COLS = 16
ROWS = 20
CELLS = COLS * ROWS
CELLPX = 32 # 每个cell的像素宽度
POS_FIRST_APPEAR = COLS / 2
SCREEN_SIZE = (COLS * CELLPX, ROWS * CELLPX)
COLOR_BG = (0, 0, 0)

def draw(grid, pos=None):
  # grid是一个list,要么值为None,要么值为'Block'
  # 非空值在eval()的作用下,用于配置颜色
  if pos: # 6x5
    s = pos - 3 - 2 * COLS # upper left position
    for p in range(0, COLS):
      q = s + p * COLS
      for i in range(q, q + 6):
        if 0 <= i < CELLS:
          # 0 <=i < CELLS:表示i这个cell在board内部。
          c = eval(grid[i] + ".color") if grid[i] else COLOR_BG
          # 执行着色。shape的cell涂对应的class设定好的颜色,否则涂黑(背景色)
          a = i % COLS * CELLPX
          b = i / COLS * CELLPX
          screen.fill(c, (a, b, CELLPX, CELLPX))
  else: # all
    screen.fill(COLOR_BG)
    for i, occupied in enumerate(grid):
      if occupied:
        c = eval(grid[i] + ".color") # 获取方块对应的颜色
        a = i % COLS * CELLPX # 横向长度
        b = i / COLS * CELLPX # 纵向长度
        screen.fill(c, (a, b, CELLPX, CELLPX))
        # fill:为cell上色, 第二个参数表示rect
  pygame.display.flip()
  # 刷新屏幕

def phi(grid1, grid2, pos): # 4x4
# 两个grid之4*4区域内是否会相撞(冲突)
  s = pos - 2 - 1 * COLS # upper left position
  for p in range(0, 4):
    q = s + p * COLS
    for i in range(q, q + 4):
      try:
        if grid1[i] and grid2[i]:
          return False
      except:
        pass
  return True

def merge(grid1, grid2):
  # 合并两个grid
  grid = grid1[:]
  for i, c in enumerate(grid2):
    if c:
      grid[i] = c
  return grid

def complete(grid):
  # 减去满行
  n = 0
  for i in range(0, CELLS, COLS):
    # 步长为一行。
    if not None in grid[i:i + COLS]:
    #这一句很容易理解错误。
    #实际含义是:如果grid[i:i + COLS]都不是None,那么执行下面的语句
      grid = [None] * COLS + grid[:i] + grid[i + COLS:]
      n += 1
  return grid, n
#n表示减去的行数,用作统计分数

pygame.init()
pygame.event.set_blocked(None)
pygame.event.set_allowed((KEYDOWN, QUIT))
pygame.key.set_repeat(75, 0)
pygame.display.set_caption('Tetris')
screen = pygame.display.set_mode(SCREEN_SIZE)
pygame.display.update()

grid = [None] * CELLS
speed = 500
screen.fill(COLOR_BG)
while True: # spawn a block
  block = choice([O, I, S, Z, L, J, T])()
  pos = POS_FIRST_APPEAR
  if not phi(grid, block.grid(pos), pos): break # you lose
  pygame.time.set_timer(KEYDOWN, speed)
  # repeatedly create an event on the event queue
  # speed是时间间隔。。。speed越小,方块下落的速度越快。。。speed应该换为其他名字

  while True: # move the block
    draw(merge(grid, block.grid(pos)), pos)
    event = pygame.event.wait()
    if event.type == QUIT: sys.exit()
    try:
      aim = {
        K_UNKNOWN: pos+COLS,
        K_UP: pos,
        K_DOWN: pos+COLS,
        K_LEFT: pos-1,
        K_RIGHT: pos+1,
      }[event.key]
    except KeyError:
      continue
    if event.key == K_UP:
      # 变形
      block.rotate()

    elif event.key in (K_LEFT, K_RIGHT) and pos / COLS != aim / COLS:
      # pos/COLS表示当前位置所在行
      # aim/COLS表示目标位置所在行
      # 此判断表示,当shape在左边界时,不允许再向左移动(越界。。),在最右边时向右也禁止
      continue

    grid_aim = block.grid(aim)
    if grid_aim and phi(grid, grid_aim, aim):
      pos = aim
    else:
      if event.key == K_UP:
        block.rotate(times=3)
      elif not event.key in (K_LEFT, K_RIGHT):
        break

  grid = merge(grid, block.grid(pos))
  grid, n = complete(grid)
  if n:
    draw(grid)
    speed -= 5 * n
    if speed < 75: speed = 75

调用的模块:

#coding:utf-8
#! /usr/bin/env python
COLS = 16
ROWS = 20

class Block():
  color = (255,255,255)
  def __init__(self):
    self._state = 0
  def __str__(self):
    return self.__class__.__name__
  def _orientations(self):
    raise NotImplementedError()
  def rotate(self, times=1):
    for i in range(times):
      if len(self._orientations())-1 == self._state:
        self._state = 0
        #只要_state比_orientations长度-1还要小,就让_state加1

      else:
        self._state += 1
  def blades(self):
    # 返回对应形状的一种旋转形状。(返回一个list,list中每个元素是一个(x,y))
    return self._orientations()[self._state]

  def grid(self, pos, cols=COLS, rows=ROWS):
    # grid()函数:对于一个形状,从它的cell中的pos位置,按照orientations的位置提示,把所有cell涂色
    # pos表示的是shape中的一个cell,也就是(0,0)
    if cols*rows <= pos:
      return None
    # 这种情况应该不可能出现吧。如果出现<=的情况
    # 那么,pos都跑到界外了。。

    grid = [None] * cols * rows
    grid[pos] = str(self)
    for b in self.blades():
      x, y = b
      # pos/cols表示pos处于board的第几行
      if pos/cols != (pos+x)/cols:
        return None
      i = pos + x + y * cols
      if i < 0:
        continue
      elif cols*rows <= i:
        return None
      grid[i] = str(self)
      # 给相应的其他位置都“涂色”,比如对于方块,是O型的,那么pos肯定是有值的,pos位于有上角。。
    return grid

# 以下每个形状class,_orientations()都返回形状的列表。(0,0)一定被包含在其中,为了省略空间所以都没有写出.
class O(Block):
  color = (207,247,0)
  def _orientations(self):
    return (
      [(-1,0), (-1,1), (0,1)],
      )
class I(Block):
  color = (135,240,60)
  def _orientations(self):
    return (
      [(-2,0), (-1,0), (1,0)],
      [(0,-1), (0,1), (0,2)],
      )
class S(Block):
  color = (171,252,113)
  def _orientations(self):
    return (
      [(1,0), (-1,1), (0,1)],
      [(0,-1), (1,0), (1,1)],
      )
class Z(Block):
  color = (243,61,110)
  def _orientations(self):
    return (
      [(-1,0), (0,1), (1,1)],
      [(1,-1), (1,0), (0,1)],
      )
class L(Block):
  color = (253,205,217)
  def _orientations(self):
    return (
      [(-1,1), (-1,0), (1,0)],
      [(0,-1), (0,1), (1,1)],
      [(-1,0), (1,0), (1,-1)],
      [(-1,-1), (0,-1), (0,1)],
      )
class J(Block):
  color = (140,180,225)
  def _orientations(self):
    return (
      [(-1,0), (1,0), (1,1)],
      [(0,1), (0,-1), (1,-1)],
      [(-1,-1), (-1,0), (1,0)],
      [(-1,1), (0,1), (0,-1)],
      )
class T(Block):
  color = (229,251,113)
  def _orientations(self):
    return (
      [(-1,0), (0,1), (1,0)],
      [(0,-1), (0,1), (1,0)],
      [(-1,0), (0,-1), (1,0)],
      [(-1,0), (0,-1), (0,1)],
      )

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

(0)

相关推荐

  • Python小游戏之300行代码实现俄罗斯方块

    前言 本文代码基于 python3.6 和 pygame1.9.4. 俄罗斯方块是儿时最经典的游戏之一,刚开始接触 pygame 的时候就想写一个俄罗斯方块.但是想到旋转,停靠,消除等操作,感觉好像很难啊,等真正写完了发现,一共也就 300 行代码,并没有什么难的. 先来看一个游戏截图,有点丑,好吧,我没啥美术细胞,但是主体功能都实现了,可以玩起来. 现在来看一下实现的过程. 外形 俄罗斯方块整个界面分为两部分,一部分是左边的游戏区域,另一部分是右边的显示区域,显示得分.速度.下一个方块样式等.

  • pyqt5实现俄罗斯方块游戏

    本章我们要制作一个俄罗斯方块游戏. Tetris 译注:称呼:方块是由四个小方格组成的 俄罗斯方块游戏是世界上最流行的游戏之一.是由一名叫Alexey Pajitnov的俄罗斯程序员在1985年制作的,从那时起,这个游戏就风靡了各个游戏平台. 俄罗斯方块归类为下落块迷宫游戏.游戏有7个基本形状:S.Z.T.L.反向L.直线.方块,每个形状都由4个方块组成,方块最终都会落到屏幕底部.所以玩家通过控制形状的左右位置和旋转,让每个形状都以合适的位置落下,如果有一行全部被方块填充,这行就会消失,并且得分

  • pygame实现俄罗斯方块游戏

    本文实例为大家分享了pygame实现俄罗斯方块的具体代码,供大家参考,具体内容如下 import random, time, pygame, sys from pygame.locals import * FPS = 25 WINDOWWIDTH = 640#整个游戏屏幕的宽 WINDOWHEIGHT = 480#整个游戏屏幕的高 BOXSIZE = 20#每个小格子的宽和高 BOARDWIDTH = 10#游戏窗口本身有10个方块的宽度 BOARDHEIGHT = 20#游戏窗口本身有20个方

  • pyQt4实现俄罗斯方块游戏

    本文实例为大家分享了pyQt4实现俄罗斯方块游戏的具体代码,供大家参考,具体内容如下 #!/usr/bin/python # -*- coding: utf-8 -*- import sys, random from PyQt4 import QtCore, QtGui class Tetris(QtGui.QMainWindow): #Tetris的构造函数,由于是QMainWindow的子类,所以要先调用父类的构造函数 def __init__(self): super(Tetris, se

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

    接上章<pygame实现俄罗斯方块游戏(基础篇1)>继续写俄罗斯方块游戏 五.计算方块之间的碰撞 在Panel类里增加函数 def check_overlap(self, diffx, diffy): for x,y in self.moving_block.get_rect_arr(): for rx,ry in self.rect_arr: if x+diffx==rx and y+diffy==ry: return True return False 修改move_block函数的判断,

  • python和pygame实现简单俄罗斯方块游戏

    本文为大家分享了python实现俄罗斯方块游戏的具体代码,供大家参考,具体内容如下 Github:Tetris 代码: # -*- coding:utf-8 -*- import pygame, sys, random, copy from pygame.locals import * pygame.init() CubeWidth = 40 CubeHeight = 40 Column = 10 Row = 20 ScreenWidth = CubeWidth * (Column + 5) S

  • pygame实现俄罗斯方块游戏(AI篇1)

    上次更新到pygame实现俄罗斯方块游戏(基础篇3) 现在继续 一.定义玩家类 定义玩家类是为了便于进行手动和机器模式或各种不同机器人模式的混合使用,增加代码扩展性. 可以先定义一个玩家基类 class Player(object): auto_mode=False # 是否是自动模式,自动模式应当不响应键盘操作 def __init__(self): pass def run(self): # 进行操作 pass 手动类和机器类继承自Player类 class HumanPlayer(Play

  • python实现俄罗斯方块游戏

    在公司实习.公司推崇Python和Django框架,所以也得跟着学点. 简单瞅了下Tkinter,和Canvas配合在一起,还算是简洁的界面开发API.threading.Thread创建新的线程,其多线程机制也算是方便. 只是canvas.create_rectangle居然不是绘制矩形,而是新建了矩形控件这点让人大跌眼镜.先开始,在线程里每次都重绘多个矩形(随数组变化),其实是每次都新建了N个矩形,结果内存暴增.原来,对矩形进行变更时,只需用canvas.itemconfig即可. 下面就是

  • 用Python编写一个简单的俄罗斯方块游戏的教程

    俄罗斯方块游戏,使用Python实现,总共有350+行代码,实现了俄罗斯方块游戏的基本功能,同时会记录所花费时间,消去的总行数,所得的总分,还包括一个排行榜,可以查看最高记录. 排行榜中包含一系列的统计功能,如单位时间消去的行数,单位时间得分等. 附源码: from Tkinter import * from tkMessageBox import * import random import time #俄罗斯方块界面的高度 HEIGHT = 18 #俄罗斯方块界面的宽度 WIDTH = 10

  • Python使用pygame模块编写俄罗斯方块游戏的代码实例

    文章先介绍了关于俄罗斯方块游戏的几个术语. 边框--由10*20个空格组成,方块就落在这里面. 盒子--组成方块的其中小方块,是组成方块的基本单元. 方块--从边框顶掉下的东西,游戏者可以翻转和改变位置.每个方块由4个盒子组成. 形状--不同类型的方块.这里形状的名字被叫做T, S, Z ,J, L, I , O.如下图所示: 模版--用一个列表存放形状被翻转后的所有可能样式.全部存放在变量里,变量名字如S_SHAPE_TEMPLATE or J_SHAPE_TEMPLATE 着陆--当一个方块

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

    上一章请点击查看:pygame实现俄罗斯方块游戏(基础篇2) 现在继续 一.给每个方块设置不同的颜色 根据代码这里可以判断正在下落的方块在那些Block子类里加一个属性最合适,而已经落下的方块颜色管理最合适的地方应该是修改在Panel类里的rect_arr Block子类里的修改比较简单,以TBlock类为例,在__init__函数加一行 self.color=(255,0,0) 在Panel的paint函数里将代码 # 绘制正在落下的方块 if self.move_block: for rec

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

    本文实例为大家分享了pygame实现俄罗斯方块游戏的具体代码,基础的第一篇,供大家参考,具体内容如下 一.初始界面 之前的游戏都比较简单,所以代码都是面向过程的写法,这次游戏后面可能会写比较复杂(比如人机对战.联机对战.使用道具对战等),这次面向对象一点来写这个项目. 游戏的窗口设计一个专门的Panel类便于负责单个游戏窗口的管理控制. 游戏主窗口按每个方块30像素,那么宽3010=300,高是3020=600 # -*- coding=utf-8 -*- import random impor

随机推荐