【Pygame Zero】簡単なゲーム11:多数キャラクターの中からクリック判定
こんにちは!
「Pythonしよう!楽しく学べるプログラミング教室」の
ラッチ先生です


スックです。よろしくね!
BGM提供:DOVA-SYNDROME
https://dova-s.jp/
・ 「poppop」by Sakuttipanda
効果音提供:Chisato’s Website
https://chisatosound.sakura.ne.jp/index.html
・ 「Accent. Brilliant [02] (Low)」:アクセント
・ 「Kiga Nukeru [01] (Long)」:アニメ

基礎プログラムと 画像を入れた
「簡単なゲーム11: スマイルboonを 探せ!」zipフォルダを
ダウンロードしてください


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


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

学習の流れ
50個の boonを動かす
boonを クリックして 判定する

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

今回の「スマイルboonを 探せ!」では、
・ boonを 動かす
・ クリック判定
・ boonを ランダムな場所で 表示する
・ セリフを 言う
プログラムがあります。
そこで、3つのモジュールを 用意しました




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

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


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

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

リスト:boons を作成して、その中にboonを 追加していくんだ

boon をクリックした時に 使うよ


boonを クリックした時の判定のプログラムを まとめたよ
50個のboonを 動かす

最初に リストboonsを 作成して
50個の boonを 表示させましょう


range( )関数を使って boonを 50個作るよ

HEIGHT = 600
boons = [] #1 リストboons 空のリストを作成
for i in range(50): #2 50回 繰り返す
x = random.randint(50, WIDTH-50) #3 x座標に 50~750からランダムに選んだ数字を 代入する
y = random.randint(50, HEIGHT-50) #4 y座標に 50~550からランダムに選んだ数字を 代入する
boon = Actor("boon_0", (x, y)) #5 boonを 生成する
boon.angle = 45 * i #6 boonの向きを 45 × i に設定する
boons.append(boon) #7 リストboonsに 追加するdef draw():
screen.fill("lavenderblush")
for boon in boons: #8 boonを 取り出す
boon.draw() #9 boonを 表示する

おおっ!boonの向きが バラバラだ
for i in range( )関数 が どのように動いているでしょうか
50個だと、わかりずらいので、boonを10個表示するで見てみましょう
コマ送りにしました。これをパソコンでは一瞬で行って 表示しています

次は、リストboon_imagesに 3つのboon画像を入れて、

3種類の boonを 表示します
boons = []
boon_images = ["boon_0", "boon_1", "boon_2"] #1 リストboon_images
for i in range(50):
idx = i % 3 #2 idx(インデックス): 3で割った余り・・・0, 1, 2
x = random.randint(50, WIDTH-50)
y = random.randint(50, HEIGHT-50)
boon = Actor(boon_images[idx], (x, y)) #3 インデックスのboon画像を生成する
boon.angle = 45 * i
boons.append(boon) 
★boonを 3種類にするポイント★
リストboon_images に 3つのboon画像を 入れました。
10. boon_images = [“boon_0”, “boon_1”, “boon_2”]

この画像をリストから取り出したい時は、
・ 画像 “boon_0″: boon_images[0]
・ 画像 “boon_1″ : boon_images[1]
・ 画像 “boon_2″: boon_images[2]
リストboon_imagesの [0], [ 1 ], [ 2 ] の番号を 利用します
12. for i in range(50):
カウンター変数「 i 」には、0, 1, 2, 3, 4, …, 48, 49 が 入ります。
ここで、便利な 「%」 (剰余算:割り算の余り) !
13. idx = i % 3
i % 3 :つまり、3で割った余りは、「 0 , 1 , 2 」
・ 0 % 3 = 0
・ 1 % 3 = 1
・ 2 % 3 = 2
・ 3 % 3 = 0
・ 4 % 3 = 1
・ 5 % 3 = 2
…
・ 48 % 3 = 0
・ 49 % 3 = 1
これを、変数idx に 代入します
16. boon = Actor(boon_images[idx], (x, y))
Actor( )クラスで、boon_images[idx] とすれば
リストboon_imagesからboonの画像を順番に取り出すことができます。

「 % 」は、便利だね

さあ、50個あるboonから
ひとつ選んでスマイルboonにしましょう
見つかりづらい最初のboonにします。

boons[0].image = "boon_smile" #1 リストboons[0]のプロパティimageを "boon_smile"に 設定する
boons[0].angle = 45 * random.randint(0, 7) #2 スマイルboonの向きを 45 × (0~7からランダムに選んだ数値) にする
なるほど!
boons[0] は、最初にスクリーンに表示されるため
重なりの奥に なって わかりづらくなるね

move_forward()メソッドを使って
それぞれの向きへ動くようにするよ

スマイルboon : boons[0] に
プロパティ on を追加して、動くスイッチにします。

boons[0].image = "boon_smile"
boons[0].angle = 45 * random.randint(0, 7)
boons[0].on = True #1 プロパティonに Trueを 設定する
def update():
if boons[0].on: #2 もし プロパティonが Trueなら
for boon in boons: #3 boonを取り出す
boon.move_forward(1) #4 boonを 動かす
if boon.x < 50 or boon.x > WIDTH-50: #5 もし 左右の壁に 触れたら
boon.angle = 180 - boon.angle #6 跳ね返す
if boon.y < 50 or boon.y > HEIGHT-50: #7 もし 上下の壁に 触れたら
boon.angle = -boon.angle #8 跳ね返す- move_forward( )メソッドとは

- 跳ね返りの 角度は
-


おおっ! スマイルboonは どこだあ?
boonのクリック判定


on_mouse_down( )関数を使って
boonを クリックした時の プログラムを 作ろう

boons[0].on = True
def on_mouse_down(pos): #1 クリックした時の関数を定義する
for boon in boons: #2 リストboonsから boonを取り出す
if boon.collidepoint_pixel(pos): #3 もし boonをクリックしたら
click_boon = boon.image #4 変数click_boonに プロパティimageのデータを 代入する
del boons[1:] #5 リストboonsの1から最後までの要素を削除する
boons[0].on = False #6 プロパティonを Falseに設定する- collidepoint_pixel( )メソッドとは

- del boons[1:] とは
-



クリックしたboonの画像によって終わり方を
game_end()関数として定義します。


背景画像を表示するために
boons[0]オブジェクトに プロパティbg を 追加します。
最初は、背景画像を入れないため None(無し)を設定しましょう
boons[0].image = "boon_smile"
boons[0].angle = 45 * random.randint(0, 7)
boons[0].on = True
boons[0].bg = None #1 プロパティbg に None(無し)を設定するdef draw():
screen.fill("lavenderblush")
if boons[0].bg: #2 もし プロパティbgに 背景画像が入ったら
screen.blit(boons[0].bg, (0, 0)) #3 背景画像を表示する
for boon in boons:
boon.draw()
text_display.draw(screen) #4 テキストディスプレイを 装備する
music.play("poppop") #5 BGMを入れる- text_displayオブジェクトとは

- musicモジュールとは


if boons[0].bg :
ここでの boons[0].bg は、
プロパティbgに背景画像が代入されたら Trueに なります!
def game_end(bg, costume, sounds, word): #1 game_end関数を定義する
music.stop() #2 BGM止める
boons[0].bg = bg #3 プロパティbgに 引数bgを 設定する
boons[0].image = costume #4 プロパティimageに 引数costumeを 設定する
sounds.play() #5 引数soundsを 再生する
boons[0].say(word, color="blue", size=70, y_offset=-70) #6 セリフを言う- sayメソッドとは


最後に boonが クリックされた時に
game_end( )関数を 実行します。
クリックされたときに 変数click_boonに クリックされた画像が
設定されています。
変数click_boonに入っている boonの画像によって
game_end()関数の引数を 変えましょう
def on_mouse_down(pos):
for boon in boons:
if boon.collidepoint_pixel(pos):
click_boon = boon.image
del boons[1:]
boons[0].on = False
if click_boon == "boon_smile": #1 もし 変数click_boonが ”boon_smile"画像なら
game_end("bg_clear", #2 game_end()関数を 実行する
"boon_ok",
sounds.accent_brilliant_02_low,
"O.K!")
else: #3 その他
game_end("bg_gameover",#4 game_end()関数を 実行する
"boon_smile",
sounds.kiga_nukeru_01_long,
"here!") - soundモジュールとは


あれっ⁉
スマイルboonを クリックしてないのに ゲームクリアになってるよ

おぉぉぉ…と、いけない!
リストboonsからboonの取り出す方法を 逆にするのを 忘れてた
なぜ、boonの取り出し方を 逆順にするかを 詳しく解説します。
1.リストboonsが 順番にboonを取り出すと、
スマイルboonが クリックされたことになります。
26. for boon in boons:
27. if boon.collidepoint_pixel(pos)

そうか!スマイルboonが 最初に反応してしまうんだね
そこで、reversed( )メソッドで、
最後からboonを取り出すことによって、スマイルboonに重なっていても
クリックされたboonが 変数click_boonに 設定されるようになります
26. for boon in reversed(boons) :
27. if boon.collidepoint_pixel(pos)
def on_mouse_down(pos):
for boon in reversed(boons): #1 reversed( )にして 逆から取り出す
if boon.collidepoint_pixel(pos):
click_boon = boon.image
del boons[1:]
boons[0].on = False
if click_boon == "boon_smile":
game_end("bg_clear",
"boon_ok",
sounds.accent_brilliant_02_low,
"O.K!")
else:
game_end("bg_gameover",
"boon_smile",
sounds.kiga_nukeru_01_long,
"here!") 
今回の学習は、これで 終了! おつかれさま
まとめ

今回は、
50個のboonを 動かして、その中からスマイルboonを探すプログラムを作りました。
import pgzrun
from pgzhelper import *
import random
from say import text_display
WIDTH = 800
HEIGHT = 600
boons = []
boon_images = ["boon_0", "boon_1", "boon_2"]
for i in range(50):
idx = i % 3
x = random.randint(50, WIDTH-50)
y = random.randint(50, HEIGHT-50)
boon = Actor(boon_images[idx], (x, y))
boon.angle = 45 * i
boons.append(boon)
boons[0].image = "boon_smile"
boons[0].angle = 45 * random.randint(0, 7)
boons[0].on = True
boons[0].bg = None
def on_mouse_down(pos):
for boon in reversed(boons):
if boon.collidepoint_pixel(pos):
click_boon = boon.image
del boons[1:]
boons[0].on = False
if click_boon == "boon_smile":
game_end("bg_clear",
"boon_ok",
sounds.accent_brilliant_02_low,
"O.K!")
else:
game_end("bg_gameover",
"boon_smile",
sounds.kiga_nukeru_01_long,
"here!")
def game_end(bg, costume, sounds, word):
music.stop()
boons[0].bg = bg
boons[0].image = costume
sounds.play()
boons[0].say(word,
color="blue",
size=70,
y_offset=-70)
def update():
if boons[0].on:
for boon in boons:
boon.move_forward(1)
if boon.x < 50 or boon.x > WIDTH-50:
boon.angle = 180 - boon.angle
if boon.y < 50 or boon.y > HEIGHT-50:
boon.angle = -boon.angle
def draw():
screen.fill("lavenderblush")
if boons[0].bg:
screen.blit(boons[0].bg, (0, 0))
for boon in boons:
boon.draw()
text_display.draw(screen)
music.play("poppop")
pgzrun.go()
たくさんのboonからクリック判定するときは、
reversed( )メソッドを使って、リストの最後から取り出しましょう

みんなも reversed()メソッドを使ってみてね
それじゃ、またね!









