bombが爆発した際、爆発範囲内に他のbombが含まれていたら連鎖させるような処理を施したいと考えて以下の内容を追加しました。
ですが、この状態でゲームを実行しbombをクリックすると「NullReferenceException: Object reference not set to an instance of an object」とエラーが発生してしまいました。
原因を自分なりに調査・模索したのですが、解決にたどり着けなかった為質問させて頂きたいと思います。
何卒宜しくお願い致します。
/// <summary>
/// 周囲のBallObjectを消去
/// </summary>
public void Explosion(GameObject deleteObj)
{
// bombの半径5mの範囲にあるBallObjectを全て消去
RaycastHit[] h = Physics.SphereCastAll(transform.position, 5.0f, Vector3.forward);
GameObject delObj;
foreach (RaycastHit hit in h)
{
if (hit.collider.CompareTag("Ball"))
{
delObj = Instantiate(deleteObj);
delObj.transform.position = hit.collider.gameObject.transform.position;
Destroy(hit.collider.gameObject);
} // 追加した部分・・・「NullReferenceException: Object reference not set to an instance of an object」とエラーが発生する
if (hit.collider.gameObject.GetComponent<BallObject>().color == GameResources.BallColor.bomb)
{
Debug.Log("連鎖");
}
}
}
Nullエラーの原因と致しまして、おそらく該当オブジェクトの初期化がされていなかった為ではないかと結論に至りました。
また、ご指摘のありました「prefabにbombなどの中身が入っていないのではないか」という件に関してですが、prefabはBallのみでBallGenerator.cs内でBallの色を変えてbombとbomb以外のBallを生成するというような処理を行っています。
重ねての質問で恐縮です。
TouchManager.cs内で処理を行いたいと考え---の中の部分を追加したのですが、画面内のbombがどの位置に(例:画面左端と右端に1個づつbombが)あったとしてもすべて同時に爆発してしまう状態となってしまいました。
自分なりに試行錯誤を繰り返してはいるのですが、思うように処理を実装できずにいます。
実現したい内容としましては
・bombによって破壊されたBallObjectをdestroyObjects配列に格納する
・destroyObjects内にbombが含まれているかどうかをチェックし、含まれていた場合はbombCountを増やす
・複数個のbombが爆発(bombCount>=2)した場合、初めに爆発したbombと同様に爆発を起こしBallObjectを破壊する ⇒ 連鎖させる
・上記の連鎖によって破壊されたBallObjectの総数をカウントしてスコアに反映させる
になります。
何か対処法などご教授いただければと思います。
よろしくお願いいたします。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class TouchManager : MonoBehaviour
{
[Header("なぞったBallObjectを格納するList")]
[SerializeField]
List<GameObject> touchBallList;
[Header("DeleteEffectObject")]
[SerializeField]
GameObject deleteEffectObj = default;
[Header("ScoreManager")]
[SerializeField]
ScoreManager scoreManager = default; // bombによって破壊されたBallObjectの数をカウントするための配列
GameObject[] destroyObjects = default;----------------------------------------------------------------------------------------// 追加した部分
// bombの連鎖によって破壊されたBallObjectの数をカウントするための配列
GameObject[] chainDestroyObjects = default;
---------------------------------------------------------------------------------------- // BallObjectを消した時のpointに掛ける倍率
const int pointMag = 100;
// bombによってBallObjectを消した時のpointに掛ける倍率
const int exPointMag = 180; void Update()
{
// マウスカーソルの位置を取得
Vector3 mousePos = Input.mousePosition;
if (Input.GetMouseButtonDown(0))
{
// bombが何個爆発したかカウントする変数
int bombCount = 0; // Listの初期化
touchBallList = new List<GameObject>();
// マウスの位置から画面奥方向へRayを放つ
Ray ray = Camera.main.ScreenPointToRay(mousePos);
// Rayと衝突したBallObjectを全て検知してListに格納
RaycastHit[] h = Physics.RaycastAll(ray, 100.0f);
// タッチしたBallObjectが0個でないとき
if (h.Length > 0)
{
// タッチしたBallObjectが選択状態でないとき
if (h[0].collider.CompareTag("Ball") && !h[0].collider.GetComponent<BallObject>().isTouch)
{
if (h[0].collider.GetComponent<BallObject>().color == GameResources.BallColor.bomb)
{
// 爆発
h[0].collider.GetComponent<BallObject>().Explosion(deleteEffectObj); destroyObjects = GameObject.FindGameObjectsWithTag("Ball");
Debug.Log("爆発で破壊したballの数:" + destroyObjects.Length);----------------------------------------------------------------------------------------// 追加した部分
// bombの爆発範囲内に別のbombが含まれていた場合bombCountを増やす
foreach (GameObject obj in destroyObjects)
{
if (obj.GetComponent<BallObject>().color == GameResources.BallColor.bomb)
{
bombCount++;
if (bombCount >= 2)
{
chainDestroyObjects = GameObject.FindGameObjectsWithTag("Ball");
foreach (GameObject chainObj in chainDestroyObjects)
{
if(chainObj.GetComponent<BallObject>().color == GameResources.BallColor.bomb)
{
chainObj.GetComponent<BallObject>().Explosion(deleteEffectObj);
}
}
Debug.Log("連鎖で破壊したballの数:" + chainDestroyObjects.Length);
}
}
}
Debug.Log("爆発したbombの数:" + bombCount);
---------------------------------------------------------------------------------------- scoreManager.AddExplosionScore(destroyObjects.Length * exPointMag);
// Debug.Log("スコア:" + (destroyObjects.Length * exPointMag));
}
else
{
h[0].collider.GetComponent<BallObject>().isTouch = true;
// BallObjectをListへ追加
touchBallList.Add(h[0].collider.gameObject);
}
}
}
}
if (Input.GetMouseButton(0))
{
// 選択状態のBallObjectが0個でないとき
if (touchBallList.Count != 0)
{
// マウスの位置から画面奥方向へRayを放つ
Ray ray = Camera.main.ScreenPointToRay(mousePos);
// Rayと衝突したBallObjectを全て検知してListに格納
RaycastHit[] h = Physics.RaycastAll(ray, 100.0f);
if (h.Length > 0)
{
// 「BallObject」かつ「選択したことのあるBallObjectでない」かつ「最初にタッチしたBallObjectの色と一致している」場合
if (h[0].collider.CompareTag("Ball") && !h[0].collider.GetComponent<BallObject>().isTouch && touchBallList[0].GetComponent<BallObject>().color == h[0].collider.GetComponent<BallObject>().color)
{
h[0].collider.GetComponent<BallObject>().isTouch = true;
// BallObjectをListへ追加
touchBallList.Add(h[0].collider.gameObject);
}
// 「BallObject」かつ「最初にタッチしたBallObjectの色と一致していない」場合はReleaseObjectを実行
else if (h[0].collider.CompareTag("Ball") && touchBallList[0].GetComponent<BallObject>().color != h[0].collider.GetComponent<BallObject>().color)
{
ReleaseObject();
}
}
else
{
ReleaseObject();
}
}
}
if (Input.GetMouseButtonUp(0))
{
ReleaseObject();
}
} /// <summary>
/// ボタンを離したらBallObjectを消去
/// </summary>
public void ReleaseObject()
{
int count = touchBallList.Count;
// 離したらマテリアルの色を戻す
foreach (GameObject obj in touchBallList)
{
// 選択状態を解除
obj.GetComponent<BallObject>().isTouch = false;
// 3個以上ならBallObjectを消去
if (count >= 3)
{
GameObject delObj = Instantiate(deleteEffectObj);
delObj.transform.position = obj.transform.position;
Destroy(obj);
}
}
// Listの要素を全消去
touchBallList.Clear();
if (count >= 3)
{
// 2^(消したBallの個数)*100をスコアとする
// Ex.3個消した場合は、2^3*100なのでスコアは800となる
scoreManager.AddScore((int)Mathf.Pow(2, count) * pointMag);
/*
Debug.Log("消したBallの数:" + count);
Debug.Log("スコア:" + (int)Mathf.Pow(2, count) * pointMag);
*/
}
}
}
bomb Countはちゃんと数字が変わってる状態なのでしょうか?
数字自体は変わってるのですが、「爆発したbombの数」ではなく、「現在画面内に存在しているbombの総数」がカウントされてしまっている状況になっています。
この部分も本来実現したい内容とは異なっている為、原因を探っております。
説明が抜けておりました。申し訳ございません。
爆発したかどうかをBooleanなどを使ってif文を作り、bomb Countを増やす方法がいいと思います。