プログラミング歴数ヶ月の初心者です。
ゲームが作りたかったので、比較的敷居の低そうな落ちものパズルをつくってみました
Qiita初投稿です。
こんな感じのゲームです(gif30秒くらいになってしまった。長い)
説明はコードの方にコメントしてあります。(ミス等多そうですが)
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]: #同じ色のブロックが縦に3列以上並んでいる場合
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]: #同じ色のブロックが横に3列以上並んでいる場合
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作りたいなーって思ってます。(ちょっと勉強したけどめちゃくちゃ難しい。。)