【Pygame Zero】簡単なゲーム15:3個のボールを10秒かわせ!
こんにちは!
「Pythonしよう!楽しく学べるプログラミング教室」の
ラッチ先生です


スックです。よろしくね!
BGM提供: DOVA-SYNDROME
https://dova-s.jp/
・ 「金魚草」 written by えすにっく・かわひろ
効果音提供:魔王魂
https://maou.audio/
・ 「maou_se_magical06」 : 魔法 マジカル06
・ 「maou_se_onepoint17」: ワンポイント17
・ 「maou_se_system23」 : システム音 システム23
・ 「maou_se_system25」 : システム音 システム25

基礎プログラムと 画像を入れた
「簡単なゲーム15: 10秒間 よけろ!」zipフォルダを
ダウンロードしてください


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


このゲームで使用している音声ファイルは、
以下のサイトからお借りしています。
各自でダウンロードして、該当するフォルダに入れてください!
BGM提供: DOVA-SYNDROME
https://dova-s.jp/
・ 「金魚草」 written by えすにっく・かわひろ
効果音提供:魔王魂
https://maou.audio/
・ 「maou_se_magical06」 : 魔法 マジカル06
・ 「maou_se_onepoint17」: ワンポイント17
・ 「maou_se_system23」 : システム音 システム23
・ 「maou_se_system25」 : システム音 システム25

学習の流れ
車を 左右キーで 動かす
ボールが 動く
ゲームの結果

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

今回の「10秒間 よけろ!」では、
・車が 動かす
・ボールの向きを ランダムに決める
プログラムがあります。
そこで、2つのモジュールを 用意しました



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

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


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

今回は、
スクリーンに タイマーを表示します・

0.1秒ずつ減っていくタイマーを作るよ
車を 左右キーで動かす

最初に
スペースキーを押したら 車を動くプログラムを作りましょう
プロパティactiveを追加して、
True/False で 車が動かすスイッチにします

car = Actor("car", (400, 300))
car.angle = 90
car.active = False #1 プロパティactiveに Falseを設定する
def on_key_down(key): #2 キーが 押されたプログラムを 定義する
if key == keys.SPACE: #3 もし スペースキーが 押されたら
car.active = True #4プロパティactiveに Trueを設定する
スペースキーを押したら True になったね

つぎに、def car_move()関数で、車の動きを定義しよう。
keyboardオブジェクトを使って
左右キーを使って 車を動かすよ

def car_move(): #1 car_move()関数を 定義する
if car.active: #2 もし プロパティactiveが Trueなら
if keyboard.right: #3 もし 右キーが 押されたら
car.angle -= 3 #4 車の向きを 3° 減らす
if keyboard.left: #5 もし 左キーが 押されたら
car.angle += 3 #6 車の向きを 3° 増やす
car.move_forward(5) #7 5pxずつ動かす
def update():
car_move() #8 car_move()関数を 実行する- move_forward( )メソッドとは?


あれれっ! 車が どっかへ行っちゃったよ

それでは、上下左右の端に当たったら 跳ね返るようにしよう
バウンディングボックスを使って プログラムを作ります。

跳ね返りの角度の出し方です。

def car_move():
if car.active:
if keyboard.right:
car.angle -= 3
if keyboard.left:
car.angle += 3
car.move_forward(5)
if car.left < 0 or car.right > WIDTH: #1 左右の壁に当たったら
car.left = max(car.left, 0) #2 左は、 左と0の大きい方を設定する
car.right = min(car.right, WIDTH) #3 右は 右と800の小さい方を設定する
sounds.maou_se_system25.play() #4 効果音を 鳴らす
car.angle = 180 - car.angle #5 向きに 跳ね返った角度を設定する 効果音提供:魔王魂
https://maou.audio/
・ 「maou_se_system25」 : システム音 システム25
- min( )関数、max( )関数とは?

- soundsオブジェクト


今度は、上下の跳ね返りです。
def car_move():
if car.active:
if keyboard.right:
car.angle -= 3 if car.top < 0 or car.bottom > HEIGHT: #1 上下の壁に当たったら
car.top = max(car.top, 0) #2 上は、上と0の大きい方を設定する
car.bottom = min(car.bottom, HEIGHT) #3 下は 下と600の小さい方を設定する
sounds.maou_se_system25.play() #4 効果音を 鳴らす
car.angle = -car.angle #5 向きに 跳ね返る角度を設定する
これで、車を動かすプログラムは完成!
3個のボールが 動く

今度は、cleate_ball()関数で
ボールを生成するプログラムを定義します。

balls = [] #1 空リストballsを 作成する
def create_ball(): #2 create_ball()関数を 定義する
ball = Actor("ball", (400, 500)) #3 ボールを生成する
ball.angle = random.randint(30, 60) #4 向きを 30~60からランダムに選んだ数値を 設定する
balls.append(ball) #5 リストballsへ追加する
ball.num = len(balls) #6 プロパティnumに リストballsに入っている要素数を設定する
if ball.num < 3: #7 もし プロパティnumが 3未満なら
clock.schedule(create_ball, 3.0) #-8 3秒後に create_ball()関数を 実行する
def update():
car_move()
def draw():
screen.fill("white")
for ball in balls: #9 リストballsから ボールを取り出す
ball.draw() #10 ボールを表示する
car.draw()- len()関数とは?

- schedule()メソッドとは?


num は、number の略語です

まだ、ボールは生成しません。
スペースキーを 押したら、cleate_ball()関数を 実行させて
ボールを 生成させましょう
def on_key_down(key):
if key == keys.SPACE:
car.active = True
create_ball() #5-⑪ ボールを生成する
新しいボールは、 前のボールの上に表示されるんだね

ball_move( )関数で
ボールが動くプログラムを作りましょう
def ball_move(): #1 ball_move()関数を 定義する
for ball in balls: #2 リストballsから ボールを取り出す
ball.move_forward(10) #3 ボールを10px動かす
def update():
car_move()
ball_move() #4 ball_move()関数を 実行する
おおっ!ボールが出てきたね。

ボールも 上下左右の壁に当たったら 跳ね返るようにするよ
def ball_move():
for ball in balls:
ball.move_forward(10)
if ball.x < 25 or ball.x > WIDTH-25: #7-1 左右の壁
ball.x = max(25, min(ball.x, WIDTH-25)) #7-2 xの範囲
ball.angle = 180 - ball.angle #7-3 跳ね返り
elif ball.y < 25 or ball.y > HEIGHT-25: #7-4 上下の壁
ball.y = max(25, min(ball.y, HEIGHT-25)) #7-5 yの範囲
ball.angle = -ball.angle #7-⑥ 跳ね返る- 跳ね返りの角度


ボールの動きも 完成したよ
ゲームの結果


まず、BGMと背景画像が表示する準備をしましょう
car = Actor("car", (400, 300))
car.angle = 90
car.active = False
car.bg = None #1 プロパティbgに None(無し)を設定する
def on_key_down(key):
if key == keys.SPACE:
car.active = True
create_ball()
music.play("金魚草") #2 BGMを入れるdef draw():
if car.bg: #3 プロパティbgに 画像が入れば
screen.blit(car.bg, (0, 0)) #4 背景画像を 表示する
else: #5 その他
screen.fill("white")
for ball in balls: - musicモジュールとは?

- blit( )メソッドとは?

- プロパティbgとは?


つぎは、
ゲームオーバーとクリアのプログラムをまとめた
game_end()関数を 定義します

def game_end(bg, sound, costume): #1 game_end()関数を 定義する
music.stop() #2 BGMを止める
car.active = False #3 プロパティactiveを Falseに設定する
car.bg = bg #4 プロパティbgに 引数bgを代入する
sound.play() #5 引数soundを 再生する
car.image = costume #6 プロパティimageを 引数costumeに 設定する
このゲームは、
10秒間ミス2回で逃げ切れば クリアです。
プレイヤーに 残り時間を表示するためタイマーを作りましょう
time = 10 #1 変数timeを 宣言 初期値:10
def on_key_down(key):
if key == keys.SPACE:
car.active = True
create_ball()
music.play("金魚草")
clock.schedule_interval(timer, 0.1) #5 0.1秒ごと timer関数を実行するdef timer(): #2 timer()関数を 定義する
global time #3 グローバル変数 time
time -= 0.1 #4 変数timeを 0.1ずつ減らす
def update():def draw():
if car.bg:
screen.blit(car.bg, (0, 0))
else:
screen.fill("white")
screen.draw.text(f"TIME : {time}",
topleft=(10, 10),
fontsize=70,
color="blue") #6 タイマー表示する
for ball in balls: BGM提供: DOVA-SYNDROME
https://dova-s.jp/
・「金魚草」 written by えすにっく・かわひろ
- schedule_interval( )メソッドとは?

- text( )メソッドとは?

- f文字列とは?


あれれ…⁉ なに、この数字!

おぉぉぉ……と!
round(time, 1) 関数を 忘れてた!!
time -= 0.1 で 「-0.1」ずつ 減るようにプログラムを書きました。
しかし、コンピューターの世界では、数は2進法で表すので
「0.1」は、
『0.0001100110011001100110011…」(無限小数)になります。

ああ! 画面に出ている数値は、
変数time から 『0.0001100110011001100110011…』が
引かれている数なんだ

そう!
そこで、round( )関数を使って、
小数点第1位までの数値にして タイムを見やすくしました。

def timer():
global time
time -= 0.1
time = round(time, 1) #変数timeの数値を 小数点第1位までにして 代入する
round( )関数は、めっちゃ便利!

変数time が 0以下になったら ゲームクリアにしよう
def ball_move():
if car.bg: #4 もし プロパティbgに 画像が入ったら
return #5 何も返さない (*ここで この関数を終了する)
for ball in balls: def timer():
global time
time -= 0.1
time = round(time, 1)
if time <= 0.0: #1 もし 変数timeが 0.0以下になったら
clock.unschedule(timer) #2 timer関数を 止める
game_end("bg_clear", sounds.maou_se_onepoint17, "car3") #3 game_end()関数を 実行する
boon が、運転してたのね

次は、ゲームオーバーのプログラムです。
まず、
ボールにプロパティ:hit を追加して、
車に触れている間を True にします。

def create_ball():
ball = Actor("ball", (400, 500))
ball.angle = random.randint(30, 60)
balls.append(ball)
ball.num = len(balls)
ball.hit = False #1 プロパティhitを Falseに設定するdef ball_move():
if car.bg:
return
for ball in balls:
ball.move_forward(10)
if ball.x < 25 or ball.x > WIDTH-25:
ball.x = max(25, min(ball.x, WIDTH-25)) ball.angle = -ball.angle
if ball.collide_pixel(car): #2 ボールが 車に触れたら
ball.hit = True #3 プロパティhitを Trueに設定する
else: #4 その他(車に触れてない)
ball.hit = False #5 プロパティhitを Falseに設定する
def game_end(bg, sound, costume): 
スピードを落として、プロパティhit が Trueの状態を 見やすくしました

ボールに触れている時は、車の色を変えて動きを止めます。
車に触れた最初
if not ball.hit:

車から離れた最初
if ball.hit:

def ball_move():
if car.bg:
return
for ball in balls:
ball.move_forward(3) if ball.collide_pixel(car):
if not ball.hit: #1 もし プロパティhitが Falseなら
car.image = "car1" #2 車の画像を "car1"に 設定する
car.active = False #3 プロパティactiveを Falseに設定する
sounds.maou_se_system23.play() #4 効果音を 入れる
ball.hit = True
else:
if ball.hit: #5 もし プロパティhitが Trueなら
car.image = "car" #6 車の画像を "car"に設定する
car.active= True #7 プロパティactiveを Trueに設定する
ball.hit = False
def game_end(bg, sound, costume): 効果音提供:魔王魂
https://maou.audio/
・ 「maou_se_system23」 : システム音 システム23

車の色で ボールが触れたかどうか わかるね

プロパティcount を追加して、
ボールに触れたら カウントします。
3回触れたら ゲームオーバーにします

car.active = False
car.bg = None
car.count = 0 #1プロパティcountに 0を設定する
time = 10
def ball_move():
if car.bg:
return
for ball in balls:
ball.move_forward(10) if ball.collide_pixel(car):
if not ball.hit:
car.image = "car1"
car.active = False
sounds.maou_se_system23.play()
car.count += 1 #2 プロパティcountが 1増える
if car.count >= 3: #3 もし プロパティcount が 3以上なら
clock.unschedule(timer) #4 timer関数を止める
clock.unschedule(create_ball) #5 create_ball関数を 止める
game_end("bg_over", sounds.maou_se_magical06, "car2") #6 game_end()関数を 実行する
ball.hit = True 
最後に、ボールに触れたら背景の色を変えましょう。
リストcolors に 色を入れます

time = 10
colors = ["honeydew", "springgreen", "yellow"] #1 リストcolorsに "honeydew", "springgreen", "yellow"を 設定するdef draw():
if car.bg:
screen.blit(car.bg, (0, 0))
else:
screen.fill(colors[car.count]) #2 リストcolorsのcount番目の色を 表示する
今回の学習は、これで 終了! おつかれさま
まとめ

今回は、
タイマーを使った ボールから逃げるゲームのプログラムを作りました。
import pgzrun
from pgzhelper import *
import random
WIDTH = 800
HEIGHT = 600
car = Actor("car", (400, 300))
car.angle = 90
car.active = False
car.bg = None
car.hit = 0
time = 10
colors = ["honeydew", "springgreen", "yellow"]
def on_key_down(key):
if key == keys.SPACE:
car.active = True
create_ball()
music.play("金魚草")
clock.schedule_interval(timer, 0.1)
def car_move():
if car.active:
if keyboard.right:
car.angle -= 3
if keyboard.left:
car.angle += 3
car.move_forward(5)
if car.left < 0 or car.right > WIDTH:
car.left = max(car.left, 0)
car.right = min(car.right, WIDTH)
sounds.maou_se_system25.play()
car.angle = 180 - car.angle
if car.top < 0 or car.bottom > HEIGHT:
car.top = max(car.top, 0)
car.bottom = min(car.bottom, HEIGHT)
sounds.maou_se_system25.play()
car.angle = -car.angle
balls = []
def create_ball():
ball = Actor("ball", (400, 500))
ball.angle = random.randint(30, 60)
balls.append(ball)
ball.num = len(balls)
ball.hitting = False
if ball.num < 3:
clock.schedule(create_ball, 3.0)
def ball_move():
if car.bg:
return
for ball in balls:
ball.move_forward(10)
if ball.x < 25 or ball.x > WIDTH-25:
ball.x = max(25, min(ball.x, WIDTH-25))
ball.angle = 180 - ball.angle
elif ball.y < 25 or ball.y > HEIGHT-25:
ball.y = max(25, min(ball.y, HEIGHT-25))
ball.angle = -ball.angle
if ball.collide_pixel(car):
if not ball.hitting:
car.image = "car1"
car.active = False
sounds.maou_se_system23.play()
car.hit += 1
if car.hit >= 3:
clock.unschedule(timer)
clock.unschedule(create_ball)
game_end("bg_over", sounds.maou_se_magical06, "car2")
ball.hitting = True
else:
if ball.hitting:
car.image = "car"
car.active = True
ball.hitting = False
def game_end(bg, sound, costume):
music.stop()
car.active = False
car.bg = bg
sound.play()
car.image = costume
def timer():
global time
time -= 0.1
time = round(time, 1)
if time <= 0.0:
clock.unschedule(timer)
game_end("bg_clear", sounds.maou_se_onepoint17, "car3")
def update():
car_move()
ball_move()
def draw():
if car.bg:
screen.blit(car.bg, (0, 0))
else:
screen.fill(colors[car.hit])
screen.draw.text(f"TIME : {time}",
topleft=(10, 10),
fontsize=70,
color="blue")
for ball in balls:
ball.draw()
car.draw()
pgzrun.go()
タイマーを表示する時
小数の場合は、 round( )関数 を使って小数点以下の桁数を
そろえましょう


みんなも、タイマー付きのゲームをつくってみよう!
それじゃあ、またね!












