PythonのTkinterで某パズルゲーム(のようなもの)をつくってみました

プログラミング歴数ヶ月の初心者です。
ゲームが作りたかったので、比較的敷居の低そうな落ちものパズルをつくってみました
Qiita初投稿です。

こんな感じのゲームです（gif30秒くらいになってしまった。長い）
![ezgif-3-3eee2fbd7703.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/558677/3932e16d-1214-9d78-4520-0ac493d1db4a.gif)

説明はコードの方にコメントしてあります。（ミス等多そうですが）

```python:panepon.py
import tkinter
import random
import math

phase = 0           #ゲーム進行を管理するための変数
cursor_x = 2        #カーソルのx座標(初期)
cursor_y = 11       #カーソルのy座標(初期)
cursor_dx = 1       #カーソルの移動量x
cursor_dy = 1       #カーソルの移動量y
block_width = 64    #ブロック幅
block_height = 64   #ブロック高さ

def right(e):                       #右キーを押した時の処理
    global cursor_x, cursor_dx      #グローバル変数を書き換えるためにグローバル宣言
    cursor_x += cursor_dx
    if cursor_x > 4:                #カーソルがゲーム枠より右に行かないための処理
        cursor_x = 4

def left(e):                        #左キーを押した時の処理
    global cursor_x, cursor_dx
    cursor_x -= cursor_dx
    if cursor_x < 0:                #カーソルがゲーム枠より左に行かないための処理
        cursor_x = 0

def up(e):                          #上キーを押した時の処理
    global cursor_y, cursor_dy
    cursor_y -= cursor_dy
    if cursor_y < 0:                #カーソルがゲーム枠より上に行かないための処理
        cursor_y = 0

def down(e):                        #下キーを押した時の処理
    global cursor_y, cursor_dy
    cursor_y += cursor_dy
    if cursor_y > 11:               #カーソルがゲーム枠より下に行かないための処理
        cursor_y = 11

def press_a(e):                     #Aキーを押した時の処理
    global a                        #グローバル変数aの定義
    a = 1                           #Aキーが押されたことを管理

def press_c(e):                     #Cキーを押した時の処理
    global c
    c = 1

def press_r(e):                     #Rキーを押した時の処理
    global r
    r = 1

block = []  #ブロックの配置を管理する配列
check = []  #チェック用の配列

for i in range(17):
    block.append([0,0,0,0,0,0])
    check.append([0,0,0,0,0,0])

def draw_block():                   #ブロック描画用関数
    cvs.delete("BLOCK")             #今まで描画していたブロックを削除
    for y in range(17):
        for x in range(6):
            if block[y][x] > 0:     #ブロックが存在する場合
                cvs.create_image(x * block_width + 35, y * block_height - block_height * 4 - 35, image=img_block[block[y][x]], tag="BLOCK")
                                    #ブロック画像の描画                                                   ブロック画像用配列

def check_block():                  #ブロックをチェックする関数
    for y in range(17):
        for x in range(6):
            check[y][x] = block[y][x]  #現在のブロック配置をcheck配列に代入

    for y in range(1,16):
        for x in range(6):
            if check[y][x] > 0:      #ブロックが存在する場合
                if check[y-1][x] == check[y][x] and check[y+1][x] == check[y][x]:  #同じ色のブロックが縦に３列以上並んでいる場合
                    if check[y][x] == 1:  #並んだブロックが赤である場合ハートに変える
                        block[y-1][x] = 6
                        block[y][x] = 6
                        block[y+1][x] = 6
                    if check[y][x] == 2:  #並んだブロックが青である場合イルカに変える
                        block[y-1][x] = 7
                        block[y][x] = 7
                        block[y+1][x] = 7
                    if check[y][x] == 3:  #並んだブロックが緑である場合クローバーに変える
                        block[y-1][x] = 8
                        block[y][x] = 8
                        block[y+1][x] = 8
                    if check[y][x] == 4:  #並んだブロックが黄色である場合ビールに変える
                        block[y-1][x] = 9
                        block[y][x] = 9
                        block[y+1][x] = 9
                    if check[y][x] == 5:  #並んだブロックが紫である場合ワインに変える
                        block[y-1][x] = 10
                        block[y][x] = 10
                        block[y+1][x] = 10
                        

    for y in range(17):
        for x in range(1,5):
            if check[y][x] > 0:
                if check[y][x-1] == check[y][x] and check[y][x+1] == check[y][x]:  #同じ色のブロックが横に３列以上並んでいる場合
                    if check[y][x] == 1:
                        block[y][x-1] = 6
                        block[y][x] = 6
                        block[y][x+1] = 6
                    if check[y][x] == 2:
                        block[y][x-1] = 7
                        block[y][x] = 7
                        block[y][x+1] = 7
                    if check[y][x] == 3:
                        block[y][x-1] = 8
                        block[y][x] = 8
                        block[y][x+1] = 8
                    if check[y][x] == 4:
                        block[y][x-1] = 9
                        block[y][x] = 9
                        block[y][x+1] = 9
                    if check[y][x] == 5:
                        block[y][x-1] = 10
                        block[y][x] = 10
                        block[y][x+1] = 10
    

def sweep_block():                  #ブロックを消す関数
    num = 0                         #ブロックが消えた個数のカウント
    for y in range(17):
        for x in range(6):
            if block[y][x] == 6:
                block[y][x] = 0
                num += 1
            if block[y][x] == 7:
                block[y][x] = 0
                num += 1
            if block[y][x] == 8:
                block[y][x] = 0
                num += 1
            if block[y][x] == 9:
                block[y][x] = 0
                num += 1
            if block[y][x] == 10:
                block[y][x] = 0
                num += 1
    return num                                          #ブロックが消えた個数を呼び出し元に返す

def drop_block():                                       #ブロックを落とす関数
    flg = False                                         #phase移行のためのチェック
    for y in range(15, -1, -1):                         #yを下から2段目の列から調べる
        for x in range(6):
            if block[y][x] != 0 and block[y+1][x] == 0: #調べている箇所にブロックがある、かつ、1マス下にブロックがない場合
                block[y+1][x] = block[y][x]             #ブロックを下に写す
                block[y][x] = 0                         #写した元のブロックを消す
                flg = True
    return flg                                          #flgを呼び出し元に戻す

def over_block():           #ゲームオーバー処理用の関数
    for x in range(6):
        if block[5][x] > 0: #ブロックがゲーム枠最上段に存在する場合
            return True
    return False

def set_up():                               #ブロックを1段上に移動する関数
    for y in range(5, 16):
        for x in range(6):
            block[y][x] = block[y + 1][x]

def set_block():                            #ブロックを最下段に出す関数
    for x in range(6):
        block[16][x] = random.randint(1, 5) #最下段に、ブロック画像用配列の1~5をランダムに配置

def ojama_block(ojama_num):                     #上段にランダムにブロックを配置する関数
    for y in range(0, ojama_num):
        for x in range(6):
            block[y][x] = random.randint(1, 5)

def cross_block():                                                          #カーソル内の左右を入れ替える関数
    if c == 1:                                                              #Cキーが押されたら
        source = block[cursor_y + 5][cursor_x]                              #変数sourceにカーソル内左側のブロックを代入
        block[cursor_y + 5][cursor_x] = block[cursor_y + 5][cursor_x + 1]   #カーソル内左側のブロックを右側のブロックと同じものにする
        block[cursor_y + 5][cursor_x + 1] = source                          #カーソル内右側のブロックをsourceと同じにする

def draw_text(text, x, y, size, col, tag):                         #テキストを表示する関数
    font = ("Times New Roman", size, "bold")                       #フォント、フォントサイズ、文字太さを先に入れておく
    cvs.create_text(x, y, text=text, fill=col, font=font, tag=tag) #テキストを表示する座標、引数で持ってきた情報を元にテキストを表示

def game_main():                #メインの処理
    global phase, a, c, r, score, combo, ojama_num, over, force, cursor_x, cursor_y
    if phase == 0:              #phaseが初期の場合(タイトル画面)
        cvs.delete("OVER")      #リスタート時のための削除処理ここから
        cvs.delete("CHARA")
        cvs.delete("RESTART")
        for y in range(17):
            for x in range(6):
                block[y][x] = 0
                draw_block()    #リスタート時のための削除処理ここまで
        draw_text("パネ◯ン", 384, 334, 100,"violet","TITLE") #テキストの描画
        draw_text(
        """
        Aキーで
        ゲームを
        始めるよ！
        
        """, 425, 590, 25, "blue", "TITLE")
        cvs.create_image(576, 650, image=chara, tag="CHARA")
        phase = 1       #phase1に移行
        score = 0       #スコア表示用の数値
        combo = 1       #コンボ数管理の変数
        ojama_num = 0   #上からブロックを降らすための数値
        force = 1       #上からブロックを降らすための数値
        over = 0        #ゲームオーバー管理用の変数
        a = 0           #Aキーが押されていない状態
        c = 0
        r = 0
    elif phase == 1:                 #phaseが1の場合
        if a == 1:                   #Aキーを押した場合
            for y in range(15):
                for x in range(6):
                    block[y][x] = 0
                    a = 0               #Aキーが押されていない状態に戻す
                    draw_block()        #ブロックの描画
                    cvs.delete("TITLE") #タイトル(テキスト)の削除
                    draw_text("ゲーム説明", 576, 30, 40, "blue", "READ")
                    draw_text("↑ ↓ ← → キーでカーソルが動くよ！", 576, 130, 20, "blue", "READ")
                    draw_text("Aキーで最下段にブロックを出すよ！", 576, 180, 20, "blue", "READ")
                    draw_text("Cキーで左右を入れ替えるよ！", 576, 230, 20, "blue", "READ")
                    draw_text("縦か横に3つ以上並んだら消えるよ！", 576, 280, 20, "blue", "READ")
                    draw_text("一定回数消すと上からブロックが降るよ！", 576, 330, 20, "blue", "READ")
                    draw_text("最上段にブロックが到達したらダメ！", 576, 380, 20, "blue", "READ")
                    phase = 2
    elif phase == 2:
        if c == 1:
            cross_block()
            c = 0
        if drop_block() == False:  #flgがFalseの場合
            phase = 3
        draw_block()
    elif phase == 3:
        check_block()
        draw_block()
        phase = 4
    elif phase == 4:
        sc = sweep_block()  #ブロックが消えた個数numをscに代入
        if sc > 9:        #消えた個数によってスコアの上昇量scを管理ここから
            sc += 100
        elif sc > 8:
            sc += 50
        elif sc > 7:
            sc += 30
        elif sc > 6:
            sc += 15
        elif sc > 5:
            sc += 7
        elif sc > 4:
            sc += 3
        elif sc > 3:
            sc += 1                 #消えた個数によってスコアの上昇量scを管理ここまで
        sc *= combo ** 4            #コンボ量の4乗をスコアの上昇量scに掛ける
        score += sc                 #スコアに上昇量を足す
        if sc > 0:                  #ブロックが消されていた場合
            combo += 1              #コンボ数をプラス1
            if combo > 2:
                cvs.delete("COMBO") #今まで表示されていたコンボ表示を削除
                draw_text(str(combo - 1)+"連鎖！", 480, 550, 50, "blue", "COMBO")
                                    #コンボ数を表示するテキスト
            ojama_num += 0.4        #上からブロックを降らす量を0.4増やす
            force += 0.05           #ブロックを消すたびに、ojama_numに掛ける数値が増える
            phase = 2
        else:
            if over_block() == False:
                phase = 5
            else:
                over = 1            #ゲームオーバー処理へ
        draw_block()
    elif phase == 5:
        combo = 1                   #コンボ数を元に戻す
        cvs.delete("COMBO")         #コンボ数表示を消す
        if ojama_num >= 1:          #ojama_numが1以上の場合
            ojama_num = math.floor(ojama_num * (force))  #ojama_numにforce掛けてを少数切り捨てする
            ojama_block(ojama_num)  #ojama_numの数値と同じ数(列)、ブロックを上にセットする
            ojama_num = 0
        if c == 1:
            cross_block()
            c = 0
            phase = 2
        if a == 1:
            a = 0
            set_up()
            set_block()
            score += 10
            phase = 2
    cvs.delete("INFO")  #スコア表示を消す
    if phase > 1:
        draw_text("SCORE", 576, 450, 40, "black", "INFO")
        draw_text(score * 10, 576, 490, 40, "black", "INFO") #スコア表示をする
    draw_block()
    if over == 1:           #ゲームオーバー処理
        cvs.delete("CHARA")                                    #今まで描画していたキャラクターを消す
        cvs.create_image(576, 650, image=chara2, tag="CHARA")  #キャラクター画像を別のものに変える
        draw_text("GAME OVER", 384, 384, 100, "black", "OVER")
        cvs.delete("READ")  #ルール説明を消す
        cvs.delete("COMBO") #コンボ表示を消す
        draw_text(
        """
        Rキーで
        タイトルに
        戻るよ...
        
        """, 425, 590, 25, "blue", "RESTART")
        if r == 1:
            phase = 0
    cvs.delete("CURSOR")  #カーソル画像を消す
    cvs.create_image(cursor_x * block_width + 67, cursor_y * block_height + 29, image=cursor, tag="CURSOR")
                          #カーソル画像を描画する
    root.after(100,game_main)  #0.1秒後にgame_main関数を呼び出す

root = tkinter.Tk()          #ウィンドウを作る
root.title("パネ◯ン")         #タイトルの設定
root.resizable(False,False)  #ウィンドウサイズを変更できないようにしている
root.bind("<Right>",right)   #Rightキーを押した時、right関数が呼ばれるようにしている
root.bind("<Left>",left)
root.bind("<Up>",up)
root.bind("<Down>",down)
root.bind("<a>",press_a)
root.bind("<c>",press_c)
root.bind("<r>",press_r)
cvs = tkinter.Canvas(root,width=768, height=768)  #キャンバスのサイズを768x768ピクセルにする
cvs.pack()                                        #キャンバスを配置する

bg = tkinter.PhotoImage(file="bg.png")  #bgに画像を代入

img_block = [
  None,
  tkinter.PhotoImage(file="red.png"),
  tkinter.PhotoImage(file="blue.png"),
  tkinter.PhotoImage(file="green.png"),
  tkinter.PhotoImage(file="yellow.png"),
  tkinter.PhotoImage(file="purple.png"),
  tkinter.PhotoImage(file="heart.png"),
  tkinter.PhotoImage(file="dolphin.png"),
  tkinter.PhotoImage(file="clover.png"),
  tkinter.PhotoImage(file="ale.png"),
  tkinter.PhotoImage(file="wine.png")
]   #ブロック画像用配列

cursor = tkinter.PhotoImage(file="cursor.png")
chara = tkinter.PhotoImage(file="chara.png")
chara2 = tkinter.PhotoImage(file="chara2.png")
cvs.create_image(384,384,image=bg)
game_main()
root.mainloop()  #GUIを表示
```

こうして見ると、マジックナンバー多いですね。気をつけたい

次はRPG作りたいなーって思ってます。（ちょっと勉強したけどめちゃくちゃ難しい。。）