【Pygame Zero】簡単なゲーム20:重力ジャンプで風船を全部割れ!
こんにちは!
「Pythonしよう!楽しく学べるプログラミング教室」の
ラッチ先生です


スックです。よろしくね!
BGM提供: DOVA-SYNDROME
https://dova-s.jp/
・ 「Sunny_Time」 written by modus
効果音提供:効果音ラボ
https://soundeffect-lab.info/
・ 「お寺の鐘」: アニメ
・ 「パッ」: アニメ
・ 「ぷよん」: アニメ
・ 「説明ウインドウが開く」: ボタン・システム音

基礎プログラムと 画像を入れた
「簡単なゲーム20: ジャンプしてタッチ!No.3」zipフォルダを
ダウンロードしてください



このゲームで使用している音声ファイルは、
以下のサイトからお借りしています。
各自でダウンロードして、該当するフォルダに入れてください!
BGM提供: DOVA-SYNDROME
https://dova-s.jp/
・ 「Sunny_Time」 written by modus
効果音提供:効果音ラボ
https://soundeffect-lab.info/
・ 「お寺の鐘」: アニメ
・ 「パッ」: アニメ
・ 「ぷよん」: アニメ
・ 「説明ウインドウが開く」: ボタン・システム音

学習の流れ
boon を キーで動かす
風船をジャンプして ゲットする
結果発表

プログラムを 実行してみよう
プログラミングの仕方を説明します
モジュールを 用意する

今回の「ジャンプしてタッチ!No.3」では、
・ 風船と 幽霊の当たり判定
・ 幽霊や風船の移動する目的地を ランダムに決める
プログラムがあります。
そこで、2つのモジュールを 用意しました



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


風船や幽霊、地面も 同じだよ
そして、属性(データ)やメソッド(命令)は、
『 . (ドット)』を付ければ、使えるよ
今回のプログラミングのポイント

今回のプログラミングのポイントが こちらです

ジャンプの上方面は、-(マイナス)になるよ
boon を キーで動かす

最初に
上キーを押したら、boon がジャンプする
boon_jump関数を作りましょう
定数:JUMP_POWER は、ジャンプ力の数値
定数:GRAVITY は、重力の数値
を 設定しましょう

定数とは、決まった数値をいれる箱だよ。
大文字で書くルールです。
HEIGHT = 600
JUMP_POWER = 17 #1 定数JUMP_POWERに 17 を設定する
GRAVITY = 0.5 #2 定数GRAVITYに 0.5 を設定する
boon = Actor("boon", (400, 200))
boon.on = False #3 プロパティonに Falseを設定する
boon.vy = 0 #4 プロパティvyに 0 を設定する- プロパティon とは?


boon_jump関数を 定義するよ
bg_img = "bg"
def boon_jump(): #1 boon_jump関数を 定義する
if not boon.on: #2 もし プロパティonが Falseなら
boon.vy += GRAVITY #3 プロパティvyが 定数GRAVITYごと増える
boon.y += boon.vy #4 y座標が プロパティvyごと 増える
def update():
boon_jump() #5 boon_jump関数を 実行する
あららっ、消えちゃった…

collide_pixel()メソッドを使って
地面に触れたら 着地するプログラムを作るよ
def boon_jump():
if not boon.on:
boon.vy += GRAVITY
boon.y += boon.vy
if boon.collide_pixel(ground): #1 地面に 触れたら
boon.bottom = ground.top #2 プロパティbottomに 地面のプロパティtopの数値を設定する
boon.vy = 0 #3 プロパティvyを 0に設定する
boon.on = True #4 プロパティonを Trueに設定する
着地! おみごと‼!

上のキーを押したら、
プロパティ:vy に、-1 ×(定数:JUMP_POWER)を設定すれば
ジャンプするよ

bg_img = "bg"
game = "play" #1 変数gameを宣言 初期値:playにする
def boon_jump():
if not boon.on: def on_key_down(key): #2 キーが押された関数を 定義する
if game == "play": #3 もし 変数gameがplayなら
if key == keys.UP and boon.on: #4 もし 上キーが押されて プロパティonがTrueなら
sounds.パッ.play() #5 効果音を 鳴らす
boon.vy = -JUMP_POWER #6 プロパティvyに ‐1× 定数JUMP_POWERを設定する
boon.on = False #7 プロパティonに Falseを設定する
def update():
boon_jump()- on_key_down関数とは?

- 効果音について?


効果音ラボサイトからの音源は、MP3形式です。
しかし、pygame zeroプログラムでは、MP3形式は使えません。WAV形式に 変換して フォルダsoundsに 入れてください

ジャンプが 完成!

キーを押したら、左右に動くよう
boon_move関数を 定義します
def boon_move(): #1 boon_move関数を 定義する
if game == "play": #2 もし 変数gameが playなら
if keyboard.right: #3 もし右キーが 押されたら
boon.flip_x = False #4 右向きにする
boon.x += 5 #5 x座標を 5pxずつ増える
if keyboard.left: #6 もし 左キーが 押されたら
boon.flip_x = True #7 左向きにする
boon.x -= 5 #8 x座標を 5pxずつ減る
boon.x = max(50, min(boon.x, WIDTH-50)) #9 x座標範囲を 50~750までにする
def update():
boon_jump()
boon_move() #10 boon_move関数を 実行する効果音提供:効果音ラボ
https://soundeffect-lab.info/
・ 「パッ」: アニメ
- keyboardオブジェクトについて?

- プロパティ:flip_xとは?

- min( )関数、max( )関数とは?


boonが 自由に動くようになったね
風船をジャンプしてゲットする

for 文を使って 5個の風船を 表示させるよ

game = "play"
b_img = ["balloon_b", "balloon_g", "balloon_p", "balloon_r", "balloon_y"] #1 リストb_imgに 風船画像を 代入する
balloons = [] #2 空リストballoonsを 作成する
for i in range(5): #3 5回繰り返す
x = random.randint(0, WIDTH) #4 x座標に 0~800からランダムに選んだ数値を設定する
balloon = Actor(b_img[i], (x, 0)) #5 風船を 生成する
balloons.append(balloon) #6 リストballoonsに 風船を追加する
def update():def draw():
screen.blit(bg_img, (0, 0))
ground.draw()
for balloon in balloons: #7 リストballoonsから 風船を取り出す
balloon.draw() #8 風船を 表示する
boon.draw()
ghost.draw()
- for文とrange関数とは?

- randint関数とは?

- appendメソッドについて


スクリーンの上に 表示するんだ!

次は、animate関数を使って
風船を個別にランダムな動きをする balloon_move(balloon)関数を
定義します

def balloon_move(balloon): #1 balloon_move関数を 定義する ★引数balloon
x = random.randint(50, 750) #2 x座標を 50~750からランダムに選んだ数値を 設定する
y = random.randint(0, 200) #3 y座標を 0~200からランダムに選んだ数値を 設定する
b_time = random.uniform(0.5, 4.0) #4 変数b_timeに 0.5~4.0からランダムに選んだ数値を 設定する
balloon.anim = animate(balloon,
duration=b_time,
pos=(x, y),
on_finished=lambda:balloon_move(balloon)) #5 プロパティanimに 風船のアニメーションを代入する
for balloon in balloons: #6 リストballoonsから 風船を取り出す
balloon_move(balloon) #7 balloon_move関数を 実行する
def update():- uniform関数とは?


風船が個別に動くプログラムのポイントです!
ポイント1
風船を動かすballoon_move( )関数に 引数balloonを 入れましょう
59. def balloon_move(balloon):
ポイント2
animate関数で作られた風船の動きアニメーションを
boonに触れたら止めるために プロパティanim に代入します。
63. balloon.anim = animate ( balloon, duration = …)

★anim:「animation」の略語

プロパティanimに 代入しないと、
アニメーションの動きの途中で止めることが できないよ
ポイント3
63. balloon.anim = animate(balloon,
64. duration = b_time,
65. on_finished=lambda: balloon_move ( balloon ))
風船の動くアニメーションが 終了したら また、balloon_move(balloon)関数を実行させるために lambda 無名関数を使います


『lambda』とは、無名関数。
lambda:balloon_move(balloon) は、
『balloon_move(balloon)関数を 実行する』と定義した関数です。
- lambda: 無名関数を使う理由
-
ここでは、なぜ lambda:無名関数を使うか 解説します。
animate( )関数の引数:on_finished には、アニメーション終了後に
実行させたい関数を 渡します。1.on_finished引数に、関数を渡すanimate ( balloon,
・・・,
on_finished = balloon_move )しかし、
これでは、balloon_move(balloon)関数には、引数balloon が あるため
エラーが発生します。
balloon_move( balloon )関数 そのまま入力すれば いいんじゃない…
2.balloon_move( balloon )と 引数balloonを入れた関数を渡す。animate (balloon,
・・・,
on_finished = balloon_move(balloon) )関数名balloon_move(balloon) に、( )が あるため エラーが発生します。
( )は、関数を実行する という働き。
つまり、
アニメーションする前に balloon_move(balloon) 関数が実行され
永遠ループに 入ります
えっ⁉ ( )は、関数を実行する意味だったんだ‼

そうだよ。
そこで、「lambda」を 使います。
3.lambda: ○○ を 使うanimate (balloon,
・・・,
on_finished = lambda : balloon_move(balloon) )lambda: balloon_move(balloon)という関数になって
引数 on_finished に渡り、アニメーションが 終了後 実行されます。
lambda :によって、
引数(balloon)が あっても すぐ実行されなくなったね
ポイント4
for文を使って
各風船オブジェクトを balloon_move(balloon)関数に 渡し 実行します。


つぎに、
boon が 風船をタッチしたか判定する
check_touch関数を 作るよ
def check_touch(): #1 check_touch関数を 定義する
if game == "play": #2 もし 変数gameが playなら
for balloon in balloons[:]: #3 コピーリストballoonsから 風船を取り出す
if balloon.collide_pixel(boon): #4 もし 風船が boonに触れたら
sounds.ぷよん.play() #5 効果音を 鳴らす
balloons.remove(balloon) #6 リストballoonsから 風船を削除する
def update():
boon_jump()
boon_move()
check_touch() #7 check_touch関数を 実行する効果音提供:効果音ラボ
https://soundeffect-lab.info/
・ 「ぷよん」: アニメ
- collide_pixelメソッド とは?


74. if balloon.collide_pixel(boon):
風船が boonに衝突すると、衝突した座標が 返り、
if 文では、 True になります。衝突してない時は、ずっと None です。
if 文では、 False になります。
- 効果音に ついて


効果音ラボサイトからの音源は、MP3形式です。
しかし、pygame zeroプログラムでは、MP3形式は使えません。WAV形式に 変換して フォルダsoundsに 入れてください
- remove()関数とは?


おおっ!風船を ゲットできてるね
結果発表


幽霊も animate関数を使って
ランダムに動くプログラムを 作ろう
def ghost_move(): #1 ghost_move関数を 定義する
x = random.randint(0, WIDTH) #2 x座標に 0~800からランダムに選んだ数値を設定する
y = random.randint(0, 500) #3 y座標に 0~500からランダムに選んだ数値を設定する
g_time = random.uniform(1.0, 3.0) #4 変数g_timeに 1.0~3.0からランダムに選んだ数値を設定する
ghost.anim = animate(ghost, duration=g_time, pos=(x,y), on_finished=ghost_move) #5 プロパティanimに 幽霊の動きアニメーションを代入する
ghost_move() #6 ghost_move関数を 実行する
def update():
幽霊も 動き出したね

最後に、set_result関数
クリアと ゲームオーバーのプログラムを 作成しましょう

def set_result(bg,
g_costume,
b_costume,
sound): #2 set_result関数を 定義する
global game, bg_img #3 グローバル変数 game, bg_img
game = "result" #4 変数gameに resultを設定する
music.stop() #5 BGMを 止める
ghost.anim.stop() #6 幽霊のアニメーションを 止める
for balloon in balloons: #7 リストballoonsから 風船を取り出す
balloon.anim.stop() #8 風船のアニメーションを 止める
bg_img = bg #9 変数bg_imgに 引数bgを設定する
ghost.image = g_costume #10 幽霊のプロパティimageに 引数g_costumeを設定する
boon.image = b_costume #11 boonのプロパティimageに 引数b_costumeを設定する
sound.play() #12 引数soundを 再生する
def update():music.play("sunny_time") #1 BGMを 流す
pgzrun.go()- music モジュールについて

- プロパティ: anim について

- 効果音 について


効果音ラボサイトからの音源は、MP3形式です。
しかし、pygame zeroプログラムでは、MP3形式は使えません。WAV形式に 変換して フォルダsoundsに 入れてください

それでは、最初に
幽霊に タッチされたら ゲームオーバーになるプログラムを作りましょう。
check_touch関数の中に 追加するよ
def check_touch():
if game == "play":
for balloon in balloons[:]:
if balloon.collide_pixel(boon):
sounds.ぷよん.play()
balloons.remove(balloon)
if boon.collide_pixel(ghost): #1 もし 幽霊に 触れたら
set_result("bg_over",
"ghost_over",
"boon_over",
sounds.お寺の鐘) #2 set_result関数を 実行する
def ghost_move():BGM提供: DOVA-SYNDROME
https://dova-s.jp/
・ 「Sunny_Time」 written by modus
効果音提供:効果音ラボ
https://soundeffect-lab.info/
・ 「お寺の鐘」: アニメ

鐘の音が いいね!

最後に、風船が なくなったらゲームクリア!
len 関数を使えば、
簡単にリストballoonsの風船の数が わかるよ

def check_touch():
if game == "play":
for balloon in balloons[:]:
if balloon.collide_pixel(boon):
sounds.ぷよん.play()
balloons.remove(balloon)
if len(balloons) == 0: #1 もし リストballoonsの要素が0なら
set_result("bg_clear",
"ghost_clear",
"boon_clear",
sounds.説明ウインドウが開く) #2 set_result関数を実行する
return #3 返す
if boon.collide_pixel(ghost):
set_result("bg_over",
"ghost_over",
"boon_over",
sounds.お寺の鐘)
BGM提供: DOVA-SYNDROME
https://dova-s.jp/
・ 「Sunny_Time」 written by modus
効果音提供:効果音ラボ
https://soundeffect-lab.info/
・ 「説明ウインドウが開く」: ボタン・システム音

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

今回は、
上キーでboon をジャンプさせる ゲームを作りました。
import pgzrun
from pgzhelper import *
import random
WIDTH = 800
HEIGHT = 600
JUMP_POWER = 17
GRAVITY = 0.5
boon = Actor("boon", (400, 200))
boon.on = False
boon.vy = 0
ghost = Actor("ghost", (700, 100))
ground = Actor("ground", midbottom=(400, 600))
bg_img = "bg"
game = "play"
b_img = ["balloon_b", "balloon_g", "balloon_p", "balloon_r", "balloon_y"]
balloons = []
def boon_jump():
if not boon.on:
boon.vy += GRAVITY
boon.y += boon.vy
if boon.collide_pixel(ground):
boon.bottom = ground.top
boon.vy = 0
boon.on = True
def on_key_down(key):
if game == "play":
if key == keys.UP and boon.on:
sounds.パッ.play()
boon.vy = -JUMP_POWER
boon.on = False
def boon_move():
if game == "play":
if keyboard.right:
boon.flip_x = False
boon.x += 5
if keyboard.left:
boon.flip_x = True
boon.x -= 5
boon.x = max(50, min(boon.x, WIDTH-50))
for i in range(5):
x = random.randint(0, WIDTH)
balloon = Actor(b_img[i], (x, 0))
balloons.append(balloon)
def balloon_move(balloon):
x = random.randint(50, 750)
y = random.randint(0, 200)
b_time = random.uniform(0.5, 4.0)
balloon.anim = animate(balloon,
duration=b_time,
pos=(x, y),
on_finished=lambda:balloon_move(balloon))
for balloon in balloons:
balloon_move(balloon)
def check_touch():
if game == "play":
for balloon in balloons[:]:
if balloon.collide_pixel(boon):
sounds.ぷよん.play()
balloons.remove(balloon)
if len(balloons) == 0:
set_result("bg_clear",
"ghost_clear",
"boon_clear",
sounds.説明ウインドウが開く)
return
if boon.collide_pixel(ghost):
set_result("bg_over",
"ghost_over",
"boon_over",
sounds.お寺の鐘)
def ghost_move():
x = random.randint(0, WIDTH)
y = random.randint(0, 500)
g_time = random.uniform(1.0, 3.0)
ghost.anim = animate(ghost, duration=g_time, pos=(x,y), on_finished=ghost_move)
ghost_move()
def set_result(bg,
g_costume,
b_costume,
sound):
global game, bg_img
game = "result"
music.stop()
ghost.anim.stop()
for balloon in balloons:
balloon.anim.stop()
bg_img = bg
ghost.image = g_costume
boon.image = b_costume
sound.play()
def update():
boon_jump()
boon_move()
check_touch()
def draw():
screen.blit(bg_img, (0, 0))
ground.draw()
for balloon in balloons:
balloon.draw()
boon.draw()
ghost.draw()
music.play("sunny_time")
pgzrun.go()
今回のジャンプのプログラムには、
定数:JUMP_POWER, GRAVITY を取り入れました。
この定数の数値を 変えるだけで
boonのジャンプが 自分の好みに変えられるよ

みなさんも、 ジャンプゲームを作ってみよう!
それじゃあ、またね!
















