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

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

ただいまの
回答率

88.60%

CANVASで描いた正方形の輪郭を認識させたい

解決済

回答 1

投稿

  • 評価
  • クリップ 1
  • VIEW 287

OG.

score 7

前提・実現したいこと

正方形の座標

ここに質問の内容を詳しく書いてください。
2Dグラフィック制作を目的としたJavascriptのCANVAS APIの学習を行っており、正方形と正方形の指定した座標が乗ったときに上に乗ったように制止するプログラムを記述したいと考えています。
自分なりの範囲で調べたりは行ったのですが、衝突検出した際にものを乗せる等のイベントの記述(消す等があったが)があまり見受けられなかったのでご質問しました。
参考になるサイト等が万が一ございましたら、またアドバイス等ありましたらご助力頂ければ幸いです。

発生している問題・エラーメッセージ

CANVASで正方形をランダムで生成し、上から下に落とし、地面に乗せるプログラムまでは実装済み。

エラーメッセージ

該当のソースコード

<!DOCTYPE HTML>
<HTML>
<HEAD>
<TITLE>test</TITLE>
<META charset="utf-8">
</HEAD>
<BODY>
<CANVAS id ="view_1" height= "600" width = "800"></CANVAS>
<div>
  <button id="startAnimation">START!</button>
  <button id="stopAnimation">STOP</button>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script type="text/javascript">
  let canvas = $("#view_1");
  let ctx = canvas.get(0).getContext("2d");

  let canvasWidth = canvas.width();
  let canvasHeight = canvas.height();

  $(window).resize(resizeCanvas);

  function resizeCanvas(){
    canvas.attr("width", $(window).get(0).innnerWidth);
    canvas.attr("height", $(window).get(0).innnerHeight);
    canvasWidth = canvas.width();
    canvasHeight = canvas.height();
  };

  resizeCanvas();

  let playAnimation = true;

  let startButton = $("#startAnimation");
  let stopButton = $("#stopAnimation");

  startButton.hide();
  startButton.click(function() {
    $(this).hide();
    stopButton.show();

    playAnimation = true;
    animate();
  });

  stopButton.click(function(){
    $(this).hide();
    startButton.show();

    playAnimation = false;
    animate();
  });

let Shape = function(x, y,width,height,gravity){
  this.x = x;
  this.y = y;
  this.width = width;
  this.height = height;
  this.gravity = gravity;
};

let shapes = new Array();

for (let squere = 0; squere < 20; squere++){
  let x =  Math.random() * 500;
  let y = Math.random() * 500; //500 * 500px 内のどこかに生成
  let width = height = 20; //20pxの正方形
  let gravity = 5;
  shapes.push(new Shape(x, y, width, height, gravity));
};

  function animate(){
      ctx.clearRect(0, 0, canvasHeight, canvasWidth);
      ctx.fillStyle = "rgb(124, 219, 255)";
      let shapesLength = shapes.length;


      for(let i = 0; i < shapesLength; i++){
        let tmpShape = shapes[i];
        if(tmpShape.y + tmpShape.height > canvasHeight){
          tmpShape.y = canvasHeight - tmpShape.height;
        }

        ctx.fillRect(tmpShape.x, tmpShape.y, tmpShape.width, tmpShape.height);
        tmpShape.y += tmpShape.gravity; //重力
      };
    if(playAnimation===true){
      setTimeout(animate, 150);
    };
  };



  animate();

</script>
</BODY>
</HTML>

試したこと

if(tmpShape.y + tmpShape.height > canvasHeight){
tmpShape.y = canvasHeight - tmpShape.height;
}
以降に更にif文で分岐させて、
(x,y)~(x + width, y)の範囲と(x, y + height)~(x + width, y + height)の範囲が一致した際にtmpShape.gravity = 0; 

にするのが良いのかなとは考えているのですが、良い記述が思いつかず

補足情報(FW/ツールのバージョンなど)

ここにより詳細な情報を記載してください。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 1

checkベストアンサー

0

CANVAS APIの学習

google検索:「javascript collision detection」すると、MDN 2D 衝突検出 が出てきます。

MDNのページでは2種類のサンプルコードが示されていますので、ご質問の「試したこと」に示されるコードを見直すヒントになると思います(矩形ですと、1になりそうです)。

  1. 矩形の判定 … 「座標軸に沿ったバウンディングボックス」
  2. 円形の判定 … 「円形衝突」

ご質問のコード内で抽象化している Shape に衝突判定メソッドを実装すると大量の判定も楽できるかもしれません。
また、アニメーション表現の応用として Canvas API でシューティングゲームを作るテーマの 過去の質問&回答 もヒントになるかと思います。

追記)
現在、Canvas の下辺に到達したら停止するコードになっていますが、
更に、他のShape との衝突を判定して停止させる必要があります。

Codepen 動くサンプル

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/07/01 17:42

    解答ありがとうございます。提示して頂いたページで試行錯誤したのですが、直接物体を指定した場合の流れは何となくの流れは理解できたのですが、
    位置を個々で指定ではなく、乱数化した物体の場合はどうやって記述したらよいか案が出せずに居ます。
    (おっしゃっていただいた衝突判定メソッドを乱数化したものに指定する)
    理解が追い付かず申し訳ございませんが、もう少しだけご助力頂けたら幸いです。

    キャンセル

  • 2020/07/02 07:21 編集

    > 衝突判定メソッドを乱数化したものに指定する
    乱数を使う意図が読めないのですが(雪のように落ちるなど、動作のアレンジになるのでしょうか)、先ずは、等速で落ちる際の「個々の衝突時、停止して積み重なる動作」を考えましょう。
    回答欄に追記しています。

    キャンセル

  • 2020/07/02 18:12

    追記のものを参考にさせて頂き無事実装まで至りました。
    ご丁寧に回答いただきありがとうございました!

    キャンセル

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

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

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