【Pygame Zero】量産04:時間差で障害物を降らせる
こんにちは!
「Pythonしよう!楽しく学べるプログラミング教室」の
ラッチ先生です


スックです。よろしくね!
BGM提供:DOVA-SYNDROME
https://dova-s.jp/
・ 「cigarette 」 by yuhei komatsu
効果音提供:Chisato’s Website
https://chisatosound.sakura.ne.jp/index.html
・ 「synthesizer_09_ascend_short」:シンセサイザーで作った音

基礎プログラムと 画像を入れた
「量産04 バケツを よけろ!」zipフォルダを ダウンロードしてください



今回は、blit( )メソッドを使って 背景画像を 入れてみたよ

学習の流れ
マウスで boonを 動かす
バケツが 上から 落ちてくる
バケツにあたるとセリフを言う
BGM・効果音を 入れる
BGM提供:DOVA-SYNDROME
https://dova-s.jp/
・ 「cigarette 」 by yuhei komatsu
効果音提供:Chisato’s Website
https://chisatosound.sakura.ne.jp/index.html
・ 「synthesizer_09_ascend_short」:シンセサイザーで作った音
プログラムを 実行してみよう
プログラミングの仕方を説明します
モジュールを 用意する

今回の「バケツを よけろ!」では、
・ boonが バケツに当たる
・ バケツが ランダムな場所で 表示する
・ boon が セリフを言う
プログラムが あります
そこで、3つのモジュールを 用意しました




モジュールとは、
関数やプログラムが書かれているファイルのことだよ
今回のプログラミングのポイント

今回は、
バケツが上からどんどん落ちてくるプログラムを 作っていきます。
scratchで言う「クローン」。
pygama zeroでは、次の手順で プログラムします

リスト:backetsを作成して、その中にバケツを 追加していくんだ

backets[:] は、『リストのコピー』と 覚えておいてね


それぞれの動きが わかりやすくなるよ


2つに 分けたよ
マウスで boonを 動かす

angle_to( ) メソッドで、
boonを マウスの方へ向くようにします

game = "play" #1 変数game 宣言 初期値:playdef on_mouse_move(pos): #2 マウスが動いた時 引数posに 座標が代入
global game #3 グローバル変数 game
if game == "play": #4 もし 変数gameが playなら
boon.angle = boon.angle_to(pos) #5 boonの向きに マウスの方へ向く角度を 代入する
マウスが動くと、引数posの中に マウスの座標が 代入されるんだ

つぎは、
マウスオブジェクトにプロパティposを追加して、
move_towards( )メソッドを使って boonをマウスの方へ 動かします


mouse.pos = 400, 300 #1 プロパティ:posに (400, 300)を 代入するdef on_mouse_move(pos):
global game
if game == "play":
boon.angle = boon.angle_to(pos)
mouse.pos = pos #2 プロパティposに マウスの座標を 代入する
def boon_move(): #3 boonの動きを 定義する
global game #4 グローバル変数 game
if game == "play": #5 もし 変数gameが playなら
boon.move_towards(mouse.pos, 5) #6 boonが マウスの方へ5pxずつ 動くdef update(): #7 更新する
boon_move() #8 boonを 動かす
これで、boon の動きは 完了です
バケツが 上から 落ちてくる

最初に
バケツを作る関数:cleate_backet( ) を定義します。
そして、
schedule_interval()メソッドを使って
0.5秒経ったら、バケツを作っていきましょう

buckets = [] #1 リストbucketsに 空のリストを 代入するdef draw():
screen.blit("background", (0, 0))
boon.draw()
for bucket in buckets: #9 リストbucketsから バケツを取り出す
bucket.draw() #10 バケツを 表示するdef create_bucket(): #2 バケツを作る関数を 定義する
x = random.randint(50, WIDTH-50) #3 x座標に 50~750からランダムに決めて代入する
y = 0 #4 y座標に 0を代入する
bucket = Actor("bucket", (x, y)) #5 バケツを 作る
bucket.angle = random.choice([-45, 45]) #6 バケツの向きに -45か45を選ぶ
buckets.append(bucket) #7 リストbucketsに 追加する
clock.schedule_interval(create_bucket, 0.5) #8 0.5秒ごとに バケツを作るdef cleate_backet( ) : バケツを作る定義
ポイント1
47. backet.angle = random.choice( [-45, 45] )
バケツの傾きを -45° か 45°にしたかったので、
choice( )関数を使いました。
ポイント2
48. backets.append (backet)

Actor( ) クラスで バケツを作ったら リストbacketsに 追加していきます。
ポイント3
66. clock.schedule_interval(cleate_backet, 0.5)
schedule_interval( ) メソッドを使って
0.5秒ごとに バケツを作るcleate_backet( ) 関数を実行します。

リストbacketsには、0.5秒ごとに バケツが追加されます。


ここまでが、バケツが作られるポイント!
まだ、スクリーンには 表示されないよ
def draw( ) : バケツを表示する
ポイント4
18. for backet in backets:
19. backet.draw( )
for 文を使って、リストbacketsに入っているバケツを
順番に 変数backetに代入して draw( ) メソッドで 表示します。
リストに入っているバケツが 表示されるよ


つぎは、
for 文を使ってバケツを 下へ動かします。
下まで動いたら 削除します。
def bucket_move(): #1 バケツの動きを 定義する
for bucket in buckets[:]: #2 リストbucketsコピーから バケツを取り出す
bucket.y += 5 #3 バケツのy座標を 5pxずつ増やす
if bucket.y > HEIGHT: #4 もし バケツのy座標が y:800pxより大きくなったら
buckets.remove(bucket) #5 バケツを リストbucketsから削除する
def update():
boon_move()
bucket_move() #6 バケツを 動かすバケツの動き

もし、リストbacketsでバケツを取り出すと
53. for backet in backets :
57. backets.remove(backet)
リストbacketsから バケツを取り出している最中に 削除すると
バケツの取り出し方が変になり、 エラーが起きる場合があります。
ホントだ!
バケツ「2」が 飛ばされるね

ポイント
リストbacketsを コピーして リストbackets [ : ] にする
53. for backet in backets [ : ]:
57. backets.remove(backet)
元のリストbacketsから要素を削除しても、
コピーしたリストbackets[:]には影響しません。

なるほどね!
リストbackets[ : ]は、
最後のバケツを取り出してから コピーするんだね
バケツにあたると セリフを言う

collidelist_pixel( )メソッドを使って、
バケツに当たったら セリフを言うようにします。

def draw():
screen.blit("background", (0, 0))
boon.draw()
for backet in backets:
backet.draw()
text_display.draw(screen) #1 テキストディスプレイを装備するdef boon_move():
global game
if game == "play":
boon.move_towards(mouse.pos, 5)
if boon.collidelist_pixel(buckets) != -1: #2 もし バケツに触れたら
game = "over" #3 変数gameに overを代入する
clock.unschedule(create_bucket) #4 create_backet()関数を止める
boon.image = "boon_ouch" #5 boonの画像を "boon_ouch"にする
boon.say("Ouch!", 2, color = "red", size=70, y_offset=-70) #6 boonが 「Ouch!」と2秒間言う
あれっ?
バケツに当たったときの数字が 「2, 1, -1」と変化してるよ

それは、当たったバケツの順番が 変わったからだよ


わかったよ!
boonに触れている間に リストbacketsの順番が 変わったんだね
バケツに当たったら セリフを言う
ポイント1
15. def draw ( ):
20. text_display .draw ( screen )
39. boon.say ( “Ouch!”, 2 color = “red”, size = 70, y_offset = -70 )
boonに セリフを言わせるために、
draw( ) 関数の定義で テキストディスプレイを装備します。
say( ) メソッドを使って、 セリフを言わせよう

ポイント2
37. clock.unschedule ( cleate_backets )
変数game が “over“に なったことで、boonの動きは止まります。
しかし、
66. clock.schedule_interval(cleate_backet, 0.5)
このschedule_interval( ) メソッドが 実行されています。
そのため、unschedule ( )メソッドで、
cleate_backets( )関数を 止めます。

BGM・効果音を 入れる
BGM提供:DOVA-SYNDROME
https://dova-s.jp/
・ 「cigarette 」 by yuhei komatsu
効果音提供:Chisato’s Website
https://chisatosound.sakura.ne.jp/index.html
・ 「synthesizer_09_ascend_short」:シンセサイザーで作った音

それでは、BGMを 入れてみましょう
Python zeroには、musicオブジェクトが標準装備であります。
やり方、以下の手順です
BGM の 流し方
1. MP3ファイルのBGMを 用意する

2. フォルダ『music』フォルダに 入れる

3. musicモジュールのメソッドを使う

def boon_move():
global game
if game == "play":
boon.move_towards(mouse.pos, 5)
if boon.collidelist_pixel(backets) != -1:
game = "over"
music.stop() #2 BGMを 止めるmusic.play("cigarette") #1 BGMを 流す
今回のプログラムに「DOVA-SYNDROME」サイトから
・ 「cigarette 」 by yuhei komatsu
BGMの曲として お借りしました。 ありがとうございます。

最後に
boonが バケツに当たった時に 効果音をつけましょう!
Python zeroには、soundsオブジェクトが標準装備であります。
次の手順で 行います
効果音のつけ方
1. WAVファイルの効果音を 用意する

2. フォルダ『sounds』フォルダに 入れる

3. soundsモジュールのplay( )メソッドを使う

今回のプログラムに『Chisato’s Website」サイトから
・ シンセサイザーで作った音: synthesizer_09_ascend_short
効果音を お借りしました。 ありがとうございます。
def boon_move():
global game
if game == "play":
boon.move_towards(mouse.pos, 5)
if boon.collidelist_pixel(buckets) != -1:
game = "over"
music.stop()
sounds.synthesizer_09_ascend_short.play() #1効果音を入れるBGM提供:DOVA-SYNDROME
https://dova-s.jp/
・ 「cigarette 」 by yuhei komatsu
効果音提供:Chisato’s Website
https://chisatosound.sakura.ne.jp/index.html
・ 「synthesizer_09_ascend_short」:シンセサイザーで作った音

これで、今回の学習は終了! おつかれさま
まとめ

今回は、
上からバケツが落ちてくるプログラムを 作りました。
import pgzrun
from pgzhelper import *
import random
from say import text_display
WIDTH = 800
HEIGHT = 590
boon = Actor("boon", (400, 300))
buckets = []
game = "play"
mouse.pos = 400, 300
def draw():
screen.blit("background", (0, 0))
boon.draw()
for bucket in buckets:
bucket.draw()
text_display.draw(screen)
def on_mouse_move(pos):
global game
if game == "play":
boon.angle = boon.angle_to(pos)
mouse.pos = pos
def boon_move():
global game
if game == "play":
boon.move_towards(mouse.pos, 5)
if boon.collidelist_pixel(buckets) != -1:
game = "over"
music.stop()
sounds.synthesizer_09_ascend_short.play()
clock.unschedule(create_bucket)
boon.image = "boon_ouch"
boon.say("Ouch!", 2, color = "red", size=70, y_offset=-70)
def create_bucket():
x = random.randint(50, WIDTH-50)
y = 0
backet = Actor("backet", (x, y))
bucket.angle = random.choice([-45, 45])
buckets.append(bucket)
clock.schedule_interval(create_bucket, 0.5)
def bucket_move():
for bucket in buckets[:]:
bucket.y += 5
if bucket.y > HEIGHT:
buckets.remove(bucket)
def update():
boon_move()
bucket_move()
music.play("cigarette")
pgzrun.go()
リストからキャラクターを削除する場合は、
リストのコピーを 使ってね。


for backet in backets[ : ] : の使い方を 覚えてね!
それじゃ、またね!
