【Pygame Zero】簡単なゲーム09:ジャンプ台からジャンプする
こんにちは!
「Pythonしよう!楽しく学べるプログラミング教室」の
ラッチ先生です


スックです。よろしくね!
BGM提供:DOVA-SYNDROME
https://dova-s.jp/
・ 「Meta Universe 」 by TECHNOTRAIN
効果音提供:Chisato’s Website
https://chisatosound.sakura.ne.jp/index.html
・ 「Accent. Brilliant [02] (Low)」:アクセント
・ 「Heal [04] (Short. Low)」: 回復の魔法
・ 「Jump [01] (High)」: アクションゲーム
・ 「Kiga Nukeru [01] (Long)」:アニメ

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


今回は、スクリーンの色を “honeydew“に したよ
「原色大事典」サイトには、URL:https://www.colordic.org/
pygame zeroで使える色が載っています


このゲームで使用している音声ファイルは、
以下のサイトからお借りしています。
各自でダウンロードして、該当するフォルダに入れてください!
BGM提供:DOVA-SYNDROME
https://dova-s.jp/
・ 「Meta Universe 」 by TECHNOTRAIN
効果音提供:Chisato’s Website
https://chisatosound.sakura.ne.jp/index.html
・ 「Accent. Brilliant [02] (Low)」:アクセント
・ 「Heal [04] (Short. Low)」: 回復の魔法
・ 「Jump [01] (High)」: アクションゲーム
・ 「Kiga Nukeru [01] (Long)」:アニメ

学習の流れ
ジャンプする
障害物が 出てくる
ゲーム終了

ゲームクリア

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

今回の「ジャンプしてタッチ!No.2」では、
・ 障害物が ランダムに 出現する
・ 障害物、風船に 触れる
プログラムがあります。
そこで、2つのモジュールを 用意しました



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

Actor( )クラスが入っている 変数boon には、
オブジェクトを動かす属性(データ)やメソッド(命令)が
あります。


属性(データ)やメソッド(命令)は、
『 . (ドット)』を付ければ、使えるよ
今回のプログラミングのポイント

今回のプログラミングには、ポイントが 3つあります

ジャンプの上方向:-(マイナス)
下方向:+(プラス)


リストballoonsを作成して、その中に4個の風船を入れるよ


クリアとゲームオーバーのプログラムを まとめたよ


2つに 分けたよ
boon を動かす

ジャンプのプログラムを作っていきます。
boonオブジェクトに 2つのプロパティ
・ jump_speed : ジャンプの時にboonが上下に動く長さを保存
・ on :地面に着地したか判定(True/ False)
を 追加します。

boon = Actor("boon", (100, 200))
boon.jump_speed = 0 #1 プロパティ:jump_speedに 0を設定する
boon.on = False #2 プロパティ:onに Falseを設定する
ground = Actor("ground", midbottom = (400, 600))
game = "play" #3 変数gameを宣言 初期値:play
def boon_jump(): #4 boon_jump()関数を 定義する
if not boon.on: #5 もし プロパティonが Falseなら
boon.jump_speed += 0.5 #6 プロパティjump_speedが 0.5ずつ増える
boon.y += boon.jump_speed #7 boonのy座標が jump_speedずつ 増える
if boon.collide_pixel(ground): #8 もし 地面に触れたら
boon.on = True #9 プロパティonに Trueを設定する
boon.jump_speed = 0 #10 jump_speedを 0に設定する
boon.bottom = ground.top #11 boonの底に 地面の頂点を代入する
def update():
boon_jump() #12 boon_jump()関数を 実行する
おおっ!着地したぞ

次に スペースキーを押したら
プロパティjump_speedを -15 に設定するよ
これで、boonは ジャンプしちゃうんだ
def on_key_down(key): #1 キーを押した関数を 定義する
if key == keys.SPACE: #2 もし スペースキーだったら
if boon.on and game == "play": #3 もしプロパティonが true かつ 変数gameが playなら
boon.jump_speed = -15 #4 プロパティjump_speedに -15を代入する
boon.on = False #5 プロパティonに Falseを設定する
sounds.jump_01_high.play() #6 効果音を 入れる- play( )メソッドとは
-

32. sounds.jump_01_high.play( )
これで、効果音が出ます。
もし、効果音の名前に大文字があった場合、エラーが出るので 小文字に直しましょう

ジャンプだ!

次に、左右キーを押したら boonが左右に動くよう
boon_move( ) 関数を 定義するよ
プロパティright と left を使って
左右の端で止まるようにしました。

def boon_move(): #1 boon_move()関数を 定義する
if game == "play": #2 もし 変数gameが playだったら
if keyboard.right: #3 もし 右キーが押されたら
if boon.right < WIDTH: #4 もし boonの右端が WIDTH(x:800)より 小さければ
boon.x += 5 #5 boonのx座標を 5pxずつ増やす
boon.flip_x = False #6 boonの向きを 右向きにする
elif keyboard.left: #7 もし 左キーが押されたら
if boon.left > 0: #8 もし boonの左端が 0以上だったら
boon.x -= 5 #9 boonのx座標を 5pxずつ減らす
boon.flip_x = True #10 boonの向きを 左向きにするdef update():
boon_jump()
boon_move() #11 boon_move()関数を 実行する- プロパティ:flip_x とは


左右の端で 止まったね。
これで、boonの動きは O.K!
障害物が 出てくる

空のblocksを 作りましょう
そして、cleate_block( )関数を 定義します。
1.確率40%で 画像stepを 出現
2.障害物を 生成
3.プロパティ speed(動く速さ):6
4.リストblocksの中に 追加する
5.cleate_block関数を
0.7から2.0秒のランダムな時間後にもう一度実行する


障害物を生成する座標(場所)を
障害物のmidbottom に指定しました。
midbottom = (WIDTH :画面の右端
ground.top:地面の上)

blocks = [] #1 リストblocks 空リストにする
def create_block(): #2 create_block( )関数を 実行する
if game == "play": #3 もし 変数gameが playなら
block = Actor("block", midbottom = (WIDTH, ground.top)) #4 blockオブジェクトを 生成する
block.speed = 6 #5 プロパティspeedを 6に設定する
blocks.append(block) #6 リストblocksに blockオブジェクトを追加する
clock.schedule(create_block, random.uniform(0.7, 2.0)) #7 0.7~2.0のランダムな時間後に create_block関数を 実行する
create_block() #8 create_block( )関数を 実行する
def draw():
screen.fill("honeydew")
ground.draw()
boon.draw()
for block in blocks: #9 リストblocksから blockオブジェクトを取り出す
block.draw() #10 blockオブジェクトを 表示する- append( )メソッドとは
-

52. blocks.append(block)
リストblocksに 生成されたblockを 追加していきます。
- uniform( )メソッドとは
-

53. random.uniform(0.7, 2.0)
0.7~2.0の間から ランダムに選んだ小数が 返ってきます
ここでは、障害物が でてくる時間に なります
- schedule( )メソッドとは
-

53. clock.schedule(cleate_block, random.uniform(0.7, 2.0))
0.7~2.0秒から ランダムに選んだ秒数後 cleate_block関数が 実行されます。
つまり、1回cleate_block関数を実行しただけで、
cleate_block関数はどんどん実行され続け、無限ループに入ります。

あれっ⁉ 障害物が 1個しか出てこないよ

ははは…!
前の障害物の上に重なって表示されるからね
block_move()関数を 定義して 動かすと 現れてくるよ
1.左へ 動かす
2.左端で 削除する
create_block()
def block_move(): #1 block_move()関数を 定義する
if game == "play": #2 もし 変数gameが playなら
for block in blocks: #3 リストblocksから ブロックを取り出す
block.x -= block.speed #4 ブロックのx座標を プロパティspeedずつ 減らす
if block.x < 0: #5 もし ブロックのx座標が 0より小さくなったら
blocks.remove(block) #6 リストblocksから ブロックを削除するdef update():
boon_jump()
boon_move()
block_move() #7 block_move()関数を 実行する
おおっ!出てきたぞ

障害物を ブロックとステップにします。

boonが、これらに触れるとゲームオーバーになりますが
ステップの茶色部分では、大ジャンプできるんだ

このジャンプで 風船にタッチが できるんだね

そうです。
random
()関数を使って 確率40%の割合で
ステップを 出そうと思います。


確率40%. . .?

これを見てください。
確率が40%は、
random
()関数で出た数値が 0.4未満にすればいいんだ

なるほど!
def create_block():
if game == "play":
if random.random() < 0.4: #1 もし ランダムに選んだ数値が 0.4未満なら
block_image = "step" #2 変数block_imageに "step"を代入する
else: #3 その他
block_image = "block" #4 変数block_imageに "block"を代入する
block = Actor(block_image, midbottom = (WIDTH, ground.top)) #5 "block"を 変数block_imageに 変える
これで、両方 出てくるようになったね
ゲーム終了


まずは、ゲームを終了するgame_end( )関数を 定義します・

boon = Actor("boon", (100, 200))
boon.jump_speed = 0
boon.on = False
boon.bg = None #2 プロパティbgに None(無し)を設定するdef game_end(bg, costume, sound): #5 game_end()関数を 定義する
global game #6 グローバル変数 game
game = "end" #7 変数gameに endを代入する
music.stop() #8 BGMを 止める
boon.bg = bg #9 プロパティbgに 引数bgを設定する
boon.image = costume #10 プロパティimageに 引数costumeを設定する
sound.play() #11 変数soundを 再生する
def draw():
screen.fill("honeydew")
if boon.bg: #3 もし プロパティbgに データが入ったら
screen.blit(boon.bg, (0, 0)) #4 プロパティbgのデータを 表示するmusic.play("meta_universe") #1 BGMを 流す- music モジュールとは

93. music.play(“meta_universe”)
BGM提供:DOVA-SYNDROME
https://dova-s.jp/
・ 「Meta Universe 」 by TECHNOTRAIN曲名の大文字は、小文字にしないとエラーが出るよ

これで、game_end( )関数が 定義できました。
bg は、backgroundの 略語だよ

それでは、collide_pixel()メソッドを使って
障害物に 触れたら ゲームオーバーにします

def block_move():
if game == "play":
for block in blocks:
block.x -= block.speed
if block.x < 0:
blocks.remove(block)
if block.collide_pixel(boon): #1 もし ブロックが boonに触れたら
if block.image == "block": #2 もし ブロックのプロパティが blockなら
game_end("bg_over", "boon_over", sounds.kiga_nukeru_01_long) #3 game_end関数を 実行する
break #4 抜ける
あれれ⁉ ステップは通り抜けちゃうね…

はい。boonが、ステップに触れる場合
2通りあります

○ステップに触れ方
1.ジャンプしていない: ゲームオーバー
2.ジャンプして ステップの上: 大ジャンプ
プロパティ:jump_speedの数値で、分けます。
def block_move():
if game == "play":
for block in blocks:
block.x -= block.speed
if block.x < 0:
blocks.remove(block)
if block.collide_pixel(boon):
if block.image == "block":
game_end("bg_over", "boon_over", sounds.kiga_nukeru_01_long)
elif block.image == "step": #1 もし プロパティ:imageが stepなら
if boon.jump_speed <= 0: #2 もし プロパティ:jump_speedが 0以下なら
game_end("bg_over", "boon_over", sounds.kiga_nukeru_01_long) #3 game_end()関数を 実行する
else: #4 その他
boon.jump_speed = 0 #5 プロパティ:jump_speedを 0に設定する
boon.bottom = block.top #6 プロパティbottomを 障害物の topにする
boon.on = True #7 プロパティon を Trueにする
break
あれっ⁉ boonが 空中で止まっているよ

おぉぉぉ……と!
ステップが 通り過ぎたら、boonは地面におちないと!
プロパティ:step を 追加して、
ステップの上にのったら、そのstepオブジェクトを 代入しちゃおう

1,boonに プロパティ: step を追加し、初期値:None(無し)
2,boonが stepの上に乗ったら、プロパティ:step に
blockオブジェクトを 代入します。
boon = Actor("boon", (100, 200))
boon.jump_speed = 0
boon.on = False
boon.bg = None
boon.step = None #1 プロパティ:stepに None(無し)を設定するdef block_move():
if game == "play":
for block in blocks:
block.x -= block.speed
if block.x < 0:
blocks.remove(block)
if block.collide_pixel(boon):
if block.image == "block":
game_end("bg_over", "boon_over", sounds.kiga_nukeru_01_long)
elif block.image == "step":
if boon.jump_speed <= 0:
game_end("bg_over", "boon_over", sounds.kiga_nukeru_01_long)
else:
boon.jump_speed = 0
boon.bottom = block.top
boon.on = True
boon.step = block #2 プロパティstepに blockオブジェクトを 代入する
break3.blockオブジェクトが 通り過ぎたら, 落ちる

boonのx座標が ステップの右端のx座標より 大きくなったら
プロパティon を Falseに 設定すると 落ちます
def boon_jump():
if not boon.on:
boon.jump_speed += 0.5
boon.y += boon.jump_speed
if boon.collide_pixel(ground):
boon.on = True
boon.jump_speed = 0
boon.bottom = ground.top
else: #3 その他(プロパティon が True)
if boon.step and (boon.step.right < boon.x): #4 ステップより右へ行った
boon.on = False #5 プロパティonを Falseに設定する
boon.step = None #6 プロパティstepを None(無し)に設定する
ちゃんと stepから 落ちたね
ゲームクリア


最後にゲームクリアのプログラミングです。
まずは、stepでのジャンプを 高くしましょう
def on_key_down(key):
if key == keys.SPACE:
if boon.on and game == "play":
if boon.step: #1 もし プロパティstepに blockオブジェクトが入っていたら
boon.jump_speed = -20 #2 プロパティjump_speedに -20を代入する
else: #3 その他
boon.jump_speed = -15
boon.on = False
sounds.jump_01_high.play()
あらら!上に突き抜けちゃった

そして、リストballoonsを作成して、
風船を4個 表示しましょう

balloons = [] #1 リストballoonsを作成 空リスト
for i in range(4): #2 4回繰り返す
x = 100 + 200 * i #3 x座標に 100+200×i を代入する
y = 100 #4 y座標に 100を 代入する
balloon = Actor("balloon", (x, y)) #5 風船オブジェクトを生成する
balloons.append(balloon) #6 リストballoonsに 追加する
def draw():
screen.fill("honeydew")
if boon.bg:
screen.blit(boon.bg, (0, 0))
for balloon in balloons: #7 リストballoonsから 風船を取り出す
balloon.draw() #8 風船を表示する
ground.draw()


風船が きれいに並んだね

remove( )メソッドを使って
boonに触れたら 削除します。


風船をremove( )メソッドで削除する時は、
リストballoonsのコピーを 使うよ
- なぜ リストballoonsの コピーを使うか
-
もし、リストballoons から 風船を取り出すと
30. for balloon in balloons:
33. balloons.remove(balloon)リストballoons から 風船を取り出している最中に 削除すると
風船の取り出し方が変になり、 エラーが起きる場合があります。
ああっ!
風船「2」が 飛ばされてるね
リストballoons を コピーして リストballoons[:]にする
30. for balloon in balloons[;]
33. balloons.remove(balloon)元のリストballoons から風船を削除しても、
コピーしたリストballoons[:]には影響しません。
なるほどね!
リストballoons[ : ] は、
最後の風船を取り出してからコピーするんだね
def boon_jump():
global game #1 グローバル変数 game
if not boon.on:
boon.jump_speed += 0.5
boon.y += boon.jump_speed
if boon.collide_pixel(ground):
boon.on = True
boon.jump_speed = 0
boon.bottom = ground.top
for balloon in balloons[:]: #2 リストballoonsのコピーから 風船を取り出す
if balloon.collide_pixel(boon): #3 boonに触れたら
sounds.heal_04_short_low.play() #4 効果音を 鳴らす
balloons.remove(balloon) #5 風船を 削除する
if len(balloons) == 0: #6 もし リストballoonsにある風船が0に なったら
game_end("bg_clear", "boon_clear", sounds.accent_brilliant_02_low) #7 game_end()関数を 実行する
else:
if boon.step and (boon.step.right < boon.x): 
今回の学習は、これで 終了! おつかれさま
まとめ

今回は、
stepの上から ジャンプするプログラムを作りました。
import pgzrun
from pgzhelper import *
import random
WIDTH = 800
HEIGHT = 600
boon = Actor("boon", (100, 200))
boon.jump_speed = 0
boon.on = False
boon.bg = None
boon.step = None
ground = Actor("ground", midbottom = (400, 600))
game = "play"
def boon_jump():
global game
if not boon.on:
boon.jump_speed += 0.5
boon.y += boon.jump_speed
if boon.collide_pixel(ground):
boon.on = True
boon.jump_speed = 0
boon.bottom = ground.top
for balloon in balloons[:]:
if balloon.collide_pixel(boon):
sounds.heal_04_short_low.play()
balloons.remove(balloon)
if len(balloons) == 0:
game_end("bg_clear", "boon_clear", sounds.accent_brilliant_02_low)
else:
if boon.step and (boon.step.right < boon.x):
boon.on = False
boon.step = None
def on_key_down(key):
if key == keys.SPACE:
if boon.on and game == "play":
if boon.step:
boon.jump_speed = -20
else:
boon.jump_speed = -15
boon.on = False
sounds.jump_01_high.play()
def boon_move():
if game == "play":
if keyboard.right:
if boon.right < WIDTH:
boon.x += 5
boon.flip_x = False
elif keyboard.left:
if boon.left > 0:
boon.x -= 5
boon.flip_x = True
blocks = []
def create_block():
if game == "play":
if random.random() < 0.4:
block_image = "step"
else:
block_image = "block"
block = Actor(block_image, midbottom = (WIDTH, ground.top))
block.speed = 6
blocks.append(block)
clock.schedule(create_block, random.uniform(0.7, 2.0))
create_block()
def block_move():
if game == "play":
for block in blocks:
block.x -= block.speed
if block.x < 0:
blocks.remove(block)
if block.collide_pixel(boon):
if block.image == "block":
game_end("bg_over", "boon_over", sounds.kiga_nukeru_01_long)
elif block.image == "step":
if boon.jump_speed <= 0:
game_end("bg_over", "boon_over", sounds.kiga_nukeru_01_long)
else:
boon.jump_speed = 0
boon.bottom = block.top
boon.on = True
boon.step = block
break
def game_end(bg, costume, sound):
global game
game = "end"
music.stop()
boon.bg = bg
boon.image = costume
sound.play()
balloons = []
for i in range(4):
x = 100 + 200 * i
y = 100
balloon = Actor("balloon", (x, y))
balloons.append(balloon)
def draw():
screen.fill("honeydew")
if boon.bg:
screen.blit(boon.bg, (0, 0))
for balloon in balloons:
balloon.draw()
ground.draw()
boon.draw()
for block in blocks:
block.draw()
def update():
boon_jump()
boon_move()
block_move()
music.play("meta_universe")
pgzrun.go()
プロパティ:jump_speedが +になっていれば、
boonが ステップの上に のったことが わかったね

○ステップに触れ方
1.ジャンプしていない: ゲームオーバー
2.ジャンプして ステップの上: 大ジャンプ
プロパティ:jump_speedの数値で、分けます。

また、プロパティ:stepを作って stepオブジェクトを 入れておくと
stepが 通り過ぎた時、 boonが地面に落ちるよ
3.blockオブジェクトが 通り過ぎたら, 落ちる

boonのx座標が ステップの右端のx座標より 大きくなったら
プロパティon を Falseに 設定すると 落ちます

マリオみたいなゲームも作れるね
それじゃ、またね!






