グループの中の最上位置の判定とスクロール

下書きしたまま放置の記事が結構ありますが、あんまりきちんとと堅苦しくなると続けられなくなるので、思いつくまま軽い感じでいきたいと思います。

今日の授業は最近の中でも面白く感じたので、記録として書いておきます。

今チャレンジしているゲームですが、実は息子は、今回のテーマの初回の授業を受けた後から、偶然にも、先生がモデルにされたサリータワーと全く同じようなものを作りたいと作り始めていました。左右に移動するもの(授業ではヘリ)から物(授業ではブロック)を落として、積み上げるというものです。

前回の授業では、ブロックが積み上げられたら、ヘリにぶつかってしまうので、そうならないようにヘリを上昇させるにはどうしたらいいでしょうね、というところで終わりました。

息子は続きを作るべく、そこに挑んでみましたが、これは難しいのです。なぜなら、「ブロックが上のほうまで積まれてきたら」というのが問題なのですが、これを判定しようにも、ブロックは一番上の位置から落としているのです。落とす時点で既に一番上にあるのですから、「ブロックの位置から・・」とやろうとすると、落とす時点でもう積んでいる。だから「積まれたブロックの一番上のものから・・」とやろうとするなら、いつ判定するのか、どうやって判定するのかということになります。この時点で、私はもう面倒くさそうと思ってしまい、授業では擬似的な方法で簡単にそれっぽく見せる方法を採られるのではないかと思っていました。

そこで、今日の授業です。授業で示された方法は、「ブロックを落としてから2秒後(連続して落としていても最後に落としたものから2秒後)に、落としたブロックをすべて調べて一番上にあるものの高さを取り、それとヘリの高さを比較して一定以上近ければ離す」というものでした。

先生は「如何に誤魔化すか」と言われましたが、私は結構な正攻法じゃないかと思ってさすが先生と思いました。

    // タッチするとブロックが落ちる(と同時にreadyAlt()が発動)
    scene.on(Event.TOUCH_START, function(e){
        dropBlock();
        // (1) タッチしたタイミングで処理を開始しよう
        readyAlt();    
    });

    function dropBlock(){
        var block1 = new PhyBoxSprite(31, 31, enchant.box2d.DYNAMIC_SPRITE);
        block1.image = core.assets["images/do_daruma.png"];
        block1.x = heli.centerX;
        block1.y = heli.centerY;
        group.addChild(block1);
    }

    // (2) 処理を遅れさせよう(readyAlt()の中身)
    function readyAlt(){
       scene.tl.clear();// これを入れることで、落とす度にリセットされ、最後に落としたものからのカウントになる
       scene.tl.delay(32);// 32フレーム経ってからceckAlt();が発動
       scene.tl.then(function(){
          checkAlt(); 
       });
    }

    // (3) ブロックを調べる処理(checkAlt()の中身)
    function checkAlt(){
        console.log("高さを調べる");
        // (4-1) グループで最も高い位置にあるブロックを調べる
        //for(初期化; 条件; 後処理;){処理}
        var borderY = 480;// 画面の一番下。これよりブロックは下へ行くことがないので、これをブロックの最上位の位置の初期値とする。
(これとブロックの位置と比較して、それより上の位置なら最上位として更新するという仕組み)
        for(var i=0; i<group.childNodes.length; i++){ // ブロックの数だけ繰り返す(ブロック全部調べる)
            console.log(i);
            var y = group.childNodes[i].y;// ブロックのi番目のy座標が取得される。
            console.log(y);
            //高い位置にあれば更新
            if(y < borderY){
                borderY = y;// 繰り返すことで最終的には一番高いyがborderYとなる。
            }
        }
        console.log("最も高い位置にあるのは:" + borderY);
        // (4-2) 高い位置から一定の距離を保つ
        var padding = 130;// ヘリと一番上のブロックの距離
        if(borderY < heli.y + padding){
              heli.y = borderY - padding;
        }
    }
    
    // (5) スクロールさせる
    scene.setScrollRange(heli,80,0);// ヘリが上に上がっていくと見えなくなるのでスクロールさせる

どうやって一番上のブロックのy座標を取り出すのかというと、まずブロックはy座標480より下に行くことはないので、borderYの初期値を480としておきます。そして、1個めのブロックのy座標と比較して、これより上ならそのy座標の値をborderYに書き換え、さらに2個めのブロックも同様・・とブロックの個数分つまり全部で繰り返せば、最終的にborderYが一番高いブロックのy座標の値に書き換えられているという訳です。プログラミングではこうやってやるんだーと感心、納得。

こうして順序立てて教えていただくと、想像したより難しくなかったですし、考え方ややり方はほかにも色々応用できそうです。

AIを使ったゲームの発表

11月最後の授業日は、2017年10月〜11月に勉強したテーマ「AIに挑戦せよ」の作品の発表(報告)でした。

AIというと最近ですと将棋を思い出します。私は将棋はルールを知っているくらいでやるにしても幼稚園程度の将棋しか指せませんが、同世代の羽生永世七冠のファンで、将棋連盟のサイト棋戦のページや対局結果をときどき見ています。将棋の内容はわかりませんが、誰が勝ったと強いとか、対戦での行き詰まる様子や、棋士のすごさや個性が面白く、自分は将棋はできないのに将棋の世界を観るのを楽しんでいるというファンです。

その将棋で、プロ棋士の名人が将棋ソフトに負けてしまいました。動的な部分では、人間は機械には勝てないというのはずいぶん前から当たり前のことでしたが、そういう単なる一方通行の働き(早く走るとか動くとか)だけではなく、さまざまな選択肢の中から最善のものを考えて判断し選択するという知能の部分でも、コンピュータは人間に迫るかそれ以上の力を持ち始めたということなのでしょう。

さて、今回やってきたのは、「ゲームAI」といわれるものです。ゲームAIには主に3つのものがあり、

・メタAI・・ゲームそのものの難易度を変える(例:クリアする度に難しくなる)
・キャラクターAI・・キャラクターの知能
・ナビゲーションAI・・地形や状況の空間的な情報を抽出するAI(例:目的地に向かう経路)

この中でも、「キャラクターAI」といわれる、あたかもゲーム内のキャラクターが知能をもってるかのように、というか、プログラミングによって知能を持たせると言ったほうがいいのでしょうか、条件に応じて動きが変わるようにプログラミングをするというものです。

授業の流れとしては、以下のようなものでした。

・タイムラインで判定のタイミングを調整する。
・ファンクション(関数)で判定の中身を作り、先のタイムラインの中で判定をする。
・パラメーターを使う。hpとmode。(hpはhpの値によってキャラクターの動きを変える。modeは、modeの値によって、実行する処理を制御することができる。modeが切り替わったときに一度だけ実行させたりすることができる。)       

ブッタ様?

・パワーメーターの作り方。
・シューティングへの応用。
・ループキャンセル

これらを、ブッタ様にプラスの弾を撃ったりマイナスの弾を撃ったりすることによって、ブッタ様の状態が変化するというサンプルを基に作っていきました。

それで、まず作ったのはサンプルを基にした「ブッタ様大噴火」。次に、課題に沿って作った「おならして帰る」。そしてシューティングへの応用ということで、前に作ったシューティング「いきなりボス」を改造して、「AIマンドラゴラ」(解説)を作りました。

今回発表では、「AIマンドラゴラ」を発表しました。

また今回もみんなの個性爆発の作品揃いで、大変楽しいものばかりでした。ブッタ様を自分の好きなキャラクターに変えたり、戦国武将の隊列だったり(絵がかわいくて上手!。息子が渡した感想に書いた言葉「私にはとても描けません」(笑))、お友達との合作で、大量のトイレットペーパーをわかめで撃っていくという素晴らしい想定、得意のドット絵で書いたかっこいいボスキャラなど、どれも自由で素晴らしいものでした。

NHK教育で金曜日にやっている番組「ビットワールド」で、「アリですよ!」という、「おもしろい答えでマス子先生たちをおどろかせよう!!」というコーナーがあるのですが、このコーナーでは最後にいつもセイコー先生が「ではマス子先生採点を」と言い、それに対してマス子先生が「全部、満点で!」と答えるのがお決まりになっているのですが、それを思い出しました。

 

おまけ:本日のツボ

「にんじんおばけ」

マンドラゴラのつもりで描いた絵に対してそれを知られない先生がつけた名前。こどもたちにすごく嫌われそう・・実際のマンドラゴラはどっちかと言うとだいこん?

マンドラゴラ

 

たぶん、瞬間移動して弾に当たってそのまま死にました。」

ボスが出てきたと思った瞬間、ミサイルだけを発射して一瞬で消えてしまいました。ボスなのに一瞬で死ぬて。それについてものすごく冷静に言い放った姿にツボりました。

 

「観音様」

ゲームの説明で「観音様が・・」と言われたので、てっきり、オリジナルの観音様が出てくるのかと思ったら、ブッタ様のことでした。(本物のブッダとはは仏陀と書き、仏様(如来)のことを指し、そのうちの一人が地球上の唯一の仏陀であるお釈迦様。それ以外だと、知られたところでは、阿弥陀如来、大日如来、など、それぞれ名前がある。仏様の頭は覚りを表すパンチパーマのような「螺髪」。)

・・で、「観音様」と呼んでいるところが、なんとも味があって、別に間違いとかではなくて、ああこの人にとっては観音様に見えたんだと宗教観みたいなのが垣間見えて、観音様という言葉が自然に出てくるところがいいなあと思ったのでした。

 

なぜか上から弾が出てくるという・・流れ弾が。・・ここが戦場だと言うことを忘れてはならない

このあと「本当はもっと大きな落石みたいなのがよかったかな」とおっしゃってました。確かに、すごく小さな弾が、ブッタ様と一緒に降っているのです。目を凝らさないとわからない、そして、一瞬の油断も許されないという決め台詞・・ここは戦場だったのね、、、というところにツボりました。

まさかの先生デビュー!? ^^;

先日、先生から大垣市主催の小学生対象のプログラミングイベントにサポートとして参加してみませんかとお声を掛けていただきまして、息子と参加させていただきました。

私ども、こういったイベントは初めてで、なにしろ今通わせていただいているCodeFriendsも開講間際まで知らなかったので、体験教室も行かないでいきなり一か八か入会申し込みをしたような状態でしたので…。

今回大垣市のイベントということでしたが、以前からこのようなICTに関するイベントが年に何度か開催されていて、CodeFriendsの先生が担当されるのは去年に引き続いて2回目だそうです。

さすがソフトピアのある大垣市はすごいですね、私どもの市町村でも学校を通じていろいろなイベントの案内がありますが、息子、娘が小学校に入って以来8年、こういったプログラミングに関するイベントの案内は一度も目にした覚えがありません。

プログラミングが学校でも必修化されるということですが、プログラミング教育に対する取り組みは、やはり地域によって格差があるのでしょうか。(このような立派な施設があることがうらやましいです)

さて、満席大盛況のイベント、当初は子供さんだけの参加の設定でしたが、先生の配慮で希望される方は保護者も一緒に見学OKとなって、いつもの教室のように、子供さんだけだったり、親子だったりの和やかな雰囲気で始まりました。

講師は尾崎先生と今井先生、ほかにサポートの先生もいらっしゃって、プロの先生方に混じってサブ講師ということで”○○先生”なんて紹介していただき(やめてもらおうかとも思いましたが、参加者の方には知ったこっちゃないことだし、こちらの都合の面倒くさい物言いはやめようと思い流れにまかせました)恐縮ばかりでしたが、すごく楽しかったです。

勉強を教えるときもそうですが、なぜかな、どうしてかな、どこが違うのかな?というとき、ちょっとヒントを出して、わかった、とかそうか!と自分で解決できて目を輝かせる子どもの姿を見るのは、嬉しいものですね。

今でこそ息子も何とかCodeFriendsの授業についていって自分で作っていますが、最初は、一つ何かをキーボードで打つ度に何かを間違えていました。

必ず間違えるので「ワンアクション、ワンエラー」と呼んでいました。自分で見つけられないと、「ちゃんと書いたのに動かない!」とさもコンピュータのほうが悪いかのように憤慨してました^^;。でも結局自分が間違えているのです。

ずいぶん間違い探しに付き合いましたが(今も)、それが役に立つとは・・というか、プログラミングってそういうことも含めての繰り返しなんですねきっと。(すごい脳トレだわ。)やってみて、間違えることで覚えていく・・考えてみれば勉強って何でもそういうものですね。

それにしても先生のわかりやすく楽しい授業で、3時間もの間子ども達が一つのことに集中して、作り上げたのですから大したものです。みんなちゃんと先生についていって動かせてました。すごい!

一日だから長いかな…と思っていましたが、終わってみるとあっという間!きっと参加された方達も、あっという間の楽しい時間だったことでしょう。(親)

できてるかな・・・みんな上手だな              (一部配慮の為加工してあります)

 

 

 

 

 

 

 

 

 

ぼくはほかの子と一緒に受けさせてもらいながら教えていたので、先生というよりも、生徒に近かったのではないかと思います。

来ていたのは様々な大垣市内の小学生で、中には、僕よりうまいのではないかという子もいました。

間違いがあると生徒さんから呼ばれるのですが、まちがいは、大抵大文字と小文字(Spriteとsprite)とか、つづりの問題が多かったと思います。

分からなくて他の先生を呼ぶこともあったので、まあ、受講料500円分くらいの手伝いは出来たのではないかと思います。勉強になりました!(以上息子)

先生方ご参加の皆様方大垣市様ありがとうございました。

武器がスキ(´ε`(レポート)

忘れないうちに、今までのをすっ飛ばして、新しいものから記録していきます。

息子はもうすぐ実力テストがあり、それに向けて毎日頑張って勉強しつつ、タイピングやドットインストールでの自習もやっておりますので、代わって息子に聞きながら記録しておきます。

2017.8~9にかけての内容です。

サンプルは「収穫せよ」というゲームで、コレクションゲーム?収集ゲームというのでしょうか?やったことがないのでよくわかりませんが、とにかく、ランダムに出てくるアイテムを集めるというものです。

それには、一度出たものを「獲った」と記憶させておく仕組みが必要です。今まで習ってきたものはすべてその画面での記録でしかなく、画面遷移をしてしまうと得点ですら残らないものでした。

それが、この仕組みを使えば、内部に記憶させておいて、出したい時に出す、消したければリセットすることができるという、いわゆる「セーブ・ロード・リセット」ということができるという訳です。

ゲームをやっていると当たり前のようにある機能も、このように一つ一つ学んでいくと、こういうことを使って作っているんだね〜、なるほど確かにこれは必要だね〜、と感慨深いものがありますね。

クラスでは、テーマは「武器」ということになりました。皆がそれぞれに作った素敵な武器を持ち寄って、作りました。

先日、できた分までの発表&報告があり、改めて見返してみましたが、個性があってほんとうに素晴らしい。私は、シュールなものも大好きなので、金床の後ろから武器が出てきてしまっていたり、武器が大根に変わったり、異様に大きな地球が出てきたり、武器がループして出現していたり、作る側の苦労も垣間見えるゲームづくりあるあるが微笑ましく、見ていると楽しいのでした。

以下作ったものについて説明します。

1.金床の配置

先生がつくられたサンプルのゲームに習って、一度に四つの武器がランダムに出るようにしました。

そのために、まず金床(鍛冶屋さんが金物を加工するための台座です。この言葉も初めて知りました。でも、この画像を出したときに、クラスのお友達はすぐに「かなとこー!」と反応してくれました。よく知ってるな〜と感心)を4つ配置します。
金床1〜金床4としました。

 //金床1
 var kanatoko = new ExSprite(120, 120);
 kanatoko.image = core.assets["images/cf307/kanatoko_suihei1.png"];
 kanatoko.x = 30;
 kanatoko.y = 170;
 kanatoko.touchEnabled = false;
 scene.addChild(kanatoko);
 kanatoko.frame = 1;

2.ランダムの変数

その金床一つ一つに対して、ランダムに武器をだすので、ランダムの変数も4つ用意します。

4種類の武器に対して、全部で100%として確率を変えることにしました。

 // 変数
 var random = getRandom(1, 100);
 var random2 = getRandom(1, 100);
 var random3 = getRandom(1, 100);
 var random4 = getRandom(1, 100);

武器は、短剣、ハンマー、ソード、スコップの4種類です。

出現する確率として、短剣50%、ハンマー30%、ソード19%、スコップ1%にして、条件分岐にします。

3.問題発生(画像の大きさが異なる問題)

そこで、はじめ、先生のサンプルのようにそれぞれの確率に対して、

 if (1 <= random && random <= 50) {
     arms1.image = (略:短剣のイメージ);
 }
 if (51 <= random && random <= 80) {
     arms1.image = (略:ハンマーのイメージ);
 }
 if (81 <= random &&random <= 99) {
     arms1.image = (略:ソードのイメージ);
 }
 if (random == 100) {
      arms1.image = (略:スコップのイメージ);
 }

のように書きました。すると、問題が発生しました。

武器の画像の大きさが異なるために、そのまま画像のイメージを入れ替えただけでは、はじめの画像の指定より小さな画像の武器はループされて表示されてしまい、大きな画像は切れてしまいます。

               

 

 

ですので、その都度画像の大きさを指定し直すという作業が必要になってしまい、それに付随して位置の微妙な調整も必要になってきてしまうということに気づきました。(要するに、たくさん書き足さなくてはならない)

4.問題の解決(関数を使って位置だけを変えて指定する)

調整すべきは、画像の大きさと、画像の位置、それぞれx方向とy方向の4つの値です。それが、4つの金床に対して4つの武器なので、4×4=16箇所になります。

そこで、一つの武器につき、出す位置を変数にした関数を一つづつ作って、金床に合わせて出す位置だけを変えて入力すればよい形にしました。こうすれば、武器それぞれに対しては大きさは固定されるので、変な出方をすることがありません。

短剣を出すための関数をArms1(x, y)としてつくります。

 //武器1を出す関数
 function Arms1(x,y){
     var arms1 = new ExSprite(60, 100);
     arms1.image = core.assets["images/cf307/tannken.png"];
     arms1.x = x;
     arms1.y = y;
     scene.addChild(arms1);
     arms1.rotate(-80);
 }

これで、金床の位置に合わせてx、yだけを指定すればいいことになります。武器2〜武器4も同様に
ハンマーを作る関数をArms2(x, y)、タガーを作る関数をArms3(x, y)、スコップを作る関数をArms4(x, y)として設定しました。

すると、今度は武器の表示をfanctionに入れたがために、そのままでは武器のタッチイベント(セーブ、武器をタッチすると消える、カードが画像入りのものに変わる)が効かなくなってしまいました。

そこで、それも一緒にfanctionの中に入れることで解決しました。(以下青字の部分)

 //武器1を出す関数
 function Arms1(x,y){
     var arms1 = new ExSprite(60, 100);
     arms1.image = core.assets["images/cf307/tannken.png"];
     arms1.x = x;
     arms1.y = y;
     scene.addChild(arms1);
     arms1.rotate(-80);
     arms1.addEventListener(Event.TOUCH_START, function(e) {
         setLocalStorage("cardA", "get");
         arms1.remove();
         cardA.frame = 1;
     });  
 }

5.カード

カードは、シルエットのカード(freme0)を出しておいて、武器を獲ったら(LocalStorageにgetとセーブされていたら)カードの絵(frame1)が出るようにします。

 var cardA = new ExSprite(128 / 2, 83);
 cardA.image = core.assets["images/cf307/tannkencard2.png"];
 if (getLocalStorage("cardA") == "get") {
     cardA.frame = 1;
 } else {
     cardA.frame = 0; 
 };
 cardA.x = 15;
 cardA.y = 390;
 scene.addChild(cardA);

6.サウンド

鍛冶屋なので、童謡「村の鍛冶屋」をBGMにしました。

7.完成したソースコード

以上を組み合わせて、以下のように完成しました。

var assets = [
    // 背景
    "images/cf307/kaziba.png",
    // カード 
    "images/cf307/tannken.png",
    "images/cf308/so-do (5).png",
    "images/cf307/kanatoko_suihei1.png",
    "images/cf308/ka-do (1).png",
    "images/cf308/ka-do (2).png",
    "images/cf307/tannkencard2.png",
    "images/cf307/hannmer90_64.png",
    "images/cf308/karahurunasukoppu (1).png",
    "images/cf308/ka-do (4).png",
    "images/cf308/ka-do (5).png",
    "images/cf307/hannmercard2.png",
    // 削除ボタン
    "images/b_red.png",
    "images/title.png",// タイトル
    "sounds/cf307/kajiya.mp3",
 
 ];

function gameStart(){// ゲーム画面
    scene = gameManager.createGameScene();
    core.replaceScene(scene); core.resume();

    // BGM
    var sound = core.assets["sounds/cf307/kajiya.mp3"].clone();
    sound.play();

    // 背景
    var back = new ExSprite(320, 480);
    back.image = core.assets["images/cf307/kaziba.png"];
    scene.addChild(back);

    //変数
    var random = getRandom(1, 100);
    var random2 = getRandom(1, 100);
    var random3 = getRandom(1, 100);
    var random4 = getRandom(1, 100);
    console.log(random);
    console.log(random2);
    console.log(random3);
    console.log(random4);
 
    //金床1
    var kanatoko = new ExSprite(120, 120);
    kanatoko.image = core.assets["images/cf307/kanatoko_suihei1.png"];
    kanatoko.x = 30;
    kanatoko.y = 170;
    kanatoko.touchEnabled = false;
    scene.addChild(kanatoko);
    kanatoko.frame = 1;
    if (1 <= random && random <= 50) {
        Arms1(30, 160);
    }
    if (51 <= random && random <= 80) {
        Arms2(30, 170);
    }
    if (81 <= random &&random <= 99) {
        Arms3(50, 170);
    }
    if (random == 100) {
        Arms4(60, 170); 
    }

    //金床2
    var kanatoko2 = new ExSprite(120, 120);
    kanatoko2.image = core.assets["images/cf307/kanatoko_suihei1.png"];
    kanatoko2.x = 180;
    kanatoko2.y = 170;
    kanatoko2.touchEnabled = false;
    scene.addChild(kanatoko2);
    kanatoko2.frame = 1;
    if (1 <= random2 && random2 <= 50) {
        Arms1(180, 160);
    }
    if (51 <= random2 && random2 <= 80) {
        Arms2(180, 170);
    }
    if (81 <= random2 && random2 <= 99) {
        Arms3(200, 170);
    }
    if (random2 == 100) {
        Arms4(210, 170); 
    }

    //金床3
    var kanatoko3 = new ExSprite(120, 120);
    kanatoko3.image = core.assets["images/cf307/kanatoko_suihei1.png"];
    kanatoko3.x = 30;
    kanatoko3.y = 250;
    kanatoko3.touchEnabled = false;
    scene.addChild(kanatoko3);
    kanatoko3.frame = 1;
    if (1 <= random3 && random3 <= 50) {
        Arms1(30, 240);
    }
    if (51 <= random3 && random3 <= 80) {
        Arms2(30, 250);
    }
    if (81 <= random3 && random3 <= 99) {
        Arms3(50, 250);
    }
    if (random3 == 100) {
        Arms4(60, 250); 
    }

    //金床4
    var kanatoko4 = new ExSprite(120, 120);
    kanatoko4.image = core.assets["images/cf307/kanatoko_suihei1.png"];
    kanatoko4.x = 180;
    kanatoko4.y = 250;
    kanatoko4.touchEnabled = false;
    scene.addChild(kanatoko4);
    kanatoko4.frame = 1;
    if (1 <= random4 && random4 <= 50) {
        Arms1(180, 240);
    }
    if (51 <= random4 && random4 <= 80) {
        Arms2(180, 250);
    }
    if (81 <= random4 && random4 <= 99) {
        Arms3(200, 250);
    }
    if (random4 == 100) {
        Arms4(210, 250); 
    }

    //短剣を表示する関数
    function Arms1(x,y){
        var arms1 = new ExSprite(60, 100);
        arms1.image = core.assets["images/cf307/tannken.png"];
        arms1.x = x;
        arms1.y = y;
        scene.addChild(arms1);
        arms1.rotate(-80);
        arms1.addEventListener(Event.TOUCH_START, function(e) {
            setLocalStorage("cardA", "get");
            arms1.remove();
            cardA.frame = 1;
        });
    }
 
    //ハンマーを表示する関数
    function Arms2(x,y){ 
        var arms2 = new ExSprite(90, 64);
        arms2.image = core.assets["images/cf307/hannmer90_64.png"];
        arms2.x = x;
        arms2.y = y;
        scene.addChild(arms2);
        //arms2.rotate(-80);
        arms2.addEventListener(Event.TOUCH_START, function(e) {
            setLocalStorage("cardB", "get");
            arms2.remove();
            cardB.frame = 1;
        });
    }

    // 短剣を表示する関数
    //もとは50、250 
    function Arms3(x,y){
        var arms3 = new ExSprite(64, 80);
        arms3.image = core.assets["images/cf308/so-do (5).png"];
        arms3.x = x;
        arms3.y = y;
        scene.addChild(arms3);
        arms3.rotate(-90);
        arms3.addEventListener(Event.TOUCH_START, function(e) {
            setLocalStorage("cardC", "get");
            arms3.remove();
            cardC.image = core.assets["images/cf308/ka-do (1).png"];
        });
    }

    //スコップを表示する関数
    function Arms4(x,y){
        var arms4 = new ExSprite(64, 80);
        arms4.image = core.assets["images/cf308/karahurunasukoppu (1).png"];
        arms4.x = x;//200
        arms4.y = y;//260
        scene.addChild(arms4);
        arms4.rotate(-90);
        arms4.addEventListener(Event.TOUCH_START, function(e) {
            setLocalStorage("cardD", "get");
            arms4.remove();
            cardD.image = core.assets["images/cf308/ka-do (4).png"];
        });
    }

    // カード
    var cardA = new ExSprite(128 / 2, 83);
    cardA.image = core.assets["images/cf307/tannkencard2.png"];
    if (getLocalStorage("cardA") == "get") {
        cardA.frame = 1;
    } else {
        cardA.frame = 0; 
    };
    cardA.x = 15;
    cardA.y = 390;
    scene.addChild(cardA);

    var cardB = new ExSprite(64, 80);
    cardB.image = core.assets["images/cf307/hannmercard2.png"];
    if (getLocalStorage("cardB") == "get") {
        cardB.frame = 1;
    } else {
        cardB.frame = 0;
    };
    cardB.x = 90;
    cardB.y = 390;
    scene.addChild(cardB);

    var cardC = new ExSprite(64, 80);
    if (getLocalStorage("cardC") == "get") {
         cardC.image = core.assets["images/cf308/ka-do (1).png"];
    } else {
        cardC.image = core.assets["images/cf308/ka-do (2).png"];
    };
    cardC.x = 165;
    cardC.y = 390;
    scene.addChild(cardC);

    var cardD = new ExSprite(64, 80);
    if (getLocalStorage("cardD") == "get") {
        cardD.image = core.assets["images/cf308/ka-do (4).png"];
    } else {
        cardD.image = core.assets["images/cf308/ka-do (5).png"];
    };
    cardD.x = 240;
    cardD.y = 390;
    scene.addChild(cardD);

    // 削除ボタン
    var button = new ExSprite(62, 55);
    button.image = core.assets["images/b_red.png"];
    button.x = 250;
    button.y = 0;
    scene.addChild(button);
    button.addEventListener(Event.TOUCH_START, function() {
        removeLocalStorage("cardA");
        removeLocalStorage("cardB");
        removeLocalStorage("cardC");
        removeLocalStorage("cardD");
    }); 
}

function titleStart(){// タイトル画面
    var scene = gameManager.createTitleScene();
    core.replaceScene(scene); core.pause();
    scene.on(enchant.Event.TOUCH_START, function(){gameStart();});
}

//==========
// EnchantJS
enchant();
var gameManager;
var core;
var scene;
window.onload = function(){
    gameManager = new common.GameManager();
    core = gameManager.createCore(320, 480);
    core.preload(assets);
    core.onload = function(){titleStart();};
    core.start();
}

8.別の書き方(先生の書き方)

「3.問題発生(画像の大きさが異なる問題)」のところの、画像の大きさが異なることについて、授業で先生が解説してくださいました。先生のやり方は、まず画像について大きさを指定しないで定義だけしておいて、あとからそれぞれサイズを指定するという方法でした。

var vegetable;
var random = getRandom(1, 4);
if(random == 1){
    vegetable = new ExSprite(80, 120);
    vegetable.image = core.assets[(略)];
    vegetable.x =  ;
    vegetable.y =  ;
}
if(random == 2){
    vegetable = new ExSprite(90, 100);
    vegetable.image = core.assets[(略)];
    vegetable.x = ;
    vegetable.y = ;
}
(略)〜〜
 〜〜
scene.addChild(vegetable);
vegetable.addEventLintener(~略

根本的にはやっていることは変わらないように思いますが、試しにそちらの書き方でも書いてみようと思います。

・・・・・・・

・・・と、やってみましたら、先生が書き足された部分について、ゆうじの場合は4箇所あるので、何度も書くのが大変なので関数にしただけで、やはりやっていたことはほぼ同じだったということに気づいたので、書き直すのはやめにしました。

要するに、先生が書き足されていた部分を、関数にして短くして書き足していたのでした。

その他、一度に4つの武器を出すことにしたために、色々書く順番が違っていましたが、こんなに書き方が違っても同じように動くのだなと大変勉強になり、興味深いものがありました。

ゆうじも授業を受けながら先生のを追って打っていたはずなのに結構違っていて、ゆうじなりに色々工夫したんだなと感心もしました。

書く順番が違っていても、ソースコードとしての順番さえ間違っていなければ、ちゃんと動くところがまたプログラミングの面白いところです。数学の解法に色々あるのに似ています。こういう、書き方にも人によって好みがあって、癖とか個性が出てくるのでしょうね。