質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

88.91%

スプライトの経過時間を取得する方法、現在のコードから自分が見つけられなかった問題点に対する指摘をお願いします。

解決済

回答 1

投稿

  • 評価
  • クリップ 0
  • VIEW 1,730

kamecha

score 41

課題

現在enchant.jsを使用して、早押しゲームを作成しているのですが、

スプライトがタッチされた時の、経過時間を取得する方法が分かりません、

また、現在のコードでは、判定のスプライトが表示されません。
様々な方法を調べたつもりですが、それでも分かりませんでした。

現在のコード

enchant();

window.onload = function(){
    var game = new Core(320, 320);
    game.preload('img/chara1.png', 'img/enchant.png', 'img/sirokuma.png');
    game.fps = 15;
    game.onload = function(){
        //待期中のシーン
        var wait = new Scene();
        //自機の作成
        var bear = new Sprite(32, 32);
        bear.image = game.assets['img/chara1.png'];
        bear.x = 30;
        bear.y = 80;
        bear.frame = 0;
        bear.on('touchstart', function(){
            game.popScene(wait);    //判定の合否の仕方が分からない...
            game.pushScene(win);
        });
        wait.addChild(bear);
        //敵の作成
        var enemy = new Sprite(32, 32);
        enemy.image = game.assets['img/sirokuma.png'];
        enemy.x = 200;
        enemy.y = 80;
        enemy.scaleX = -1;
        enemy.frame = 2;
        wait.addChild(enemy);

        game.pushScene(wait);

        //反応基準?のシーン作成
        var second = new Scene();
        var judge = new Sprite(64, 64);
        judge.image = game.assets['img/enchant.png'];
        judge.x = 100;
        judge.y = 10;
        second.addChild(judge);
        //タイミング
        var limit = 3 + rand(3);

        second.on('enterframe', function(){
            var progress = game.frame / game.fps;
            var timelimit = limit - progress + "";
            if (timelimit <= 0) {
                game.pushScene(second);
            }
        });

        var label = new Label();
        label.x = 250;
        label.y = 5;
        label.text = 0;
        label.font = '14px "Arial"';
        label.on('enterframe', function(){
            label.text = game.frame;
        });
        game.rootScene.addChild(label);

        //勝利した時のシーン
        var win = new Scene();

        var bear1 = new Sprite(32, 32);
        bear1.image = game.assets['img/chara1.png'];
        bear1.x = 160;
        bear1.y = 80;
        bear1.frame = 1;
        win.addChild(bear1);

        var enemy1 = new Sprite(32, 32);
        enemy1.image = game.assets['img/chara1.png'];
        enemy1.x = 180;
        enemy1.y = 70;
        enemy1.scaleX = -1;
        enemy1.frame = 8;
        win.addChild(enemy1);

        //敗北シーン
        var lose = new Scene();

        var bear2 = new Sprite(32, 32);
        bear1.image = game.assets['img/chara1.png'];
        bear1.x = 120;
        bear1.y = 70;
        bear1.frame = 3;
        lose.addChild(bear2);

        var enemy2 = new Sprite(32, 32);
        enemy1.image = game.assets['img/sirokuma.png'];
        enemy1.x = 140;
        enemy1.y = 80;
        enemy1.scaleX = -1;
        enemy1.frame = 3;
        lose.addChild(enemy2);

    }
    game.debug();
};

function rand(n){
    return Math.floor(Math.random() * (n + 1));
}

解決したいこと

現在のままでは、完成の見通しがつきません。
そのため、

  • スプライトの経過時間の取得
  • 判定を行うための、アイデア
  • 現在のコードの様々な問題点
    等を出来れば教えていただきたいです。

追記*******
ほとんど初心者のコードなので、普通の人が見るとおかしなコードである可能性大です。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 過去に投稿した質問と同じ内容の質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 1

checkベストアンサー

+3

経過時間の概念は主に二通りありゲーム内の時間か現実時間があります。

ゲーム内の時間の場合はゲーム開始から終了するまで加算され続けるカウンタを見て判断します。
これをFrameと呼び、1秒間でカウンタが1から60になる場合はそのゲームは60fpsで動いているという表現をします。逆に言えば現在のFrame数値が120ならばゲーム開始から2秒経過した状態です。
enchant.jsではゲーム内フレームはgame.frameで取得できるためそのままgame.frameをどこかで記憶し、後で現在のgame.frameと記憶したgame.frameを比較して時間を判定する事が可能です。
今回の場合は早押しゲームという事なので、自分が想定したゲームの開始と同時にgame.frameを何らかの変数に記憶して置きましょう。ゲームが60fpsで動いていると仮定し、現在のgame.frameと記憶したgame.frameの数値との差が300なら5秒経過したと言えます。
enchant.jsの場合はgame.fpsを変更することでゲーム更新速度を変更する事が可能です。

現実時間の場合はJavascriptのDateオブジェクトを使うと良いでしょう。これはPC内の時計を基準とした現在時刻などを取得できます。時刻を取得した後は上記のframeと流れはそれほど変わりません
余談ですがあくまでもPC内の時計を基準としているので時計を弄ってしまえば簡単に意図した挙動から外れる事が可能です。この不正を防止する際はサーバー通信を使用して時刻を記憶する所をサーバー側にしてしまえば不正はできません(基準がサーバー側の時計なので)。もしくはどこかのオープンサーバーから時刻のみ取得するなどでも可能でしょう。

さてSprite毎に経過時間を取得したい場合、Spriteを出現させるタイミングでgame.frameをSpriteのメンバ変数を拡張して記憶してしまいましょう。例えば[judge]を拡張する場合はjudge.frametime = game.frameのようにして記憶し、現在のgame.frameと比較する事でそのSpriteの経過時間を比較していると言えるでしょう。これでSpriteの時間は比較できると思います。

また注意点として、投稿主さんの下記コードですが

second.on('enterframe', function(){
            var progress = game.frame / game.fps;
            var timelimit = limit - progress + "";
            if (timelimit <= 0) {
                game.pushScene(second);
            }
});


この場合timelimitが0以下になるとシーンがpushされますが、次の更新処理の際にも条件はtrueになっているためまたシーンがpushされます。これが何度もpushされている状態になり戻らないため一度pushしたら条件から外れるような条件を組みましょう。

少し長くなりましたがご参考になればと思います。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/05/02 00:02

    maintimeには、ゲーム自体の(game.frame / game.fps)が格納されています。

    キャンセル

  • 2017/05/02 00:49

    judge.frametimeの使い方はそれで大丈夫です。

    さて問題なのが、secondに実装されている'enterframe'で指定されているfunctionですがこれは1秒間にgame.fps回数分実行されるメソッドになっております。
    timelimit == limit の条件では例えばlimitが3の場合、3秒後・・・つまり60fpsでは180フレーム目にこの条件がtrueになります。そしてそこから60Frameが経過し240Frame目に条件がfalseになる流れになります。つまり、180~239Frameの計60回の処理は条件がtrueになるため結果として60回Secondシーンがpushされつづけます。
    実装方法は色々なやり方がありますがゲームによって最適な形は違います。
    安直に考えるならば下記のように、1つのboolデータが入った変数を条件に加えるなどですね。
    if (timelimit == limit && end) { //endにはtrueが入っている状態です
    game.pushScene(second);
    end = false;
    }
    初心者ということですが && などの論理演算子は大丈夫でしょうか?
    このように条件に入った後、その条件式の条件を変えるような処理を組むと1フレームだけで制御する事ができたりします。
    他にも変数を用意せずに game.frame == 180 にすれば3秒のみ1フレームでも経過したら条件から抜けるようになります。
    どちらかというとgame.frameを直接比較した方がシンプルですね。
    game.frameは1フレーム毎、game.frame/game.fpsは1秒毎の比較なのでそこは注意しましょう。

    キャンセル

  • 2017/05/04 12:59

    なるほど、有り難うございます!
    何度も試してみます!
    (初心者は、実際にやるのがいいと思うので...)

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 88.91%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • トップ
  • JavaScriptに関する質問
  • スプライトの経過時間を取得する方法、現在のコードから自分が見つけられなかった問題点に対する指摘をお願いします。