プログラミングに数学を感じるのは(2)

プログラミングはすごく数学に似ています。似ている、というのは、考え方はもちろんのこと、理解の仕方や積み重ねで勉強していくところとか、勉強の仕方も似ている・・というより、私はもろ数学だと思いました。

「学校(小学校から高校)で習う数学は、本当の数学ではない」と私の中学時代の数学の先生は言いました。「大学に行ったらさっぱりチンプンカンプンで、それでも数学という学問の、大海原の一滴を見たに過ぎなかった」と言われましたが、私もそのとおりだと思います。

確かに、高校までの、問題から答えを導き出すような数学は、数学を使ったパズルゲームのようなもので、基礎的な数の扱いに過ぎません。積み木遊びのような。それでも、積み木遊びが幼児にとってはとても大切な良い遊びであるように、数の扱い方や計算、順序だてた物事の考え方など、身について役に立つことはたくさんあります。

プログラミングも目的に向かって一つの解答を導くものです。こういう風に動かすにはどうしたらいいか、という問題があるとしたら、公式をつかって組み立てていきます。組み立てていくときには、順番(論理)というものがすごく重要で、いろんなパーツを順序良く当てはめて解いていくパズルと似ています。そして、一つの解(プログラム)が導かれますが、それは一つではなくて、色々な解き方があるというところも同じです。

いろんな公式が増えていって、それを組み合わせ、前に使ったものを土台にしてどんどんピラミッドのように積み重ねられて複雑な大きな問題も解けるようになる、というところも同じです。

公式を知っただけでは問題は解けなくて、いろんなパターンの問題を実際に解いてみて、使い方もいろんなパターンで身につけて初めて解けるようになるというところも同じです。メソッドを教えてもらってプログラミングしてみても、最初は大抵うまくいかないことがほとんどです。トライ(トライアル)・アンド・エラーの繰り返しです。そして、公式も最初に覚えなくても使ううちに自然に覚えていくように、コードも打ち込んでいくうちに覚えていきます。

その過程には「そういうことだったのか!」という発見もたくさんあって、そして解けたときの喜びは、問題が難しければ難しいほど、大きいものです。

・・というわけで、数学は、プログラミングの為にあるのはもちろんのこと(笑)、詰まる所、数学も、プログラミングも、ゲームだ (から面白い)ということがわかりました😆 

シャッフルを紙とペンでやってみる

前回の、「フィッシャ–イェーツのシャッフルを視覚化してみる」の続きです。

フィッシャー-イェーツのシャッフル

紙とペンで、実際やってみるとよくわかります。一番簡単な、3つの数字、123の並びをシャッフルしてみます。このやり方に従ってすべての場合を出したときに、6通りが均等になっていれば、確率的に正しいことがわかります。

簡単なのですぐできます。

ダステンフェルトの手法(正しいやり方)

これをプログラミング的に書いたダステンフェルトのやり方もやってみましょう。

            (↑この部分、3つとも j=2 ではなくて、j=1 の間違いです。書き間違えてる!!)

ダステンフェルトの手法(間違ったやり方)

前の記事フィッシャ–イェーツのシャッフルを視覚化してみるの中の、赤いやり方の処理と青いやり方の処理をごちゃまぜにした間違ったやり方です。当初、ウィキペディアの説明が間違っているのではないかと思ってやってみたのですが、それは私の勘違いで、そちらの説明は合っていました。前の記事も訂正しておきました。でもこれはこれで間違いの例なので載せておきます。数字でやるなら数字で、順番でやるなら順番で、統一しないといけないということです。

結果、4通りとなってしまいました。

これは、1順目で、2以外の数字が二番目にくる結果が1通りあるので、それに対して2順目で2通りあり、合計1×2通りが狂うからです。

ということで、やはり間違いであることがわかりました。

ところで、このダステンフェルトの手法

要素数が n の配列 a をシャッフルする(添字は0からn-1):
  in - 1 から 1 まで減少させながら、以下を実行する
       j に 0 以上 i 以下のランダムな整数を代入する
       a[j] と a[i]を交換する

は、フィッシャー−イェーツをコンピュータ向けに改良したものとあって、内容がプログラミングの書き方(forループ)そのものです。

だからもし、プログラミングを習っていなかったら、これが何を言おうとしているのか、多分わからなかったと思います。そんなところからも、またすごく面白みを感じたのでした。

【追記】

あれから大学時代の古い記憶がかすかに蘇ってきて、何の科目か何の勉強かも思い出せないのですが、レポートをやるために本を調べていたときに、iとjの出てくる、こんなような説明の意味がさっぱりわからなくて半日以上考えたり調べたりしたけれどわからなくて諦めたことがあって(当時はまだパソコンもなかったし)、もしかするとこれだったのかな・・とふと思いました。上の「ダステンフェルドの手法」の文には、日本語的に致命的な欠陥があると思います。(笑

〜減少させながら、以下を「繰り返し」実行する

と書くのが正確なのではなかろうか٩(๑`^´๑)۶。繰り返し処理というのは普通の数学教育では一般的ではないので、プログラミングをやっている人にはパッと見ですぐわかることでも、やったことのない人には「減少させながら以下を実行する」とだけ書かれても意味不明だと思います。

フィッシャ–イェーツのシャッフルを視覚化してみる

・swap視覚化

・80本の棒のシャッフル

1.フィッシャ–イェーツのシャッフルとは

先日の授業では、シャッフルを教えてもらいました。

その中で、「フィッシャ–イェーツのシャッフル」を簡単にしたものを扱いました。そこで、フィッシャ–イェーツのシャッフルとは実際どういう動きでシャッフルしているのか知りたくて、視覚化した物を作ってみようと思って、その為に調べてみました。

ウィキペディアのフィッシャ–イェーツのシャッフルによると、

  1. 1 から N までの数字を書く。
  2. まだ消されてない数字の数を数え、1 からその数以下までのランダムな数字 k を選ぶ。
  3. 残っている数字から k 番目の数字を消し、別の場所にその数字を書き出す。
  4. すべての数字が消されるまで手順 2, 3 を繰り返す。
  5. 手順3で書かれた数列が元の数値からのランダム順列となるとなる

というものです。

何かを訳したものだと思いますが「消されていない」「消されるまで」となっていてわかりにくいですが、これは「選ばれていない」「選ばれる」と読み換えるとわかりやすいと思います。

例えば1〜5までの数字、12345をシャッフルする場合、

⑴ 1から5までの数字を書く→12345

⑵ まだ選択されていない数字の数を数え→ここではまだ一つも選択されていないので5つ

 1からその数以下までのランダムな数字kを選ぶ→1から5までのランダムな数字例えば3を選んだとする

⑶ 残っている数字(ここでは12345)から3番目の数字を選び(ここでは3)、それを結果として書き出す(シャッフルの結果の5桁の最初の数字が3となる)残った数は1245となる

⑷ ⑵⑶を繰り返す。次は二巡目なので、まだ選択されていないのは4つ、1から4までのランダムな数、また3を選んだとする

残っている数(1245)の3番目の数字(4)を選び、結果に加える。(先の3と合わせて、34となる。残った数は125となる)

これをなくなるまで繰り返す。(3巡目)3個数字が残っているので、1〜3までのランダムな数字、1が選ばれたとして125の1番目の数字、1を結果として加えて、341となり、残ったのは25。

(4巡目)2個数字が残っているので、1〜2までのランダムな数字、2が選ばれたとして、25の2番目の数字、5が選択されて、結果として加えられて3415、残った数字は2の一つ。

(5巡目)最後2という数字がが1個残っていて、ランダムな数字といっても1しかないので、1番目の数2が選択されて、結果に加えられて、最終結果は34152となる、

これがこのシャッフルの仕方です。

2.ダステンフェルドの手法

さらに、現代ではこれをコンピュータでの使用を想定して改良した、ダステンフェルドの手法が採用されているとのことです。これは

要素数が n の配列 a をシャッフルする(添字は0からn-1):
  in - 1 から 1 まで減少させながら、以下を実行する
       j に 0 以上 i 以下のランダムな整数を代入する
       a[j] と a[i]を交換する

というもので、先のフィッシャ–イェーツとの違いは・・これもnを5としてやってみたらわかるでしょう。

a[0]~a[4]までの5つの配列がある。a[0]a[1]a[2]a[3]a[4]

iを4から1まで減少させながら(つまりは4回。5回ではない)、jに0以上i以下(こちらは一巡目は0から5までの5つの数字となる)のランダムな数字を入れて、a[ j ]とa[ i ]を交換する。

・・先のフィッシャ–イェーツはランダムに選んでそれを結果として最後に加えていく方法でしたが、交換という方法を使うことによって後ろから付け加えていくという形で無駄を省いてやっているようなイメージですね。

ダステンフェルドの手法で同じように12345でやってみると・・

(1巡目)i=4、jを0から4までのランダムな数字、例えば3とすれば、a[3]とa[4]を交換して、(4と5)

12354。

(2巡目)i=3、jは0から3までのランダムな数字、例えば1とすれば、a[1]とa[3]を交換して、(2と4)

14352。

(3巡目)i=2、jは0から2までのランダムな数字、例えば0とすれば、a[0]とa[2]を交換して、(1と3)

34152。

(4巡目)i=1、jは0から1までのランダムな数字、例えば1とすれば、a[1]とa[1]を交換して、(2と2)

34152 

となります。

なぜ5つの数字に対して5巡ではなくて4巡なのかというと、仮に5巡目をやったとしても、a[0]とa[0]の交換になると決まっているので、やる意味がないからです。

これを別の言い方で説明すると、

1巡目・・5つの全部の数字のうちどれかをランダムに選んで5と交換する。
(「5」と「1~5のどれか」を交換する)

2巡目・・1巡目で交換した5以外の4つの数字からランダムに一つ選んでそれと4を交換する。
(「4」と「1~4のどれか」を交換する)

3巡目・・1、2巡目で交換した5、4以外の3つ数字からランダムに一つ選んでそれと3を交換する。
(「3」と「1~3のどれか」を交換する)

4巡目・・1、2、3巡目で交換した5、4、3以外の数字2つのうちランダムに一つ選んでそれと2を交換する。(「2」と「1~2のどれか」を交換する)

つまりもっと簡単に書くと、

(1)「5」と「1~5のどれか」を交換する

(2)「4」と「1~4のどれか」を交換する

(3)「3」と「1~3のどれか」を交換する

(4)「2」と「1~2のどれか」を交換する

あるいは、以下の処理でも同じです。

(1)「5番目」と「1~5番目」のどれかを交換する

(2)「4番目」と「1~4番目」のどれかを交換する

(3)「3番目」と「1~3番目」のどれかを交換する

(4)「2番目」と「1~2番目」のどれかを交換する              

やっていることはこれだけです。

青い方のやり方と赤い方のやりかたの違いがわかるでしょうか?例えば青い方の4は、数字の4のことですが(配列のどこにあっても)、赤い方は「そのとき4番目にある数字」であって、数字の4とは限りません。青い方なら青い方でやって、赤い方のやり方と混ぜてはいけません。(ごっちゃにした間違いの例

ダステンフェルドの手法のプログラミングでは、赤い方の処理をやっています。どうしてかというと、forループの繰り返し処理の中でその都度配列の並びが上書きされるからです。紙とペンでやってすべての場合がでるかどうか確かめてみました(メモ)が面白いことにどちらもすべての場合が出ます。ダステン先生はすごいですね。

これをコードで書くと授業でやったものを使って、

//シャッフル
function shuffle() {
    // カードグループの一番最後の添え字
    var last = cardGroup.childNodes.length - 1;

    // 繰り返し処理
    // for(初期化; 繰り返し条件; 後処理){処理}
    for(var i=last; i>0; i--){
    // for(var i=0; i<=last; i++){ 授業ではこのように書きました
        console.log(i);

        // 添え字を使ってカードを呼び出す
        var card1 = cardGroup.childNodes[i];

        // ランダムで添え字を作る
        var r = getRandom(0, i); // ここをlastではなく、iにするのが精度的には正しいそうです
        //var r = getRandom(0, last); 授業ではこのように書きました

        // 添え字を使ってカードを呼び出す
        var card2 = cardGroup.childNodes[r];

        // 交換処理
        swap(card1, card2);
    }
}

となります。

授業で書いたものは、簡単にしたものということで、正確なものとは異なっているようです。

ランダムで添字を作るの部分は、配列の全部、(上のコードの場合(0、last))から取り出すと、厳密にいうとシャッフルの精度が下がる(確率が均等でなくなる)のだそうです。ランダムの範囲は、ずっと配列のどこでも好きなところからとるのではなく、まだ取り変えていない範囲(0、i)に減らしていくというのが、正しいやり方だそうです。うーん難しい。サイトにも間違えて書かれてあるところが多いそうです。

こちらのサイトが参考になりました。

これはこれで、一つの間違いがわかりました。

 

これとはまた別の疑問がでてきてしまいました。上のソースコードの書き方はWikipediaの説明部分の

改良されたアルゴリズム(ダステンフェルドの手法)

要素数が n の配列 a をシャッフルする(添字は0からn-1):
  in - 1 から 1 まで減少させながら、以下を実行する
       j に 0 以上 i 以下のランダムな整数を代入する
       a[j] と a[i]を交換する

のやり方に従ったものです。

でも、Wikipediaには続きがあって、「紙とペンを使用した場合」として実際にやってみる説明が書かれているのですが、これとは違う(間違ってる?)ということに気づいてしまいました。Wikipediaですから、間違いがあるのはあることなのかも知れませんね、どちらが正しいのだろう・・多分、下の「紙とペンを使用した場合」の説明のほうが間違っていると私は思います。どこが違うかというと、下の説明の部分で、赤字にした部分です。これが、下のやり方では8番目の数字、7番目の数字、6番目の数字・・2番目の数字となっているのですが、先の説明のやり方に従うなら、「8番目の数字」ではなくて、「数字の8」(どこの順番にあろうが)、「7番目の数字」ではなくて、「数字の7」と交換しなければならないはずです。

たぶん、そのほうが正しいです。(わかる方いたら教えていただきたいです)正しくないです、下のWikipediaの説明で合ってました。(後述)

間違っている気がするWikipediaの説明部分↓

紙とペンを使用した場合

ここでは同じ例をダステンフェルドの手法で行う。上記の例では数字の消去と書き出しを行ったが、今回は選ばれていない数字の中で最後の数字との入れ替えを行う。前と同様に1から8までの数字をメモしておく。

範囲 乱数 メモ 結果
    1 2 3 4 5 6 7 8  

1から8までの数字の中でランダムな数字を取得する。今回は6だったとする。この場合、6番目と8番目の数字を交換する。

範囲 乱数 メモ 結果
1–8 6 1 2 3 4 5 8 7 6

次は1から7までの数字の中でランダムな数字を取得する。2だった場合、2番目と7番目の数字を交換する。

範囲 乱数 メモ 結果
1–7 2 7 3 4 5 8 2 6

続けて1から6までの数字の中でランダムな数字を取得する。ここで取得した数字が6だった場合、6番目の数字をそのまま結果とする。今回の例で言えば8を結果とする。結果の数列が完成するまで、ここまでの処理を繰り返す。

範囲 乱数 メモ 結果
1–6 6 1 7 3 4 5 8 2 6
1–5 1 5 7 3 4 1 8 2 6
1–4 3 5 7 4 3 1 8 2 6
1–3 3 5 7 4 3 1 8 2 6
1–2 1 7 5 4 3 1 8 2 6

この時点で処理が終了し、「7 5 4 3 1 8 2 6」という順列が得られる。

また調べてみてわかったら書きます。👩🏻‍💻 (→紙とペンでやってみて確かめてみました。やはり間違ってました)やっぱり合ってました^^; すみません〜💦この前の授業(9/8)の後、プログラミングでは上記の赤い方の処理でやっているのだということに気づきました。この説明を、私は青い方のやり方が書いてあると思って間違いと思ってしまったのですが、赤い方のやり方で書いてあったということがわかりました。すごい勉強になりました。

結果、ダステンフェルドの手法を視覚化してつくって以下のようにつくってみました。

3.完成作品

・12345のシャッフル

もっとたくさんで見てみたくて、80本のバーでも作ってみました。

上の段も下の段も同じシャッフルをしています。上は色が混ざっていくことでシャッフルされている様子がわかります。下の段は、移動済みのものが青から赤に色が変わっていきます。

・80本の棒のシャッフル

プログラミングに数学を感じるのは(1)

プログラミングでゲームづくりをしてみてよく思うことは、数学と近いということです。

まず、数学をよく使います。でもこれはプログラミングだけではないでしょう。何か物づくりをしようと思ったら、図形や曲線、動きの距離や速さや加速度など、数字が必要になってきます。

数学はどちらかというと、教科の中では嫌われ者のイメージです。積み重ねの学問なので、ひとたびわからなくなるとその先からはもうついていけなくなって、一旦苦手になると嫌いにならざるを得ないですし、難しいと言えば難しいのかも知れない。

だから、よく言われるのが、「数学なんて将来役に立つのかよ。三平方の定理、三角関数、そんなもの社会に出てから使うか?」という将来の自分に数学不要説。

こういう言われ方をするのは、数学が顕著だと思います。「それ将来必要?使う?」あまり他の教科では耳にしません。

だけど、考えてみたら、体育や部活の、野球にしたってサッカーにしたって、実際に将来それを使うなんてプロの競技者くらいなものです(体力強化や娯楽でという意味は別として)。でもそれを無意味だと言う人はいない。やっていて楽しいからです。

だけど数学は楽しくない。嫌い。だから「こんなものやって何になる!」と言いたくなる。(気持ちは分かる)

けれど、いつか新聞記事で、社会に出てから役にたった教科は何かというアンケートで「数学」が一番になっていました。意外でしたがやっぱり、と思いました。世の中のもので数が関係ないものはないからです。

ゲームをつくるにも数学はたくさん出てくるわけで、そこで、「数学はゲームのために必要なんだよ!」といつか先生が言われた言葉ですが、私は溜飲の下がる思いが致しました。

「そうなんだよ!みんな数学が嫌いでそんなもの要らないって言うけど、みんなの大好きなゲームは、数学がなかったら作れないんだよ!ゲームが楽しいのも数学のおかげだ!もう要らないなんて言わせない!」

(元々は数学は物理のためにあるというのが正しいです。数学は物理学の計算部門が独立したものだからです)

AIマンドラゴラ

AIに挑戦せよという授業の中で作ったものです。

前の、45.ブッタ様大噴火47.おならして帰る を応用してシューティングゲームにして、ダメージによって敵の画像・攻撃・動きが変わるようにしました。

マンドラゴラのつもりで描いた敵が、にんじんに見えてしまうのは、頭の葉っぱが短すぎたからでしょう。

(授業での発表のとき、デモ用に当たり判定を外してゲームオーバーにならないようにしておきました。発表が終わったので元に戻したら、先生が「ああ、これマンドラゴラか〜」と言われて再度プレイされて、一瞬でやられてゲームオーバーになってしまい可笑しかったです)

工夫やこだわり

・ボスのビームは関数 function bossbeam(w, h, b)を作って、変化させた

・クリアのときの大爆発

ソースコード

おならして帰る

タイトルですが、これは、テキストの中に課題として 

//プレイヤーの位置まで迫って、(おならして)帰って左右移動

とあったので、そのとおりに作ったものです。

娘にやってもらったら、「なにこれーやだー最低ー!」と引いていました。。。

【ポイント】

・ifの条件分岐は、上から判定していくので、順番を考える

・modeパラメーターを設定して、条件を満たしたときに一度だけ発動するようにする

・tl.clearとtl.unloopの違いを理解して使い分ける

 (1)タイムラインを止める(別の動きにするために今のtlの動きを即時止める)
 boss.tl.clear();
 (2)タイムラインのループのオン
 boss.tl.loop();
 (3)タイムラインのループオフ(tlのloopを止める)
 boss.tl.unloop();
ソースコード

『PCNこどもプロコン2017冬』で佳作をいただきました

いつもこちらに素敵なコメントを寄せてくださるりょうくんのお母さんからお勧めをいただいて、『PCNこどもプロコン2017冬』コンテストに応募したところ、ソフトウェア部門中学生の部で佳作をいただきました。

自分一人で作ったものしか出したくないと言って出した3作品の中の、2作品(文房軍シューティングAIマンドラゴラを倒せ)でいただきました。

一次審査の結果の「佳作」ということで、最終審査に進むエントリー作品には残ることができませんでしたが、それでもCODE FRIENDSの授業で作ったものそのままだったので(本当はブラッシュアップして応募したかったのですが、この時期いろいろあってできませんでした💦)、佳作にも入れるとは思っていなかったので、大変嬉しくすごく自信になったようです。

授業の中で作ったまんまなので、まるまる教えてくださった先生のおかげということでもあります。

皆様ありがとうございました〜-人-

いただいた講評のカード(クリックで拡大)

息子の大発見?

息子がゲームつくりをしていて面白いことを発見して、ブログに書いてくれというので書きます。

息子から、「ちょっとお母さん助けてよ!」とHelpがありました。

何?とPCを覗き込むと、htmlファイルをブラウザで開いて(すると先生の作られたCodeFriendsのロゴが出るわけですが)、それをクリックして実行しようとすると、びっくり、印刷の画面が出るのです。しかも、キャンセルを押しても消えない!ここで、これを消したくばこちらへ電話・・と出れば詐欺サイトですが、そうではなく、ひたすら消えない!

・・なにそれ・・こんな症状見たことないよ・・「また◯◯◯の有害電磁波か?」(息子がPCを触るとよくエラーがでるので、私はそう読んでいます。元々は私の父からです。父のPCはいつもおかしくなり、いつも私に聞いてくるので、勝手に「じいちゃんの有害電磁波」と呼称しています。実はおかしな操作(気づかないうちにどこかをクリックしたり)しているのですが。)

どこを書き換えたの?何か触った?と聞くと、変なことはしていない、と言います。

(そんなのわかんないよ・・)と思いながら息子に書き換えたところを見せてもらいました。

息子はプログラミング教室の先生が作ってくださったenchant.jsを基にしたフレームワークをつかってゲームを作っていますが、「指定した内容を表示する」というメソッドで、

for (var i = 0; i < arrayOfStrings.length; i++) {
    print(arrayOfStrings[i] + " / ");
}

と書いたそうです。自分でどこかで調べてきて、見よう見まね書いたのです。

「ここにprintってあるじゃん、だから印刷、プリントの画面が出るんじゃないの?」私は冗談半分で言いました。

息子も「そんなことあるわけない」と半分呆れて、真に受けませんでした。

でも・・しばらくして半信半疑でこの一行を無効にしたら、その印刷の画面は消えて正常に戻ったのです。息子はびっくりして笑っていました。

よくわからないことを書くから・・。でも自分なりに調べてやろうとしたのだから、よし!

たとえこのゲームが完成しなくても、これらの経験が無駄になることは決してないでしょう。(でも完成させて欲しいな。なんでそんな難しいことやろうとするんだろう・・とヤキモキしたりしながらも見守っている親です。)

 

配列と比例を使った放射弾のつくり方

・・改めて、発表のときの動画を見返してみましたが、先生がうろたえてみえるので、それは驚いていらっしゃったからだそうですが(まさかあのようなものが出てくるとは思ってなかったでしょうね)、でもそのときはどうしてうろたえているのか私もわかりませんでしたので私は私で「あちゃー外したかな?」と思ってどぎまぎしています。それ以前に、人前で自分の作品を披露して反応を確かめたのも生まれて初めてです。見ながらいろいろ笑ってしまいました。

「しめじ先生の大冒険」の中で、実は一番気に入っているのは、おたすけボタンをクリックしたときに、おざき先生から一斉に発射される矢が、みんなのところへ放射されるところです。

これは、プレゼンのときに通常モードではなかなかクリアまでいけない場合に、ショートカットしてクリア画面を見ていただくためにつくりました。

これは、先生のキャラがどの位置にいても、矢が放射状に一人ひとりをめがけて向かっているように角度を変えて飛んでいくところがきれいで我ながらうまくできたなーと思っています。

当然、最初は垂直の矢が、みんなに向かって垂直の角度で飛んでいくわけです。それではおかしい感じなので、角度をつけることにしました。

その際に、本当なら、三角関数を使ってその都度計算するのが正確なのでしょうが、ここではそういう難しいことはせずに、擬似的に、距離と角度についての比だけで、つくってみました。思いの外うまくいって一発でできたので、自分でも驚いたので記録しておきたいと思います。

例えば、しめじ先生が左端Aの位置にあるとします。すると、左下のゾンビに向かう矢の角度は、垂直方向に対して0°です。そして、しめじ先生が右端Bの位置に移動したとすると、Aの位置の矢の角度に比べて、右回転方向にa°回転すればいいわけです。

そこで、角度の計算ソフトを使うか、目分量でもいいので、角度の最大値(一番端に来た時の角度)であるa°を決めます。この場合40°くらいです。ですので、しめじ先生が「Aの位置(ゾンビから最も近い位置)からBの位置(ゾンビから最も離れた位置)に動いたとき、矢の角度が0°(最小値)からa°(最大値)に変化する」というように比例させればいいと考えました。

上の例はゾンビが端ですが実際は13体それぞれ違った位置にあるので、それぞれについてこの考え方を適用すると、一つひとつのゾンビとしめじ先生について「x座標の距離」に比例させればいいということになります。(x座標が同じなら角度0°、最大離れた時が角度40°となるよう比例させればよい

お助けモード発動

配列は、授業ではやっていないと思いますが、たぬきが飛びながらコインをとる横スクロールのゲームのときに、先生がサンプルを掲示板に貼ってくださったものを参考にしています。

配列と当たり判定

この中で、矢を放つ部分は以下です。

ゾンビは上の段と下の段の二列に別れているので、そのように書きました。上下に数値をずらして一つでまとめて書こうと思えば書けると思いますが、面倒だったので分けました。

この中で以下のように矢の傾きを計算しています。

// 矢の角度を変えるための計算
//var k = 52 / 225 * (teache.x - zombies[ya].x) 
//arrow.rotate(k);

kが、矢の回転角度です。それぞれのゾンビの位置に対応させてこの角度に傾けたいということです。角度の最小値と最大値(ゾンビとしめじ先生が最も離れたときの矢の角度)が-52°と52°、しめじ先生とゾンビのx座標の距離の差の最小値が-225、最大値が225なので、分母を225にすれば、しめじ先生とゾンビが同じx座標にあるときteache.x – zombies[ya].x=0、最も負の方向に離れたときは=-225となり、矢の角度は-52°(最も負の方向に傾く)から、同じx座標のときは0°(垂直)になって、また正の方向に離れれば離れるほど52°に近づいて矢が傾きます。

距離の変化(-225〜225の変化)に対応して、-52°〜52°の範囲で自動的に変化させることができます。

(解説)しめじ先生の大冒険

ゲームはこちら

念願かなって、授業にて作品を発表することができました。(一度やってみたかったので・・・もう思い残すことはありません(笑)

しかし、ちょっと想像以上にサプライズに成功してしまって驚かせてしまったようですが、引かれてしらけてしまったらどうしようかとそれだけが心配でしたので、盛り上がっていただけてよかったです。(「ぼくのトイレットペーパー!!」と叫んでくれたのには嬉しかったですね。)

喜んでいただいたので、技術的なことはもうどうでもよくなって(実際純粋にプレイする側としては問題は面白いかどうかであってどうやって作ったかとかはどうでもいいわけで)、盛り上がってプレイしていただいたのをただ嬉しく見つめていました。

時間もオーバーしていましたし、感想のカードをくれたのは一人だけだったのですが(それでも十分嬉しいです)、面倒ぐさがりの息子が「お母さんにも感想!」と言って急いで感想を直接紙に書いてくれました。「記念的な作品を上手くゲームにしていてすごいと思います」。ちょっと日本語がおかしいですが、上手くゲームにできて記念的な作品になりましたということが言いたかったのでしょう、息子にも何か伝わったんだと思って嬉しく思いました。

ここで工夫したところや難しかったところを記録しておきます。

難しかったところ

・吹き出しのセリフのところ

吹き出しやセリフの大きさがそれぞれ違うので、出る場所に合わせてさらに左右の画面からはみ出さないように出すのに調整が大変でした。

・音と動きのタイミング

動きに合わせて音を選ぶのとタイミングを合わせるのに苦労しました。

・ドット絵

難しくはないですが、一番時間がかかるのがこのドット絵です。満足がいかないと思えば際限がない。デザイナーさんってすごいなー。

工夫したところ

・連射できてしまうと端にいてピュンピュン撃てばいいだけになって簡単すぎるのでできないようにしました。

・バグに捕まって穴に落ちるところは、スクロールをつかってみました。今井先生がつくってくださった、上下左右の設定が便利でした(・・・が最初何度やってもうまくいかず、まさか先生の設定が間違っていると思わず2日間悪戦苦闘したのでした。私の2日間の苦労を返して・・!(笑))

・虫の動き・・最初はまっすぐに向かってくる動きにしたのですが、それだとなぜか異様に気持ち悪かったので、ジグザグに動くようにしました。

・揃ったらクリアというところはストレージを使いました。

・クリアの胴上げをイメージしたところは、box2dをつかってジャンプさせています。簡単にリアルな動きをつくることができました。

【モバイルでバグが出るのを修正】

授業での発表の後に何気なくipadのほうでも開いてみたところ、途中で止まってしまうことに気づきました。もしかしてモバイルでは正常に動かない?・・どうやらそのようでした。

通常モードではバグに捕まったところで(!まさにバグのところでバグ)、おたすけモードでは全員揃って生徒たちに連行されるところで止まります。

モバイルのほうではconsole.logを見ることもできないのでどうしてなのか全く見当もつきませんでした。最初はスクロールレンジをつかっているのが原因かな?と思いましたが、おたすけモードのほうでは使っていないのでそうではないと思われました。

ここで両方に共通するのは、BGMの音を止めているということです。それしかありません。このBGMは、forを使って10回繰り返すように設定してあります。1回につき約140秒なので、さすがに10回繰り返すうちにはクリアするでしょうと。forを使っているのは、普通のスクリプトのループでは、ローカルや他の環境では動かなくなるからです。(画像が出ず真っ白になる)

その中で、音を制御するために、ENTER_FRAMEを使ったのですが、それが原因じゃないかと思って、その部分を無効にしたら、やはり動きました。しかしそれではBGMを止めることができなくなります。

それでこのENTER_FRAMEを使わずに音を止めようとしたのですが、そうすると今度はBGMのループがうまくいかなくなります。2回目から再生されなくなったり、2回目以降再生されても止められなくなったり。やはりENTER_FRAMEを使ったほうがうまくいくと思われました。

そこまでの考えに行き着いて、もっとやりたかったんですが夜も更けてきて明日も早起きして主人のお弁当つくらないといけないし、お風呂に入ろう、そしたらいい考えが思いつくんじゃないか、と自分に言い聞かせてお風呂に入りました。

そうしたらなんと言うことでしょう、お風呂の中で思いついたのです。ENTER_FRAMEの判定の条件が効きっぱなしになっているのが負荷になっているのではないかと。

ifの条件を満たしたらstopなのですが、それが一回こっきりではなくて、ずっと条件を満たして働き続けてしまう書き方になっているのがいけないんじゃないかと気付きました。

AIのところで教えていただいたのを思い出して、条件を満たした時に1回だけ働くように書き直してみました。すると、やはりそのとおりだったみたいで、動くようになりました。ヤッター/

これから何かに行き詰まったら、お風呂に入ることにします^^;

修正前

修正後

(通常モード)しめじ先生の大冒険ソースコード
(おたすけモード)しめじ先生の大冒険ソースコード