[初心者向け]Pythonista3のsceneでゲーム作成〜簡単なゲーム作ってみる〜
こんにちは。
普段プログラミングを趣味として自分なりに楽しんでやっています。
その中で学んだ事などを備忘録として残し、僕の思いも少し付け足してnoteにまとめています。
今回はPythonista3のsceneでゲーム作成編の最後の記事です。
実際に簡単なゲームを考えて、コード書いて実行してみて、コード追加して、実行してみる。
という流れでいきたいと思います。
作成するゲーム
まず作成するゲームの内容を見ていきましょう。
複雑なモノではないので全体像はイメージしやすいかと思います。まず大まかな定義↓
『ランダムに出現するボールをタッチして消すゲーム』
これを基に考えていきます。
まず「画面」はメインのゲームのループとして必要です。
そして画面に描画するのは「移動するボール」です。(複数)
その移動するボールを「タップ(タッチ)」して消します。(メインのプログラムで実装)
以上を踏まえるとメインクラスとボールクラスが有ればこの簡単なボール消しゲームは作れそうです。
なので、とりあえずメインとボールのクラスを考えてみます。
もし何か足りなかったら後から追加しましょう。
----------メインクラス
メインクラスはSceneクラスを継承します。
初期化(setup)
◯背景色は黒にしたい。
◯ボールが複数個出現するので、ボール情報を保持する為にリストを作りたい。
メソッド
◎ボールを追加したい。
◎ボールを描画したい。
◎ボールの位置を更新したい。
◎画面をタッチした時に反応させたい。
◎ボールがタッチされたかどうかの判定をしたい。
----------ボールクラス
初期化(init)
◯ボールのx座標
◯ボールのy座標
◯ボールの幅
◯ボールの高さ
◯ボールのx座標方向の速度
◯ボールのy座標方向の速度
メソッド
◎ボールを描画したい
◎ボールの位置を更新したい
◎ボールが壁に当たったかどうかの判定をしたい
とりあえずこれでいきましょう。
一つずつ段階を踏んで機能を加えて作成していきます。
メインのクラスを作成
まずはメインのゲームクラスを作成して画面を表示させてみます。
Gameクラス
from scene import *
class Game(Scene):
def setup(self):
self.background_color = 'black'
def update(self):
pass
def draw(self):
pass
def touch_began(self, touch):
pass
def hit_judgment(self,x,y):
pass
run(Game())
これで右上の▷ボタンを押して実行すれば黒い画面が表示されるはずです。
これでメインの方の基礎はできたので次にボールクラスを作成していきます。
Ballクラス
class Ball:
def __init__(self):
self.w = 50 #ボールの幅
self.h = self.w #ボールの高さ(幅と同じ)
self.x = 200 #ボールのx座標
self.y = 200 #ボールのy座標
self.vx = 2 #ボールのx方向の速度
self.vy = 2 #ボールのy方向の速度
def draw(self):
#円を描画
ellipse(self.x, self.y, self.w, self.h)
これで描画する準備が整ったのでメインのGameクラスに戻ってBallクラスをインスタンス化して描画させる処理を書きましょう。
Gameクラス
class Game(Scene):
def setup(self):
self.background_color = 'black' #背景色
self.ball = Ball() #ボールクラスをインスタンス化
def draw(self):
#ボールクラスのdrawメソッドを実行
self.ball.draw()
これでボールが画面上に描画されると思います。
右上の▷ボタンを押して実行してみてください。
描画できれば、次はボールを動かしていきます。
ボールクラスにupdateメソッドを追加します。
Ballクラス
def update(self):
#ボールのx座標にx方向の速度を足す
self.x += self.vx
#ボールのy座標にy方向の速度を足す
self.y += self.vy
次にゲームクラスのupdateメソッドに処理を書きます。
Gameクラス
def update(self):
#ボールクラスのupdateメソッドを実行
self.ball.update()
これでボールが右斜め上に向かって移動して行くと思います。
右上の▷ボタンを押して実行してみましょう。
このままではボールが画面外に消えてしまうのでボールが消えないように処理を加えます。
ボールが画面の端に当たったら跳ね返る処理をボールクラスに追加します。
Ballクラス
def hit_check(self, super):
#ボールの左側が画面の左側よりも小さい時
if self.x < 0:
self.x = 0
self.vx *= -1
#ボールの右側が画面の右側よりも大きい時
elif self.x + self.w > super.size.width:
self.x = super.size.width - self.w
self.vx *= -1
#ボールの下側が画面の下側よりも小さい時
elif self.y < 0:
self.y = 0
self.vy *= -1
#ボールの上側が画面の上側よりも大きい時
elif self.y + self.h > super.size.height:
self.y = super.size.height - self.h
self.vy *= -1
hit_checkメソッドを作成して引数にsuperとしています。このsuperの部分にはGameクラスのインスタンスを割り当てます。
それぞれボールが画面の端に到達した時の処理を条件分岐で対応しています。
速度 *= -1をしているのはボールを跳ね返らせる為に速度を反転させないといけないからです。
これでボールを跳ね返らせる処理ができたので、ゲームクラスのupdateメソッドのところにこのhit_checkメソッドを追加しましょう。
Gameクラス
def update(self):
#ボールクラスのupdateメソッドを実行
self.ball.update()
#ボールクラスのhit_checkメソッドを実行(引数にselfを渡す)
self.ball.hit_check(self)
これでボールが画面内を跳ね返り続けるようになりました。
一度右上の▷ボタンを押して実行してみましょう。
次は画面をタッチした時にボールをタッチしたかどうかの判定をしないといけないので、その処理を追加していきます。
まずはゲームクラスのtouch_beganメソッドを書いていきます。
Gameクラス
def touch_began(self, touch):
#タッチした時の画面のx座標
x = touch.location.x
#タッチした時の画面のy座標
y = touch.location.y
これで画面をタッチした時に、タッチした部分のx座標とy座標が取得できます。
続いてボールをタッチしたかどうかの判定をしないといけないので判定するメソッドを作成していきます。
ゲームクラスのtouch_beganメソッドの下らへんに書いてください。
Gameクラス
def hit_judgment(self,x,y):
#条件分岐でタッチした時のx座標とy座標がボールの描画範囲内に存在するかどうかを判定
if self.ball.x < x < self.ball.x+self.ball.w+5 and self.ball.y-5 < y < self.ball.y+self.ball.h+5:
print('Hit!!!!!!!!!!!')
else:
print('NoHit')
そして先程のtouch_beganメソッドに1行コードを追加します↓
def touch_began(self, touch):
#タッチした時の画面のx座標
x = touch.location.x
#タッチした時の画面のy座標
y = touch.location.y
#ヒット判定のメソッドを実行(引数にxとyを割り当てる)
self.hit_judgment(x,y)
これでプレイヤーが画面をタッチした時の座標がボールの範囲内に有れば「Hit!!!!!!!!」と表示され、範囲外であれば「NoHit」と表示されると思います。
一度右上の▷ボタンを押して実行してみましょう。
色々タッチして表示が変わるか試してみてください!
次に、ボールを複数表示させられるようにしていきます。
とりあえず現在の全体コードを載せておきます。
全体コード(途中)
from scene import *
class Ball:
def __init__(self):
self.w = 50 #ボールの幅
self.h = self.w #ボールの高さ(幅と同じ)
self.x = 200 #ボールのx座標
self.y = 200 #ボールのy座標
self.vx = 2 #ボールのx方向の速度
self.vy = 2 #ボールのy方向の速度
def draw(self):
#円を描画
ellipse(self.x, self.y, self.w, self.h)
def update(self):
#ボールのx座標にx方向の速度を足す
self.x += self.vx
#ボールのy座標にy方向の速度を足す
self.y += self.vy
def hit_check(self, super):
#ボールの左側が画面の左側よりも小さい時
if self.x < 0:
self.x = 0
self.vx *= -1
#ボールの右側が画面の右側よりも大きい時
elif self.x + self.w > super.size.width:
self.x = super.size.width - self.w
self.vx *= -1
#ボールの下側が画面の下側よりも小さい時
elif self.y < 0:
self.y = 0
self.vy *= -1
#ボールの上側が画面の上側よりも大きい時
elif self.y + self.h > super.size.height:
self.y = super.size.height - self.h
self.vy *= -1
class Game(Scene):
def setup(self):
self.background_color = 'black' #背景色
self.ball = Ball() #ボールクラスをインスタンス化
def draw(self):
#ボールクラスのdrawメソッドを実行
self.ball.draw()
def update(self):
#ボールクラスのupdateメソッドを実行
self.ball.update()
#ボールクラスのhit_checkメソッドを実行(引数にselfを渡す)
self.ball.hit_check(self)
def touch_began(self, touch):
#タッチした時の画面のx座標
x = touch.location.x
#タッチした時の画面のy座標
y = touch.location.y
#ヒット判定のメソッドを実行(引数にxとyを割り当てる)
self.hit_judgment(x,y)
def hit_judgment(self,x,y):
#条件分岐でタッチした時のx座標とy座標がボールの描画範囲内に存在するかどうかを判定
if self.ball.x < x < self.ball.x+self.ball.w+5 and self.ball.y-5 < y < self.ball.y+self.ball.h+5:
print('Hit!!!!!!!!!!!')
else:
print('NoHit')
run(Game())
ボールを複数表示できるようにする
まず、ゲームクラスのsetupのところでボールをインスタンス化していると思うので、それを消して以下のようにリストを作成します。
Gameクラス(setup)
def setup(self):
self.background_color = 'black' #背景色
#ボールを管理する為のリストを作成
self.ball_list = []
#ボールリストにインスタンスを追加
self.ball_list.append(Ball())
次にdrawメソッドを変更していきます。
Gameクラス(draw)
def draw(self):
#もしボールリストが空じゃなかったら
if self.ball_list:
#ボールリストの中身をfor文でループして
for ball in self.ball_list:
#ボールのdrawメソッドを実行
ball.draw()
次も同じようにupdateメソッドも変更していきます。
Gameクラス(update)
def update(self):
#もしボールリストが空じゃなかったら
if self.ball_list:
#ボールリストの中身をfor文でループして
for ball in self.ball_list:
#ボールのupdateメソッドとhit_checkメソッドを実行
ball.update()
ball.hit_check(self)
次にhit_checkメソッドを変更していきます。
Gameクラス(hit_check)
def hit_judgment(self,x,y):
#もしボールリストが空じゃなかったら
if self.ball_list:
#ボールリストの中身をfor文でループして
for ball in self.ball_list:
#条件分岐でタッチした時のx座標とy座標がボールの描画範囲内に存在するかどうかを判定
if ball.x < x < ball.x+ball.w+5 and ball.y-5 < y < ball.y+ball.h+5:
print('Hit!!!!!!!!!!!')
else:
print('NoHit')
これで複数のボールを管理できるようになったので、ボールが複数出現するようにプログラムを追加していきます。
ここからrandomモジュールのrandintを利用するので1番上でインポートしておきましょう。
from random import randint
そしてゲームクラスの最後の方にボールを追加するためのメソッドを作成します。
Gameクラス(新しくadd_ballメソッドを追加)
def add_ball(self):
#ランダムにボールを出現させるために2つのランダムな整数値を用意
random_num = randint(1, 100)
random_num2 = randint(1, 100)
#もし2つのランダムな整数値が同じなら
if random_num == random_num2:
#ボールリストにインスタンス化したボールを追加
self.ball_list.append(Ball())
一度右上の▷ボタンを押して実行してみましょう。
ボールがランダムに出現すると思います。
ただ、これだとボールが同じ方向に同じ速度で移動するだけなので面白くありません。
なので、ボールの大きさとボールの出現場所とボールの速度もランダムにしましょう。
Ballクラス(init)
def __init__(self, super):
#ボールの幅
self.w = randint(50, 100)
#ボールの高さ(幅と同じ)
self.h = self.w
#ボールのx座標初期値
self.x = randint(0, super.size.width-self.w)
#ボールのy座標初期値
self.y = randint(0, super.size.height-self.h)
#ボールのx方向の速度
self.vx = randint(0, 3)
#ボールのy方向の速度
self.vy = randint(0, 3)
あと、ボールクラスをインスタンス化する時に引数を入れ忘れないようにしてください。
#ゲームクラスinitの所とadd_ballメソッドの所のBall()をBall(self)に変更
self.ball_list.append(Ball(self))
そして、ボールをタッチしたらボールが消えるようにしたいので、ゲームクラスのhit_judgmentメソッドの条件分岐の後のprint(Hit!!!!!!!!!)からprint(NoHit)までを消して以下の1行を追加します。
#リストからボールを削除する
self.ball_list.remove(ball)
これでボールをタッチした時にボールが消えるようになりました!
右上の▷ボタンを押して実行してみましょう。
ランダムにボールが出現して、ボールをタッチするとボールが消えると思います!
一応これで簡単なボール消しゲームの完成です。
ボールを消してもずっと出続けるので終わりがありませんが、、、。
全体コード(完成版)
from scene import *
from random import randint
class Ball:
def __init__(self, super):
#ボールの幅
self.w = randint(50, 100)
#ボールの高さ(幅と同じ)
self.h = self.w
#ボールのx座標初期値
self.x = randint(0, super.size.width-self.w)
#ボールのy座標初期値
self.y = randint(0, super.size.height-self.h)
#ボールのx方向の速度
self.vx = randint(0, 3)
#ボールのy方向の速度
self.vy = randint(0, 3)
def draw(self):
#円を描画
ellipse(self.x, self.y, self.w, self.h)
def update(self):
#ボールのx座標にx方向の速度を足す
self.x += self.vx
#ボールのy座標にy方向の速度を足す
self.y += self.vy
def hit_check(self, super):
#ボールの左側が画面の左側よりも小さい時
if self.x < 0:
self.x = 0
self.vx *= -1
#ボールの右側が画面の右側よりも大きい時
elif self.x + self.w > super.size.width:
self.x = super.size.width - self.w
self.vx *= -1
#ボールの下側が画面の下側よりも小さい時
elif self.y < 0:
self.y = 0
self.vy *= -1
#ボールの上側が画面の上側よりも大きい時
elif self.y + self.h > super.size.height:
self.y = super.size.height - self.h
self.vy *= -1
class Game(Scene):
def setup(self):
self.background_color = 'black' #背景色
#ボールを管理する為のリストを作成
self.ball_list = []
#ボールリストにインスタンスを追加
self.ball_list.append(Ball(self))
def draw(self):
#もしボールリストが空じゃなかったら
if self.ball_list:
#ボールリストの中身をfor文でループして
for ball in self.ball_list:
#ボールクラスのdrawメソッドを実行
ball.draw()
def update(self):
#もしボールリストが空じゃなかったら
if self.ball_list:
#ボールリストの中身をfor文でループして
for ball in self.ball_list:
#ボールクラスのupdateメソッドとhit_checkメソッドを実行
ball.update()
ball.hit_check(self)
#ボール追加処理
self.add_ball()
def touch_began(self, touch):
#タッチした時の画面のx座標
x = touch.location.x
#タッチした時の画面のy座標
y = touch.location.y
#ヒット判定のメソッドを実行(引数にxとyを割り当てる)
self.hit_judgment(x,y)
def hit_judgment(self,x,y):
#もしボールリストが空じゃなかったら
if self.ball_list:
#ボールリストの中身をfor文でループして
for ball in self.ball_list:
#条件分岐でタッチした時のx座標とy座標がボールの描画範囲内に存在するかどうかを判定
if ball.x-5 < x < ball.x+ball.w+5 and ball.y-5 < y < ball.y+ball.h+5:
self.ball_list.remove(ball)
def add_ball(self):
#ランダムにボールを出現させるために2つのランダムな整数値を用意
random_num = randint(1, 100)
random_num2 = randint(1, 100)
#もし2つのランダムな整数値が同じなら
if random_num == random_num2:
#ボールリストにインスタンス化したボールを追加
self.ball_list.append(Ball(self))
run(Game())
以上になります。
これだけのコードで簡単なゲームが作成できました。
まとめ的なやつ
お疲れ様でした。
この記事では、機能は充分ではありませんが簡単なゲームを作成しました。
ここからスコアを表示させたりステージを作って難易度を上げていったり、ボールの個数がn個を超えるとゲームオーバーにしたり。
あなたの思い描く機能を追加したりするのも勉強になると思います。
また、今回僕が書いたコードが正解とは限りません。
なので、あなただったらどういう風に作成するのかを考えたりして色々試してやってみてください!
最後まで読んでいただきありがとうございました!
では、またお会いしましょう!
この記事が気に入ったらサポートをしてみませんか?