パワーポイントでゲームを自作する:キャラクターを洗ってあげよう

パワポお風呂ゲーム ゲーム

ここでご紹介するのは、別記事に書いた自作パワポゲームの一部です。ゲーム全体について知りたい方は、以下の記事をお読みください。

このゲームでは、泥だらけになったクマのボビー君をシャンプーで洗って、シャワーで流してあげます。全身の汚れが落ちたら、湯船に入ることができます。

ゲームを作った経緯や、「ボビーって誰??」という点に関しては、上記の関連記事に書いてありますので、ここではパワーポイントのスライド構成やアニメーション設定、マクロの記述について詳しくご紹介します。

スライド構成:OnSlideShowPageChangeを使わずに初期化をおこなう方法

このゲームは、3枚のスライドから成り立っています。ほとんどアニメーションが設定されていない「扉」となるスライドが1枚、シャンプーをつけたりシャワーを流したりするスライドが1枚、そしてボビーが湯船に入るスライドが1枚、という構成です。

パワポお風呂ゲーム - スライド構成

オブジェクトの配置がほぼ同じなのにスライドを分けているのは、ひとつのスライドですべてのアニメーションを設定すると、重なり合って編集しにくいというのももちろんありますが、この一連のゲームをおこなう際に必ず「扉スライド」を通るようにしておくことで、初期化を確実におこなえるメリットがあるためです。

このゲームの中では、ボビーの体の上の「汚れ」やシャンプーの「泡」を、スライド外の見えないところに隠したり、スライド内に戻したりして、「汚れを洗って落とす」という動きを実現しています。これは汚れをクリックした時に呼び出すマクロの中でおこなうわけですが、もう一度プレイする時、つまり別のスライドに行って戻ってきた時には、すべてが最初の位置に戻っていてくれないと困ります。つまり初期化です。通常、あるスライドが表示された時に必ず何かの操作がおこなわれるようにするためには、VBA内にあらかじめ用意されている、
 OnSlideShowPageChange
という関数を使う必要があります。ただしこの関数、調べた限りでは挙動が安定しません。ppsm形式のファイルでは実行されないとか、Active-X コントロールなるものを最初のスライドに配置する必要があるとかで、ここに書いておけば絶対大丈夫というものではなさそうです。そこで、既存の(よくわからない)関数を使わずに初期化をおこなう方法として、「扉スライド」が有効です。

上記の3枚のスライドのうち、最初のスライドでできるのは、シャンプーボトルかシャワーボタンのクリックだけです。クリックするとスライド②へジャンプし、そこではじめてオブジェクトの移動が起きます。つまり初期化しなければならないのは、スライド②のオブジェクト位置だけです。スライド②に行くためには、必ずスライド①でシャンプーボトルかシャワーボタンをクリックしなければならないので、そのとき呼び出されるマクロの中で初期化をおこなえば確実ということになります(前提として、クリックによる画面切り替えはオフにしておくものとします)。

このように、初期化が必要なスライドの手前に扉スライドをおいて、初期化なしでは中に入れないようにする構造を、私は個人的に「引き出し構造」と呼んでいます。ゲーム作成に限らず、インタラクティブなスライド作成で初期化にお困りの方には、有用な手段かと思います。

アニメーションの設定

ここではスライド②で設定している、シャンプーやシャワーのアニメーションについて説明します。このスライドは、以下のオブジェクトで成り立っています。

パワポお風呂ゲーム - アニメーションを設定するオブジェクト

(A)はボビーの体の上の「汚れ」で、これにはアニメーションが設定されていません。次章で詳述するマクロの中で、ボビーの体の上からスライドの外へ移動させているだけです。アニメーションが設定されているのは、赤枠で囲った4種類の図形です。

 (B)汚れにつけるシャンプーの泡
 (C)シャワー
 (D)シャンプーボトルのノズル
 (E)シャンプーボトルから出てくる泡

これらは、プレイヤーがシャンプーボトルを押したり、シャワーボタンを押したり、汚れをクリックしたりする操作に合わせて動くはずですが、私のつくったアニメーションでは、以下のようにすべての動きが固定順序で並んでいます。

アニメーションのタイムライン
  • step 0
    (B)の強調効果(拡大/縮小とシーソー)

    ⇒汚れにつけるシャンプーの泡がモコモコする

  • step 1
    (D)の直線軌跡
    (E)の直線軌跡と強調効果(拡大)

    ⇒シャンプーボトルがプッシュされ、泡が出てくる

  • step 2
    (E)の終了効果(クリア)

    ⇒シャンプーボトルから出てきた泡が消える

  • step 3
    (C)の開始効果(ワイプ)
    (C)の直線軌跡 ※繰り返し設定
    (B)の終了効果(図形)

    ⇒シャワーが流れ、汚れにつける泡が消える

  • step 4
    (C)の終了効果(ワイプ)

    ⇒シャワーが止まる

これは、私の使用しているOfficeのバージョンが古くて、すべての動きをVBAで言うMain Sequenceに記述するしかなかったためです。アニメーションのトリガー条件として「特定の図形をクリック」が選べるバージョンであれば、ゲームの設計方法も全く異なってくるでしょう。ここでは、上記のように単一時間軸上に設定されたアニメーションを使って、いかにインタラクティブな動作を実現するか見ていきます。

マクロの記述

このゲームを作成する上で、VBAのエディタに書き込んだ関数は、以下の5つです。

関数名実装するオブジェクト
Clean_Bath
Start_Bathスライド①のシャンプーボトルとシャワーボタン
Click_Dirtスライド②の汚れ
Click_Shampoo     スライド②のシャンプーボトル
Click_Showerスライド②のシャワーボタン

これらをエディタに書き込んでコンパイルした後、スライド編集画面で該当オブジェクトを右クリックして、「オブジェクトの動作設定」→「マクロの実行」から実装します。

必要な変数の定義と初期化

各種変数を定義する部分と、初期化関数Clean_Bathは、以下のようなものです。これはスライド内の特定のオブジェクトに実装するわけではなく、後述のStart_Bathの中で使います。

Dim dirt(7) As String
Dim shampoo(7) As String
Dim l_dirt(7) As Double
Dim l_shampoo(7) As Double
Dim flagShampoo As Long
Dim flagShower As Long
Dim flagWashed(7) As Long

Sub Clean_Bath()

    ''''''''''''''''''''''''''''''''''''''''''
    dirt(1) = "Freeform 21"
    dirt(2) = "Picture 4"
    dirt(3) = "Freeform 12"
    dirt(4) = "Freeform 15"
    dirt(5) = "Freeform 20"
    dirt(6) = "Freeform 9"
    dirt(7) = "Picture 10"

    shampoo(1) = "Cloud 16"
    shampoo(2) = "Cloud 23"
    shampoo(3) = "Cloud 24"
    shampoo(4) = "Cloud 25"
    shampoo(5) = "Cloud 26"
    shampoo(6) = "Cloud 27"
    shampoo(7) = "Cloud 28"
    
    l_dirt(1) = 137.0286
    l_dirt(2) = 112.7176
    l_dirt(3) = 95.44701
    l_dirt(4) = 234.9642
    l_dirt(5) = 231.0002
    l_dirt(6) = 197.0654
    l_dirt(7) = 177.6951

    l_shampoo(1) = 112.8189
    l_shampoo(2) = 95.52756
    l_shampoo(3) = 88.10472
    l_shampoo(4) = 214.8637
    l_shampoo(5) = 224.1769
    l_shampoo(6) = 184.0544
    l_shampoo(7) = 170.9399
    ''''''''''''''''''''''''''''''''''''''''''
    flagShampoo = 0
    flagShower = 0
    
    Dim i As Integer
    For i = 1 To 7
        flagWashed(i) = 0
        SlideShowWindows(1).View.Slide.Shapes(dirt(i)).Left = l_dirt(i)
        SlideShowWindows(1).View.Slide.Shapes(shampoo(i)).Left = -100
    Next i
    
End Sub

dirt(7)とshampoo(7)というのは、ボビーの体の上の「汚れ」や、その上につける「シャンプーの泡」として用意する7つの図形の名前を入れる文字列配列です。この名前はパワポが自動的に割り振るもので、事前に把握して関数の中に書き込む必要があります。スライドの編集画面では各図形の名前がダイレクトに出てきませんが、「アニメーションウィンドウ」を表示させると、アニメーションを設定した図形の名前が日本語で表示されますので、日本語と英語の対応が分かっていれば、そこから知ることができます。「雲」であれば「Cloud」、「図」であれば「Picture」といった具合です。

l_dirt(7)とl_shampoo(7)というのは、汚れや泡がボビーの体についた状態での位置情報です。これらの図形はゲーム中に必要に応じてスライドの外に移動させるので、スライド内に戻すときに元通り表示されるように、正しい位置を記録しておかなくてはなりません。ここに入れる値は、後述の関数Click_Dirtの中の最初の一行をコメントアウトして実行すれば、メッセージボックスの中に表示されます。dirt(7)とshampoo(7)に入れる図形名も、ここで確認することができます。

ここまで定数の入力が終わったら、プログラム行番号44から初期化に入ります。まず3種類のフラグを初期化しますが、それぞれのフラグの意味は以下の通りです。

flagShampoo シャンプーボトルが押されて泡が出てきている状態かどうか
flagShower シャワーが流れているか止まっているか
flagWashed(7)     各汚れがシャワーで洗い流されたかどうか

次に、オブジェクトの位置を初期化します。「汚れ」は先ほど入力した初期位置 l_dirtに置き、それぞれの汚れにつける「シャンプーの泡」は、最初スライドの外に隠しておくので初期位置-100としてセットします。

扉スライドから中に入る関数

次の関数Start_Bathは、スライド①のシャワーボタンとシャンプーボトルに実装します。このスライドは単なる「扉」なので、ここでは洗いをおこないません。この関数でスライド②に移動してから様々な動きがスタートします。

Sub Start_Bath(shp As Shape)

    ''''''''''''''''''''''''''''''''''''''''''
    Dim iSlideBath As Long
    iSlideBath = 15
    
    Dim s(2) As String
    s(1) = "Picture 26"   'shampoo
    s(2) = "Picture 25"   'shower
    ''''''''''''''''''''''''''''''''''''''''''
    
    With SlideShowWindows(1).View
    
        Dim i As Integer
        i = 0
        If shp.name = s(1) Then i = 1
        If shp.name = s(2) Then i = 2
        If i = 0 Then Exit Sub
        
        .GotoSlide iSlideBath + 1
        Clean_Bath
        If i = 1 Then Click_Shampoo
        If i = 2 Then Click_Shower
    
    End With

End Sub

最初に定義しているiSlideBathというのは、このお風呂ゲームにおけるスライド①が、パワーポイント全体の中で何枚目のスライドに当たるかを入れる変数です。私の場合は、もともとクマのボビーの一日を追ったゲームの一部として作ったので、この値が15となっています。

次のs(2)という文字列配列には、シャンプーボトルとシャワーボタンとしてスライド①に配置している図形の名前を入れています。クリックした図形がどちらだったかによって、その後の処理を場合分けするためです。私は1つの関数で済ませたかったのでこのようにしていますが、Start_ShampooとStart_Showerという2つの関数に分ければ、図形名を定義したりIf文で判定したりする必要はなくなり、プログラム行番号21〜24だけが残ります。すなわち「1つ後ろのスライドに移動し」、「初期化をおこない」、「シャンプーボトル(またはシャワーボタン)をクリックする」。

シャンプーボトルをクリックした時に呼び出す関数

次に、スライド②でシャンプーボトルをクリックした時に呼び出す関数を見てみます。

Sub Click_Shampoo()

    With SlideShowWindows(1).View
    
        'hide faded shampoo
        Dim i As Integer
        For i = 1 To 7
            If flagWashed(i) = 1 Then .Slide.Shapes(shampoo(i)).Left = -100
        Next i
            
        .GotoClick 0
        .Next
        If flagShower = 1 Then flagShower = 0
        flagShampoo = 1
    End With

End Sub

シャンプーボトルをクリックした時に画面上で起こる動きは、「シャンプーボトルから泡が出てくる」アニメーションの動きだけです。しかしこの関数の中では、アニメーションを再生する前にまず「シャワーを浴びることで消えたはずの泡」をスライドの外に移動させています。

泡はもともとスライドの外に隠されていますが、汚れがクリックされるとその上に乗っかる形でスライド内に位置移動します。そこにシャワーを流すと、アニメーションの効果で泡がフェイドアウトするわけですが、泡は見えなくなっただけでスライド内にとどまっています。ということは、残りの汚れに泡をつけるためにアニメーションを巻き戻したら、洗い流されたはずの泡が現れてしまいます。そこでプログラム行番号5〜9で、「それまでに洗い流されたはずの泡」つまり「flagWashedが立っている泡」の位置を-100に変更して、スライドの外に戻します。そのうえで、アニメーションを巻き戻してスライドの外で泡をモコモコさせ(行番号:11)、シャンプーボトルのノズルから新しい泡を出現させ(行番号:12)、汚れがクリックされたらそこに現れるようにセットしておきます。

ちなみにプレイヤーがシャワーを流しっぱなしの状態でシャンプーボトルを押すと、シャワーは自動的に止まります。というのは、アニメーションはすべて直列で記述されていて、「シャンプーが泡立つ→シャワーが流れる→シャンプーが消える」という順番なので、シャンプーが泡立つところまでアニメーションを巻き戻すと、シャワーが消えてしまうからです。行番号13はそういう場合を想定して、「シャワーが止まった」という状態をflagShowerに反映させる操作です。

汚れをクリックした時に呼び出す関数

スライド②でボビーの体の上の汚れをクリックした時に呼び出す関数は、以下のようなものです。

Sub Click_Dirt(shp As Shape)

    'MsgBox shp.name & "  " & shp.Left

    If flagShampoo = 0 Then Exit Sub
    
    With SlideShowWindows(1).View
        
        Dim iDirt As Long
        iDirt = 0
        Dim i As Integer
        For i = 1 To 7
            If shp.name = dirt(i) Then
                iDirt = i
                Exit For
            End If
        Next i
        If iDirt = 0 Then Exit Sub

        .Slide.Shapes(shampoo(iDirt)).Left = l_shampoo(iDirt)
        .Slide.Shapes(dirt(iDirt)).Left = -100
        flagShampoo = 0

    End With

End Sub

プログラム行番号3のコメントは、この関数を実装した図形の名前と位置を知りたい場合に使うものです。コメントアウトして実行すれば、メッセージボックスに表示されます。

この関数は一言で言うと、シャンプーボトルから出てきた泡をボビーの体の汚れにつける(実際にはシャンプーボトル下の泡を消して、汚れの上に別の泡を表示させる)ものです。なので、事前にシャンプーボトルが押されていなかった場合は何も起こらないようにします(行番号:5)。

そのうえで、クリックした図形の名前がdirt(1)〜dirt(7)のどれと一致するかをチェックし(行番号:9〜17)、もしどれとも一致しなかった場合はマクロを終了します(行番号:18)。どれかと一致した場合は、その汚れの上に泡を出現させ(行番号:20)、泡の下の汚れはスライドの外に移動させます(行番号:21)。あとでシャワーを流したときに、汚れがとれたように見せるためです。

シャワーボタンをクリックした時に呼び出す関数

スライド②でシャワーボタンをクリックした時に呼び出す関数は、以下のようなものです。

Sub Click_Shower()

    With SlideShowWindows(1).View
    
        If flagShower = 0 Then
            'hide faded shampoo
            Dim i As Integer
                For i = 1 To 7
                    If flagWashed(i) = 1 Then .Slide.Shapes(shampoo(i)).Left = -100
            Next i
            
            'set flag for existing shampoo
            For i = 1 To 7
                If .Slide.Shapes(dirt(i)).Left = -100 Then flagWashed(i) = 1
            Next i
            
            .GotoClick 2
            .Next
            flagShower = 1
            
        Else
            .GotoClick 3
            .Next
            flagShower = 0
            
            Dim flagDone As Long
            flagDone = 1
            For i = 1 To 7
                flagDone = flagDone * flagWashed(i)
            Next i
            If flagDone = 1 Then .Next
        End If
        
    End With

End Sub

まず「シャワー開始」のクリックか「シャワー停止」のクリックかを、flagShowerで見分けます。フラグが0、つまりシャワーが流れていない時に押されたのならシャワー開始。フラグが1、つまりシャワーが流れている時に押されたのならシャワー停止です。

まずシャワー開始だった場合は、先ほどClick_Shampooの中で出てきた「洗い流されたはずの泡をスライドの外に隠す」操作をここでもおこないます(プログラム行番号:6〜10)。これは、プレイヤーが汚れに泡をつけてシャワーで流した後に、シャンプーボトルではなくてシャワーボタンを押したときのための措置です。次に、汚れの図形がスライド外に移動済みかどうかを判断して、flagWashedのフラグを立てます(行番号:12〜15)。最後に、シャワーが流れて泡がフェイドアウトするアニメーションを実行し、flagShowerを立てます(行番号:17〜19)。

シャワー停止のクリックだった場合は、シャワーが消えるアニメーションを実行し、flagShowerを0にします(行番号:22〜24)。その後の記述は、「すべての汚れが洗い流されたかどうか」、つまり「flagWashed(1)〜(7)がすべて1であるかどうか」の判定です。もしYesであったら、ボビーが湯船につかる次のスライドへ移動します。

これで「シャンプーボトルをクリックする」「シャワーボタンをクリックする」「汚れをクリックする」という操作がどの順番で起きても、不自然なくボビーのバスタイムが進行するゲームが完成します。興味がわいた方は、よければ上のマクロをコピーして使ってください。各人が書き直す必要があるのは、以下の値のみです。

iSlideBath最初のスライド番号
s(1)~(2)シャンプーボトルとシャワーボタンの図形名
dirt(1)~(7)汚れの図形名
shampoo(1)~(7)泡の図形名
l_dirt(1)~(7)汚れの位置
l_shampoo(1)~(7)   泡の位置

簡単?難しい?2種類の対象年齢

このゲームは、それほどゲーム性が高くありません。「勝ち/負け」や「成功/失敗」に結果が分かれるわけでもなく、ただひたすらボビー君を洗ってあげるだけです。でも小さい子どもやお世話好きの女の子は、意外とこういうのが好きですね。好きなキャラクターのイラストでも貼ってあげたら、とても喜ぶでしょう。うちの2歳の娘も、生真面目にひとつひとつの汚れをクリックしては洗い流し、全部できると「ママもやってごらん」と席をゆずってくれます。ありがとう、ママうまくできるかなあ、やってみるね・・

プログラムそのものは、結構頭を使います。プレイヤーがどれをどの順番でクリックしても大丈夫なように、あらゆるパターンを考えて書かないと、つけていないはずのシャンプーが急に各所でモコモコ泡立ち始めたりと、変なことになります。しかし高度なプログラミングの知識を要するわけではなく、使う構文はせいぜいFor文くらいなので、プログラミングの練習問題に最適。あなたはボビー君の汚れに任意の順番でシャンプーをつけて洗い流し、湯船に入れるようにしてあげられますか?うまくできるかなあ、やってみてね・・

タイトルとURLをコピーしました