#概要
習いたてのPythonを使って、ゲームを作ってみました。
上を見すぎず作ろうとしたつもりでしたが、これでも無力さを感じました、
ゲームとしては、敵の玉に当たらないようにしながらすべての玉を壊すというものです。
しかし正直なところ、これは結論から言うと失敗に終わっています。(笑)
#参考
こちらのサイトを参考にさせていただきました。
[selfって?]https://www.sejuku.net/blog/64106
[キー入力]https://www.rumadra.com/2019/06/14/python-tkinter-keyboard/#i-3
[移動入力]https://algorithm.joho.info/programming/python/pygame-keyevent-move-character/
#簡単な仕組み
##敵の作成
class ENEMY:
def __init__(self,x,y,dx,dy,color):
self.x = x
self.y = y
self.dx = dx
self.dy = dy
self.color = color
def display(self,canvas):
self.x = self.x + self.dx
self.y = self.y + self.dy
canvas.create_oval(self.x -10, self.y-10, self.x +10, self.y +10, fill =self.color , width = 0, tag = self.color)
def move(self):
if self.x+10 >= canvas.winfo_width():
self.dx = random.random()*-1
if self.x-10 <= 0:
self.dx = random.random()
if self.y+10 >= 900:
self.dy = random.random()*-1
if self.y-1 <= 0:
self.dy = random.random()
def erase(self,canvas):
canvas.delete(self.color)
敵を作っていますが、特に変わったところはありません。
##プレイヤー
class PLAYER:
def __init__(self,x,y,color):
self.x=x
self.y=y
self.color=color
def display(self,canvas):
canvas.create_polygon(self.x, self.y, self.x-8, self.y+16, self.x+8, self.y+16, fill=self.color, width=1, tag="a")
def move(self,dx,dy):
global player_place_x,player_place_y
if self.x+dx >= canvas.winfo_width():
dx = 0
elif self.x+dx <= 0:
dx = 0
elif self.y+dy >= canvas.winfo_height()-16: #三角形の頂点からの距離調整の16
dy = 0
elif self.y+dy <= 0:
dy = 0
else:
self.x = self.x + dx
self.y = self.y + dy
player_place_x = self.x
player_place_y = self.y
def erase(self,canvas):
canvas.delete("a")
ここも特に変わったところはなく、入力処理によって得た変化量を足して表示を繰り返しているだけです。
##移動入力の処理
問題はここからです。
知識量が追い付かなくなってきました。
def KeyUp(event):
global playerdy
playerdy= -0.2
def KeyDown(event):
global playerdy
playerdy = 0.2
def ResetUp(event):
global playerdy
playerdy = 0
def ResetDown(event):
global playerdy
playerdy = 0
def KeyRight(event):
global playerdx
playerdx = 0.2
def KeyLeft(event):
global playerdx
playerdx = -0.2
def ResetRight(event):
global playerdx
playerdx=0
def ResetLeft(event):
global playerdx
playerdx=0
矢印キーを押し続けている間だけ動かそうと思ったところうまくいかず、さらにはpygame
を使わずにcanvas
とtkinter
だけで行くという謎のこだわりもあって手こずりました。
##苦難の元
何につまづいたかというと、これです。
canvas = tk.Canvas(root, width = 1700, height = 900, bg = "black")
canvas.place(x = 0, y = 0)
canvas.focus_set() #必須注意
この下に書いてあるよくわからん一文が必要だったんです。それがわからずに一体何日悩んだことか、、、
これはどうやらキャンバスをアクティブにする一文なのかな?
本当にこれのせいで大量の時間を奪われました(笑)
##プレイヤーの攻撃
プレイヤーが敵を攻撃する要素としてミサイルを実現しました。といってもスペースキーを入力したところから真っすぐ飛ぶだけですが(笑)
class BULLET:
def __init__(self,x,y):
self.x = x
self.y = y
self.for_del = None
def howmany(self):
if self.y <= -10:
return False
else:
return True
def delete(self,canvas):
canvas.delete(self.for_del)
def display(self,canvas):
self.for_del=canvas.create_oval(self.x-1,self.y-4,self.x+1,self.y+4,fill="white",width=0)
self.y = self.y -5
まぁ、ここはいいとして次に行きましょう。
##THE 苦難再び
def ammo_loop():
a=0
b=0
label = tk.Label(root,text=("残り敵数"+str((len(balls)))+"体"),font=("helvetica",18))
label.place(x=100,y=100)
for i in range(len(bullet)):
for j in range(len(balls)):
if len(balls) - b <= 0:
break
elif (bullet[len(bullet)-i-1].x >= balls[len(balls)-j-1].x-10) and (bullet[len(bullet)-i-1].x <= balls[len(balls)-j-1].x+10) and (bullet[len(bullet)-i-1].y >= balls[len(balls)-j-1].y-10) and (bullet[len(bullet)-i-1].y <= balls[len(balls)-j-1].y+10):
balls[j].erase(canvas)
bullet[i].delete(canvas)
del bullet[len(bullet)-i-1]
del balls[len(balls)-j-1]
b = b + 1
break
how_long = len(bullet)
for j in range(len(bullet)):
count = bullet[how_long-j-1].howmany()
if how_long - a <= 0:
break
elif count == False:
del bullet[how_long-j-1]
a = a + 1
ん~。自分でもよくわかってません。(笑)
残りの敵の数を表示したり、当たり判定をしてます。なににつまづいたかというと、ミサイルの消去です。
ここでのつまづきポイントはミサイルを消すとリストがバグる!ってことです。
なぜこれが起きたのか僕なりに考えてみたところ、for文
ですべてのミサイルの要素に適用したところ、一つミサイルが当たってインスタンスが破棄されたときに元の要素の数にずれが生じるからです。そこで、len
メソッドを用いることで無理やり回避しています。
#反省、失敗
-まともに動かない時がある
これは、最悪な失敗でした。当たり判定がしっかりと働かずに弾や敵がその場に残ることがありました。
-時間のせいで未完成
本当は敵がプレイヤーに向けてミサイルを撃ってきたり、効果音をつけたり、360°撃てるようにしたかったけれど、実力不足で無理でした、、、
-コードがぐちゃぐちゃ
途中から自分でもわからなくなったところがあったので、、、
#学んだこと
-手を動かせ(試せ)
-調べろ
-見やすく努めろ
#まとめ
という感じで完成?という感じです。(笑)それもこれも、自分の勉強不足のせいで一つ一つに時間がかかったせいで、納得のいかない完成度になってしまったからです。今回の難所はおおまかに2つだったのですが、僕の力ではこいつらにバカみたいな時間を食われてしまいました。いつかリベンジしてやる、、、
#一応ソースコード
#coding = utf-8
#各種インポート
import tkinter as tk
import random
player_place_x = 0
player_place_y = 0
playerdx=0
playerdy=0
check = 0
reloading_time=15
ammo_x = None
ammo_y = None
count = True
reload = 0
global player_life,counter,x,y,a,b,k,t,counting
a = random.randint(0,1700)
b = random.randint(0,600)
x=0
y=0
k=1700
t=900
counter=0
counting=0
player_life = 3
#ランダムな位置へのモブの設置
class ENEMY:
def __init__(self,x,y,dx,dy,color):
self.x = x
self.y = y
self.dx = dx
self.dy = dy
self.color = color
def display(self,canvas):
self.x = self.x + self.dx
self.y = self.y + self.dy
canvas.create_oval(self.x -10, self.y-10, self.x +10, self.y +10, fill =self.color , width = 0, tag = self.color)
def move(self):
if self.x+10 >= canvas.winfo_width():
self.dx = random.random()*-1
if self.x-10 <= 0:
self.dx = random.random()
if self.y+10 >= 900:
self.dy = random.random()*-1
if self.y-1 <= 0:
self.dy = random.random()
def erase(self,canvas):
canvas.delete(self.color)
class PLAYER:
def __init__(self,x,y,color):
self.x=x
self.y=y
self.color=color
def display(self,canvas):
canvas.create_polygon(self.x, self.y, self.x-8, self.y+16, self.x+8, self.y+16, fill=self.color, width=1, tag="a")
def move(self,dx,dy):
global player_place_x,player_place_y
if self.x+dx >= canvas.winfo_width():
dx = 0
elif self.x+dx <= 0:
dx = 0
elif self.y+dy >= canvas.winfo_height()-16: #三角形の頂点からの距離調整の16
dy = 0
elif self.y+dy <= 0:
dy = 0
else:
self.x = self.x + dx
self.y = self.y + dy
player_place_x = self.x
player_place_y = self.y
def erase(self,canvas):
canvas.delete("a")
def KeyUp(event):
global playerdy
playerdy= -0.2
def KeyDown(event):
global playerdy
playerdy = 0.2
def ResetUp(event):
global playerdy
playerdy = 0
def ResetDown(event):
global playerdy
playerdy = 0
def KeyRight(event):
global playerdx
playerdx = 0.2
def KeyLeft(event):
global playerdx
playerdx = -0.2
def ResetRight(event):
global playerdx
playerdx=0
def ResetLeft(event):
global playerdx
playerdx=0
def KeySpace(event): #スペース入力受付
global check
check = 1
def KeySpaceReset(event): #スペースリリース受付
global check
check = 0
class BULLET:
def __init__(self,x,y):
self.x = x
self.y = y
self.for_del = None
def howmany(self):
if self.y <= -10:
return False
else:
return True
def delete(self,canvas):
canvas.delete(self.for_del)
def display(self,canvas):
self.for_del=canvas.create_oval(self.x-1,self.y-4,self.x+1,self.y+4,fill="white",width=0)
self.y = self.y -5
def ammo_loop():
a=0
b=0
label = tk.Label(root,text=("残り敵数"+str((len(balls)))+"体"),font=("helvetica",18))
label.place(x=100,y=100)
for i in range(len(bullet)):
for j in range(len(balls)):
if len(balls) - b <= 0:
break
elif (bullet[len(bullet)-i-1].x >= balls[len(balls)-j-1].x-10) and (bullet[len(bullet)-i-1].x <= balls[len(balls)-j-1].x+10) and (bullet[len(bullet)-i-1].y >= balls[len(balls)-j-1].y-10) and (bullet[len(bullet)-i-1].y <= balls[len(balls)-j-1].y+10):
balls[j].erase(canvas)
bullet[i].delete(canvas)
del bullet[len(bullet)-i-1]
del balls[len(balls)-j-1]
b = b + 1
break
how_long = len(bullet)
for j in range(len(bullet)):
count = bullet[how_long-j-1].howmany()
if how_long - a <= 0:
break
elif count == False:
del bullet[how_long-j-1]
a = a + 1
def reset():
global counter,a,b
if counter >= 400:
a = random.randint(0,1700)
b = random.randint(0,900)
counter = 0
else:
counter = counter + 1
print("print"+str(counter))
def attack():
global a,b,k,t,counting
canvas.delete("attack_a")
canvas.delete("attack_b")
canvas.create_rectangle(a,-k,a+70,1700-k,fill="red",width = 0,tag="attack_a")
canvas.create_rectangle(-t,b,900-t,b+70,fill="red",width = 0,tag = "attack_b")
k = k -10
t = t -10
def judge():
global player_place_x,player_place_y,player_life,k,t
for i in balls:
if (player_place_x >= i.x-10 and player_place_x <= i.x+10 and player_place_y >= i.y-10 and player_place_y <= i.y+10) or (player_place_x >= a and player_place_x <= a+90 and player_place_y >= -k and player_place_x <= 1700-k) or (player_place_x >= -t and player_place_x <= 900 -t and player_place_y >= b and player_place_y <= b + 70):
player_life = player_life - 1
if player_life == 0:
label = tk.Label(root, text =("Game Over!!"), font =("helvetica", 28))
label.place(x= 850, y= 450)
label2 = tk.Label(root, text = ("5秒後に終了します"),font = ("helvetica",30))
label2.place(x=850, y=400)
root.after(5000,quit)
def create(): #ミサイルの生成
global player_place_x,player_place_y
bullet.append(BULLET(player_place_x,player_place_y))
def reload_time(): #リロード判断
global reloading_time,reload
reloading_time = reloading_time - 1
if reloading_time <= 0:
reload = 1
def Reload_reset(): #リロードリセット
global reloading_time
reloading_time = 50
def player_do():
player.erase(canvas)
player.display(canvas)
player.move(playerdx,playerdy)
def quit():
root.destroy()
def loop():
global reload,check
reset()
attack()
judge()
ammo_loop()
for i in balls:
player_do() #プレイヤーの動き
i.erase(canvas)
i.display(canvas)
i.move()
for i in bullet:
i.delete(canvas)
i.display(canvas)
if check == 1: #スペース入力判断
if reload == 1: #リロード判断
create()
Reload_reset()
reload = 0
else:
reload_time()
else:
reload_time()
root.after(10,loop)
bullet = []
player = PLAYER(850,820,"white")
balls = [
ENEMY(random.randint (0,1700),random.randint (0,900),1,-1,"blue"),
ENEMY(random.randint (0,1700),random.randint (0,900),1,-1,"red"),
ENEMY(random.randint (0,1700),random.randint (0,900),-1,1,"purple"),
ENEMY(random.randint (0,1700),random.randint (0,900),1,1,"yellow"),
ENEMY(random.randint (0,1700),random.randint (0,900),-1,1,"silver"),
ENEMY(random.randint (0,1700),random.randint (0,900),-1,1,"pink"),
ENEMY(random.randint (0,1700),random.randint (0,900),-1,1,"yellow"),
ENEMY(random.randint (0,1700),random.randint (0,900),-1,1,"white"),
ENEMY(random.randint (0,1700),random.randint (0,900),-1,1,"brown"),
ENEMY(random.randint (0,1700),random.randint (0,900),-1,1,"pink"),
ENEMY(random.randint (0,1700),random.randint (0,900),-1,1,"gold"),
ENEMY(random.randint (0,1700),random.randint (0,900),-1,1,"white"),
ENEMY(random.randint (0,1700),random.randint (0,900),-1,1,"green")
]
root = tk.Tk()
root.geometry("1700x900")
canvas = tk.Canvas(root, width = 1700, height = 900, bg = "black")
canvas.place(x = 0, y = 0)
canvas.focus_set() #必須注意
canvas.bind("<Up>",KeyUp)
canvas.bind("<Down>",KeyDown)
canvas.bind("<Right>",KeyRight)
canvas.bind("<Left>",KeyLeft)
canvas.bind("<KeyRelease-Up>",ResetUp)
canvas.bind("<KeyRelease-Down>",ResetDown)
canvas.bind("<KeyRelease-Left>",ResetLeft)
canvas.bind("<KeyRelease-Right>",ResetRight)
canvas.bind("<Key-space>",KeySpace)
canvas.bind("<KeyRelease-space>",KeySpaceReset)
root.after(10,loop)
root.mainloop()