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

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

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

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

Q&A

解決済

2回答

301閲覧

(JavaScriptゲーム)虫をクリックしたらTrueを返したい

mercredi

総合スコア26

JavaScript

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

0グッド

0クリップ

投稿2017/07/31 23:19

JavaScriptで虫をクリックすると加点するゲームを作っております。画像を挿入する前にcontext.arcでサークルを描いてクリックした時はTrueが帰ってきておりましたが、サークルをImageに変えると全てがFalseで返ってきてきてしまいます。

*変えた部分は、虫の画像とBackgroud画像を挿入しました。
Trueを返したいBoolean ValueはisOnCircleです。

###常にFalseが返ってきてしまう(虫の画像を挿入した場合)

var Bug = (function () { function Bug() { } return Bug; }()); var jumpInterval; var interval = 4000; var bug = new Bug(); var canvas = document.getElementById('canvas'); canvas.width =727 canvas.height = 483; var context = canvas.getContext('2d'); var background = new Image(); background.src = "images/lawn.jpg"; background.onload = function () { context.drawImage(background, 0, 0); } function handleClick(evt) { console.log(evt.x + ',' + evt.y); var x = evt.x - 100; var y = evt.y - 100; // (x - center_x)^2 + (y - center_y)^2 < radius^2 var isOnCircle = Math.pow(x - bug.x, 2) + Math.pow(y - bug.y, 2) < Math.pow(bug.r, 2); console.log(isOnCircle); if (interval > 500) { interval -= 300; } else { interval = 500; } console.log(interval); } function jump() { bug.x = ((Math.random() * 10324897) % 500) + 1; bug.y = ((Math.random() * 10324897) % 500) + 1; bug.r = 32; context.clearRect(0, 0, canvas.width, canvas.height); var background = new Image(); background.src = "images/lawn.jpg"; background.onload = function () { context.drawImage(background, 0, 0); } console.log(bug.x); console.log(bug.y); context.beginPath(); var bugImage = new Image(); bugImage.src = "images/bug.PNG"; bugImage.onload = function () { context.drawImage(bugImage, bug.x, bug.y); } context.stroke(); clearInterval(jumpInterval); jumpInterval = setInterval(jump, interval); } jumpInterval = setInterval(jump, interval); canvas.addEventListener("click", handleClick);

###クリックするとTrueがきちんと返ってくる(サークルで試した場合)

var Bug = (function () { function Bug() { } return Bug; }()); var jumpInterval; var interval = 4000; var bug = new Bug(); var canvas = document.getElementById('canvas'); canvas.width =727 canvas.height = 483; var context = canvas.getContext('2d'); function handleClick(evt) { console.log(evt.x + ',' + evt.y); var x = evt.x - 100; var y = evt.y - 100; //(x - center_x)^2 + (y - center_y)^2 < radius^2 var isOnCircle = Math.pow(x - bug.x, 2) + Math.pow(y - bug.y, 2) < Math.pow(bug.r, 2); console.log(isOnCircle); if (interval > 500) { interval -= 300; } else { interval = 500; } console.log(interval); } function jump() { bug.x = ((Math.random() * 10324897) % 500) + 1; bug.y = ((Math.random() * 10324897) % 500) + 1; bug.r = 32; context.clearRect(0, 0, canvas.width, canvas.height); console.log(bug.x); console.log(bug.y); context.beginPath(); context.arc(bug.x, bug.y, bug.r, 0, 2 * Math.PI); context.stroke(); clearInterval(jumpInterval); jumpInterval = setInterval(jump, interval); } jumpInterval = setInterval(jump, interval); canvas.addEventListener("click", handleClick);

###補足情報(言語/FW/ツール等のバージョンなど)
ちなみにr(半径)の32はちゃんと虫の画像を計って得た値です。

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

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

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

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

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

guest

回答2

0

ベストアンサー

バグがあるようですね…虫だけにな!(ドヤ顔)

さて、真面目に回答します。
見た所、問題の本質はここにあるように感じました。

javascript

1var bugImage = new Image(); 2bugImage.src = "images/bug.PNG"; 3 4bugImage.onload = function () { 5 context.drawImage(bugImage, bug.x, bug.y); 6}

setIntervalでジャンプ処理するたびにここを通っていますが、onloadメソッドはイメージソースの読み込み完了時に非同期で呼び出されるのです。
うまく成功したとしても、非同期描画になり、描画された頃には虫は次の場所へ移動している可能性があります(「残像だ」)。
また、この記述方式だと、おそらく2回目以降はbug.png読み込みがキャッシュ経由して一瞬で終わり、onload = funct...と悠長に登録したものが、呼び出されもしないということも多々発生しているはずです。

javascript

1var bugImage = new Image(); 2bugImage.onload = function () { 3 context.drawImage(bugImage, bug.x, bug.y); 4} 5bugImage.src = "images/bug.PNG";

キャッシュで呼び出しミスが発生しないためには、先にonload登録をして、その後読み込むように書きます。
これは単純にImageの読み込みの定跡なので、まる覚えして、今後気をつけて下さい。

で、ゲームが成立するためには、頻繁に呼び出すsetInterval中にこの非同期呼び出しをしないような工夫が必要です。
backgroundbugImageは最初に読み込んで、後は使いまわしましょう。大体の流れはこんな感じです。

var image_count = 2;// 2個読み込むよ var load_image = function(){ image_count--; if (image_count == 0){ game_start();// 画像2ファイルの読み込みが完了したらゲームスタートです。 } }; var bugImage = new Image(); bugImage.onload = load_image; bugImage.src = "images/bug.PNG"; var background = new Image(); background.onload = load_image; background.src = "images/lawn.jpg"; var game_start = function(){ // この中にいままで書いてた本体部分を記述してください。 }

こうすると、画像読み込み完了ごとにload_imageが呼び出されることで、image_countが減っていき、0になった時点(=すべての画像読み込みが完了した時点)でゲームスタートです。
ゲームスタート時点で画像の読み込みは事前に完了していることが保証されるので、jumpの中身は

javascript

1 context.clearRect(0, 0, canvas.width, canvas.height); 2 context.drawImage(background, 0, 0); 3 context.drawImage(bugImage, bug.x, bug.y)

こういう風に、寄り道なしでまっすぐに記述できます。
これでバグは消え(むしろ現れ?)、判定もうまくいくようになるはずです。

投稿2017/08/01 01:28

zohnam

総合スコア1441

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

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

mercredi

2017/08/01 02:12

なるほど!素晴らしいです。とてもわかりやすく何度も読み返しました、ありがとうございました。 Jumpの中身は -------------- function jump() { bug.x = (Math.random() * 500 + 1) + 1; //ここの計算式はモジュールを使う必要ありませんでした。 bug.y = (Math.random() * 500 + 1) + 1; bug.r = 32; context.clearRect(0, 0, canvas.width, canvas.height); context.drawImage(background, 0, 0); context.drawImage(bugImage, bug.x-32, bug.y-32)//Imageだとサークルと違って座標が左上にくるらしいので、半径分(32)マイナスしました。 clearInterval(jumpInterval); jumpInterval = setInterval(jump, interval); } ----------------------------- (すみません、コメント欄だとコードも文章も一緒になっちゃうみたいで。。) このように書き、言われた通りにすべて直したら成功しました。ありがとうございました!
guest

0

javascript

1bug.x = (Math.random() * 500 + 1) + 1;

これって、カッコを外して

bug.x = Math.random() * 500 + 2;

ということになります。虫の座標範囲だから多少間違ってても問題ありませんが、今後ゲームを作る上でランダムを使いこなせないと致命的です。
例えば、サイコロの1~6を出す場合は、こう記述します。

javascript

1var n = Math.floor(Math.random() * 6) + 1;

Math.floor(Math.random() * 6) で0~5の6つの数字が出ます。それに1を足して、1~6になります。
一定範囲の整数値であれば、数字が違うだけで、このパターンになりますので、覚えておきましょう。
考え方としては、出したい数字の範囲がいくつあるのか数えて、その数字が「かけるいくつ」の部分になります。
そして、出したい数字の最小値が、「たすいくつ」の部分になります。
範囲の数字を考えるときは、最小値・最大値を「含むのか含まないのか」に注意しましょう。

もうひとつ、ランダムな成功判定のやり方です。
命中率のパラメータがパーセント単位でhitに入ってるとして、このようになります。

javascript

1if (Math.floor(Math.random()*100)) < hit){ 2 // 判定成功 3} else { 4 // 判定失敗 5}

ランダム値は0~99の100パターン出現します。
hitに20が入っていたとしたら、0~19の20パターンでは判定成功します。20~99の80パターンでは失敗します。
つまり、成功率20%で、成功判定側の処理に行きます。

このふたつを覚えておけば、あとはなんとでも応用できるかと思います。

投稿2017/08/01 04:09

zohnam

総合スコア1441

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

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

mercredi

2017/08/12 16:58

お礼が遅くなってしまってすみません。丁寧な解説本当にありがとうございます。 ランダムの使い方勉強になりました。ランダムの計算式を作るときに理屈で覚えておけばわかりやすいですね。数学の先生みたいです(笑)ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問