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

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

ただいまの
回答率

88.90%

Javascript 2つの同一色のブロックを消した際、その上に乗っていたブロックを落下

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 204

OG.

score 4

前提・実現したいこと

CANVAS APIにてJavascriptの学習を行っております。
上の記述で消した2つの四角の上にも、まだブロックがある場合
(空中に浮いている状態になっているもの)をy += gravity して下のブロックがある箇所or地面まで持っていきたいと思っているのですが、思い詰まっています。

前回に引き続きですが、考え方・記述等ご助力頂ければ幸いです。

該当のソースコード(必要そうな個所を記載)

      let canvas = $("maingame");
      let ctx = canvas.get(0).getContext("2d"); //決まり文句

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

      let playGame;

      let playAnimation = false;

      let score = 0;
      let koWidth = 80;
      let koHeight = 100;

      let colors = ["rgb(240,255,240)", "rgb(81, 102, 107)", "rgb(92, 66, 123)", "rgb(39, 125, 160)"];


      let title = $("#title");
      let startButton = $("#startAnimation");
      let gameover = $("#gameover");
      let restart = $("#restart");
      let titleback = $("#titleback");

      //抽象化
      function Shape(x, y, width, height, gravity, boxColor) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.gravity = gravity;
        this.boxColor = boxColor;

        this.fixed = false; //静止の有無
      };

      Shape.prototype.update = function (others) {
        //地面の設定
        let ground = {
          x: 100,
          y: canvasHeight - 50,
          width: canvasWidth - 200,
          height: 0
        }
        //地面に触れるor触れないの処理
        if (!this.fixed && this.collision(ground)) {
          this.y = canvasHeight - this.height - 50;

          if ((this.y > koHeight && this.x > koWidth && this.x + this.height <
              canvasWidth -
              koWidth)) {//エリア内に全て入っていればOK
            score++;
            return this.fixed = true;
          } else {//エリア外に触れてるのでgameover演出
            gameover.show();
            restart.show();
            playAnimation = false; 

            restart.click(function (e) {
              location.reload();
            });
          }
        }

        if (this.fixed) return;

        others.some(other => {
          //他のShapeとの衝突確認
          if (other.fixed && other.collision(this)) {
            this.y = other.y - this.height;

     if(this.boxColor === other.boxColor ){ 
              //同色が積まれたときに消す記述
              this.number = 0;
              this.x = baseX + 1;
              this.y = baseY + 1;
              this.width = 0;
              this.height = 0;

              other.x = baseX + 2;
              other.y = baseY + 2;
              other.width = 0;
              other.height = 0;
              score++

             /*if {
               ここら辺で追記…?

            }*/

            }

            if (this.y > koHeight && this.x > koWidth && this.x + this.height <
              canvasWidth -
              koWidth) {
              score++;
              return this.fixed = true;

            } else {
              gameover.show();
              restart.show();
              playAnimation = false; //gameover演出

              restart.click(function (e) {
                location.reload();
              });
            }
          }
        });

        if (!this.fixed) {
          this.y += this.gravity;
          //1コマごとの変化の記述はここで
        }
      }

      Shape.prototype.render = function (ctx) {
        ctx.beginPath();
        ctx.fillStyle = this.boxColor; //物体の色、場所
        ctx.rect(this.x, this.y, this.width, this.height);
        ctx.fill();

        ctx.strokeStyle = "rgba(5, 5, 5, 0.9)";
        ctx.lineWidth = 1;
        ctx.stroke();
      }

      Shape.prototype.collision = function (shape) {
        let rect1 = this,
          rect2 = shape;
        return rect1.x < rect2.x + rect2.width &&
          rect1.x + rect1.width > rect2.x &&
          rect1.y < rect2.y + rect2.height &&
          rect1.height + rect1.y > rect2.y; //衝突判定
      }
      /*ここから初期位置配置*/
      let shapes = new Array();

      function onClick() { //出現させるブロックの位置、大きさ、落ちる速度
        let width = height = Math.floor(Math.random() * 80 + 30);
        let x = event.clientX - blockP.offsetLeft - width / 2;
        let y = 10;
        let gravity = 5;
        let boxColor = colors[Math.floor(Math.random() * colors.length)];

        shapes.push(new Shape(x, y, width, height, gravity, boxColor));
      }

      shapes.addEventListener('click', onClick, false);
      /*ここまで*/

      function animate() {
        ctx.clearRect(0, 0, canvasWidth, canvasHeight);
        ctx.drawImage(img, 100, 648, 400, 60); //土台

        for (let shape of shapes) {
          shape.update(shapes);
          shape.render(ctx);
        }

        if (playAnimation === true) {
          setTimeout(animate, 33);
        };
      };

      animate();

試したこと

ここらへんで記載するのかなとは思ってます。(コメントアウトしてる部分)
othersがfixedになっていて、かつcollisionがふれていない対象を取れれば実装できるかと考えているのですが、
コメントアウトの部分だとothers.collisionがfunctionになっていない為エラーが発生してしまいました。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 2

checkベストアンサー

+1

64行目 if (this.fixed) return;を消して、
66行目 others.some(other => {
this.fixed=others.some(other => {とし、{}内で停止するときだけtrueを返すようにすれば、fixedの更新と停止判定が同時にできるようになります。

質問と関係ないけど92行目

if (this.y > koHeight && this.x > koWidth && this.x + this.height < 
    canvasWidth - koWidth) {


x + heightwidthと比較してるけど、あってるのかな?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/07/16 10:06

    回答ありがとうございます。

    すみません。64行目を消し、66行目のものに変更をかけたのですが最初のブロックが地面に接した時点でブロックが消失するようになってしまいました…
    これは更に別途some内に記述が必要なのでしょうか?

    キャンセル

  • 2020/07/16 20:12

    //地面に触れるor触れないの処理
    の部分をothers.some()のブロックの下に持っていったほうが良いかもです。
    地面に衝突したあと、下にブロックが無いのでそのまま落下してるかもしれません。

    もう一つはshapesの自分自身との衝突判定を除外しないと、落下が止まった瞬間自分自身と衝突して消えてしまってるかもしれません。
    `this===other`で除外できればいいですが、うまく動かないのであれば、x,yが同じ値のshapesはないと仮定して`this.x==other.x && this.y==other.y`で判定するくらいですかね。

    単純にsomeの中に追加してしまうとshapes数×shapes数 回、地面との判定をすることになるのでちょっと無駄が多いです。(shapes数 回あれば十分)
    ground自体を特別なshapesとして追加してしまうのは一つの手です。`isErasable`等の属性を追加して、消滅判定はスキップしたり。

    キャンセル

  • 2020/07/20 10:38

    評価が遅くなり大変申し訳ございません。
    カレイドスコープさんのコメントを参考に色々模索してみたのですが、今度は地面上でビタビタと振動を続けたり逆方向に飛んで行くようになってしまい…

    恐らく大きく修正が必要だと判断したため、Javascriptのロジックの勉強がもう少しじっくりと時間をかけて行って実装しようと思います。
    ご丁寧にご説明頂きありがとうございます!

    キャンセル

0

this.fixed を変更する条件を考えてみましょう。

現状は、他のShapeと接触したら、update() しても値が変わらないようにするためのフラグになっているはずです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2020/07/15 17:41

    回答ありがとうございます。
    原因としては some()での衝突有無の検出でtrue or false仕分け→衝突した時点でreturn文でthis.fixed = trueにしてしまっているのでそれ以降はtrueのままになってしまっている。
    なので下のものが消えてしまってもtrue状態を抜けずに物体が浮いてしまっている。
    って感じでしょうか?

    つまりreturn文を改修する必要があるってことですかね…(場所的にはコメントアウトした上のreturn付近…?)

    キャンセル

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

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

関連した質問

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