はじめに
こんにちは。
今回は**「追いかけっこゲーム」**を作っていきたいと思います。
完成するとこんな感じに動きます!
赤い円が自分(player)で青い円が敵(enemy)です。
マウスカーソルを操作して、赤い円を動かすことができます。青い円に触れたら止まります。つまりゲームオーバーといった感じです!
環境
- Windows 10 home
- Python 3.7.1
numpyを使うので以下のコマンドでインストールしておきましょう。
pip install numpy
「追いかけっこゲーム」の制作
インポート
使うライブラリは以下の2つです。
import tkinter as tk
import numpy as np
ウィンドウの作成
import tkinter as tk
import numpy as np
class Application(tk.Frame):
def __init__(self,master):
super().__init__(master)
self.pack()
self.width=self.height=500
master.geometry(str(self.width)+"x"+str(self.height))
master.title("追いかけっこゲーム")
def main():
win = tk.Tk()
app = Application(master = win)
app.mainloop()
if __name__ == "__main__":
main()
このプログラムでウィンドウを作っていきます。
サイズは500×500です。タイトル名は追いかけっこゲームです。
詳しくはPythonによるTkinterを使った雛形(クラス化手法)の記事をご参照ください。
敵の動きのベクトル取得に関して
敵の動きのベクトルは以下のenemyVec関数で取得しています。少しややこしい部分なので、解説を入れようと思います。
def enemyVec(self,player,enemy,speed):#敵の動き(x,y)のベクトルを返す
rad=np.arctan((player.y-enemy.y)/(player.x-enemy.x))#向き(角度の計算)
if player.x-enemy.x >= 0:
vx=np.cos(rad)*speed
vy=np.sin(rad)*speed
else:
vx=np.cos(rad)*(-1*speed)
vy=np.sin(rad)*(-1*speed)
return [vx,vy]
引数として、playerオブジェクトとenemyオブジェクトを渡しています。それぞれの中心座標を計算で使うためです。ここで、この2つのオブジェクトの向きの計算が少しややこしくなると思います。つまり、2点間の角度の計算です。
2点の座標が分かっているので、ベクトルのx成分とy成分を求めることができます。
(例) A(x1,y1),B(x2,y2)の場合
\vec{AB} =
\begin{matrix}
x2 - x1 \\
y2 - y1
\end{matrix}
そして、x軸とベクトルがなす角度θを以下のtanの逆関数を使って表すことができます。
θ = \tan^-1(\frac{y}{x})
tanθの範囲が-π/2~π/2なので、playerとenemyのx座標の差の正負で場合分けをし、speedに-1をかけて、方向を変えています。
完成したプログラム
こちらが完成したプログラムになります。
import tkinter as tk
import numpy as np
class Circle():
def __init__(self,canvas,x,y,r,color,tag=None):
self.canvas = canvas
self.x = x #円の中心のx座標
self.y = y #円の中心のy座標
self.r = r #円の半径
self.color = color
self.tag = tag
def createCircle(self):
self.canvas.create_oval(self.x-self.r,self.y-self.r,self.x+self.r,self.y+self.r,fill=self.color,tag=self.tag)
class Application(tk.Frame):
def __init__(self,master):
super().__init__(master)
self.pack()
self.width=self.height=500
master.geometry(str(self.width)+"x"+str(self.height))
master.title("追いかけっこゲーム")
self.canvas = tk.Canvas(master,width=self.width,height=self.height,bg="black")
self.canvas.pack()
self.player = Circle(self.canvas,250,250,30,"red","player") #インスタンスplayerの生成
self.enemy = Circle(self.canvas,0,0,30,"blue","enemy") #インスタンスenemyの生成
self.canvas.bind("<Motion>",self.mouseEvent)
self.master.after(50,self.update)
def update(self):
if self.judgeflag(self.player,self.enemy):
eV = self.enemyVec(self.player,self.enemy,10)
self.enemy.x += eV[0]
self.enemy.y += eV[1]
self.canvas.delete("player")
self.canvas.delete("enemy")
self.player.createCircle()
self.enemy.createCircle()
self.master.after(50,self.update)
def enemyVec(self,player,enemy,speed): #敵の動き(x,y)のベクトルを返す
rad=np.arctan((player.y-enemy.y)/(player.x-enemy.x)) #向き(角度の計算)
if player.x-enemy.x >= 0:
vx=np.cos(rad)*speed
vy=np.sin(rad)*speed
else:
vx=np.cos(rad)*(-1*speed)
vy=np.sin(rad)*(-1*speed)
return [vx,vy]
def judgeflag(self,player,enemy): #当たり判定
if np.sqrt((player.x-enemy.x)**2+(player.y-enemy.y)**2) > player.r+enemy.r: return True
else: return False
def mouseEvent(self,event):
self.player.x = event.x
self.player.y = event.y
def main():
win = tk.Tk()
app = Application(master=win)
app.mainloop()
if __name__ == "__main__":
main()
以上で追いかけっこゲームは完成になります。
ここまで読んでいただき、ありがとうございました。