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

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

新規登録して質問してみよう
ただいま回答率
85.48%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

enchant.js

enchant.jsとは、アプリやゲームを簡単に開発できるオープンソースのHTML5+JavaScriptベースのフレームワークです。プログラミング学習にも用いられ、多くの素材やプラグインが用意されています。

Q&A

解決済

1回答

3556閲覧

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

kamecha

総合スコア41

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

enchant.js

enchant.jsとは、アプリやゲームを簡単に開発できるオープンソースのHTML5+JavaScriptベースのフレームワークです。プログラミング学習にも用いられ、多くの素材やプラグインが用意されています。

0グッド

0クリップ

投稿2017/04/30 13:11

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

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

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

#現在のコード

lang

1enchant(); 2 3window.onload = function(){ 4 var game = new Core(320, 320); 5 game.preload('img/chara1.png', 'img/enchant.png', 'img/sirokuma.png'); 6 game.fps = 15; 7 game.onload = function(){ 8 //待期中のシーン 9 var wait = new Scene(); 10 //自機の作成 11 var bear = new Sprite(32, 32); 12 bear.image = game.assets['img/chara1.png']; 13 bear.x = 30; 14 bear.y = 80; 15 bear.frame = 0; 16 bear.on('touchstart', function(){ 17 game.popScene(wait); //判定の合否の仕方が分からない... 18 game.pushScene(win); 19 }); 20 wait.addChild(bear); 21 //敵の作成 22 var enemy = new Sprite(32, 32); 23 enemy.image = game.assets['img/sirokuma.png']; 24 enemy.x = 200; 25 enemy.y = 80; 26 enemy.scaleX = -1; 27 enemy.frame = 2; 28 wait.addChild(enemy); 29 30 game.pushScene(wait); 31 32 //反応基準?のシーン作成 33 var second = new Scene(); 34 var judge = new Sprite(64, 64); 35 judge.image = game.assets['img/enchant.png']; 36 judge.x = 100; 37 judge.y = 10; 38 second.addChild(judge); 39 //タイミング 40 var limit = 3 + rand(3); 41 42 second.on('enterframe', function(){ 43 var progress = game.frame / game.fps; 44 var timelimit = limit - progress + ""; 45 if (timelimit <= 0) { 46 game.pushScene(second); 47 } 48 }); 49 50 var label = new Label(); 51 label.x = 250; 52 label.y = 5; 53 label.text = 0; 54 label.font = '14px "Arial"'; 55 label.on('enterframe', function(){ 56 label.text = game.frame; 57 }); 58 game.rootScene.addChild(label); 59 60 //勝利した時のシーン 61 var win = new Scene(); 62 63 var bear1 = new Sprite(32, 32); 64 bear1.image = game.assets['img/chara1.png']; 65 bear1.x = 160; 66 bear1.y = 80; 67 bear1.frame = 1; 68 win.addChild(bear1); 69 70 var enemy1 = new Sprite(32, 32); 71 enemy1.image = game.assets['img/chara1.png']; 72 enemy1.x = 180; 73 enemy1.y = 70; 74 enemy1.scaleX = -1; 75 enemy1.frame = 8; 76 win.addChild(enemy1); 77 78 //敗北シーン 79 var lose = new Scene(); 80 81 var bear2 = new Sprite(32, 32); 82 bear1.image = game.assets['img/chara1.png']; 83 bear1.x = 120; 84 bear1.y = 70; 85 bear1.frame = 3; 86 lose.addChild(bear2); 87 88 var enemy2 = new Sprite(32, 32); 89 enemy1.image = game.assets['img/sirokuma.png']; 90 enemy1.x = 140; 91 enemy1.y = 80; 92 enemy1.scaleX = -1; 93 enemy1.frame = 3; 94 lose.addChild(enemy2); 95 96 } 97 game.debug(); 98}; 99 100function rand(n){ 101 return Math.floor(Math.random() * (n + 1)); 102} 103

#解決したいこと
現在のままでは、完成の見通しがつきません。
そのため、

  • スプライトの経過時間の取得
  • 判定を行うための、アイデア
  • 現在のコードの様々な問題点

等を出来れば教えていただきたいです。

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

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

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

ゲーム内の時間の場合はゲーム開始から終了するまで加算され続けるカウンタを見て判断します。
これを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の時間は比較できると思います。

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

Javascript_enchant.js

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

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

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

投稿2017/04/30 17:08

marimom7

総合スコア37

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kamecha

2017/05/01 13:20

Spriteに対するjudge.frametime = game.frame のような game.frameと、 ゲーム自体のgame.frameは違うのですか?
marimom7

2017/05/01 13:39

語弊がありましたね。 まずゲーム自体のgame.frameとframtimeに格納するgame.frameは同じものです。 ただし!game.frameは現在のgameの時間です。それに対してSpriteが出現したタイミングでgame.frameを格納したframetimeは出現した瞬間の時間を記憶しています。 つまり現在の時間とSpriteに保存されている時間を比較すると、Spriteが出現した時間からどれだけ時間が経過したのか判定ができます。これを応用するならば例えば早押しボタンが3つになった時でも1つ1つに対してgame.frameを記憶しておくと、それぞれのボタンがどのタイミングで押されたか判定できます。 judgeはSpriteオブジェクトですがそのSpriteオブジェクトに対してframetimeという私が勝手に作成した変数を追加している状況になっております。 例えば judge.frametime = 3; とするとSpriteオブジェクトのメンバ変数「frametime」に3を格納するという意味合いになります。
kamecha

2017/05/01 15:01

何となく理解しました。ということは var second = new Scene(); var judge = new Sprite(64, 64); judge.image = game.assets['img/enchant.png']; judge.x = 100; judge.y = 10; judge.frametime = (game.frame / game.fps); second.addChild(judge); //タイミング var limit = 3 + rand(3); second.on('enterframe', function(){ var timelimit = maintime - judge.frametime; if (timelimit = limit) { game.pushScene(second); } }); のようにコードを記述すると、limitに格納した秒数後にsecondが表示されると言うことですか?
kamecha

2017/05/01 15:02

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

2017/05/01 15: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秒毎の比較なのでそこは注意しましょう。
kamecha

2017/05/04 03:59

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問