簡単なゲーム

【Pygame Zero】簡単なゲーム18:ビーム連射!シューティングゲーム

ratch2025

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

ラッチ先生
ラッチ先生
スック
スック

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

今回のプロジェクトは、こちら!

BGM提供: DOVA-SYNDROME
https://dova-s.jp/
「Time Paradox 」 written by 風人

効果音提供:効果音ラボ
https://soundeffect-lab.info/
「スイッチを押す」: アニメ
「ステータス治療1」: 戦闘[1]
「爆発1」:戦闘[2]

ラッチ先生
ラッチ先生

基礎プログラムと 画像を入れた
「簡単なゲーム18: シューティングゲーム!」zipフォルダを
ダウンロードしてください

pythonしよう!簡単なゲーム18:戦闘機と背景画像を表示するを解説
pythonしよう!簡単なゲーム18:シューティングゲームzipの中身
スック
スック

このゲームで使用している音声ファイルは、
以下のサイトからお借りしています。

各自でダウンロードして、該当するフォルダに入れてください!

BGM提供: DOVA-SYNDROME
https://dova-s.jp/
「Time Paradox 」 written by 風人

効果音提供:効果音ラボ
https://soundeffect-lab.info/
「スイッチを押す」: アニメ
「ステータス治療1」: 戦闘[1]
「爆発1」:戦闘[2]

pythonしよう!簡単なゲーム18:シューティングゲームzipの中身
スポンサーリンク

戦闘機を 左右キーで 動かす

敵が 襲来する

結果発表

pythonしよう!簡単なゲーム18:結果発表

プログラムを 実行してみよう




ラッチ先生
ラッチ先生

今回の「シューティングゲーム」では、
・ビームと 敵、戦闘機と敵 が 衝突する
・ 敵が現れる場所や 敵の動く速さを ランダムに決める
プログラムがあります。

そこで、2つのモジュールを 用意しました

pythonしよう!簡単なゲーム15:pgzhelperモジュールの解説
pythonしよう!簡単なゲーム18:randomモジュールの解説
スック
スック

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

ラッチ先生
ラッチ先生

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

pythonしよう!簡単なゲーム17:変数jetの解説
スック
スック

ビームや敵も 同じだよ

そして、属性(データ)やメソッド(命令)は、
『 . (ドット)』を付ければ、使えるよ




ラッチ先生
ラッチ先生

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

スック
スック

updateアップデート()関数の引数dtデルタタイム を使って 敵を削除します




ラッチ先生
ラッチ先生

最初に、
戦闘機を左右に動かす jetジェット_moveムーヴ関数を 定義しましょう

Python
def jet_move(): #1 jet_move関数を定義する
    if jet.active: #2 プロパティactiveが Trueなら
        if keyboard.right: #3 もし 右キーが 押されたら
            jet.x += 5 #4 x座標を 5pxずつ増える

        if keyboard.left: #5 もし 左キーが 押されたら
            jet.x -= 5 #6 x座標を 5pxずつ減らす

        jet.x = max(35, min(WIDTH-35, jet.x)) #7 x座標に 35~765を代入する

def update():
    jet_move() #8 jet_move()関数を 実行する
Q
プロパティ: active とは?
Q
keyboardオブジェクト とは?
pythonしよう!簡単なゲーム18:keyboardオブジェクトの解説
Q
max( ), min()関数 とは?
pythonしよう!簡単なゲーム18:min(), max()関数の解説
スック
スック

クリアやゲームオーバーになったら
プロパティ:activeアクティブFalseフォルス にして 戦闘機の動きを止めるよ

ラッチ先生
ラッチ先生

次は、戦闘機から 出す beamビームを作っていきましょう

Python
beams = [] #1 空リストbeamsを 作成する

def create_beam(): #2 create_beam関数を 定義する
    beam = Actor("beam", (jet.x, jet.y + 50)) #3 ビームを 生成する
    beams.append(beam) #4 リストbeamsに ビームを追加する

clock.schedule_interval(create_beam, 0.2) #5 create_beam関数を 0.2秒ごと実行する

def jet_move(): 
Python
def draw():
    screen.blit(bg_image, (0, 0))
    jet.draw()
    for beam in beams: #6 リストbeamsから beamを取り出す
        beam.draw() #7 beamを 表示する
Q
append( )メソッド とは?
pythonしよう!簡単なゲーム18:append( )メソッドの解説
Q
schedule_interval( )メソッド とは?
pythonしよう!簡単なゲーム18:schedule_interval( )メソッドの解説
スック
スック

beamビームは 戦闘機の上に 表示されるのね!

ラッチ先生
ラッチ先生

beamビームを動かすbeamビーム_moveムーヴ( )関数を定義しましょう

Python
clock.schedule_interval(create_beam, 0.2)

def beam_move(): #1 beam_move()関数を 定義する
    for beam in beams[:]: #2 コピーリストbeamsから beamを取り出す
        beam.y -= 10 #3 beamのy座標を 10pxずつ減らす

        if beam.y < 0: #4 もし beamのy座標が 0未満になったら
            beams.remove(beam) #5 リストbeamsから beamを削除する
Python
def update():
    jet_move()
    beam_move() #6 beam_move()関数を 実行する
Q
remove( )メソッド とは?
pythonしよう!簡単なゲーム18:remove( )メソッドの解説
スック
スック

あれっ? beamsビームズ [ : ] に なってるよ

ラッチ先生
ラッチ先生

beamビームは、上の端へ行ったら 削除します。
リストbeamsビームズ から beamビームを 取り出すと エラーが出る場合があります。
こういう場合は、リストbeamsビームズ のコピーから 取り出しましょう

スック
スック

戦闘機のプログラムは、これで完成だよ




ラッチ先生
ラッチ先生

次は、
敵を 生成するcleateクリエイト_enemyエネミー 関数を 定義しましょう

敵のオブジェクトに プロパティを追加します
speedスピード   : 敵の動く速さ
hitヒット     : ビームの当たり判定 True / False
hitヒット_timerタイマー : ビームに当たってからのタイマー

Python
beams = [] 
enemies = [] #1 空リストenemiesを 作成する

def create_enemy(): #2 create_enemy関数を 定義する
    x = random.randint(35, WIDTH-35) #3 x座標を 35~765からランダムに選んで設定する 
    enemy = Actor("enemy", (x, 0)) #4 敵を 生成する
    enemy.speed = random.randint(3, 10) #5 プロパティspeedを 3~10から選んだ数値を設定する
    enemy.hit = False #6 プロパティhitを Falseに設定する
    enemy.hit_timer = 0 #7 プロパティhit_timerを 0に設定する
    enemies.append(enemy) #8 リストenemiesに enemyを追加する

clock.schedule_interval(create_enemy, 0.5) #9 0.5秒ごとに create_enemy関数を 実行する
Python
def draw():
    screen.blit(bg_image, (0, 0))
    jet.draw()
    for beam in beams: 
        beam.draw()
    for enemy in enemies:  #10 リストenemiesから 敵を取り出す
        enemy.draw()  #11 敵を 表示する
Q
randint( )メソッド とは?
pythonしよう!簡単なゲーム18:randint( )メソッドの解説
Q
append( )メソッド とは?
pythonしよう!簡単なゲーム18:append( )メソッドの解説
Q
schedule_interval( )メソッド とは?
pythonしよう!簡単なゲーム18:schedule_interval( )メソッドの解説
スック
スック

敵が どんどん出現しているね

ラッチ先生
ラッチ先生

enemyエネミー_moveムーヴ関数で
敵を動かすプログラムを 定義しましょう

プロパティspeedスピードに入っている数値が ランダムなので
いろいろな速さで 敵が襲ってくるよ

Python
clock.schedule_interval(create_enemy, 0.5)

def enemy_move(): #1 enemy_move関数を 定義する
    for enemy in enemies[:]: #2 コピーリストenemiesから 敵を取り出す
        enemy.y += enemy.speed # 3 y座標が プロパティspeedごと増える

        if enemy.y > HEIGHT: #4 もし y座標が 800より大きくなったら
            enemies.remove(enemy) #5 リストenemiesから 敵を削除する
Python
def update():
    jet_move()
    beam_move()
    enemy_move() #6 enemy_move関数を 実行する
スック
スック

おおっ!いいねぇ

ラッチ先生
ラッチ先生

ビームに当たったら、プロパティhitヒットTrueトゥルーにして
敵の動きを 止めるよ

Python
def enemy_move(): 
    for enemy in enemies[:]:
        if enemy.hit: #7 もし プロパティhitが Trueなら
            continue #8 下のプログラムを 飛ばす
        enemy.y += enemy.speed

        for beam in beams: #1 リストbeamsから beamを取り出す
            if beam.collide_pixel(enemy): #2 もし 敵に当たっていたら
                enemy.hit = True #3 プロパティhitを Trueに設定する
                sounds.スイッチを押す.play() #4 効果音を 鳴らす
                enemy.image = "enemy_over" #5 画像を "enemy_over"
                break #6 抜ける

        if enemy.y > HEIGHT: 
            enemies.remove(enemy) 

効果音提供:効果音ラボ
https://soundeffect-lab.info/
「スイッチを押す」: アニメ

Q
continue とは?
pythonしよう!簡単なゲーム18:continueの解説
Q
collide_pixel( )メソッド とは?
pythonしよう!簡単なゲーム18:collide_pixel( )メソッドの解説
Q
効果音について
pythonしよう!簡単なゲーム18:soundsオブジェクトの解説
スック
スック

効果音ラボサイトからの音源は、MP3形式です。
しかし、pygame zeroプログラムでは、MP3形式は使えません。

WAV形式に 変換して フォルダsoundsに 入れてください

スック
スック

プロパティhitヒットTrueトゥルー になったら 止まったね

ラッチ先生
ラッチ先生

updateアップデート()関数の引数 dt(デルタタイム)を使って
ビームに当たり 0.2秒 経ったら消えるようにします。

Python
def enemy_move(dt):  #3 enemy_move関数を 定義する
    for enemy in enemies[:]:
        if enemy.hit:
            enemy.hit_timer += dt #4 プロパティhit_timerを dtずつ増やす
            if enemy.hit_timer >= 0.2: #5 もし プロパティhit_timerが 0.2秒以上になったら
                enemies.remove(enemy) #6 リストenemiesから 敵を削除する
            continue 
Python
def update(dt): #1 引数dtで デルタタイムを受け取る
    jet_move()
    beam_move()
    enemy_move(dt)  #2 引数dtに 渡す 

効果音提供:効果音ラボ
https://soundeffect-lab.info/
「スイッチを押す」: アニメ

Q
remove( )メソッド とは?
pythonしよう!簡単なゲーム18:remove( )メソッドの解説
スック
スック

0.2秒だと短くて、プロパティhitヒット_timerタイマーの動きが わからないので
2秒以上になったら 削除したよ

pythonしよう!簡単なゲーム18:結果発表
ラッチ先生
ラッチ先生

setセット_resultリザルト( )関数で 結果発表を定義しましょう

pythonしよう!簡単なゲーム18:set_result()関数の解説
Python
bg_image = "bg"
result = None #1 変数resultを宣言 初期値:None(無し)

beams = [] 
enemies = []

def set_result(result_val,
               image,
               sound,
               keep_enemies): #3 set_result関数を 定義する
    global result, bg_image #4 グローバル変数result, bg_image

    music.stop() #5 BGMを 止める
    jet.active = False #6 戦闘機:プロパティactiveに Falseを設定する
    clock.unschedule(create_beam) #7 create_beam関数を 止める
    clock.unschedule(create_enemy) #8 create_enemy関数を 止める
    result = result_val #9 変数resultに 引数imageを 代入する
    bg_image = image #10 変数bg_imageに 引数imageを 代入する
    sound.play() #11 効果音を 鳴らす
    enemies[:] = keep_enemies #12 リストコピーenemiesに 引数keep_enemiesを 代入する
    
Python
music.play("time_paradox") #2 BGMを 流す

pgzrun.go()
Q
musicモジュールとは?
pythonしよう!簡単なゲーム18:musicモジュールの解説
Q
unschedule() メソッドとは?
pythonしよう!簡単なゲーム18:unschedule()メソッドの解説
スック
スック

クリアとゲームオーバーの共通項目です。
・ BGMを 止める
・ 戦闘機の動きを 止める
cleateクリエイト_enemyエネミー関数を 止める
cleateクリエイト_beamビーム関数を 止める 

ラッチ先生
ラッチ先生

最初に、
敵が 戦闘機に当たったら ゲームオーバーのプログラムを作りましょう

Python
def enemy_move(dt):
    if result:  #1 もし 変数resultに 値(over または clear)が入れば
        return  #2 返す ★つまり、ここから下のプログラムは やりません!
    
    for enemy in enemies[:]:
        if enemy.hit:
            enemy.hit_timer += dt 
            if enemy.hit_timer >= 0.2: 
                enemies.remove(enemy) 
            continue 

        enemy.y += enemy.speed

        if enemy.collide_pixel(jet): #3 もし 戦闘機に 当たったら
            jet.image = "jet_over" #4 戦闘機の画像を jet_overに設定する
            set_result("over", 
                       "bg_over", 
                       sounds.爆発1,
                       [enemy]) #5 set_result関数を 実行する
            return #6 返す 
        
        for beam in beams: 

BGM提供: DOVA-SYNDROME
https://dova-s.jp/
「Time Paradox 」 written by 風人

効果音提供:効果音ラボ
https://soundeffect-lab.info/
「スイッチを押す」: アニメ
「爆発1」:戦闘[2]

スック
スック

おおっ!すべてが止まったね

ラッチ先生
ラッチ先生

敵を 20機爆破したら ゲームクリアにします。

変数hitヒット を作って、そこに敵を爆破した数値を入れましょう

Python
bg_image = "bg"
result = None
hit = 0 #1 変数hitを宣言 初期値: 0
Python
def enemy_move(dt):
    global hit #2 グローバル変数hit
    if result:  
        return  
    
    for enemy in enemies[:]:
        if enemy.hit:
            enemy.hit_timer += dt 
Python
        for beam in beams: 
            if beam.collide_pixel(enemy): 
                enemy.hit = True 
                sounds.スイッチを押す.play() 
                enemy.image = "enemy_over"
                hit += 1 #3 変数hitを 1ずつ増やす
                if hit >= 20: #4 もし 変数hitが 20以上なら
                    set_result("clear",
                               "bg_clear",
                               sounds.ステータス治療1,
                               []) #5 set_result関数を 実行する
                    return #6 返す
                 
                break 

        if enemy.y > HEIGHT: 
Python
def draw():
    screen.blit(bg_image, (0, 0))
    screen.draw.text(f"HIT: {hit}",
                     (30, 20), 
                     fontsize=70, 
                     color="orange") #7 表示する
    jet.draw()

BGM提供: DOVA-SYNDROME
https://dova-s.jp/
「Time Paradox 」 written by 風人

効果音提供:効果音ラボ
https://soundeffect-lab.info/
「スイッチを押す」: アニメ
「ステータス治療1」: 戦闘[1]
「爆発1」:戦闘[2]

Q
screen.drawモジュールとは?
pythonしよう!簡単なゲーム18:screen.drawモジュールの解説
Q
f 文字列とは?
pythonしよう!簡単なゲーム18:f 文字列の解説
スック
スック

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




ラッチ先生
ラッチ先生

今回は、
シューティングゲームを作りました。

シューティングゲーム!
Python
import pgzrun
import random
from pgzhelper import *

WIDTH = 800
HEIGHT = 600

jet = Actor("jet", (400, 500))
jet.active = True

bg_image = "bg"
result = None 
hit = 0 

beams = [] 
enemies = [] 

def set_result(result_val,
               image,
               sound,
               keep_enemies): 
    global result, bg_image 

    music.stop() 
    jet.active = False 
    clock.unschedule(create_beam) 
    clock.unschedule(create_enemy) 
    result = result_val 
    bg_image = image 
    sound.play() 
    enemies[:] = keep_enemies 

def create_enemy(): 
    x = random.randint(35, WIDTH-35) 
    enemy = Actor("enemy", (x, 0))
    enemy.speed = random.randint(3, 10) 
    enemy.hit = False 
    enemy.hit_timer = 0 
    enemies.append(enemy) 

clock.schedule_interval(create_enemy, 0.5) 

def enemy_move(dt): 
    global hit 
    if result: 
        return 
    
    for enemy in enemies[:]: 
        if enemy.hit: 
            enemy.hit_timer += dt 
            if enemy.hit_timer > 0.2: 
                enemies.remove(enemy) 
            continue 
        
        enemy.y += enemy.speed 

        if enemy.collide_pixel(jet): 
            jet.image = "jet_over" 
            set_result("over",
                       "bg_over",
                       sounds.爆発1,
                       [enemy]) 
            return 

        for beam in beams: 
            if beam.collide_pixel(enemy): 
                enemy.hit = True 
                sounds.スイッチを押す.play() 
                enemy.image = "enemy_over" 
                hit += 1 
                if hit >= 20: 
                    set_result("clear",
                               "bg_clear",
                               sounds.ステータス治療1,
                               []) 
                    return 
                
                break 

        if enemy.y > HEIGHT: 
            enemies.remove(enemy) 

def create_beam(): 
    beam = Actor("beam", (jet.x, jet.y-50)) 
    beams.append(beam) 

clock.schedule_interval(create_beam, 0.2) 

def beam_move(): 
    for beam in beams[:]: 
        beam.y -= 10 

        if beam.y < 0: 
            beams.remove(beam) 
            
def jet_move(): 
    if jet.active: 
        if keyboard.right: 
            jet.x += 5 

        elif keyboard.left: 
            jet.x -= 5 

        jet.x = max(35, min(jet.x, WIDTH-35)) 

def update(dt): 
    jet_move() 
    beam_move() 
    enemy_move(dt) 

def draw():
    screen.blit(bg_image, (0, 0))
    screen.draw.text(f"HIT: {hit}",
                     (30, 20),
                     fontsize=70,
                     color="orange") 
    jet.draw()
    for beam in beams: 
        beam.draw()
    for enemy in enemies: 
        enemy.draw() 

music.play("time_paradox") 

pgzrun.go()
ラッチ先生
ラッチ先生

たくさんいる敵に、それぞれタイマーをつける時は、
dt (デルタタイム)を 使いましょう

updateアップデート関数の引数dtデルタタイム から簡単に読み込むことができます

スック
スック

みなさんも、 シューティングゲームを作ってみよう!

それじゃあ、またね!

スポンサーリンク
ABOUT ME
ラッチ先生
ラッチ先生
こんにちは!
「Pythonしよう!楽しく学べるプログラミング教室」の学長、ラッチです。

scratchのように楽しく学べるPython講座です。
・図やアニメーションを使って、わかりやすく楽しく学べる!
・毎回の授業が新しい発見の連続!
・プログラミングの考え方が身につき、自分のやりたいことが形にできるように。

この3点をモットーにサイトを立ち上げました。 よろしくお願いします
記事URLをコピーしました