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

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

ただいまの
回答率

90.49%

  • C#

    7390questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Unity3D

    1347questions

    Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

衝突判定でflagをtrueにしたのに、メソッドではfalseのままになる。

解決済

回答 3

投稿

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

Kuronekoya

score 18

いつもお世話になっています。
今回はUnity3Dについて伺います。

現在落ちゲームを作っているのですが、衝突判定とメソッドが上手くかみ合いません。
というのも、ブロックが下に落ちるメソッドを作り、壁にブロックが衝突した時点でそのメソッドを終わらせたいと思い、
flagがfalseの時、メソッド内で処理を繰り返し行い、ブロックが壁に衝突した時点でflagをtrueにして処理を終わらせる、という手を取ろうと思ったのですが、OnCollisionEnter内ではflagはtrueになるものの、メソッド内ではfalseのままなのです。

説明ではわかり難いと思いますが、原因のわかる方、どうぞご教授いただけませんでしょうか。よろしくお願いいたします。

Class A
mBlock [0].FallBlock (block);


Class B
bool flag = false;

public void FallBlock(Block block){
 //flagがfalseの間はブロックが落ちる
  while(flag == false){
    //ブロックが落ちる処理
    Vector3 blockPos = block.transform.position;
    blockPos -= -1;
    block.transform.position = blockPos;
  }
}

private void OnCollisionEnter(Collision collision){
  //壁に衝突したらflagをtrueにする
  if(collision.gameObject.tag == "Wall"){
    flag = true;
  }
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 3

checkベストアンサー

0

FallBlock() 内の while がCPU占有ループ(CPU時間をOSや他のスレッドに渡さずにずっとCPUを使い続ける状態)になっているように思われます。
gameobject の移動は Update() イベントハンドラを使うのが一般的ではないかと。

// BlockCtl.cs
using UnityEngine;
using System.Collections;

public class BlockCtrl : MonoBehaviour {
  bool flag = false;
  void Start () {
  }
  void Update() {
    if (!flag) {
      Vector3 blockPos = transform.position;
      blockPos -= -1;
      transform.position = blockPos;
    }
  }
  void OnCollisionEnter(Collision collision) {
    //壁に衝突したらflagをtrueにする
    if(collision.gameObject.tag == "Wall"){
      flag = true;
    }
  }
}

ゲームコントローラー他の設計が解らないので必ずしもこのような記述にはならないこともあると思いますが、ご参考になれば。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/04/27 15:09

    tkanda様、ご回答ありがとうございます。
    Update()を使えば確かに早いですね!この方法で上手くいきそうです。
    コードまで書いていただき、本当にありがとうございます。
    この方法を使って再度書き直してみようと思います。
    ご回答ありがとうございました!

    キャンセル

0

Unity3Dを触ったことがないので、的外れなことを書いているかもしれませんが、

while(flag == false){
    //ブロックが落ちる処理
    (略)
  }
}


このループはループ内でフラグを変更する箇所がないので、他に非同期でフラグを変えてくれる処理がないと永遠にループし続けることになりませんか?

OnCollisionEnter()というイベントハンドラがありますが、提示いただいているコードを見る限り、FallBlock()関数から一旦抜けないとOnCollisionEnter()へ処理が移らないのではないでしょうか?

もし、別の場所でTask.Run()している処理があるのであればその処理で発生する他のイベントでフラグを戻している処理がないか確認してみてください(あまり論理的な方法ではないですが、フラグを変化させている箇所にブレークポイントを貼りまくってどこでフラグを戻しているかデバッガで追うのも一つの手です)。

あとはflagの宣言にvolatileをつけて、コンパイラから最適化されないようにすることで、回避できるかもしれません。
while内部でflagが変化する処理がないため、flagのチェック処理がスキップされる場合があります。volatileをつけて宣言すると最適化の際にも常に新しいflagの値をチェックしてくれるようになります。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/04/27 15:07

    KoichiSugiyama様、ご回答どうもありがとうございます。
    なるほど。FallBlock()関数の途中でOnCollisionEnter()へ移すことはできないのですね。
    一応ブレークポイントを置いたりDebug.Logを置いて色々調べてはみたのですが、結果はわかりませんでした…
    初心者すぎて、volatileというものを初めて聞きました。そんな方法があるのですね!
    一度調べてみます。
    ご回答、どうもありがとうございました!

    キャンセル

0

whileの用法は別として、クラス内の変数の値が変わるのはおかしいです。
(「flagがtrue/falseになる」のはDebug.Log等で確認済みという想定で回答します)

1.記載の部分の他に、flagをfalseにしている部分はありませんか?(そこが暴発していませんか?)

2.衝突しているのは正しいオブジェクトですか?
mBlock [0].FallBlock (block);
という部分を見るに、ブロックは複数あるようですが、flagがtrueにならない(=動き続ける)のはmBlock[0]で間違いありませんか?
「ブロックAは衝突していて、ブロックBは衝突していない」という状況だった場合、ブロックAではflag=true、ブロックBではfalg=falseとなりますが、この点は確認していますか?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2016/04/27 15:15

    sakura_hana様、ご回答ありがとうございます。
    おっしゃる通り、Debug.Logとブレークポイントで確認済みです。

    1の回答ですが、記載の部分以外にflagを変えている部分がなく、暴発してるような気配がありません…。
    そして2の回答なのですが、ブロックはこれから増やしていくために配列に入れていますが、現在の時点ではまだ1つしか作っていないので、1つだけが反応している、というのも考えにくいようです。
    そもそもの設計が悪いのかもしれません…ご回答いただいたのに解決に至らず申し訳ありません…。
    もう一度、設計からやり直してみようと思います。
    前回に引き続き、ご回答いただき本当にありがとうございました!

    キャンセル

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

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

関連した質問

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

  • C#

    7390questions

    C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

  • Unity3D

    1347questions

    Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。