【Pygame Zero】ゲームの技01:背景の画像を 変えよう!

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


スックです。よろしくね!

基礎プログラムと 画像を入れた
「見た目08 boon シューティング」zipフォルダを ダウンロードしてください



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

学習の流れ
boonを マウスで動かす
boonが 弾を発射する
弾が 敵に当たると 背景が変わる
敵に襲われると セリフを言う

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

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




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

今回は、
ゲーム中 背景の画面を切り替えるプログラムを 作っていきます。
ポイントが 3つあります。


Actor( ) クラスで作るオブジェクトの座標は、画像の中心。
間違えないようにね!



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


2つに 分けたよ
boonを マウスで動かす

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

game = "play" #1 変数game を宣言 初期値:"play"
mouse.pos = 100, 500 #2 マウスの座標に x座標100、y座標500を代入する
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の向きに マウスの方へ向く角度を 代入する
ポイント
32. 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を自由に動かせるね!
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(60) #6 弾を 60px前に 出す
def update(): #7 更新する
boon_move()
beam_move() #8 弾を 動かす

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

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

beam.visible = False #1 プロパティvisibleに Falseにする
def beam_move():
global game
if game == "play":
if not beam.visible: #2 もし、プロパティvisibleが Falseなら
beam.pos = boon.pos
beam.angle = boon.angle q
beam.move_forward(60)
beam.visible = True #3 プロパティvisibleを Trueにする
else: #4 それ以外(プロパティvisibleが Trueなら)
beam.move_forward(20) #5 弾を 20pxずつ動かす
if beam.x < 0 or beam.x > WIDTH or beam.y < 0 or beam.y > HEIGHT: #6 左右上下の端に 行ったら
beam.visible = False #7 プロパティを Falseにする

beam_move()関数の動きを スローモーションで 表しました。
実際は、下のようになるよ

おお!
ちゃんと、boonの前から発射されてるね
弾が敵に当たると 背景が 変わる

つぎは、背景を変えるプログラムです。
3枚の背景画像を 使います。
変数backgraunds を作って、リストに3枚入れて 代入します
変数bg_index は、背景の番号を 入れます。


プログラミングでは、順番は『0』から 始まるよ

そして、
blit( ) メゾットで、背景画像を 表示させます

backgrounds = ["bg1", "bg2", "bg3"] #1 変数backgrounds に、3枚の背景画像のリストを 代入する
bg_index = 0 #2 変数bg_index に、0 を代入する
def draw():
screen.blit(backgrounds[bg_index], (0, 0)) #3 背景画像を 表示する


おお! いいねぇ

次に
敵を 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_forward(2) #5 敵は 2pxずつ 動く
def update():
boon_move()
beam_move()
enemy_move() #6 敵を 動かす

あらら…⁉ 敵につかまっちゃってるねえ

そして、
while True構文を使って
弾に当たったら、300px以上離れた場所を ランダムに決めます


collide_pixel( ) メゾットを使って
敵が 弾に当たったか 判定するよ

def enemy_move():
global game, bg_index
if game == "play":
enemy.angle = enemy.angle_to(boon)
enemy.move_forward(2)
if enemy.collide_pixel(beam): #1 敵が 弾に当たったら
while True: #2 繰り返す
enemy.x = random.randint(50, WIDTH-50) #3 敵のx座標を 50~750からランダムで選ぶ
enemy.y = random.randint(50, HEIGHT-50) #4 敵のy座標を 50~540からランダムで選ぶ
if enemy.distance_to(boon) > 300: #5 もし、boonまでの距離が 300px以上なら
bg_index = (bg_index+1) % len(backgrounds)
break #6 繰り返しから抜ける

while Trueの繰り返しは、一瞬で行われるよ

変数bg_index + 1 で、次の背景画像にします。
ただし、リストgroundsには、3枚の画像しかないので
66. (bg_index + 1) % len(backgrounds)
・ bg_index: 0 ⇒ (0 + 1) % 3 ⇒ 1
・ bg_index: 1⇒ (1 + 1) % 3 ⇒ 2
・ bg_index: 2⇒ (2 + 1) % 3 ⇒ 0
演算子『%』:割り算の余り を使います

def enemy_move():
global game, bg_index
if game == "play":
enemy.angle = enemy.angle_to(boon)
enemy.move_forward(2)
if enemy.collide_pixel(beam):
while True:
enemy.x = random.randint(50, WIDTH-50)
enemy.y = random.randint(50, HEIGHT-50)
if enemy.distance_to(boon) > 300:
bg_index = (bg_index+1) % len(backgrounds) #1 変数bg_indexに、 次のリスト番号を代入する
break

背景が 変わったね
敵に襲われると セリフを言う


boonが敵に襲われたら、
変数:gameを “over”にして、
say( ) メゾットで、2秒間セリフを言わせて 終了させます
from say import text_display #1 sayモジュールから クラスtext_displayを使えるようにします
def draw():
screen.blit(backgrounds[bg_index], (0, 0))
boon.draw()
enemy.draw()
beam.draw()
text_display.draw(screen) #2 テキスト表示装備を 準備する

これで、
キャラクターにセリフが言える状態になったよ

def enemy_move():
global game, bg_index
if game == "play":
enemy.angle = enemy.angle_to(boon)
enemy.move_forward(2)
if enemy.collide_pixel(beam):
while True:
elif enemy.collide_pixel(boon): #1 もし、敵が boonに触れたら
game = "over" #2 変数gamaに "over"を代入する
boon.image = "ouch_boon" #3 boonの画像を "ouch_boon"に する
boon.say("Ouch!", 2, color="red", size=70, y_offset=-70) #4 boonが 2秒間 "Ouch!"と 言う

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

今回は、
弾に当たると 背景が変わるプログラムを 作りました。
import pgzrun
from pgzhelper import *
import random
from say import text_display
WIDTH = 800
HEIGHT = 590
boon = Actor("boon", (100, 500))
enemy = Actor("enemy", (700, 100))
beam = Actor("beam", (100, 500))
game = "play"
mouse.pos = 100, 500
beam.visible = False
backgrounds = ["bg1", "bg2", "bg3"]
bg_index = 0
def draw():
screen.blit(backgrounds[bg_index], (0, 0))
boon.draw()
enemy.draw()
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 boon_move():
global game
if game == "play":
boon.move_towards(mouse.pos, 3)
def beam_move():
global game
if game == "play":
if not beam.visible:
beam.pos = boon.pos
beam.angle = boon.angle
beam.move_forward(60)
beam.visible = True
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, bg_index
if game == "play":
enemy.angle = enemy.angle_to(boon)
enemy.move_forward(2)
if enemy.collide_pixel(beam):
while True:
enemy.x = random.randint(50, WIDTH-50)
enemy.y = random.randint(50, HEIGHT-50)
if enemy.distance_to(boon) > 300:
bg_index = (bg_index+1) % len(backgrounds)
break
elif enemy.collide_pixel(boon):
game = "over"
boon.image = "ouch_boon"
boon.say("Ouch!", 2, color="red", size=70, y_offset=-70)
def update():
boon_move()
beam_move()
enemy_move()
pgzrun.go()

スクリーンに背景画像を 表示するには、
blit( ) メゾットを 使いましょう


そして、背景を 変える手順は、
1. リスト: backgaroundsの中に 複数の画像を 入れる
2. 変数: bg_indexを作成し、リスト番号を入れる
3. ( bg_index + 1 ) % len (backgrouns) で
次のリスト番号にする

好きな背景画像を 入れてみてね。
それじゃ、またね!