【Pygame Zero】ゲームの技02:効果音をつけよう!

こんにちは!
「Pythonしよう!楽しく学べるプログラミング教室」の
ラッチ先生です


スックです。よろしくね!
効果音提供:Chisato’s Website
https://chisatosound.sakura.ne.jp/index.html

基礎プログラムと 画像を入れた
「ゲームの技02 boon シューティング!No.2」zipフォルダを ダウンロードしてください



この基礎プログラムは、こちらの記事で解説しています

学習の流れ
スペースキーを 押すと 弾を発射する
弾に当たると 爆破アニメーションになる
敵に襲われると セリフを言う

効果音をつける
効果音提供:Chisato’s Websiteサイト
プログラムを 実行してみよう
プログラミングの仕方を説明します
モジュールを 用意する

今回の「boon シューティング!No.2」では、
・ boonを マウスで動かす
・ 敵が 爆破アニメーションする
・ 敵を ランダムな場所へ 配置する
・ boon が セリフを言う
プログラムが あります
そこで、4つのモジュールを 用意しました





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

今回は、
効果音を入れたプログラムを 作っていきます。
ポイントが 4つあります。

今回のプログラムに『Chisato’s Website」サイトから
・ 弾の発射音: laser_gun_09_high_powered.wav
・ 敵の爆発音: synthesizer_09_ascend_short.wav
・ 敵に捕まる音: death_explosion_03_player.wav
3つの効果音を お借りしました。 ありがとうございます。

大きさや透明は、ちゃんと調節できるよ


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


2つに 分けたよ
スペースキーを押すと 弾を発射する

最初に、
boonを マウスで 動かす プログラムを 作りましょう
mouseオブジェクトに プロパティ「pos」を 追加して
動いているマウスの座標を 入れます

game = "play" #1 変数gameを宣言 初期値:"play"
mouse.pos = 400, 300 #2 マウスの座標に x座標400, y座標300を 代入する
def on_mouse_move(pos): #3 動いているマウスの座標を取得して posに 代入する
global game #4 グローバル変数 game
mouse.pos = pos #5 オブジェクトマウスの座標に posの座標を 代入する
if game == "play": #6 もし、変数gameが "play"だったら
boon.angle = boon.angle_to(pos) #7 boonの向きに マウスの方へ向く角度を 代入する
ポイント
33. boon.angle = boon.angle_to(pos)
boon.angle_to( ) メゾットを使って、 boonを マウスの方へ向かせます


angle_to( ) メゾットは、便利だね

つぎに、
move_towards( )メゾットを 使って、
マウスの方へ 動くようにします。

def boon_move(): #1 boonの動きを まとめる
global game #2 グローバル変数 game
if game == "play": #3 もし 変数gameが "play"だったら
boon.move_towards(mouse.pos, 3) #4 boonをマウスの方へ 3pxずつ動かす
def update(): #4 更新する
boon_move() #5 boonを 動かす

つぎは、弾を発射させます。
弾を boonの前に 表示させましょう
def beam_move(): #1 弾の動きを まとめる
global game #2 グローバル変数 game
if game == "play": #3 もし 変数gameが "play"だったら
beam.pos = boon.pos #4 弾の座標に boonの座標を 代入する
beam.angle = boon.angle #5 弾の向きに boonの向きを 代入する
beam.move_forward(50) #6 弾を 50px 前に出す
def update():
boon_move()
beam_move() #7 弾を 動かす

おお!
boonの前に弾があるぞ

変数beamに プロパティ『visible』を追加して、
弾の表示・非表示のスイッチに しましょう
そして、
・boonの前に位置する過程を 非表示
・弾を発射 を 表示
という プログラムにします

beam.visible = False #1 プロパティvisubleに Falseを 代入する
def on_key_down(key): #2 押されたキーを取得して、keyに代入する
if key == keys.SPACE: #3 もし、スペースキーが押されたら
beam.visible = True #4 プロパティvisibleに Trueを 代入する
def beam_move():
global game
if game == "play":
if not beam.visible: #5 もし プロパティvisibleが Falseなら
beam.pos = boon.pos
beam.angle = boon.angle
beam.move_forward(50)
else: #6 その他は(visibleがTureなら)
beam.move_forward(20) #7 弾は 20pxずつ 動く
if beam.x < 0 or beam.x > WIDTH or beam.y < 0 or beam.y > HEIGHT: #8 もし、上下左右の 端へ行ったら
beam.visible = False #9 プロパティvisibleに Falseを代入する

あれれ! 弾が ずっと表示されてるよ

おぉぉぉ…っと!
draw( ) 関数の中で、beam.visibleが Trueの時だけ表示させます
def draw():
screen.fill("white")
boon.draw()
enemy.draw(screen)
if beam.visible: #1 もし プロパティvisibleが Trueなら
beam.draw() #2 弾を 表示する

おっ! いいねぇ
弾に当たると 爆破アニメーション

move_towards( ) メゾットを使って
敵を boonの方へ 動くようにしましょう
def enemy_move(): #1 敵の動きを まとめる
global game #2 グローバル変数 game
if game == "play": #3 もし 変数gameが "play"なら
enemy.angle = enemy.angle_to(boon) #4 敵の向きに boonの方へ向く角度を代入する
enemy.move_towards(boon, 2) #5 boonの方へ 2pxずつ動く
def update():
boon_move()
beam_move()
enemy_move() #6 敵を 動かす

敵が 襲ってくるね

つぎは、
enemyオブジェクトに プロパティ: hitを 追加します

爆破アニメーションプログラム
1.visualモジュールの VisualEffect( ) を 使う
11. enemy = VisualEffect ( “enemy“, (700, 100) )
23. enemy.draw (screen)
2. 弾に 当たったら、プロパティ『 hit 』が Trueになる
透明・拡大アニメーションを 開始する
72. enemy.alpha_animation( )
73. enemy.scale_animation ( 0.03 , 4 )
3. プロパティ『 hit 』が True になったら
透明+拡大アニメーションを 実行する
77. result = enemy.process_animation( )
4. 透明・拡大 どちらかが終わったら アニメーション終了 “finished”
敵を リセットして、プロパティ『 hit 』を False にする
79. enemy.reset_effects( )
80. enemy.hit = False
enemy = VisualEffect("enemy", (700, 100)) #1 VisualEffect()クラスに 変える
enemy.hit = False #2 プロパティhitに Falseを代入する
def draw():
screen.fill("white")
boon.draw()
enemy.draw(screen) #3 スクリーンに つなげる
def enemy_move():
global game
if game == "play":
if not enemy.hit: #4 もし プロパティhit が Falseなら
enemy.angle = enemy.angle_to(boon)
enemy.move_towards(boon, 2)
if enemy.collide_pixel(beam) and beam.visible: #5 もし弾に当たり、弾が表示なら
enemy.alpha_animation() #6 透明アニメーション開始
enemy.scale_animation(0.03, 4) #7 拡大アニメーション開始
enemy.hit = True #8 プロパティhit に Trueを 代入する
else: #9 その他(プロパティhit が True)
result = enemy.process_animation() #10 透明+拡大アニメーションを 実行する
if result == "finished": #11 もし 変数resultが "finished"なら
enemy.reset_effects() #12 敵を リセットにする
enemy.hit = False #13 プロパティhit に Falseを代入する

この爆破アニメーションのスピードは、
プロパティ animation_speed で 変えられます。

enemy.animation_speed = 3 # プロパティanimation_speed に 3を代入する

○ プロパティ
・ alpha_increment
・ animation_speed
○ メゾット
・ scale_animation( 増加量, 目標倍率 )
この数値をいろいろ変えて、
自分の気に入った爆破アニメーションを 作ってね

敵が 爆破したら、
while True構文を使って
boonから300px以上 離れた所で リセットさせるよ

def enemy_move():
global game
if game == "play":
if not enemy.hit:
enemy.angle = enemy.angle_to(boon)
else:
result = enemy.process_animation()
if result == "finished":
enemy.reset_effects()
while True: #1
enemy.x = random.randint(50, WIDTH-50) #2 敵のx座標に 50~750からランダムに選んだ値を 代入する
enemy.y = random.randint(50, HEIGHT-50) #3 滝のy座標に 50~540からランダムに選んだ値 を代入する
if enemy.distance_to(boon) > 300: #4 もし boonから300px以上 離れたなら
enemy.hit = False #5 プロパティhit に Falseを代入する
break #6 繰り返しから抜ける

コマ送りで 見せています。
本当は、一瞬で この動きをしているんだ

そして、
sayモジュールのtext_display()クラスを使って
敵に襲われたら、動きを止めて セリフを言わせよう

def draw():
screen.fill("white")
boon.draw()
enemy.draw(screen)
if beam.visible:
beam.draw()
text_display.draw(screen) #1 テキストディスプレイをスクリーンにつなげる
def boon_move():
global game
if game == "play":
boon.move_towards(mouse.pos, 3)
if enemy.collide_pixel(boon) and not enemy.hit: #2 敵が boonに触れて、敵が弾に当たっていなかったら
game = "over" #3 変数gameに "over"を代入する
game_over() #4 ゲームオーバーを 行う
def game_over(): #5 ゲームオーバーの動きを まとめる(関数)
boon.image = "ouch_boon" #6 boonの画像を "ouch_boon"にする
boon.say("Ouch!", 2, color="red", size=70, y_offset=-70) #7 「Ouch!」と2秒間言う

変数game が “over“になったから、すべての動きが 止まったね
効果音をつける

最後に 効果音を つけていこう
効果音の再生するプログラム
1.フォルダ「sounds 」 に 効果音の音源を 入れる
音声ファイル形式:wav

2.Python zeroには、
効果音を鳴らす『sounds』オブジェクトが はじめから用意してあります。
play( ) メゾットで、効果音を再生する

今回のプログラムに『Chisato’s Website」サイトから
・ 弾の発射音: laser_gun_09_high_powered.wav
・ 敵の爆発音: synthesizer_09_ascend_short.wav
・ 敵に捕まる音: death_explosion_03_player.wav
3つの効果音を お借りしました。 ありがとうございます。
def on_key_down(key):
if key == keys.SPACE:
sounds.laser_gun_09_high_powered.play() #1 弾の発射音を再生する
beam.visible = True
def boon_move():
global game
if game == "play":
boon.move_towards(mouse.pos, 3)
if enemy.collide_pixel(boon) and not enemy.hit:
sounds.death_explosion_03_player.play() #2 敵に捕まった効果音を再生する
game = "over"
def enemy_move():
global game
if game == "play":
if not enemy.hit:
enemy.angle = enemy.angle_to(boon)
enemy.move_towards(boon, 2)
if enemy.collide_pixel(beam) and beam.visible:
sounds.synthesizer_09_ascend_short.play() #3 弾が当たった効果音を再生する
enemy.alpha_animation()

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

今回は、
シューティングゲームに効果音を入れたプログラムを 作りました。
import pgzrun
from pgzhelper import *
from visual import VisualEffect
import random
from say import text_display
WIDTH = 800
HEIGHT = 590
boon = Actor("boon", (400, 300))
enemy = VisualEffect("enemy", (700, 100))
beam = Actor("beam", (400, 300))
game = "play"
mouse.pos = 400, 300
beam.visible = False
enemy.hit = False
enemy.animation_speed = 3
def draw():
screen.fill("white")
boon.draw()
enemy.draw(screen)
if beam.visible:
beam.draw()
text_display.draw(screen)
def on_mouse_move(pos):
global game
mouse.pos = pos
if game == "play":
boon.angle = boon.angle_to(pos)
def on_key_down(key):
if key == keys.SPACE:
sounds.laser_gun_09_high_powered.play()
beam.visible = True
def boon_move():
global game
if game == "play":
boon.move_towards(mouse.pos, 3)
if enemy.collide_pixel(boon) and not enemy.hit:
sounds.death_explosion_03_player.play()
game = "over"
game_over()
def beam_move():
global game
if game == "play":
if not beam.visible:
beam.pos = boon.pos
beam.angle = boon.angle
beam.move_forward(50)
else:
beam.move_forward(20)
if beam.x < 0 or beam.x > WIDTH or beam.y < 0 or beam.y > HEIGHT:
beam.visible = False
def enemy_move():
global game
if game == "play":
if not enemy.hit:
enemy.angle = enemy.angle_to(boon)
enemy.move_towards(boon, 2)
if enemy.collide_pixel(beam) and beam.visible:
sounds.synthesizer_09_ascend_short.play()
enemy.alpha_animation()
enemy.scale_animation(0.03, 4)
enemy.hit = True
else:
result = enemy.process_animation()
if result == "finished":
enemy.reset_effects()
while True:
enemy.x = random.randint(50, WIDTH-50)
enemy.y = random.randint(50, HEIGHT-50)
if enemy.distance_to(boon) > 300:
enemy.hit = False
break
def update():
boon_move()
beam_move()
enemy_move()
def game_over():
boon.image = "ouch_boon"
boon.say("Ouch!", 2, color="red", size=70, y_offset=-70)
pgzrun.go()

効果音は、soundsオブジェクトで 簡単に使えます。

みんなも好きな効果音を『sounds』フォルダに入れて 鳴らしてみよう
それじゃ、またね!