2018年12月16日日曜日

WxPythonのテトリスがあったのでコードを読んでみた。№2ブロック表示

参考サイト

テトリス
http://wxpython.at-ninja.jp/thetetrisgame.html

だいぶ複雑なコードなので順に読み解いていきます。
最初はウィンドウなどの表示のみのコードでしたが、今回はブロックも表示してみます。

コードの流れ

Shapeクラスでcoordsを決定してブロックの形状を決定します。
それをOnPaintで実際の座標に変換して、drawSquareでブロックを
描きます
coordsでの形状表示が、OnPaintで実際の座標に変換される時
y軸方向の表示が上下逆になります。


コード

E:\MyBackups\goolgedrive\myprg_main\python_my_prg\wxpython\game_tetoris_draw_kakidasi.py


# coding: UTF-8
#http://wxpython.at-ninja.jp/thetetrisgame.html
#テトリス
#ゲームは少し簡略化してあるので理解しやすいと思います。 アプ
#リケーションを立ち上げるとすぐにゲームが開始されます。 pキー
#を押すと、ゲームを中断することができます。 スペースキーでテ
#トリミノを即座に落下させることができます。 dキーはミノを1行
#ずつ落下させます。(落下速度を少し速くしたい場合に使いましょ
#う) ゲーム速度は一定で、速くなることはありません。 スコアは
#消去した行数です。

# tetris.py

import wx
import random

#SetFocus ( ) 
#これにより、キーボード入力を受け取るウィンドウが設定されます。
#別にこの関数いらないと思う。今までウィンドウのフォーカスを
#気にしなくてもうまくいっていた。

class MyApp(wx.App):
    def __init__(self): 
        #エラーが出たらファイルに書き出す
        wx.App.__init__(self, redirect=True, filename="game_tetoris_log.txt")
        #wx.App.__init__(self, redirect=True )



class Tetris(wx.Frame):
    def __init__(self, parent, id, title):
        wx.Frame.__init__(self, parent, id, title, size=(180, 380))
        #ステータスバー作成
        self.statusbar = self.CreateStatusBar()
        self.statusbar.SetStatusText('0')
        #boardはBoardクラスにも使われているからややこしい
        self.board = Board(self)
        self.board.SetFocus()
        #初期値設定 タイマースタート
        self.board.start()
        self.Centre()
        self.Show(True)

class Board(wx.Panel):
    BoardWidth  = 10
    BoardHeight = 22
    Speed       = 300
    ID_TIMER    = 1

    def __init__(self, parent):
        wx.Panel.__init__(self, parent)
        #イベントをidで区別しているようだ
        # evet_id.py 参照
        self.curPiece           = Shape()#現在のブロックのオブジェクト
        self.nextPiece          = Shape()#次のブロックのオブジェクト

        #現在落下中のブロックを描画するときは、ミノを self.curX
        #と self.curY の位置に描画します。 そして、座標テーブ
        #ルを参照し、4つの正方形全てを描画します。
        self.curX               = 0
        self.curY               = 0
        self.board              = []#ブロックのミノの位置

        #再描画の時OnPaintを呼び出す
        self.Bind(wx.EVT_PAINT, self.OnPaint)


        #ブロックのセル一個の幅、高さ
        self.squareWidth = 17
        self.squareHeight = 15
        self.boardTop = 3


    def start(self):
        self.newPiece()


    def OnPaint(self, event):
        dc = wx.PaintDC(self)

        #次の段階では現在落下中のを描画します。
        #curPiece.shapeは初期値で0
        #curPieceは現在のブロックのオブジェクト
        #Shape()によってpieceShapeが0(Tetrominoes.NoShape)となる
        #しかしsetRandomShape()によって、pieceShapeがランダムに1~7のどれかになる
        if self.curPiece.shape() != Tetrominoes.NoShape:
            #ブロックは4つのセルでできているからrange()
            for i in range(4):
                #例えば coords = [[0, -1], [0, 0], [1, 0], [1, 1]] とすると

                #    ■                [1, 1]
                #  ■■        [0, 0]  [1, 0] 
                #  ■        [0, -1]

                #x(i) coords[index][0]を返す
                x = self.curX + self.curPiece.x(i)
                y = self.curY - self.curPiece.y(i)
                #def drawSquare(self, dc, x, y, shape):
                self.drawSquare(dc, 0 + x * self.squareWidth,
                                self.boardTop + (Board.BoardHeight - y - 1) * self.squareHeight)

                #例えば coords = [[0, -1], [0, 0], [1, 0], [1, 1]] とすると
                #coords[x,-1]の時newPiece()の処理→上の処理後以下となる
                #つまりちょうどyの最低値で うまく0となるよう作られている
                #self.curY                    20
                #self.curPiece.y(i) y        -1
                #y                            21
                #Board.BoardHeight - y - 1   0

                #例えばcoords = [[0, 1], [0, 0], [1, 0], [1, 1]] とすると
                #  ■■        [0, 1]  [1, 1]
                #  ■■        [0, 0]  [1, 0] 

                #coords[x,0]の時newPiece()の処理→上の処理後以下となる
                #つまりちょうどyの最低値で うまく0となるよう作られている
                #self.curY                    21
                #self.curPiece.y(i) y        0
                #y                            21
                #Board.BoardHeight - y - 1    0
                #つまりどのような形状であれ、最初のブロックの表示時ウィンドウ
                #の最上部にピッタリと隙間なく表示される



    #newpiece() メソッドはランダムに新しいミノを生成します。
    #ミノを初期位置に配置できなければ、ゲームオーバーです。
    def newPiece(self):
        #現在のブロックのオブジェクトに次のブロックのオブジェクトを入れる
        self.curPiece = self.nextPiece

        #ブロック位置の初期化?
        #minYの動作は以下のとおり
        #self.coords [[0, -1], [0, 0], [1, 0], [1, 1]]とすると
        #minYは、coordsの中で一番ちいさなyを返す
        #例えばminYが0とすると、curYは21となる

        #実際の表示は
        # coordsとは上下が反転して表示される
        #  ■        curY=20        [0, -1]
        #  ■■        curY=21        [0, 0]  [1, 0]
        #    ■        curY=22        [1, 1]
        
        #self.curY = Board.BoardHeight - 1 、ブロックの上の部分が
        #切れて見えなくなる事がある
        #   _
        #   ■■ [0, 0][1, 0]
        #     ■
        #

        #self.curY = Board.BoardHeight とするとさらに切れてしまう
        #   __ [0, 0][1, 0]
        #     ■  [0, 1]

        #以上から、curYはブロックに対して最適な表示位置を示すパラメータと思われる

        self.curX = Board.BoardWidth / 2 + 1
        self.curY = Board.BoardHeight - 1 + self.curPiece.minY()
        

    #def drawSquare(self, dc, x, y, shape):
    def drawSquare(self, dc, x, y):

        dc.SetBrush(wx.Brush('#000000'))
        dc.DrawRectangle(x + 1, y + 1, self.squareWidth - 2,
                         self.squareHeight - 2)



#shape ブロックの形状を決める
class Tetrominoes(object):
    NoShape        = 0
    ZShape         = 1
    SShape         = 2
    LineShape      = 3
    TShape         = 4
    SquareShape    = 5
    LShape         = 6
    MirroredLShape = 7

#Shape クラスはテトリミノの情報を保持しています。
class Shape(object):
    coordTable = (
        ((0, 0), (0, 0), (0, 0), (0, 0)),

        ((0, -1), (0, 0), (-1, 0), (-1, 1)),
        ((0, -1), (0, 0), (1, 0), (1, 1)),

        ((0, -1), (0, 0), (0, 1), (0, 2)),
        ((-1, 0), (0, 0), (1, 0), (0, 1)),

        ((0, 0), (1, 0), (0, 1), (1, 1)),
        ((-1, -1), (0, -1), (0, 0), (0, 1)),
        ((1, -1), (0, -1), (0, 0), (0, 1)))

    def __init__(self):
        #ミノの作成中に、 空の座標リストを作成します。 この
        #リストは、テトリミノの座標を保持します。 例えば、(0,
        #        -1), (0, 0), (1, 0), (1, 1) のタプルは回転し
        #たS-テトリミノを表します。 以下の図表がミノを図示し
        #ています。

        #[[0, 0], [0, 0], [0, 0], [0, 0]]を作成
        self.coords = [[0, 0] for i in range(4)]
        #0をセット
        self.pieceShape = Tetrominoes.NoShape
        self.setShape(Tetrominoes.NoShape)

    def shape(self):
        #0を返す
        return self.pieceShape

    def setShape(self, shape):
        #self.coords = [[0, -1], [0, 0], [1, 0], [1, 1]]
        self.coords = [[0, 1], [0, 0], [1, 0], [1, 1]]
        self.pieceShape = 2


    def x(self, index):
        return self.coords[index][0]

    def y(self, index):
        return self.coords[index][1]

    def setX(self, index, x):
        self.coords[index][0] = x

    def setY(self, index, y):
        self.coords[index][1] = y

    #coordsの中で一番ちいさなxを返す
    def minX(self):
        m = self.coord[0][0]
        for i in range(4):
            m = min(m, self.coords[i][0])

        return m

    #coordsの中で一番大きいxを返す
    def maxX(self):
        m = self.coord[0][0]
        for i in range(4):
            m = max(m, self.coords[i][0])

        return m

    #self.coords [[0, -1], [0, 0], [1, 0], [1, 1]]とすると
    #coordsの中で一番ちいさなyを返す
    def minY(self):
        m = self.coords[0][1]
        for i in range(4):
            m = min(m, self.coords[i][1])
        return m

    #coordsの中で一番大きいyを返す
    def maxY(self):
        m = self.coords[0][1]
        for i in range(4):
            m = max(m, self.coords[i][1])

        return m

    def rotatedLeft(self):
        if self.pieceShape == Tetrominoes.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

    def rotatedRight(self):
        if self.pieceShape == Tetrominoes.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

#app = wx.App()
app = MyApp()
Tetris(None, -1, 'tetris.py')
app.MainLoop()

0 件のコメント:

コメントを投稿

About

参加ユーザー

連絡フォーム

名前

メール *

メッセージ *

ブログ アーカイブ

ページ

Featured Posts