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

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

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

Q&A

解決済

2回答

1272閲覧

Unityで複数のPlayerを同じスクリプトで制御したい

KeyCase

総合スコア1

0グッド

0クリップ

投稿2021/05/24 03:20

編集2021/05/27 04:25

Unityで複数のPlayerを同じスクリプトで制御したい

マウスのみで遊べる2Dゲームを制作しているのですが
①カーソルが重なっていると、どの位置から弾が発射されるかのSpriteを描画
②クリックされると拡大され且つ弾発射準備
③クリックが離されると弾を発射
④弾発射後再度撃てるようになるまでのクールタイム

という処理をするオブジェクト(Player)をシーン上に
4つ置いているのですが、1つのオブジェクトが弾発射後クールタイムに入っている時に
残りの3つのオブジェクトにカーソルが触れると弾を発射していないのに
クールタイムに入ってしまいます。
弾を発射したオブジェクトにのみクールタイムに入ってほしいのです
クールタイムのフラグを共有しているから
上記のようになってしまうと思うのですが
どのようにしたら共有しないようにできるでしょうか
4つのオブジェクトにPlayerMouseSelectをアタッチしています。

よろしくお願いします。

該当のソースコード

C#

1public class PlayerMouseSelect : MonoBehaviour 2{ 3 [SerializeField] 4 private GameObject clickEffect, shotEffect; 5 6 [SerializeField] 7 public GameObject mouseObj; 8 private PlayerSelectManager psMg; 9 private GameObject target; 10 private GameObject child; 11 private int enterTimer; 12 private int clickTimer; 13 14 private Vector3 scale; 15 private Vector3 normalScale; //元の大きさを保存 16 17 [SerializeField] 18 private int coolTime; //弾発射のクールタイム 19 private float coolTimer; 20 21 private AudioSource audioSource; 22 public List<AudioClip> audioClip = new List<AudioClip>(); //SE 23 24 // Start is called before the first frame update 25 void Start() 26 { 27 audioSource = gameObject.AddComponent<AudioSource>(); 28 29 psMg = mouseObj.GetComponent<PlayerSelectManager>(); 30 enterTimer = 0; 31 clickTimer = 0; 32 33 scale = transform.localScale; 34 normalScale = scale; 35 36 coolTimer = 0; 37 } 38 39 // Update is called once per frame 40 void Update() 41 { 42 target = psMg.GetTargetObj(); 43 44 if (!target) return; 45 46 MouseEnter(); 47 MouseDown(); 48 MouseUp(); 49 MouseExit(); 50 CoolTime(); 51 } 52 53 //カーソルが重なった時 54 void MouseEnter() 55 { 56 if (psMg.GetCoolFlg()) return; 57 if (psMg.GetPlayerHit() && enterTimer == 0) 58 { 59 enterTimer = 1; 60 61 //拡大 62 ExpansionScale(0.15f, 0.15f); 63 64 //SE 65 audioSource.PlayOneShot(audioClip[0]); 66 67 //十字のレーザーポインタ描画 68 psMg.LaserPointer(true, false); 69 } 70 71 } 72 73 //クリック時 74 void MouseDown() 75 { 76 if (psMg.GetCoolFlg()) return; 77 if (psMg.GetPlayerClick() && clickTimer == 0) 78 { 79 clickTimer = 1; 80 81 //クリック時のエフェクト生成 82 Instantiate(clickEffect, target.transform.position, target.transform.rotation); 83 audioSource.PlayOneShot(audioClip[1]); 84 85 //拡大 86 ExpansionScale(0.5f, 0.5f); 87 88 //色を水色 89 psMg.ColorChange(0.0f, 0.9f, 1.0f, 1.0f); 90 //十字のコライダーをtrue 91 psMg.LaserPointer(true, true); 92 } 93 } 94 95 //クリック離した時 96 void MouseUp() 97 { 98 if (psMg.GetCoolFlg()) return; 99 100 if (psMg.GetPlayerShot()) 101 { 102 clickTimer = 0; 103 104 psMg.SetPlayerClick(false); 105 psMg.SetCoolFlg(true); 106 //ショット時のエフェクト生成 107 Instantiate(shotEffect, target.transform.position, target.transform.rotation); 108 audioSource.PlayOneShot(audioClip[2]); 109 110 //元の色に戻す(白) 111 psMg.ColorChange(1.0f, 1.0f, 1.0f, 1.0f); 112 113 //十字のレーザーポインタ描画しない 114 //十字のコライダーをfalse 115 psMg.LaserPointer(false, false); 116 117 //拡大していたのを元の大きさに戻す 118 NormalScale(); 119 } 120 } 121 122 //カーソルが離れた時 123 void MouseExit() 124 { 125 if (psMg.GetCoolFlg()) return; 126 if (!psMg.GetPlayerHit()) 127 { 128 enterTimer = 0; 129 //十字のレーザーポインタ描画しない 130 //十字のコライダーをfalse 131 psMg.LaserPointer(false, false); 132 133 //拡大していたのを元の大きさに戻す 134 NormalScale(); 135 } 136 } 137 138 //クールタイム 139 void CoolTime() 140 { 141 if (!psMg.GetCoolFlg()) 142 { 143 coolTimer = 0; 144 return; 145 } 146 psMg.SetPlayeShot(false); 147 if (psMg.GetCoolFlg()) 148 { 149 psMg.ColorChange(1.0f, 1.0f, 1.0f, 0.5f); 150 //NormalScale(); 151 psMg.LaserPointer(false, false); 152 coolTimer += Time.deltaTime; 153 if (coolTimer >= coolTime) 154 { 155 psMg.ColorChange(1.0f, 1.0f, 1.0f, 1.0f); 156 psMg.SetCoolFlg(false); 157 } 158 } 159 160 } 161 162 //targetを拡大 163 void ExpansionScale(float addX, float addY) 164 { 165 scale.x += addX; 166 scale.y += addY; 167 target.transform.localScale = scale; 168 } 169 170 //元の大きさ 171 void NormalScale() 172 { 173 scale.x = normalScale.x; 174 scale.y = normalScale.y; 175 target.transform.localScale = scale; 176 } 177 178}

C#

1public class PlayerSelectManager : MonoBehaviour 2{ 3 private float maxDistance; //Rayの長さ 4 private int layerMask; //1~7番目のレイヤーを無視 5 private bool playerHit; //Playerに触れている 6 private bool beforShot; //クリック時 7 private bool shot; //クリック離すと弾を発射 8 private bool coolFlg; //弾発射のクールタイム 9 10 //選択されているPlayer 11 private GameObject targetObj; 12 public GameObject GetTargetObj() { return targetObj; } 13 public void SetTargetObj(GameObject obj) { targetObj = obj; } 14 15 //マウスカーソルが当たっているかどうか 16 public bool GetPlayerHit() { return playerHit; } 17 public void SetPlayerHit(bool hit) { playerHit = hit; } 18 19 //左クリック押下 20 public bool GetPlayerClick() { return beforShot; } 21 public void SetPlayerClick(bool click) { beforShot = click; } 22 23 //左クリック離した 24 public bool GetPlayerShot() { return shot; } 25 public void SetPlayeShot(bool shotF) { shot = shotF; } 26 27 //クールタイム 28 public bool GetCoolFlg() { return coolFlg; } 29 public void SetCoolFlg(bool flg) { coolFlg = flg; } 30 31 //targetObjの色を変更 32 public void ColorChange(float r, float g, float b, float a) 33 { targetObj.GetComponent<SpriteRenderer>().color = new Color(r, g, b, a); } 34 35 //レーザーポインターの描画、コライダー 36 public void LaserPointer(bool spriteFlg, bool coliderFlg) 37 { 38 //targetObjの子供 39 foreach (Transform childObj in targetObj.transform) 40 { 41 childObj.GetComponent<SpriteRenderer>().enabled = spriteFlg; 42 43 //targetObjの孫 44 foreach (Transform grandChildObj in childObj) 45 { 46 grandChildObj.GetComponent<BoxCollider2D>().enabled = coliderFlg; 47 } 48 } 49 } 50 51 // Start is called before the first frame update 52 void Start() 53 { 54 maxDistance = 1.0f; 55 layerMask = 1 << 8; 56 playerHit = false; 57 beforShot = false; 58 shot = false; 59 coolFlg = false; 60 } 61 62 // Update is called once per frame 63 void Update() 64 { 65 //メインカメラ上のマウスカーソルのある位置からRayを飛ばす 66 Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); 67 68 RaycastHit2D hitObj = Physics2D.Raycast((Vector2)ray.origin, (Vector2)ray.direction, maxDistance, layerMask); 69 70 //if (GetCoolFlg()) return; 71 //当たったもの(hitObj)がPlayeなら 72 // hitObjを少し拡大、レーザーポインター描画(hitObjの子供) 73 if (hitObj.collider != null) 74 { 75 if (hitObj.collider.gameObject.layer == LayerMask.NameToLayer("Player")) 76 { 77 SetTargetObj(hitObj.collider.gameObject); 78 SetPlayerHit(true); 79 } 80 } 81 else 82 { 83 //当たっていなかったら元の大きさに、レーザーポインターfalse 84 SetPlayerHit(false); 85 } 86 87 //クリックされたらhitObjさらに拡大、色を水色、レーザーポインターの当たり判定true 88 if (GetPlayerHit()) 89 { 90 if (Input.GetMouseButton(0)) 91 { 92 SetPlayerClick(true); 93 } 94 } 95 else if (Input.GetMouseButton(0)) 96 { 97 if (GetPlayerHit()) 98 { 99 SetPlayerClick(true); 100 } 101 } 102 103 //クリック離すと弾が発射、hitObj元の大きさに、レーザーポインターfalse 104 if (GetPlayerClick()) 105 { 106 if (Input.GetMouseButtonUp(0)) 107 { 108 SetPlayeShot(true); 109 } 110 } 111 112 } 113 114}

試したこと

Playerごとにスクリプトを作成すれば動くが
同じスクリプトで制御したい。

OnMouseEnter()やOnMouseDown()等を使用したが
判定が反応しなくなったりする時があったので使用をやめた。

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

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

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

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

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

退会済みユーザー

退会済みユーザー

2021/05/27 06:42

あまりC#な書き方でない気がします…読みにくいです。 PlayerMouseSelectのUpdate内に追加、 if (!target) return; 次の行に if (!target != this.gameObject) return; こうするとどうなりますか?
KeyCase

2021/05/29 09:04 編集

コメントありがとうございます。 if (!target != this.gameObject) return; を追加すると、PlayerMouseSelect内の 各関数が呼ばれなくなしました。
guest

回答2

0

自己解決

フラグ関連をPlayerMouseSelectで
管理することにより解決しました。

投稿2021/06/01 09:29

KeyCase

総合スコア1

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

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

0

質問から気になっている部分通り、coolFlgをpsMgが持っているため、
MouseUp()から一度psMg.SetCoolFlag(true)されてしまうと
Enter、Upなどのメソッドで
if(psMg.GetCoolFlg()) return;となっていますので、以降の処理は打ち切ってしまいます。
原因はこの処理で間違いないかと思いますが他の問題も結構ありそうです。

コードを試した訳ではないので憶測ですが、
例えば、PlayerMouseSelectのUpdate内でif(!target) return;となっていますのでtargetを取得出来ていなければcoolTimeも走りません。

MouseEnter,Down,Up,Exit,CoolTimeと実行しますが、psMgの状態targetObjはrayのHitで変更される。という部分を見るに
Enter→Down→ここで別オブジェクトにドラッグ→Upなどでのバグも発生しそうな気がします。

個人的にcoolTimeが何を指しているか?がちょっと分かりませんでした。
Playerの操作を一定以上受け付けないようになのか、
選択されたオブジェクトは一定時間後にならないと弾を発射出来ないという意味なのか?
感覚的には下記ですが、コードを見ると上記を作りたいように見えます、、、

共有しない方法となってますが、psMgは一つ、PlayerMouseSelectが各オブジェクトごと、となっている様ですので個々の情報はPlayerMouseSelect側で管理するか。psMgに配列など用意して個々を判断するか?でしょうか。

正直、psMgの処理はEventSystemsを利用した方が楽な気がしますが、使う使わないは個人の自由だと思いますので。

投稿2021/05/29 19:51

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問