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

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

新規登録して質問してみよう
ただいま回答率
85.50%
C#

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

Unity3D

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

2回答

3890閲覧

Unity プレハブを作りオブジェクトそれぞれ処理を実行

torano

総合スコア92

C#

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

Unity3D

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

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

1クリップ

投稿2016/08/16 14:37

#環境
Unity5.4
mono4.4.2

#やっていること
ゲームオブジェクトを適当にひとつ作りフォントを黄色にした後、以下のスクリプトをコンポーネントとして埋め込みました。

このスクリプトはマウスでクリックした場所にそのオブジェクトがあれば赤色にし、時間経過で元の黄色に戻るというスクリプトです。

using UnityEngine; using System.Collections; public class myscript : MonoBehaviour { GameObject obj; Color c; bool flg = false; int counter = 0; void Update () { if (Input.GetMouseButtonDown (0)) { Vector3 pos = Input.mousePosition; Ray ray = Camera.main.ScreenPointToRay (pos); RaycastHit hit; if (Physics.Raycast (ray, out hit, 100f)) { obj = hit.collider.gameObject; c = obj.GetComponent<Renderer> ().material.color; obj.GetComponent<Renderer> ().material.color = Color.red; counter = 100; flg = true; } } if (flg) { if (--counter == 0) { flg = false; obj.GetComponent<Renderer> ().material.color = c; } } } }

実行し、クリックすると少しの間赤色になった後、黄色に戻ります。

このゲームオブジェクトのプレハブを作り、ゲームオブジェクトを幾つか複製して実行。

#わからないこと
赤色にはなるのですが、少し待っても元の色(黄色)に戻りません。

いろいろ試行錯誤してみて、スクリプトを以下のように変更してみました。

using UnityEngine; using System.Collections; public class myscript : MonoBehaviour { GameObject obj; Color c; bool flg = false; int counter; void Start () { c = GetComponent<Renderer> ().material.color; // 変更点 } void Update () { if (Input.GetMouseButtonDown (0)) { Vector3 pos = Input.mousePosition; Ray ray = Camera.main.ScreenPointToRay (pos); RaycastHit hit; if (Physics.Raycast (ray, out hit, 100f)) { obj = hit.collider.gameObject; obj.GetComponent<Renderer> ().material.color = Color.red; counter = 100; flg = true; } } if (flg) { if (--counter == 0) { flg = false; GetComponent<Renderer> ().material.color = c; // 変更点 } } } }

このスクリプトだと最後にすべて黄色に戻りますが、想定していた結果とは違いました。

これだと、いくつか赤色にした場合、すべて一斉に黄色になってしまします。それぞれのオブジェクトが、それぞれクリックした時間から一定時間後に元の色に戻る、というようにしたいです。

例えば、A,Bというオブジェクト(プレハブ)があったとします。まずAをクリックして赤色にし、次にBをオブジェクトを赤にします。Aを最初に押したので、Aが先に元の色に戻り、次にBが元の色に戻る、というようにです。

#疑問点
一つ目は、最初のスクリプトではなぜ元の色に戻らないか。

二つ目は、どのようにすればうまくいくか。

よろしくお願いします。

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

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

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

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

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

guest

回答2

0

using UnityEngine; using System.Collections; public class myscript : MonoBehaviour { GameObject obj; Color c; bool flg; int counter; void Start () { c = GetComponent<Renderer> ().material.color; } void Update () { if (Input.GetMouseButtonDown (0)) { Vector3 pos = Input.mousePosition; Ray ray = Camera.main.ScreenPointToRay (pos); RaycastHit hit; if (Physics.Raycast (ray, out hit, 100f) && hit.collider.gameObject.name == gameObject.name) { obj = hit.collider.gameObject; obj.GetComponent<Renderer> ().material.color = Color.red; flg = true; counter = 100; } } if (flg) { Debug.Log (counter); if (--counter == 0) { flg = false; obj.GetComponent<Renderer> ().material.color = c; } } } }

投稿2016/08/20 11:50

torano

総合スコア92

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

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

0

ベストアンサー

ソースを見たところ、クリック時の動作がクリックされたオブジェクトを赤色にする&自分のカウンターを100にする&フラグを立てるとなっています。
つまり、あるオブジェクトの被クリックに対し、全てのオブジェクトが一斉に反応しています。
1、2の両疑問点共にここが原因と思われます。

疑問点1

何かしらのオブジェクトがクリックされた場合、全てのオブジェクトがクリックされたオブジェクトを赤色にしています。
それぞれのオブジェクトはこのとき赤色にしたオブジェクトを覚えておき、カウンターが0となった際に記憶していたオブジェクトを黄色にしています。
単体のオブジェクトでしたら問題ありませんが、複数のオブジェクトが同様のロジックで動いた場合、黄色にすべきオブジェクトの変数には最後に赤色になったオブジェクトが共通で入っていることになります。
このため最後にクリックされたオブジェクト以外は時間経過で黄色になりません。
流れとしては恐らく以下のようになっております。時間経過で下方向へ状態が変化します。

オブジェクトA.objオブジェクトB.obj操作
NullNull
オブジェクトAオブジェクトAオブジェクトAをクリック
オブジェクトBオブジェクトBオブジェクトBをクリック
100フレーム経過
オブジェクトBオブジェクトB

両オブジェクト共にオブジェクトBを黄色くするため、オブジェクトAは赤いままとなります。
直接的な解決策としては、二つ目に挙げられたソースのロジックで問題無いと思われます。

疑問点2

上で述べた通り、何かしらのオブジェクトクリック時には全てのオブジェクトが反応しています。
このとき全てのオブジェクトが一斉にタイマーの初期処理も行っているため、結果としてタイマーの始点が揃っていると思われます。
例示されていたA,Bオブジェクトの挙動を図で示しますと、恐らく以下のようになっております。

オブジェクトAオブジェクトB操作
Aの被クリックに反応Aの被クリックに反応オブジェクトAをクリック
Aを赤色にするAを赤色にする
Aのカウンター初期化Bのカウンター初期化
10フレーム経過
Bの被クリックに反応Bの被クリックに反応オブジェクトBをクリック
Bを赤色にするBを赤色にする
Aのカウンター初期化Bのカウンター初期化
100フレーム経過
Aを黄色にするBを黄色にするA,B両方のカウンターが0以下になる

解決策としては

  • クリック時の条件にクリックされたオブジェクトが自分自身であるという条件を加える
  • 既にフラグが立っていればタイマーの初期化処理をしない

等が考えられます。

なお個人的な意見ですが、この手のアクションをコードベースで制御するのであればコルーチンを用いた方が簡易ではないかと思います。

投稿2016/08/19 04:54

eckolo

総合スコア27

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

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

torano

2016/08/20 11:49 編集

ありがとうございます。なぜうまくいかないかがよくわかりました。要するにクリックするたびに2つ目のif文内の処理が行われていて、objが最後にクリックしたオブジェクトになっているわけですね。 2つ目のスクリプトを以下のように変更してみたらうまくいきました。 2つ目のif文の条件をPhysics.Raycast (ray, out hit, 100f) && hit.collider.gameObject.name == gameObject.name)に。 最後の色を元に戻す部分をobj.GetComponent<Renderer> ().material.color = c;に。 他の解決策も試してみたのですが実装の仕方がよくわかりませんでした。。。 もしよろしければ教えてください。よろしくお願いします。
eckolo

2016/08/23 21:02

hit.collider.gameObject.name == gameObject.nameですと、偶然別オブジェクト同士の名称が同じ場合に判定がおかしくなります。hit.collider.gameObject == gameObjectの方が正確な判定となります。 なお「既にフラグが立っていればタイマーの初期化処理をしない」方法ですが、よくよく考えてみたところ結局上記の判定が別途必要になりました。 フラグの管理のみでこの問題を解決するのは困難かと思われます。申し訳ありません。 コルーチンとは、フレーム毎の連側的な状態変化を関数内での繰り返し処理として記述する手法です。 「一連のアクション」を実装する場合、非常に有用となります。 コルーチンに関しましては、既に多数の解説が存在しています。「コルーチン」の名称で色々と調べてみてください。
torano

2016/08/25 12:00

ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問