mirror of
https://github.com/fofolee/uTools-Manuals.git
synced 2025-06-10 16:48:17 +08:00
762 lines
77 KiB
HTML
762 lines
77 KiB
HTML
<h1 id="俄罗斯方块游戏">俄罗斯方块游戏</h1>
|
||
<p>本章我们要制作一个俄罗斯方块游戏。</p>
|
||
<h2 id="tetris">Tetris</h2>
|
||
<blockquote>
|
||
<p>译注:称呼:方块是由四个小方格组成的</p>
|
||
</blockquote>
|
||
<p>俄罗斯方块游戏是世界上最流行的游戏之一。是由一名叫Alexey Pajitnov的俄罗斯程序员在1985年制作的,从那时起,这个游戏就风靡了各个游戏平台。</p>
|
||
<p>俄罗斯方块归类为下落块迷宫游戏。游戏有7个基本形状:S、Z、T、L、反向L、直线、方块,每个形状都由4个方块组成,方块最终都会落到屏幕底部。所以玩家通过控制形状的左右位置和旋转,让每个形状都以合适的位置落下,如果有一行全部被方块填充,这行就会消失,并且得分。游戏结束的条件是有形状接触到了屏幕顶部。</p>
|
||
<p>方块展示:</p>
|
||
<figure>
|
||
<img class="whitelist" src="docs/PyQt5/images/11-tetrominoes.png" alt="tetrominoes" />
|
||
</figure>
|
||
<p>PyQt5是专门为创建图形界面产生的,里面一些专门为制作游戏而开发的组件,所以PyQt5是能制作小游戏的。</p>
|
||
<p>制作电脑游戏也是提高自己编程能力的一种很好的方式。</p>
|
||
<h2 id="开发">开发</h2>
|
||
<p>没有图片,所以就自己用绘画画出来几个图形。每个游戏里都有数学模型的,这个也是。</p>
|
||
<p>开工之前:</p>
|
||
<ul>
|
||
<li>用<code>QtCore.QBasicTimer()</code>创建一个游戏循环</li>
|
||
<li>模型是一直下落的</li>
|
||
<li>模型的运动是以小块为基础单位的,不是按像素</li>
|
||
<li>从数学意义上来说,模型就是就是一串数字而已</li>
|
||
</ul>
|
||
<p>代码由四个类组成:Tetris, Board, Tetrominoe和Shape。Tetris类创建游戏,Board是游戏主要逻辑。Tetrominoe包含了所有的砖块,Shape是所有砖块的代码。</p>
|
||
<div class="sourceCode" id="cb1"><pre><code class="language-python"><a class="sourceLine" id="cb1-1" data-line-number="1"><span class="co">#!/usr/bin/python3</span></a>
|
||
<a class="sourceLine" id="cb1-2" data-line-number="2"><span class="co"># -*- coding: utf-8 -*-</span></a>
|
||
<a class="sourceLine" id="cb1-3" data-line-number="3"></a>
|
||
<a class="sourceLine" id="cb1-4" data-line-number="4"><span class="co">"""</span></a>
|
||
<a class="sourceLine" id="cb1-5" data-line-number="5"><span class="co">ZetCode PyQt5 tutorial </span></a>
|
||
<a class="sourceLine" id="cb1-6" data-line-number="6"></a>
|
||
<a class="sourceLine" id="cb1-7" data-line-number="7"><span class="co">This is a Tetris game clone.</span></a>
|
||
<a class="sourceLine" id="cb1-8" data-line-number="8"></a>
|
||
<a class="sourceLine" id="cb1-9" data-line-number="9"><span class="co">Author: Jan Bodnar</span></a>
|
||
<a class="sourceLine" id="cb1-10" data-line-number="10"><span class="co">Website: zetcode.com </span></a>
|
||
<a class="sourceLine" id="cb1-11" data-line-number="11"><span class="co">Last edited: August 2017</span></a>
|
||
<a class="sourceLine" id="cb1-12" data-line-number="12"><span class="co">"""</span></a>
|
||
<a class="sourceLine" id="cb1-13" data-line-number="13"></a>
|
||
<a class="sourceLine" id="cb1-14" data-line-number="14"><span class="im">from</span> PyQt5.QtWidgets <span class="im">import</span> QMainWindow, QFrame, QDesktopWidget, QApplication</a>
|
||
<a class="sourceLine" id="cb1-15" data-line-number="15"><span class="im">from</span> PyQt5.QtCore <span class="im">import</span> Qt, QBasicTimer, pyqtSignal</a>
|
||
<a class="sourceLine" id="cb1-16" data-line-number="16"><span class="im">from</span> PyQt5.QtGui <span class="im">import</span> QPainter, QColor </a>
|
||
<a class="sourceLine" id="cb1-17" data-line-number="17"><span class="im">import</span> sys, random</a>
|
||
<a class="sourceLine" id="cb1-18" data-line-number="18"></a>
|
||
<a class="sourceLine" id="cb1-19" data-line-number="19"><span class="kw">class</span> Tetris(QMainWindow):</a>
|
||
<a class="sourceLine" id="cb1-20" data-line-number="20"> </a>
|
||
<a class="sourceLine" id="cb1-21" data-line-number="21"> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-22" data-line-number="22"> <span class="bu">super</span>().<span class="fu">__init__</span>()</a>
|
||
<a class="sourceLine" id="cb1-23" data-line-number="23"> </a>
|
||
<a class="sourceLine" id="cb1-24" data-line-number="24"> <span class="va">self</span>.initUI()</a>
|
||
<a class="sourceLine" id="cb1-25" data-line-number="25"> </a>
|
||
<a class="sourceLine" id="cb1-26" data-line-number="26"> </a>
|
||
<a class="sourceLine" id="cb1-27" data-line-number="27"> <span class="kw">def</span> initUI(<span class="va">self</span>): </a>
|
||
<a class="sourceLine" id="cb1-28" data-line-number="28"> <span class="co">'''initiates application UI'''</span></a>
|
||
<a class="sourceLine" id="cb1-29" data-line-number="29"></a>
|
||
<a class="sourceLine" id="cb1-30" data-line-number="30"> <span class="va">self</span>.tboard <span class="op">=</span> Board(<span class="va">self</span>)</a>
|
||
<a class="sourceLine" id="cb1-31" data-line-number="31"> <span class="va">self</span>.setCentralWidget(<span class="va">self</span>.tboard)</a>
|
||
<a class="sourceLine" id="cb1-32" data-line-number="32"></a>
|
||
<a class="sourceLine" id="cb1-33" data-line-number="33"> <span class="va">self</span>.statusbar <span class="op">=</span> <span class="va">self</span>.statusBar() </a>
|
||
<a class="sourceLine" id="cb1-34" data-line-number="34"> <span class="va">self</span>.tboard.msg2Statusbar[<span class="bu">str</span>].<span class="ex">connect</span>(<span class="va">self</span>.statusbar.showMessage)</a>
|
||
<a class="sourceLine" id="cb1-35" data-line-number="35"> </a>
|
||
<a class="sourceLine" id="cb1-36" data-line-number="36"> <span class="va">self</span>.tboard.start()</a>
|
||
<a class="sourceLine" id="cb1-37" data-line-number="37"> </a>
|
||
<a class="sourceLine" id="cb1-38" data-line-number="38"> <span class="va">self</span>.resize(<span class="dv">180</span>, <span class="dv">380</span>)</a>
|
||
<a class="sourceLine" id="cb1-39" data-line-number="39"> <span class="va">self</span>.center()</a>
|
||
<a class="sourceLine" id="cb1-40" data-line-number="40"> <span class="va">self</span>.setWindowTitle(<span class="st">'Tetris'</span>) </a>
|
||
<a class="sourceLine" id="cb1-41" data-line-number="41"> <span class="va">self</span>.show()</a>
|
||
<a class="sourceLine" id="cb1-42" data-line-number="42"> </a>
|
||
<a class="sourceLine" id="cb1-43" data-line-number="43"></a>
|
||
<a class="sourceLine" id="cb1-44" data-line-number="44"> <span class="kw">def</span> center(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-45" data-line-number="45"> <span class="co">'''centers the window on the screen'''</span></a>
|
||
<a class="sourceLine" id="cb1-46" data-line-number="46"> </a>
|
||
<a class="sourceLine" id="cb1-47" data-line-number="47"> screen <span class="op">=</span> QDesktopWidget().screenGeometry()</a>
|
||
<a class="sourceLine" id="cb1-48" data-line-number="48"> size <span class="op">=</span> <span class="va">self</span>.geometry()</a>
|
||
<a class="sourceLine" id="cb1-49" data-line-number="49"> <span class="va">self</span>.move((screen.width()<span class="op">-</span>size.width())<span class="op">/</span><span class="dv">2</span>, </a>
|
||
<a class="sourceLine" id="cb1-50" data-line-number="50"> (screen.height()<span class="op">-</span>size.height())<span class="op">/</span><span class="dv">2</span>)</a>
|
||
<a class="sourceLine" id="cb1-51" data-line-number="51"> </a>
|
||
<a class="sourceLine" id="cb1-52" data-line-number="52"></a>
|
||
<a class="sourceLine" id="cb1-53" data-line-number="53"><span class="kw">class</span> Board(QFrame):</a>
|
||
<a class="sourceLine" id="cb1-54" data-line-number="54"> </a>
|
||
<a class="sourceLine" id="cb1-55" data-line-number="55"> msg2Statusbar <span class="op">=</span> pyqtSignal(<span class="bu">str</span>)</a>
|
||
<a class="sourceLine" id="cb1-56" data-line-number="56"> </a>
|
||
<a class="sourceLine" id="cb1-57" data-line-number="57"> BoardWidth <span class="op">=</span> <span class="dv">10</span></a>
|
||
<a class="sourceLine" id="cb1-58" data-line-number="58"> BoardHeight <span class="op">=</span> <span class="dv">22</span></a>
|
||
<a class="sourceLine" id="cb1-59" data-line-number="59"> Speed <span class="op">=</span> <span class="dv">300</span></a>
|
||
<a class="sourceLine" id="cb1-60" data-line-number="60"></a>
|
||
<a class="sourceLine" id="cb1-61" data-line-number="61"> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>, parent):</a>
|
||
<a class="sourceLine" id="cb1-62" data-line-number="62"> <span class="bu">super</span>().<span class="fu">__init__</span>(parent)</a>
|
||
<a class="sourceLine" id="cb1-63" data-line-number="63"> </a>
|
||
<a class="sourceLine" id="cb1-64" data-line-number="64"> <span class="va">self</span>.initBoard()</a>
|
||
<a class="sourceLine" id="cb1-65" data-line-number="65"> </a>
|
||
<a class="sourceLine" id="cb1-66" data-line-number="66"> </a>
|
||
<a class="sourceLine" id="cb1-67" data-line-number="67"> <span class="kw">def</span> initBoard(<span class="va">self</span>): </a>
|
||
<a class="sourceLine" id="cb1-68" data-line-number="68"> <span class="co">'''initiates board'''</span></a>
|
||
<a class="sourceLine" id="cb1-69" data-line-number="69"></a>
|
||
<a class="sourceLine" id="cb1-70" data-line-number="70"> <span class="va">self</span>.timer <span class="op">=</span> QBasicTimer()</a>
|
||
<a class="sourceLine" id="cb1-71" data-line-number="71"> <span class="va">self</span>.isWaitingAfterLine <span class="op">=</span> <span class="va">False</span></a>
|
||
<a class="sourceLine" id="cb1-72" data-line-number="72"> </a>
|
||
<a class="sourceLine" id="cb1-73" data-line-number="73"> <span class="va">self</span>.curX <span class="op">=</span> <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb1-74" data-line-number="74"> <span class="va">self</span>.curY <span class="op">=</span> <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb1-75" data-line-number="75"> <span class="va">self</span>.numLinesRemoved <span class="op">=</span> <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb1-76" data-line-number="76"> <span class="va">self</span>.board <span class="op">=</span> []</a>
|
||
<a class="sourceLine" id="cb1-77" data-line-number="77"></a>
|
||
<a class="sourceLine" id="cb1-78" data-line-number="78"> <span class="va">self</span>.setFocusPolicy(Qt.StrongFocus)</a>
|
||
<a class="sourceLine" id="cb1-79" data-line-number="79"> <span class="va">self</span>.isStarted <span class="op">=</span> <span class="va">False</span></a>
|
||
<a class="sourceLine" id="cb1-80" data-line-number="80"> <span class="va">self</span>.isPaused <span class="op">=</span> <span class="va">False</span></a>
|
||
<a class="sourceLine" id="cb1-81" data-line-number="81"> <span class="va">self</span>.clearBoard()</a>
|
||
<a class="sourceLine" id="cb1-82" data-line-number="82"> </a>
|
||
<a class="sourceLine" id="cb1-83" data-line-number="83"> </a>
|
||
<a class="sourceLine" id="cb1-84" data-line-number="84"> <span class="kw">def</span> shapeAt(<span class="va">self</span>, x, y):</a>
|
||
<a class="sourceLine" id="cb1-85" data-line-number="85"> <span class="co">'''determines shape at the board position'''</span></a>
|
||
<a class="sourceLine" id="cb1-86" data-line-number="86"> </a>
|
||
<a class="sourceLine" id="cb1-87" data-line-number="87"> <span class="cf">return</span> <span class="va">self</span>.board[(y <span class="op">*</span> Board.BoardWidth) <span class="op">+</span> x]</a>
|
||
<a class="sourceLine" id="cb1-88" data-line-number="88"></a>
|
||
<a class="sourceLine" id="cb1-89" data-line-number="89"> </a>
|
||
<a class="sourceLine" id="cb1-90" data-line-number="90"> <span class="kw">def</span> setShapeAt(<span class="va">self</span>, x, y, shape):</a>
|
||
<a class="sourceLine" id="cb1-91" data-line-number="91"> <span class="co">'''sets a shape at the board'''</span></a>
|
||
<a class="sourceLine" id="cb1-92" data-line-number="92"> </a>
|
||
<a class="sourceLine" id="cb1-93" data-line-number="93"> <span class="va">self</span>.board[(y <span class="op">*</span> Board.BoardWidth) <span class="op">+</span> x] <span class="op">=</span> shape</a>
|
||
<a class="sourceLine" id="cb1-94" data-line-number="94"> </a>
|
||
<a class="sourceLine" id="cb1-95" data-line-number="95"></a>
|
||
<a class="sourceLine" id="cb1-96" data-line-number="96"> <span class="kw">def</span> squareWidth(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-97" data-line-number="97"> <span class="co">'''returns the width of one square'''</span></a>
|
||
<a class="sourceLine" id="cb1-98" data-line-number="98"> </a>
|
||
<a class="sourceLine" id="cb1-99" data-line-number="99"> <span class="cf">return</span> <span class="va">self</span>.contentsRect().width() <span class="op">//</span> Board.BoardWidth</a>
|
||
<a class="sourceLine" id="cb1-100" data-line-number="100"> </a>
|
||
<a class="sourceLine" id="cb1-101" data-line-number="101"></a>
|
||
<a class="sourceLine" id="cb1-102" data-line-number="102"> <span class="kw">def</span> squareHeight(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-103" data-line-number="103"> <span class="co">'''returns the height of one square'''</span></a>
|
||
<a class="sourceLine" id="cb1-104" data-line-number="104"> </a>
|
||
<a class="sourceLine" id="cb1-105" data-line-number="105"> <span class="cf">return</span> <span class="va">self</span>.contentsRect().height() <span class="op">//</span> Board.BoardHeight</a>
|
||
<a class="sourceLine" id="cb1-106" data-line-number="106"> </a>
|
||
<a class="sourceLine" id="cb1-107" data-line-number="107"></a>
|
||
<a class="sourceLine" id="cb1-108" data-line-number="108"> <span class="kw">def</span> start(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-109" data-line-number="109"> <span class="co">'''starts game'''</span></a>
|
||
<a class="sourceLine" id="cb1-110" data-line-number="110"> </a>
|
||
<a class="sourceLine" id="cb1-111" data-line-number="111"> <span class="cf">if</span> <span class="va">self</span>.isPaused:</a>
|
||
<a class="sourceLine" id="cb1-112" data-line-number="112"> <span class="cf">return</span></a>
|
||
<a class="sourceLine" id="cb1-113" data-line-number="113"></a>
|
||
<a class="sourceLine" id="cb1-114" data-line-number="114"> <span class="va">self</span>.isStarted <span class="op">=</span> <span class="va">True</span></a>
|
||
<a class="sourceLine" id="cb1-115" data-line-number="115"> <span class="va">self</span>.isWaitingAfterLine <span class="op">=</span> <span class="va">False</span></a>
|
||
<a class="sourceLine" id="cb1-116" data-line-number="116"> <span class="va">self</span>.numLinesRemoved <span class="op">=</span> <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb1-117" data-line-number="117"> <span class="va">self</span>.clearBoard()</a>
|
||
<a class="sourceLine" id="cb1-118" data-line-number="118"></a>
|
||
<a class="sourceLine" id="cb1-119" data-line-number="119"> <span class="va">self</span>.msg2Statusbar.emit(<span class="bu">str</span>(<span class="va">self</span>.numLinesRemoved))</a>
|
||
<a class="sourceLine" id="cb1-120" data-line-number="120"></a>
|
||
<a class="sourceLine" id="cb1-121" data-line-number="121"> <span class="va">self</span>.newPiece()</a>
|
||
<a class="sourceLine" id="cb1-122" data-line-number="122"> <span class="va">self</span>.timer.start(Board.Speed, <span class="va">self</span>)</a>
|
||
<a class="sourceLine" id="cb1-123" data-line-number="123"></a>
|
||
<a class="sourceLine" id="cb1-124" data-line-number="124"> </a>
|
||
<a class="sourceLine" id="cb1-125" data-line-number="125"> <span class="kw">def</span> pause(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-126" data-line-number="126"> <span class="co">'''pauses game'''</span></a>
|
||
<a class="sourceLine" id="cb1-127" data-line-number="127"> </a>
|
||
<a class="sourceLine" id="cb1-128" data-line-number="128"> <span class="cf">if</span> <span class="kw">not</span> <span class="va">self</span>.isStarted:</a>
|
||
<a class="sourceLine" id="cb1-129" data-line-number="129"> <span class="cf">return</span></a>
|
||
<a class="sourceLine" id="cb1-130" data-line-number="130"></a>
|
||
<a class="sourceLine" id="cb1-131" data-line-number="131"> <span class="va">self</span>.isPaused <span class="op">=</span> <span class="kw">not</span> <span class="va">self</span>.isPaused</a>
|
||
<a class="sourceLine" id="cb1-132" data-line-number="132"> </a>
|
||
<a class="sourceLine" id="cb1-133" data-line-number="133"> <span class="cf">if</span> <span class="va">self</span>.isPaused:</a>
|
||
<a class="sourceLine" id="cb1-134" data-line-number="134"> <span class="va">self</span>.timer.stop()</a>
|
||
<a class="sourceLine" id="cb1-135" data-line-number="135"> <span class="va">self</span>.msg2Statusbar.emit(<span class="st">"paused"</span>)</a>
|
||
<a class="sourceLine" id="cb1-136" data-line-number="136"> </a>
|
||
<a class="sourceLine" id="cb1-137" data-line-number="137"> <span class="cf">else</span>:</a>
|
||
<a class="sourceLine" id="cb1-138" data-line-number="138"> <span class="va">self</span>.timer.start(Board.Speed, <span class="va">self</span>)</a>
|
||
<a class="sourceLine" id="cb1-139" data-line-number="139"> <span class="va">self</span>.msg2Statusbar.emit(<span class="bu">str</span>(<span class="va">self</span>.numLinesRemoved))</a>
|
||
<a class="sourceLine" id="cb1-140" data-line-number="140"></a>
|
||
<a class="sourceLine" id="cb1-141" data-line-number="141"> <span class="va">self</span>.update()</a>
|
||
<a class="sourceLine" id="cb1-142" data-line-number="142"></a>
|
||
<a class="sourceLine" id="cb1-143" data-line-number="143"> </a>
|
||
<a class="sourceLine" id="cb1-144" data-line-number="144"> <span class="kw">def</span> paintEvent(<span class="va">self</span>, event):</a>
|
||
<a class="sourceLine" id="cb1-145" data-line-number="145"> <span class="co">'''paints all shapes of the game'''</span></a>
|
||
<a class="sourceLine" id="cb1-146" data-line-number="146"> </a>
|
||
<a class="sourceLine" id="cb1-147" data-line-number="147"> painter <span class="op">=</span> QPainter(<span class="va">self</span>)</a>
|
||
<a class="sourceLine" id="cb1-148" data-line-number="148"> rect <span class="op">=</span> <span class="va">self</span>.contentsRect()</a>
|
||
<a class="sourceLine" id="cb1-149" data-line-number="149"></a>
|
||
<a class="sourceLine" id="cb1-150" data-line-number="150"> boardTop <span class="op">=</span> rect.bottom() <span class="op">-</span> Board.BoardHeight <span class="op">*</span> <span class="va">self</span>.squareHeight()</a>
|
||
<a class="sourceLine" id="cb1-151" data-line-number="151"></a>
|
||
<a class="sourceLine" id="cb1-152" data-line-number="152"> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(Board.BoardHeight):</a>
|
||
<a class="sourceLine" id="cb1-153" data-line-number="153"> <span class="cf">for</span> j <span class="kw">in</span> <span class="bu">range</span>(Board.BoardWidth):</a>
|
||
<a class="sourceLine" id="cb1-154" data-line-number="154"> shape <span class="op">=</span> <span class="va">self</span>.shapeAt(j, Board.BoardHeight <span class="op">-</span> i <span class="op">-</span> <span class="dv">1</span>)</a>
|
||
<a class="sourceLine" id="cb1-155" data-line-number="155"> </a>
|
||
<a class="sourceLine" id="cb1-156" data-line-number="156"> <span class="cf">if</span> shape <span class="op">!=</span> Tetrominoe.NoShape:</a>
|
||
<a class="sourceLine" id="cb1-157" data-line-number="157"> <span class="va">self</span>.drawSquare(painter,</a>
|
||
<a class="sourceLine" id="cb1-158" data-line-number="158"> rect.left() <span class="op">+</span> j <span class="op">*</span> <span class="va">self</span>.squareWidth(),</a>
|
||
<a class="sourceLine" id="cb1-159" data-line-number="159"> boardTop <span class="op">+</span> i <span class="op">*</span> <span class="va">self</span>.squareHeight(), shape)</a>
|
||
<a class="sourceLine" id="cb1-160" data-line-number="160"></a>
|
||
<a class="sourceLine" id="cb1-161" data-line-number="161"> <span class="cf">if</span> <span class="va">self</span>.curPiece.shape() <span class="op">!=</span> Tetrominoe.NoShape:</a>
|
||
<a class="sourceLine" id="cb1-162" data-line-number="162"> </a>
|
||
<a class="sourceLine" id="cb1-163" data-line-number="163"> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">4</span>):</a>
|
||
<a class="sourceLine" id="cb1-164" data-line-number="164"> </a>
|
||
<a class="sourceLine" id="cb1-165" data-line-number="165"> x <span class="op">=</span> <span class="va">self</span>.curX <span class="op">+</span> <span class="va">self</span>.curPiece.x(i)</a>
|
||
<a class="sourceLine" id="cb1-166" data-line-number="166"> y <span class="op">=</span> <span class="va">self</span>.curY <span class="op">-</span> <span class="va">self</span>.curPiece.y(i)</a>
|
||
<a class="sourceLine" id="cb1-167" data-line-number="167"> <span class="va">self</span>.drawSquare(painter, rect.left() <span class="op">+</span> x <span class="op">*</span> <span class="va">self</span>.squareWidth(),</a>
|
||
<a class="sourceLine" id="cb1-168" data-line-number="168"> boardTop <span class="op">+</span> (Board.BoardHeight <span class="op">-</span> y <span class="op">-</span> <span class="dv">1</span>) <span class="op">*</span> <span class="va">self</span>.squareHeight(),</a>
|
||
<a class="sourceLine" id="cb1-169" data-line-number="169"> <span class="va">self</span>.curPiece.shape())</a>
|
||
<a class="sourceLine" id="cb1-170" data-line-number="170"></a>
|
||
<a class="sourceLine" id="cb1-171" data-line-number="171"> </a>
|
||
<a class="sourceLine" id="cb1-172" data-line-number="172"> <span class="kw">def</span> keyPressEvent(<span class="va">self</span>, event):</a>
|
||
<a class="sourceLine" id="cb1-173" data-line-number="173"> <span class="co">'''processes key press events'''</span></a>
|
||
<a class="sourceLine" id="cb1-174" data-line-number="174"> </a>
|
||
<a class="sourceLine" id="cb1-175" data-line-number="175"> <span class="cf">if</span> <span class="kw">not</span> <span class="va">self</span>.isStarted <span class="kw">or</span> <span class="va">self</span>.curPiece.shape() <span class="op">==</span> Tetrominoe.NoShape:</a>
|
||
<a class="sourceLine" id="cb1-176" data-line-number="176"> <span class="bu">super</span>(Board, <span class="va">self</span>).keyPressEvent(event)</a>
|
||
<a class="sourceLine" id="cb1-177" data-line-number="177"> <span class="cf">return</span></a>
|
||
<a class="sourceLine" id="cb1-178" data-line-number="178"></a>
|
||
<a class="sourceLine" id="cb1-179" data-line-number="179"> key <span class="op">=</span> event.key()</a>
|
||
<a class="sourceLine" id="cb1-180" data-line-number="180"> </a>
|
||
<a class="sourceLine" id="cb1-181" data-line-number="181"> <span class="cf">if</span> key <span class="op">==</span> Qt.Key_P:</a>
|
||
<a class="sourceLine" id="cb1-182" data-line-number="182"> <span class="va">self</span>.pause()</a>
|
||
<a class="sourceLine" id="cb1-183" data-line-number="183"> <span class="cf">return</span></a>
|
||
<a class="sourceLine" id="cb1-184" data-line-number="184"> </a>
|
||
<a class="sourceLine" id="cb1-185" data-line-number="185"> <span class="cf">if</span> <span class="va">self</span>.isPaused:</a>
|
||
<a class="sourceLine" id="cb1-186" data-line-number="186"> <span class="cf">return</span></a>
|
||
<a class="sourceLine" id="cb1-187" data-line-number="187"> </a>
|
||
<a class="sourceLine" id="cb1-188" data-line-number="188"> <span class="cf">elif</span> key <span class="op">==</span> Qt.Key_Left:</a>
|
||
<a class="sourceLine" id="cb1-189" data-line-number="189"> <span class="va">self</span>.tryMove(<span class="va">self</span>.curPiece, <span class="va">self</span>.curX <span class="op">-</span> <span class="dv">1</span>, <span class="va">self</span>.curY)</a>
|
||
<a class="sourceLine" id="cb1-190" data-line-number="190"> </a>
|
||
<a class="sourceLine" id="cb1-191" data-line-number="191"> <span class="cf">elif</span> key <span class="op">==</span> Qt.Key_Right:</a>
|
||
<a class="sourceLine" id="cb1-192" data-line-number="192"> <span class="va">self</span>.tryMove(<span class="va">self</span>.curPiece, <span class="va">self</span>.curX <span class="op">+</span> <span class="dv">1</span>, <span class="va">self</span>.curY)</a>
|
||
<a class="sourceLine" id="cb1-193" data-line-number="193"> </a>
|
||
<a class="sourceLine" id="cb1-194" data-line-number="194"> <span class="cf">elif</span> key <span class="op">==</span> Qt.Key_Down:</a>
|
||
<a class="sourceLine" id="cb1-195" data-line-number="195"> <span class="va">self</span>.tryMove(<span class="va">self</span>.curPiece.rotateRight(), <span class="va">self</span>.curX, <span class="va">self</span>.curY)</a>
|
||
<a class="sourceLine" id="cb1-196" data-line-number="196"> </a>
|
||
<a class="sourceLine" id="cb1-197" data-line-number="197"> <span class="cf">elif</span> key <span class="op">==</span> Qt.Key_Up:</a>
|
||
<a class="sourceLine" id="cb1-198" data-line-number="198"> <span class="va">self</span>.tryMove(<span class="va">self</span>.curPiece.rotateLeft(), <span class="va">self</span>.curX, <span class="va">self</span>.curY)</a>
|
||
<a class="sourceLine" id="cb1-199" data-line-number="199"> </a>
|
||
<a class="sourceLine" id="cb1-200" data-line-number="200"> <span class="cf">elif</span> key <span class="op">==</span> Qt.Key_Space:</a>
|
||
<a class="sourceLine" id="cb1-201" data-line-number="201"> <span class="va">self</span>.dropDown()</a>
|
||
<a class="sourceLine" id="cb1-202" data-line-number="202"> </a>
|
||
<a class="sourceLine" id="cb1-203" data-line-number="203"> <span class="cf">elif</span> key <span class="op">==</span> Qt.Key_D:</a>
|
||
<a class="sourceLine" id="cb1-204" data-line-number="204"> <span class="va">self</span>.oneLineDown()</a>
|
||
<a class="sourceLine" id="cb1-205" data-line-number="205"> </a>
|
||
<a class="sourceLine" id="cb1-206" data-line-number="206"> <span class="cf">else</span>:</a>
|
||
<a class="sourceLine" id="cb1-207" data-line-number="207"> <span class="bu">super</span>(Board, <span class="va">self</span>).keyPressEvent(event)</a>
|
||
<a class="sourceLine" id="cb1-208" data-line-number="208"> </a>
|
||
<a class="sourceLine" id="cb1-209" data-line-number="209"></a>
|
||
<a class="sourceLine" id="cb1-210" data-line-number="210"> <span class="kw">def</span> timerEvent(<span class="va">self</span>, event):</a>
|
||
<a class="sourceLine" id="cb1-211" data-line-number="211"> <span class="co">'''handles timer event'''</span></a>
|
||
<a class="sourceLine" id="cb1-212" data-line-number="212"> </a>
|
||
<a class="sourceLine" id="cb1-213" data-line-number="213"> <span class="cf">if</span> event.timerId() <span class="op">==</span> <span class="va">self</span>.timer.timerId():</a>
|
||
<a class="sourceLine" id="cb1-214" data-line-number="214"> </a>
|
||
<a class="sourceLine" id="cb1-215" data-line-number="215"> <span class="cf">if</span> <span class="va">self</span>.isWaitingAfterLine:</a>
|
||
<a class="sourceLine" id="cb1-216" data-line-number="216"> <span class="va">self</span>.isWaitingAfterLine <span class="op">=</span> <span class="va">False</span></a>
|
||
<a class="sourceLine" id="cb1-217" data-line-number="217"> <span class="va">self</span>.newPiece()</a>
|
||
<a class="sourceLine" id="cb1-218" data-line-number="218"> <span class="cf">else</span>:</a>
|
||
<a class="sourceLine" id="cb1-219" data-line-number="219"> <span class="va">self</span>.oneLineDown()</a>
|
||
<a class="sourceLine" id="cb1-220" data-line-number="220"> </a>
|
||
<a class="sourceLine" id="cb1-221" data-line-number="221"> <span class="cf">else</span>:</a>
|
||
<a class="sourceLine" id="cb1-222" data-line-number="222"> <span class="bu">super</span>(Board, <span class="va">self</span>).timerEvent(event)</a>
|
||
<a class="sourceLine" id="cb1-223" data-line-number="223"></a>
|
||
<a class="sourceLine" id="cb1-224" data-line-number="224"> </a>
|
||
<a class="sourceLine" id="cb1-225" data-line-number="225"> <span class="kw">def</span> clearBoard(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-226" data-line-number="226"> <span class="co">'''clears shapes from the board'''</span></a>
|
||
<a class="sourceLine" id="cb1-227" data-line-number="227"> </a>
|
||
<a class="sourceLine" id="cb1-228" data-line-number="228"> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(Board.BoardHeight <span class="op">*</span> Board.BoardWidth):</a>
|
||
<a class="sourceLine" id="cb1-229" data-line-number="229"> <span class="va">self</span>.board.append(Tetrominoe.NoShape)</a>
|
||
<a class="sourceLine" id="cb1-230" data-line-number="230"></a>
|
||
<a class="sourceLine" id="cb1-231" data-line-number="231"> </a>
|
||
<a class="sourceLine" id="cb1-232" data-line-number="232"> <span class="kw">def</span> dropDown(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-233" data-line-number="233"> <span class="co">'''drops down a shape'''</span></a>
|
||
<a class="sourceLine" id="cb1-234" data-line-number="234"> </a>
|
||
<a class="sourceLine" id="cb1-235" data-line-number="235"> newY <span class="op">=</span> <span class="va">self</span>.curY</a>
|
||
<a class="sourceLine" id="cb1-236" data-line-number="236"> </a>
|
||
<a class="sourceLine" id="cb1-237" data-line-number="237"> <span class="cf">while</span> newY <span class="op">></span> <span class="dv">0</span>:</a>
|
||
<a class="sourceLine" id="cb1-238" data-line-number="238"> </a>
|
||
<a class="sourceLine" id="cb1-239" data-line-number="239"> <span class="cf">if</span> <span class="kw">not</span> <span class="va">self</span>.tryMove(<span class="va">self</span>.curPiece, <span class="va">self</span>.curX, newY <span class="op">-</span> <span class="dv">1</span>):</a>
|
||
<a class="sourceLine" id="cb1-240" data-line-number="240"> <span class="cf">break</span></a>
|
||
<a class="sourceLine" id="cb1-241" data-line-number="241"> </a>
|
||
<a class="sourceLine" id="cb1-242" data-line-number="242"> newY <span class="op">-=</span> <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb1-243" data-line-number="243"></a>
|
||
<a class="sourceLine" id="cb1-244" data-line-number="244"> <span class="va">self</span>.pieceDropped()</a>
|
||
<a class="sourceLine" id="cb1-245" data-line-number="245"> </a>
|
||
<a class="sourceLine" id="cb1-246" data-line-number="246"></a>
|
||
<a class="sourceLine" id="cb1-247" data-line-number="247"> <span class="kw">def</span> oneLineDown(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-248" data-line-number="248"> <span class="co">'''goes one line down with a shape'''</span></a>
|
||
<a class="sourceLine" id="cb1-249" data-line-number="249"> </a>
|
||
<a class="sourceLine" id="cb1-250" data-line-number="250"> <span class="cf">if</span> <span class="kw">not</span> <span class="va">self</span>.tryMove(<span class="va">self</span>.curPiece, <span class="va">self</span>.curX, <span class="va">self</span>.curY <span class="op">-</span> <span class="dv">1</span>):</a>
|
||
<a class="sourceLine" id="cb1-251" data-line-number="251"> <span class="va">self</span>.pieceDropped()</a>
|
||
<a class="sourceLine" id="cb1-252" data-line-number="252"> </a>
|
||
<a class="sourceLine" id="cb1-253" data-line-number="253"></a>
|
||
<a class="sourceLine" id="cb1-254" data-line-number="254"> <span class="kw">def</span> pieceDropped(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-255" data-line-number="255"> <span class="co">'''after dropping shape, remove full lines and create new shape'''</span></a>
|
||
<a class="sourceLine" id="cb1-256" data-line-number="256"> </a>
|
||
<a class="sourceLine" id="cb1-257" data-line-number="257"> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">4</span>):</a>
|
||
<a class="sourceLine" id="cb1-258" data-line-number="258"> </a>
|
||
<a class="sourceLine" id="cb1-259" data-line-number="259"> x <span class="op">=</span> <span class="va">self</span>.curX <span class="op">+</span> <span class="va">self</span>.curPiece.x(i)</a>
|
||
<a class="sourceLine" id="cb1-260" data-line-number="260"> y <span class="op">=</span> <span class="va">self</span>.curY <span class="op">-</span> <span class="va">self</span>.curPiece.y(i)</a>
|
||
<a class="sourceLine" id="cb1-261" data-line-number="261"> <span class="va">self</span>.setShapeAt(x, y, <span class="va">self</span>.curPiece.shape())</a>
|
||
<a class="sourceLine" id="cb1-262" data-line-number="262"></a>
|
||
<a class="sourceLine" id="cb1-263" data-line-number="263"> <span class="va">self</span>.removeFullLines()</a>
|
||
<a class="sourceLine" id="cb1-264" data-line-number="264"></a>
|
||
<a class="sourceLine" id="cb1-265" data-line-number="265"> <span class="cf">if</span> <span class="kw">not</span> <span class="va">self</span>.isWaitingAfterLine:</a>
|
||
<a class="sourceLine" id="cb1-266" data-line-number="266"> <span class="va">self</span>.newPiece()</a>
|
||
<a class="sourceLine" id="cb1-267" data-line-number="267"> </a>
|
||
<a class="sourceLine" id="cb1-268" data-line-number="268"></a>
|
||
<a class="sourceLine" id="cb1-269" data-line-number="269"> <span class="kw">def</span> removeFullLines(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-270" data-line-number="270"> <span class="co">'''removes all full lines from the board'''</span></a>
|
||
<a class="sourceLine" id="cb1-271" data-line-number="271"> </a>
|
||
<a class="sourceLine" id="cb1-272" data-line-number="272"> numFullLines <span class="op">=</span> <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb1-273" data-line-number="273"> rowsToRemove <span class="op">=</span> []</a>
|
||
<a class="sourceLine" id="cb1-274" data-line-number="274"></a>
|
||
<a class="sourceLine" id="cb1-275" data-line-number="275"> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(Board.BoardHeight):</a>
|
||
<a class="sourceLine" id="cb1-276" data-line-number="276"> </a>
|
||
<a class="sourceLine" id="cb1-277" data-line-number="277"> n <span class="op">=</span> <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb1-278" data-line-number="278"> <span class="cf">for</span> j <span class="kw">in</span> <span class="bu">range</span>(Board.BoardWidth):</a>
|
||
<a class="sourceLine" id="cb1-279" data-line-number="279"> <span class="cf">if</span> <span class="kw">not</span> <span class="va">self</span>.shapeAt(j, i) <span class="op">==</span> Tetrominoe.NoShape:</a>
|
||
<a class="sourceLine" id="cb1-280" data-line-number="280"> n <span class="op">=</span> n <span class="op">+</span> <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb1-281" data-line-number="281"></a>
|
||
<a class="sourceLine" id="cb1-282" data-line-number="282"> <span class="cf">if</span> n <span class="op">==</span> <span class="dv">10</span>:</a>
|
||
<a class="sourceLine" id="cb1-283" data-line-number="283"> rowsToRemove.append(i)</a>
|
||
<a class="sourceLine" id="cb1-284" data-line-number="284"></a>
|
||
<a class="sourceLine" id="cb1-285" data-line-number="285"> rowsToRemove.reverse()</a>
|
||
<a class="sourceLine" id="cb1-286" data-line-number="286"> </a>
|
||
<a class="sourceLine" id="cb1-287" data-line-number="287"></a>
|
||
<a class="sourceLine" id="cb1-288" data-line-number="288"> <span class="cf">for</span> m <span class="kw">in</span> rowsToRemove:</a>
|
||
<a class="sourceLine" id="cb1-289" data-line-number="289"> </a>
|
||
<a class="sourceLine" id="cb1-290" data-line-number="290"> <span class="cf">for</span> k <span class="kw">in</span> <span class="bu">range</span>(m, Board.BoardHeight):</a>
|
||
<a class="sourceLine" id="cb1-291" data-line-number="291"> <span class="cf">for</span> l <span class="kw">in</span> <span class="bu">range</span>(Board.BoardWidth):</a>
|
||
<a class="sourceLine" id="cb1-292" data-line-number="292"> <span class="va">self</span>.setShapeAt(l, k, <span class="va">self</span>.shapeAt(l, k <span class="op">+</span> <span class="dv">1</span>))</a>
|
||
<a class="sourceLine" id="cb1-293" data-line-number="293"></a>
|
||
<a class="sourceLine" id="cb1-294" data-line-number="294"> numFullLines <span class="op">=</span> numFullLines <span class="op">+</span> <span class="bu">len</span>(rowsToRemove)</a>
|
||
<a class="sourceLine" id="cb1-295" data-line-number="295"></a>
|
||
<a class="sourceLine" id="cb1-296" data-line-number="296"> <span class="cf">if</span> numFullLines <span class="op">></span> <span class="dv">0</span>:</a>
|
||
<a class="sourceLine" id="cb1-297" data-line-number="297"> </a>
|
||
<a class="sourceLine" id="cb1-298" data-line-number="298"> <span class="va">self</span>.numLinesRemoved <span class="op">=</span> <span class="va">self</span>.numLinesRemoved <span class="op">+</span> numFullLines</a>
|
||
<a class="sourceLine" id="cb1-299" data-line-number="299"> <span class="va">self</span>.msg2Statusbar.emit(<span class="bu">str</span>(<span class="va">self</span>.numLinesRemoved))</a>
|
||
<a class="sourceLine" id="cb1-300" data-line-number="300"> </a>
|
||
<a class="sourceLine" id="cb1-301" data-line-number="301"> <span class="va">self</span>.isWaitingAfterLine <span class="op">=</span> <span class="va">True</span></a>
|
||
<a class="sourceLine" id="cb1-302" data-line-number="302"> <span class="va">self</span>.curPiece.setShape(Tetrominoe.NoShape)</a>
|
||
<a class="sourceLine" id="cb1-303" data-line-number="303"> <span class="va">self</span>.update()</a>
|
||
<a class="sourceLine" id="cb1-304" data-line-number="304"> </a>
|
||
<a class="sourceLine" id="cb1-305" data-line-number="305"></a>
|
||
<a class="sourceLine" id="cb1-306" data-line-number="306"> <span class="kw">def</span> newPiece(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-307" data-line-number="307"> <span class="co">'''creates a new shape'''</span></a>
|
||
<a class="sourceLine" id="cb1-308" data-line-number="308"> </a>
|
||
<a class="sourceLine" id="cb1-309" data-line-number="309"> <span class="va">self</span>.curPiece <span class="op">=</span> Shape()</a>
|
||
<a class="sourceLine" id="cb1-310" data-line-number="310"> <span class="va">self</span>.curPiece.setRandomShape()</a>
|
||
<a class="sourceLine" id="cb1-311" data-line-number="311"> <span class="va">self</span>.curX <span class="op">=</span> Board.BoardWidth <span class="op">//</span> <span class="dv">2</span> <span class="op">+</span> <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb1-312" data-line-number="312"> <span class="va">self</span>.curY <span class="op">=</span> Board.BoardHeight <span class="op">-</span> <span class="dv">1</span> <span class="op">+</span> <span class="va">self</span>.curPiece.minY()</a>
|
||
<a class="sourceLine" id="cb1-313" data-line-number="313"> </a>
|
||
<a class="sourceLine" id="cb1-314" data-line-number="314"> <span class="cf">if</span> <span class="kw">not</span> <span class="va">self</span>.tryMove(<span class="va">self</span>.curPiece, <span class="va">self</span>.curX, <span class="va">self</span>.curY):</a>
|
||
<a class="sourceLine" id="cb1-315" data-line-number="315"> </a>
|
||
<a class="sourceLine" id="cb1-316" data-line-number="316"> <span class="va">self</span>.curPiece.setShape(Tetrominoe.NoShape)</a>
|
||
<a class="sourceLine" id="cb1-317" data-line-number="317"> <span class="va">self</span>.timer.stop()</a>
|
||
<a class="sourceLine" id="cb1-318" data-line-number="318"> <span class="va">self</span>.isStarted <span class="op">=</span> <span class="va">False</span></a>
|
||
<a class="sourceLine" id="cb1-319" data-line-number="319"> <span class="va">self</span>.msg2Statusbar.emit(<span class="st">"Game over"</span>)</a>
|
||
<a class="sourceLine" id="cb1-320" data-line-number="320"></a>
|
||
<a class="sourceLine" id="cb1-321" data-line-number="321"></a>
|
||
<a class="sourceLine" id="cb1-322" data-line-number="322"></a>
|
||
<a class="sourceLine" id="cb1-323" data-line-number="323"> <span class="kw">def</span> tryMove(<span class="va">self</span>, newPiece, newX, newY):</a>
|
||
<a class="sourceLine" id="cb1-324" data-line-number="324"> <span class="co">'''tries to move a shape'''</span></a>
|
||
<a class="sourceLine" id="cb1-325" data-line-number="325"> </a>
|
||
<a class="sourceLine" id="cb1-326" data-line-number="326"> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">4</span>):</a>
|
||
<a class="sourceLine" id="cb1-327" data-line-number="327"> </a>
|
||
<a class="sourceLine" id="cb1-328" data-line-number="328"> x <span class="op">=</span> newX <span class="op">+</span> newPiece.x(i)</a>
|
||
<a class="sourceLine" id="cb1-329" data-line-number="329"> y <span class="op">=</span> newY <span class="op">-</span> newPiece.y(i)</a>
|
||
<a class="sourceLine" id="cb1-330" data-line-number="330"> </a>
|
||
<a class="sourceLine" id="cb1-331" data-line-number="331"> <span class="cf">if</span> x <span class="op"><</span> <span class="dv">0</span> <span class="kw">or</span> x <span class="op">>=</span> Board.BoardWidth <span class="kw">or</span> y <span class="op"><</span> <span class="dv">0</span> <span class="kw">or</span> y <span class="op">>=</span> Board.BoardHeight:</a>
|
||
<a class="sourceLine" id="cb1-332" data-line-number="332"> <span class="cf">return</span> <span class="va">False</span></a>
|
||
<a class="sourceLine" id="cb1-333" data-line-number="333"> </a>
|
||
<a class="sourceLine" id="cb1-334" data-line-number="334"> <span class="cf">if</span> <span class="va">self</span>.shapeAt(x, y) <span class="op">!=</span> Tetrominoe.NoShape:</a>
|
||
<a class="sourceLine" id="cb1-335" data-line-number="335"> <span class="cf">return</span> <span class="va">False</span></a>
|
||
<a class="sourceLine" id="cb1-336" data-line-number="336"></a>
|
||
<a class="sourceLine" id="cb1-337" data-line-number="337"> <span class="va">self</span>.curPiece <span class="op">=</span> newPiece</a>
|
||
<a class="sourceLine" id="cb1-338" data-line-number="338"> <span class="va">self</span>.curX <span class="op">=</span> newX</a>
|
||
<a class="sourceLine" id="cb1-339" data-line-number="339"> <span class="va">self</span>.curY <span class="op">=</span> newY</a>
|
||
<a class="sourceLine" id="cb1-340" data-line-number="340"> <span class="va">self</span>.update()</a>
|
||
<a class="sourceLine" id="cb1-341" data-line-number="341"> </a>
|
||
<a class="sourceLine" id="cb1-342" data-line-number="342"> <span class="cf">return</span> <span class="va">True</span></a>
|
||
<a class="sourceLine" id="cb1-343" data-line-number="343"> </a>
|
||
<a class="sourceLine" id="cb1-344" data-line-number="344"></a>
|
||
<a class="sourceLine" id="cb1-345" data-line-number="345"> <span class="kw">def</span> drawSquare(<span class="va">self</span>, painter, x, y, shape):</a>
|
||
<a class="sourceLine" id="cb1-346" data-line-number="346"> <span class="co">'''draws a square of a shape'''</span> </a>
|
||
<a class="sourceLine" id="cb1-347" data-line-number="347"> </a>
|
||
<a class="sourceLine" id="cb1-348" data-line-number="348"> colorTable <span class="op">=</span> [<span class="bn">0x000000</span>, <span class="bn">0xCC6666</span>, <span class="bn">0x66CC66</span>, <span class="bn">0x6666CC</span>,</a>
|
||
<a class="sourceLine" id="cb1-349" data-line-number="349"> <span class="bn">0xCCCC66</span>, <span class="bn">0xCC66CC</span>, <span class="bn">0x66CCCC</span>, <span class="bn">0xDAAA00</span>]</a>
|
||
<a class="sourceLine" id="cb1-350" data-line-number="350"></a>
|
||
<a class="sourceLine" id="cb1-351" data-line-number="351"> color <span class="op">=</span> QColor(colorTable[shape])</a>
|
||
<a class="sourceLine" id="cb1-352" data-line-number="352"> painter.fillRect(x <span class="op">+</span> <span class="dv">1</span>, y <span class="op">+</span> <span class="dv">1</span>, <span class="va">self</span>.squareWidth() <span class="op">-</span> <span class="dv">2</span>, </a>
|
||
<a class="sourceLine" id="cb1-353" data-line-number="353"> <span class="va">self</span>.squareHeight() <span class="op">-</span> <span class="dv">2</span>, color)</a>
|
||
<a class="sourceLine" id="cb1-354" data-line-number="354"></a>
|
||
<a class="sourceLine" id="cb1-355" data-line-number="355"> painter.setPen(color.lighter())</a>
|
||
<a class="sourceLine" id="cb1-356" data-line-number="356"> painter.drawLine(x, y <span class="op">+</span> <span class="va">self</span>.squareHeight() <span class="op">-</span> <span class="dv">1</span>, x, y)</a>
|
||
<a class="sourceLine" id="cb1-357" data-line-number="357"> painter.drawLine(x, y, x <span class="op">+</span> <span class="va">self</span>.squareWidth() <span class="op">-</span> <span class="dv">1</span>, y)</a>
|
||
<a class="sourceLine" id="cb1-358" data-line-number="358"></a>
|
||
<a class="sourceLine" id="cb1-359" data-line-number="359"> painter.setPen(color.darker())</a>
|
||
<a class="sourceLine" id="cb1-360" data-line-number="360"> painter.drawLine(x <span class="op">+</span> <span class="dv">1</span>, y <span class="op">+</span> <span class="va">self</span>.squareHeight() <span class="op">-</span> <span class="dv">1</span>,</a>
|
||
<a class="sourceLine" id="cb1-361" data-line-number="361"> x <span class="op">+</span> <span class="va">self</span>.squareWidth() <span class="op">-</span> <span class="dv">1</span>, y <span class="op">+</span> <span class="va">self</span>.squareHeight() <span class="op">-</span> <span class="dv">1</span>)</a>
|
||
<a class="sourceLine" id="cb1-362" data-line-number="362"> painter.drawLine(x <span class="op">+</span> <span class="va">self</span>.squareWidth() <span class="op">-</span> <span class="dv">1</span>, </a>
|
||
<a class="sourceLine" id="cb1-363" data-line-number="363"> y <span class="op">+</span> <span class="va">self</span>.squareHeight() <span class="op">-</span> <span class="dv">1</span>, x <span class="op">+</span> <span class="va">self</span>.squareWidth() <span class="op">-</span> <span class="dv">1</span>, y <span class="op">+</span> <span class="dv">1</span>)</a>
|
||
<a class="sourceLine" id="cb1-364" data-line-number="364"></a>
|
||
<a class="sourceLine" id="cb1-365" data-line-number="365"></a>
|
||
<a class="sourceLine" id="cb1-366" data-line-number="366"><span class="kw">class</span> Tetrominoe(<span class="bu">object</span>):</a>
|
||
<a class="sourceLine" id="cb1-367" data-line-number="367"> </a>
|
||
<a class="sourceLine" id="cb1-368" data-line-number="368"> NoShape <span class="op">=</span> <span class="dv">0</span></a>
|
||
<a class="sourceLine" id="cb1-369" data-line-number="369"> ZShape <span class="op">=</span> <span class="dv">1</span></a>
|
||
<a class="sourceLine" id="cb1-370" data-line-number="370"> SShape <span class="op">=</span> <span class="dv">2</span></a>
|
||
<a class="sourceLine" id="cb1-371" data-line-number="371"> LineShape <span class="op">=</span> <span class="dv">3</span></a>
|
||
<a class="sourceLine" id="cb1-372" data-line-number="372"> TShape <span class="op">=</span> <span class="dv">4</span></a>
|
||
<a class="sourceLine" id="cb1-373" data-line-number="373"> SquareShape <span class="op">=</span> <span class="dv">5</span></a>
|
||
<a class="sourceLine" id="cb1-374" data-line-number="374"> LShape <span class="op">=</span> <span class="dv">6</span></a>
|
||
<a class="sourceLine" id="cb1-375" data-line-number="375"> MirroredLShape <span class="op">=</span> <span class="dv">7</span></a>
|
||
<a class="sourceLine" id="cb1-376" data-line-number="376"></a>
|
||
<a class="sourceLine" id="cb1-377" data-line-number="377"></a>
|
||
<a class="sourceLine" id="cb1-378" data-line-number="378"><span class="kw">class</span> Shape(<span class="bu">object</span>):</a>
|
||
<a class="sourceLine" id="cb1-379" data-line-number="379"> </a>
|
||
<a class="sourceLine" id="cb1-380" data-line-number="380"> coordsTable <span class="op">=</span> (</a>
|
||
<a class="sourceLine" id="cb1-381" data-line-number="381"> ((<span class="dv">0</span>, <span class="dv">0</span>), (<span class="dv">0</span>, <span class="dv">0</span>), (<span class="dv">0</span>, <span class="dv">0</span>), (<span class="dv">0</span>, <span class="dv">0</span>)),</a>
|
||
<a class="sourceLine" id="cb1-382" data-line-number="382"> ((<span class="dv">0</span>, <span class="dv">-1</span>), (<span class="dv">0</span>, <span class="dv">0</span>), (<span class="op">-</span><span class="dv">1</span>, <span class="dv">0</span>), (<span class="op">-</span><span class="dv">1</span>, <span class="dv">1</span>)),</a>
|
||
<a class="sourceLine" id="cb1-383" data-line-number="383"> ((<span class="dv">0</span>, <span class="dv">-1</span>), (<span class="dv">0</span>, <span class="dv">0</span>), (<span class="dv">1</span>, <span class="dv">0</span>), (<span class="dv">1</span>, <span class="dv">1</span>)),</a>
|
||
<a class="sourceLine" id="cb1-384" data-line-number="384"> ((<span class="dv">0</span>, <span class="dv">-1</span>), (<span class="dv">0</span>, <span class="dv">0</span>), (<span class="dv">0</span>, <span class="dv">1</span>), (<span class="dv">0</span>, <span class="dv">2</span>)),</a>
|
||
<a class="sourceLine" id="cb1-385" data-line-number="385"> ((<span class="op">-</span><span class="dv">1</span>, <span class="dv">0</span>), (<span class="dv">0</span>, <span class="dv">0</span>), (<span class="dv">1</span>, <span class="dv">0</span>), (<span class="dv">0</span>, <span class="dv">1</span>)),</a>
|
||
<a class="sourceLine" id="cb1-386" data-line-number="386"> ((<span class="dv">0</span>, <span class="dv">0</span>), (<span class="dv">1</span>, <span class="dv">0</span>), (<span class="dv">0</span>, <span class="dv">1</span>), (<span class="dv">1</span>, <span class="dv">1</span>)),</a>
|
||
<a class="sourceLine" id="cb1-387" data-line-number="387"> ((<span class="op">-</span><span class="dv">1</span>, <span class="dv">-1</span>), (<span class="dv">0</span>, <span class="dv">-1</span>), (<span class="dv">0</span>, <span class="dv">0</span>), (<span class="dv">0</span>, <span class="dv">1</span>)),</a>
|
||
<a class="sourceLine" id="cb1-388" data-line-number="388"> ((<span class="dv">1</span>, <span class="dv">-1</span>), (<span class="dv">0</span>, <span class="dv">-1</span>), (<span class="dv">0</span>, <span class="dv">0</span>), (<span class="dv">0</span>, <span class="dv">1</span>))</a>
|
||
<a class="sourceLine" id="cb1-389" data-line-number="389"> )</a>
|
||
<a class="sourceLine" id="cb1-390" data-line-number="390"></a>
|
||
<a class="sourceLine" id="cb1-391" data-line-number="391"> <span class="kw">def</span> <span class="fu">__init__</span>(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-392" data-line-number="392"> </a>
|
||
<a class="sourceLine" id="cb1-393" data-line-number="393"> <span class="va">self</span>.coords <span class="op">=</span> [[<span class="dv">0</span>,<span class="dv">0</span>] <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">4</span>)]</a>
|
||
<a class="sourceLine" id="cb1-394" data-line-number="394"> <span class="va">self</span>.pieceShape <span class="op">=</span> Tetrominoe.NoShape</a>
|
||
<a class="sourceLine" id="cb1-395" data-line-number="395"></a>
|
||
<a class="sourceLine" id="cb1-396" data-line-number="396"> <span class="va">self</span>.setShape(Tetrominoe.NoShape)</a>
|
||
<a class="sourceLine" id="cb1-397" data-line-number="397"> </a>
|
||
<a class="sourceLine" id="cb1-398" data-line-number="398"></a>
|
||
<a class="sourceLine" id="cb1-399" data-line-number="399"> <span class="kw">def</span> shape(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-400" data-line-number="400"> <span class="co">'''returns shape'''</span></a>
|
||
<a class="sourceLine" id="cb1-401" data-line-number="401"> </a>
|
||
<a class="sourceLine" id="cb1-402" data-line-number="402"> <span class="cf">return</span> <span class="va">self</span>.pieceShape</a>
|
||
<a class="sourceLine" id="cb1-403" data-line-number="403"> </a>
|
||
<a class="sourceLine" id="cb1-404" data-line-number="404"></a>
|
||
<a class="sourceLine" id="cb1-405" data-line-number="405"> <span class="kw">def</span> setShape(<span class="va">self</span>, shape):</a>
|
||
<a class="sourceLine" id="cb1-406" data-line-number="406"> <span class="co">'''sets a shape'''</span></a>
|
||
<a class="sourceLine" id="cb1-407" data-line-number="407"> </a>
|
||
<a class="sourceLine" id="cb1-408" data-line-number="408"> table <span class="op">=</span> Shape.coordsTable[shape]</a>
|
||
<a class="sourceLine" id="cb1-409" data-line-number="409"> </a>
|
||
<a class="sourceLine" id="cb1-410" data-line-number="410"> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">4</span>):</a>
|
||
<a class="sourceLine" id="cb1-411" data-line-number="411"> <span class="cf">for</span> j <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">2</span>):</a>
|
||
<a class="sourceLine" id="cb1-412" data-line-number="412"> <span class="va">self</span>.coords[i][j] <span class="op">=</span> table[i][j]</a>
|
||
<a class="sourceLine" id="cb1-413" data-line-number="413"></a>
|
||
<a class="sourceLine" id="cb1-414" data-line-number="414"> <span class="va">self</span>.pieceShape <span class="op">=</span> shape</a>
|
||
<a class="sourceLine" id="cb1-415" data-line-number="415"> </a>
|
||
<a class="sourceLine" id="cb1-416" data-line-number="416"></a>
|
||
<a class="sourceLine" id="cb1-417" data-line-number="417"> <span class="kw">def</span> setRandomShape(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-418" data-line-number="418"> <span class="co">'''chooses a random shape'''</span></a>
|
||
<a class="sourceLine" id="cb1-419" data-line-number="419"> </a>
|
||
<a class="sourceLine" id="cb1-420" data-line-number="420"> <span class="va">self</span>.setShape(random.randint(<span class="dv">1</span>, <span class="dv">7</span>))</a>
|
||
<a class="sourceLine" id="cb1-421" data-line-number="421"></a>
|
||
<a class="sourceLine" id="cb1-422" data-line-number="422"> </a>
|
||
<a class="sourceLine" id="cb1-423" data-line-number="423"> <span class="kw">def</span> x(<span class="va">self</span>, index):</a>
|
||
<a class="sourceLine" id="cb1-424" data-line-number="424"> <span class="co">'''returns x coordinate'''</span></a>
|
||
<a class="sourceLine" id="cb1-425" data-line-number="425"> </a>
|
||
<a class="sourceLine" id="cb1-426" data-line-number="426"> <span class="cf">return</span> <span class="va">self</span>.coords[index][<span class="dv">0</span>]</a>
|
||
<a class="sourceLine" id="cb1-427" data-line-number="427"></a>
|
||
<a class="sourceLine" id="cb1-428" data-line-number="428"> </a>
|
||
<a class="sourceLine" id="cb1-429" data-line-number="429"> <span class="kw">def</span> y(<span class="va">self</span>, index):</a>
|
||
<a class="sourceLine" id="cb1-430" data-line-number="430"> <span class="co">'''returns y coordinate'''</span></a>
|
||
<a class="sourceLine" id="cb1-431" data-line-number="431"> </a>
|
||
<a class="sourceLine" id="cb1-432" data-line-number="432"> <span class="cf">return</span> <span class="va">self</span>.coords[index][<span class="dv">1</span>]</a>
|
||
<a class="sourceLine" id="cb1-433" data-line-number="433"></a>
|
||
<a class="sourceLine" id="cb1-434" data-line-number="434"> </a>
|
||
<a class="sourceLine" id="cb1-435" data-line-number="435"> <span class="kw">def</span> setX(<span class="va">self</span>, index, x):</a>
|
||
<a class="sourceLine" id="cb1-436" data-line-number="436"> <span class="co">'''sets x coordinate'''</span></a>
|
||
<a class="sourceLine" id="cb1-437" data-line-number="437"> </a>
|
||
<a class="sourceLine" id="cb1-438" data-line-number="438"> <span class="va">self</span>.coords[index][<span class="dv">0</span>] <span class="op">=</span> x</a>
|
||
<a class="sourceLine" id="cb1-439" data-line-number="439"></a>
|
||
<a class="sourceLine" id="cb1-440" data-line-number="440"> </a>
|
||
<a class="sourceLine" id="cb1-441" data-line-number="441"> <span class="kw">def</span> setY(<span class="va">self</span>, index, y):</a>
|
||
<a class="sourceLine" id="cb1-442" data-line-number="442"> <span class="co">'''sets y coordinate'''</span></a>
|
||
<a class="sourceLine" id="cb1-443" data-line-number="443"> </a>
|
||
<a class="sourceLine" id="cb1-444" data-line-number="444"> <span class="va">self</span>.coords[index][<span class="dv">1</span>] <span class="op">=</span> y</a>
|
||
<a class="sourceLine" id="cb1-445" data-line-number="445"></a>
|
||
<a class="sourceLine" id="cb1-446" data-line-number="446"> </a>
|
||
<a class="sourceLine" id="cb1-447" data-line-number="447"> <span class="kw">def</span> minX(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-448" data-line-number="448"> <span class="co">'''returns min x value'''</span></a>
|
||
<a class="sourceLine" id="cb1-449" data-line-number="449"> </a>
|
||
<a class="sourceLine" id="cb1-450" data-line-number="450"> m <span class="op">=</span> <span class="va">self</span>.coords[<span class="dv">0</span>][<span class="dv">0</span>]</a>
|
||
<a class="sourceLine" id="cb1-451" data-line-number="451"> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">4</span>):</a>
|
||
<a class="sourceLine" id="cb1-452" data-line-number="452"> m <span class="op">=</span> <span class="bu">min</span>(m, <span class="va">self</span>.coords[i][<span class="dv">0</span>])</a>
|
||
<a class="sourceLine" id="cb1-453" data-line-number="453"></a>
|
||
<a class="sourceLine" id="cb1-454" data-line-number="454"> <span class="cf">return</span> m</a>
|
||
<a class="sourceLine" id="cb1-455" data-line-number="455"></a>
|
||
<a class="sourceLine" id="cb1-456" data-line-number="456"> </a>
|
||
<a class="sourceLine" id="cb1-457" data-line-number="457"> <span class="kw">def</span> maxX(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-458" data-line-number="458"> <span class="co">'''returns max x value'''</span></a>
|
||
<a class="sourceLine" id="cb1-459" data-line-number="459"> </a>
|
||
<a class="sourceLine" id="cb1-460" data-line-number="460"> m <span class="op">=</span> <span class="va">self</span>.coords[<span class="dv">0</span>][<span class="dv">0</span>]</a>
|
||
<a class="sourceLine" id="cb1-461" data-line-number="461"> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">4</span>):</a>
|
||
<a class="sourceLine" id="cb1-462" data-line-number="462"> m <span class="op">=</span> <span class="bu">max</span>(m, <span class="va">self</span>.coords[i][<span class="dv">0</span>])</a>
|
||
<a class="sourceLine" id="cb1-463" data-line-number="463"></a>
|
||
<a class="sourceLine" id="cb1-464" data-line-number="464"> <span class="cf">return</span> m</a>
|
||
<a class="sourceLine" id="cb1-465" data-line-number="465"></a>
|
||
<a class="sourceLine" id="cb1-466" data-line-number="466"> </a>
|
||
<a class="sourceLine" id="cb1-467" data-line-number="467"> <span class="kw">def</span> minY(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-468" data-line-number="468"> <span class="co">'''returns min y value'''</span></a>
|
||
<a class="sourceLine" id="cb1-469" data-line-number="469"> </a>
|
||
<a class="sourceLine" id="cb1-470" data-line-number="470"> m <span class="op">=</span> <span class="va">self</span>.coords[<span class="dv">0</span>][<span class="dv">1</span>]</a>
|
||
<a class="sourceLine" id="cb1-471" data-line-number="471"> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">4</span>):</a>
|
||
<a class="sourceLine" id="cb1-472" data-line-number="472"> m <span class="op">=</span> <span class="bu">min</span>(m, <span class="va">self</span>.coords[i][<span class="dv">1</span>])</a>
|
||
<a class="sourceLine" id="cb1-473" data-line-number="473"></a>
|
||
<a class="sourceLine" id="cb1-474" data-line-number="474"> <span class="cf">return</span> m</a>
|
||
<a class="sourceLine" id="cb1-475" data-line-number="475"></a>
|
||
<a class="sourceLine" id="cb1-476" data-line-number="476"> </a>
|
||
<a class="sourceLine" id="cb1-477" data-line-number="477"> <span class="kw">def</span> maxY(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-478" data-line-number="478"> <span class="co">'''returns max y value'''</span></a>
|
||
<a class="sourceLine" id="cb1-479" data-line-number="479"> </a>
|
||
<a class="sourceLine" id="cb1-480" data-line-number="480"> m <span class="op">=</span> <span class="va">self</span>.coords[<span class="dv">0</span>][<span class="dv">1</span>]</a>
|
||
<a class="sourceLine" id="cb1-481" data-line-number="481"> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">4</span>):</a>
|
||
<a class="sourceLine" id="cb1-482" data-line-number="482"> m <span class="op">=</span> <span class="bu">max</span>(m, <span class="va">self</span>.coords[i][<span class="dv">1</span>])</a>
|
||
<a class="sourceLine" id="cb1-483" data-line-number="483"></a>
|
||
<a class="sourceLine" id="cb1-484" data-line-number="484"> <span class="cf">return</span> m</a>
|
||
<a class="sourceLine" id="cb1-485" data-line-number="485"></a>
|
||
<a class="sourceLine" id="cb1-486" data-line-number="486"> </a>
|
||
<a class="sourceLine" id="cb1-487" data-line-number="487"> <span class="kw">def</span> rotateLeft(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-488" data-line-number="488"> <span class="co">'''rotates shape to the left'''</span></a>
|
||
<a class="sourceLine" id="cb1-489" data-line-number="489"> </a>
|
||
<a class="sourceLine" id="cb1-490" data-line-number="490"> <span class="cf">if</span> <span class="va">self</span>.pieceShape <span class="op">==</span> Tetrominoe.SquareShape:</a>
|
||
<a class="sourceLine" id="cb1-491" data-line-number="491"> <span class="cf">return</span> <span class="va">self</span></a>
|
||
<a class="sourceLine" id="cb1-492" data-line-number="492"></a>
|
||
<a class="sourceLine" id="cb1-493" data-line-number="493"> result <span class="op">=</span> Shape()</a>
|
||
<a class="sourceLine" id="cb1-494" data-line-number="494"> result.pieceShape <span class="op">=</span> <span class="va">self</span>.pieceShape</a>
|
||
<a class="sourceLine" id="cb1-495" data-line-number="495"> </a>
|
||
<a class="sourceLine" id="cb1-496" data-line-number="496"> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">4</span>):</a>
|
||
<a class="sourceLine" id="cb1-497" data-line-number="497"> </a>
|
||
<a class="sourceLine" id="cb1-498" data-line-number="498"> result.setX(i, <span class="va">self</span>.y(i))</a>
|
||
<a class="sourceLine" id="cb1-499" data-line-number="499"> result.setY(i, <span class="op">-</span><span class="va">self</span>.x(i))</a>
|
||
<a class="sourceLine" id="cb1-500" data-line-number="500"></a>
|
||
<a class="sourceLine" id="cb1-501" data-line-number="501"> <span class="cf">return</span> result</a>
|
||
<a class="sourceLine" id="cb1-502" data-line-number="502"></a>
|
||
<a class="sourceLine" id="cb1-503" data-line-number="503"> </a>
|
||
<a class="sourceLine" id="cb1-504" data-line-number="504"> <span class="kw">def</span> rotateRight(<span class="va">self</span>):</a>
|
||
<a class="sourceLine" id="cb1-505" data-line-number="505"> <span class="co">'''rotates shape to the right'''</span></a>
|
||
<a class="sourceLine" id="cb1-506" data-line-number="506"> </a>
|
||
<a class="sourceLine" id="cb1-507" data-line-number="507"> <span class="cf">if</span> <span class="va">self</span>.pieceShape <span class="op">==</span> Tetrominoe.SquareShape:</a>
|
||
<a class="sourceLine" id="cb1-508" data-line-number="508"> <span class="cf">return</span> <span class="va">self</span></a>
|
||
<a class="sourceLine" id="cb1-509" data-line-number="509"></a>
|
||
<a class="sourceLine" id="cb1-510" data-line-number="510"> result <span class="op">=</span> Shape()</a>
|
||
<a class="sourceLine" id="cb1-511" data-line-number="511"> result.pieceShape <span class="op">=</span> <span class="va">self</span>.pieceShape</a>
|
||
<a class="sourceLine" id="cb1-512" data-line-number="512"> </a>
|
||
<a class="sourceLine" id="cb1-513" data-line-number="513"> <span class="cf">for</span> i <span class="kw">in</span> <span class="bu">range</span>(<span class="dv">4</span>):</a>
|
||
<a class="sourceLine" id="cb1-514" data-line-number="514"> </a>
|
||
<a class="sourceLine" id="cb1-515" data-line-number="515"> result.setX(i, <span class="op">-</span><span class="va">self</span>.y(i))</a>
|
||
<a class="sourceLine" id="cb1-516" data-line-number="516"> result.setY(i, <span class="va">self</span>.x(i))</a>
|
||
<a class="sourceLine" id="cb1-517" data-line-number="517"></a>
|
||
<a class="sourceLine" id="cb1-518" data-line-number="518"> <span class="cf">return</span> result</a>
|
||
<a class="sourceLine" id="cb1-519" data-line-number="519"></a>
|
||
<a class="sourceLine" id="cb1-520" data-line-number="520"></a>
|
||
<a class="sourceLine" id="cb1-521" data-line-number="521"><span class="cf">if</span> <span class="va">__name__</span> <span class="op">==</span> <span class="st">'__main__'</span>:</a>
|
||
<a class="sourceLine" id="cb1-522" data-line-number="522"> </a>
|
||
<a class="sourceLine" id="cb1-523" data-line-number="523"> app <span class="op">=</span> QApplication([])</a>
|
||
<a class="sourceLine" id="cb1-524" data-line-number="524"> tetris <span class="op">=</span> Tetris() </a>
|
||
<a class="sourceLine" id="cb1-525" data-line-number="525"> sys.exit(app.exec_())</a></code></pre></div>
|
||
<p>游戏很简单,所以也就很好理解。程序加载之后游戏也就直接开始了,可以用P键暂停游戏,空格键让方块直接落到最下面。游戏的速度是固定的,并没有实现加速的功能。分数就是游戏中消除的行数。</p>
|
||
<pre><code class="language-python">self.tboard = Board(self)
|
||
self.setCentralWidget(self.tboard)</code></pre>
|
||
<p>创建了一个Board类的实例,并设置为应用的中心组件。</p>
|
||
<pre><code class="language-python">self.statusbar = self.statusBar()
|
||
self.tboard.msg2Statusbar[str].connect(self.statusbar.showMessage)</code></pre>
|
||
<p>创建一个<code>statusbar</code>来显示三种信息:消除的行数,游戏暂停状态或者游戏结束状态。<code>msg2Statusbar</code>是一个自定义的信号,用在(和)Board类(交互),<code>showMessage()</code>方法是一个内建的,用来在statusbar上显示信息的方法。</p>
|
||
<pre><code class="language-python">self.tboard.start()</code></pre>
|
||
<p>初始化游戏:</p>
|
||
<pre><code class="language-python">class Board(QFrame):
|
||
|
||
msg2Statusbar = pyqtSignal(str)
|
||
... </code></pre>
|
||
<p>创建了一个自定义信号<code>msg2Statusbar</code>,当我们想往<code>statusbar</code>里显示信息的时候,发出这个信号就行了。</p>
|
||
<pre><code class="language-python">BoardWidth = 10
|
||
BoardHeight = 22
|
||
Speed = 300</code></pre>
|
||
<p>这些是<code>Board</code>类的变量。<code>BoardWidth</code>和<code>BoardHeight</code>分别是board的宽度和高度。<code>Speed</code>是游戏的速度,每300ms出现一个新的方块。</p>
|
||
<pre><code class="language-python">...
|
||
self.curX = 0
|
||
self.curY = 0
|
||
self.numLinesRemoved = 0
|
||
self.board = []
|
||
...</code></pre>
|
||
<p>在<code>initBoard()</code>里初始化了一些重要的变量。<code>self.board</code>定义了方块的形状和位置,取值范围是0-7。</p>
|
||
<pre><code class="language-python">def shapeAt(self, x, y):
|
||
return self.board[(y * Board.BoardWidth) + x]</code></pre>
|
||
<p><code>shapeAt()</code>决定了board里方块的的种类。</p>
|
||
<pre><code class="language-python">def squareWidth(self):
|
||
return self.contentsRect().width() // Board.BoardWidth</code></pre>
|
||
<p>board的大小可以动态的改变。所以方格的大小也应该随之变化。<code>squareWidth()</code>计算并返回每个块应该占用多少像素–也即<code>Board.BoardWidth</code>。</p>
|
||
<pre><code class="language-python">def pause(self):
|
||
'''pauses game'''
|
||
|
||
if not self.isStarted:
|
||
return
|
||
|
||
self.isPaused = not self.isPaused
|
||
|
||
if self.isPaused:
|
||
self.timer.stop()
|
||
self.msg2Statusbar.emit("paused")
|
||
|
||
else:
|
||
self.timer.start(Board.Speed, self)
|
||
self.msg2Statusbar.emit(str(self.numLinesRemoved))
|
||
|
||
self.update()</code></pre>
|
||
<p><code>pause()</code>方法用来暂停游戏,停止计时并在<code>statusbar</code>上显示一条信息。</p>
|
||
<pre><code class="language-python">def paintEvent(self, event):
|
||
'''paints all shapes of the game'''
|
||
|
||
painter = QPainter(self)
|
||
rect = self.contentsRect()
|
||
...</code></pre>
|
||
<p>渲染是在paintEvent()方法里发生的<code>QPainter</code>负责PyQt5里所有低级绘画操作。</p>
|
||
<pre><code class="language-python">for i in range(Board.BoardHeight):
|
||
for j in range(Board.BoardWidth):
|
||
shape = self.shapeAt(j, Board.BoardHeight - i - 1)
|
||
|
||
if shape != Tetrominoe.NoShape:
|
||
self.drawSquare(painter,
|
||
rect.left() + j * self.squareWidth(),
|
||
boardTop + i * self.squareHeight(), shape)</code></pre>
|
||
<p>渲染游戏分为两步。第一步是先画出所有已经落在最下面的的图,这些保存在<code>self.board</code>里。可以使用<code>shapeAt()</code>查看这个这个变量。</p>
|
||
<pre><code class="language-python">if self.curPiece.shape() != Tetrominoe.NoShape:
|
||
|
||
for i in range(4):
|
||
|
||
x = self.curX + self.curPiece.x(i)
|
||
y = self.curY - self.curPiece.y(i)
|
||
self.drawSquare(painter, rect.left() + x * self.squareWidth(),
|
||
boardTop + (Board.BoardHeight - y - 1) * self.squareHeight(),
|
||
self.curPiece.shape())</code></pre>
|
||
<p>第二步是画出更在下落的方块。</p>
|
||
<pre><code class="language-python">elif key == Qt.Key_Right:
|
||
self.tryMove(self.curPiece, self.curX + 1, self.curY)</code></pre>
|
||
<p>在<code>keyPressEvent()</code>方法获得用户按下的按键。如果按下的是右方向键,就尝试把方块向右移动,说尝试是因为有可能到边界不能移动了。</p>
|
||
<pre><code class="language-python">elif key == Qt.Key_Up:
|
||
self.tryMove(self.curPiece.rotateLeft(), self.curX, self.curY)</code></pre>
|
||
<p>上方向键是把方块向左旋转一下</p>
|
||
<pre><code class="language-python">elif key == Qt.Key_Space:
|
||
self.dropDown()</code></pre>
|
||
<p>空格键会直接把方块放到底部</p>
|
||
<pre><code class="language-python">elif key == Qt.Key_D:
|
||
self.oneLineDown()</code></pre>
|
||
<p>D键是加速一次下落速度。</p>
|
||
<pre><code class="language-python">def tryMove(self, newPiece, newX, newY):
|
||
|
||
for i in range(4):
|
||
|
||
x = newX + newPiece.x(i)
|
||
y = newY - newPiece.y(i)
|
||
|
||
if x < 0 or x >= Board.BoardWidth or y < 0 or y >= Board.BoardHeight:
|
||
return False
|
||
|
||
if self.shapeAt(x, y) != Tetrominoe.NoShape:
|
||
return False
|
||
|
||
self.curPiece = newPiece
|
||
self.curX = newX
|
||
self.curY = newY
|
||
self.update()
|
||
return True</code></pre>
|
||
<p><code>tryMove()</code>是尝试移动方块的方法。如果方块已经到达board的边缘或者遇到了其他方块,就返回False。否则就把方块下落到想要</p>
|
||
<pre><code class="language-python">def timerEvent(self, event):
|
||
|
||
if event.timerId() == self.timer.timerId():
|
||
|
||
if self.isWaitingAfterLine:
|
||
self.isWaitingAfterLine = False
|
||
self.newPiece()
|
||
else:
|
||
self.oneLineDown()
|
||
|
||
else:
|
||
super(Board, self).timerEvent(event)</code></pre>
|
||
<p>在计时器事件里,要么是等一个方块下落完之后创建一个新的方块,要么是让一个方块直接落到底(move a falling piece one line down)。</p>
|
||
<pre><code class="language-python">def clearBoard(self):
|
||
|
||
for i in range(Board.BoardHeight * Board.BoardWidth):
|
||
self.board.append(Tetrominoe.NoShape)</code></pre>
|
||
<p><code>clearBoard(</code>)方法通过<code>Tetrominoe.NoShape</code>清空<code>broad</code>。</p>
|
||
<pre><code class="language-python">def removeFullLines(self):
|
||
|
||
numFullLines = 0
|
||
rowsToRemove = []
|
||
|
||
for i in range(Board.BoardHeight):
|
||
|
||
n = 0
|
||
for j in range(Board.BoardWidth):
|
||
if not self.shapeAt(j, i) == Tetrominoe.NoShape:
|
||
n = n + 1
|
||
|
||
if n == 10:
|
||
rowsToRemove.append(i)
|
||
|
||
rowsToRemove.reverse()
|
||
|
||
|
||
for m in rowsToRemove:
|
||
|
||
for k in range(m, Board.BoardHeight):
|
||
for l in range(Board.BoardWidth):
|
||
self.setShapeAt(l, k, self.shapeAt(l, k + 1))
|
||
|
||
numFullLines = numFullLines + len(rowsToRemove)
|
||
...</code></pre>
|
||
<p>如果方块碰到了底部,就调用<code>removeFullLines()</code>方法,找到所有能消除的行消除它们。消除的具体动作就是把符合条件的行消除掉之后,再把它上面的行下降一行。注意移除满行的动作是倒着来的,因为我们是按照重力来表现游戏的,如果不这样就有可能出现有些方块浮在空中的现象。</p>
|
||
<pre><code class="language-python">def newPiece(self):
|
||
|
||
self.curPiece = Shape()
|
||
self.curPiece.setRandomShape()
|
||
self.curX = Board.BoardWidth // 2 + 1
|
||
self.curY = Board.BoardHeight - 1 + self.curPiece.minY()
|
||
|
||
if not self.tryMove(self.curPiece, self.curX, self.curY):
|
||
|
||
self.curPiece.setShape(Tetrominoe.NoShape)
|
||
self.timer.stop()
|
||
self.isStarted = False
|
||
self.msg2Statusbar.emit("Game over")</code></pre>
|
||
<p><code>newPiece()</code>方法是用来创建形状随机的方块。如果随机的方块不能正确的出现在预设的位置,游戏结束。</p>
|
||
<pre><code class="language-python">class Tetrominoe(object):
|
||
|
||
NoShape = 0
|
||
ZShape = 1
|
||
SShape = 2
|
||
LineShape = 3
|
||
TShape = 4
|
||
SquareShape = 5
|
||
LShape = 6
|
||
MirroredLShape = 7</code></pre>
|
||
<p><code>Tetrominoe</code>类保存了所有方块的形状。我们还定义了一个<code>NoShape</code>的空形状。</p>
|
||
<p>Shape类保存类方块内部的信息。</p>
|
||
<pre><code class="language-python">class Shape(object):
|
||
|
||
coordsTable = (
|
||
((0, 0), (0, 0), (0, 0), (0, 0)),
|
||
((0, -1), (0, 0), (-1, 0), (-1, 1)),
|
||
...
|
||
)
|
||
... </code></pre>
|
||
<p>coordsTable元组保存了所有的方块形状的组成。是一个构成方块的坐标模版。</p>
|
||
<pre><code class="language-python">self.coords = [[0,0] for i in range(4)]</code></pre>
|
||
<p>上面创建了一个新的空坐标数组,这个数组将用来保存方块的坐标。</p>
|
||
<p>坐标系示意图:</p>
|
||
<figure>
|
||
<img class="whitelist" src="docs/PyQt5/images/11-coordinates.png" alt="coordinates" />
|
||
</figure>
|
||
<p>上面的图片可以帮助我们更好的理解坐标值的意义。比如元组<code>(0, -1), (0, 0), (-1, 0), (-1, -1)</code>代表了一个Z形状的方块。这个图表就描绘了这个形状。</p>
|
||
<pre><code class="language-python">def rotateLeft(self):
|
||
|
||
if self.pieceShape == Tetrominoe.SquareShape:
|
||
return self
|
||
|
||
result = Shape()
|
||
result.pieceShape = self.pieceShape
|
||
|
||
for i in range(4):
|
||
|
||
result.setX(i, self.y(i))
|
||
result.setY(i, -self.x(i))
|
||
|
||
return result</code></pre>
|
||
<p><code>rotateLeft()</code>方法向右旋转一个方块。正方形的方块就没必要旋转,就直接返回了。其他的是返回一个新的,能表示这个形状旋转了的坐标。</p>
|
||
<p>程序展示:</p>
|
||
<figure>
|
||
<img class="whitelist" src="docs/PyQt5/images/11-tetris.png" alt="Tetris" />
|
||
</figure>
|