C#
1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public abstract class MovingObject : MonoBehaviour { 6 7 public float moveTime = 100f; 8 9 public LayerMask blockingLayer; 10 11 private BoxCollider2D boxCollider; 12 private Rigidbody2D rb2D; 13 //moveTimeを計算するのを単純化するための変数 14 private float inverseMoveTime; 15 16 // Use this for initialization 17 protected virtual void Start () { 18 //BoxCollider2DとRigidbody2Dを何度もGetComponentしなくて済むよう 19 //Startメソッドにてキャッシュしておく 20 boxCollider = GetComponent<BoxCollider2D>(); 21 rb2D = GetComponent<Rigidbody2D>(); 22 //デフォルトだと 1f ÷ 0.1f = 10.0f 23 inverseMoveTime = 1f / moveTime; 24 } 25 26 protected bool Move(int xDir, int yDir, out RaycastHit2D hit) 27 { 28 //現在地を取得 29 Vector2 start = transform.position; 30 //目的地を取得 31 Vector2 end = start + new Vector2(xDir, yDir); 32 //自身のColliderを無効にし、Linecastで自分自身を判定しないようにする 33 boxCollider.enabled = false; 34 //現在地と目的地との間にblockingLayerのついたオブジェクトが無いか判定 35 hit = Physics2D.Linecast(start, end, blockingLayer); 36 //Colliderを有効に戻す 37 boxCollider.enabled = true; 38 //何も無ければSmoothMovementへ遷移し移動処理 39 if (hit.transform == null) 40 { 41 StartCoroutine(SmoothMovement(end)); 42 //移動が成功したことを伝える 43 return true; 44 } 45 //移動に失敗したことを伝える 46 return false; 47 } 48 49 protected IEnumerator SmoothMovement(Vector3 end) 50 { 51 //現在地から目的地を引き、2点間の距離を求める(Vector3型) 52 //sqrMagnitudeはベクトルを2乗したあと2点間の距離に変換する(float型) 53 float sqrRemainingDistance = (transform.position - end).sqrMagnitude; 54 //2点間の距離が0になった時、ループを抜ける 55 //Epsilon : ほとんど0に近い数値を表す 56 while (sqrRemainingDistance > float.Epsilon) 57 { 58 //現在地と移動先の間を1秒間にinverseMoveTime分だけ移動する場合の、 59 //1フレーム分の移動距離を算出する 60 Vector3 newPosition = Vector3.MoveTowards(rb2D.position, end, inverseMoveTime * Time.deltaTime); 61 //算出した移動距離分、移動する 62 rb2D.MovePosition(newPosition); 63 //現在地が目的地寄りになった結果、sqrRemainDistanceが小さくなる 64 sqrRemainingDistance = (transform.position - end).sqrMagnitude; 65 //1フレーム待ってから、while文の先頭へ戻る 66 yield return null; 67 } 68 } 69 70 71 //移動を試みるメソッド 72 //virtual : 継承されるメソッドに付ける修飾子 73 //<T>:ジェネリック機能 型を決めておかず、後から指定する 74 protected virtual void AttemptMove<T>(int xDir, int yDir) 75 //ジェネリック用の型引数をComponent型で限定 76 where T : Component 77 { 78 RaycastHit2D hit; 79 //Moveメソッド実行 戻り値がtrueなら移動成功、falseなら移動失敗 80 bool canMove = Move(xDir, yDir, out hit); 81 //Moveメソッドで確認した障害物が何も無ければメソッド終了 82 if (hit.transform == null) 83 { 84 return; 85 } 86 //障害物があった場合、障害物を型引数の型で取得 87 //型が<T>で指定したものと違う場合、取得できない 88 T hitComponent = hit.transform.GetComponent<T>(); 89 //障害物がある場合OnCantMoveを呼び出す 90 if (!canMove && hitComponent != null) 91 { 92 OnCantMove(hitComponent); 93 } 94 } 95 96 97 //abstract: メソッドの中身はこちらでは書かず、サブクラスにて書く 98 //<T>:AttemptMoveと同じくジェネリック機能 99 //障害物があり移動ができなかった場合に呼び出される 100 protected abstract void OnCantMove<T>(T component) where T : Component; 101} 102
C#
1using System.Collections; 2using System.Collections.Generic; 3using UnityEngine; 4 5public class Enemy : MovingObject 6{ 7 public Transform target; 8 private GameObject nearestfood; 9 private float dist; 10 private Statistics empty; 11 12 // Use this for initialization 13 protected override void Start() 14 { 15 GameManager.instance.AddEnemyToList(this); 16 17 GameObject[] foods = GameObject.FindGameObjectsWithTag("Food"); 18 foreach(GameObject food in foods) 19 { 20 Vector3 foodPos = food.transform.position; 21 dist = Vector3.Distance(this.transform.position, food.transform.position); 22 nearestfood = null; 23 if(dist < 16) 24 { 25 nearestfood = food; 26 target = nearestfood.transform; 27 } 28 } 29 30 //target = GameObject.FindGameObjectWithTag("Food").transform; 31 base.Start(); 32 33 empty = GetComponent<Statistics>(); 34 } 35 36 private void Update() 37 { 38 if(gameObject.transform.position == target.transform.position) 39 { 40 GameObject[] foods = GameObject.FindGameObjectsWithTag("Food"); 41 foreach (GameObject food in foods) 42 { 43 Vector3 foodPos = food.transform.position; 44 dist = Vector3.Distance(this.transform.position, food.transform.position); 45 nearestfood = null; 46 if (dist < 16) 47 { 48 nearestfood = food; 49 target = nearestfood.transform; 50 } 51 } 52 } 53 54 } 55 56 /*public void RemoveEnemy(int script) 57 { 58 if (empty.HP <= 0) 59 { 60 GameManager empty = GetComponent<GameManager>(); 61 empty.enemies.RemoveAt(script); 62 } 63 }*/ 64 65 protected override void AttemptMove<T>(int xDir, int yDir) 66 { 67 empty = GetComponent<Statistics>(); 68 empty.HP--; 69 //Call the AttemptMove function from MovingObject. 70 base.AttemptMove<T>(xDir, yDir); 71 } 72 73 //MoveEnemy is called by the GameManger each turn to tell each Enemy to try to move towards the player. 74 public void MoveEnemy() 75 { 76 //Declare variables for X and Y axis move directions, these range from -1 to 1. 77 //These values allow us to choose between the cardinal directions: up, down, left and right. 78 int xDir = 0; 79 int yDir = 0; 80 81 //If the difference in positions is approximately zero (Epsilon) do the following: 82 if (Mathf.Abs(target.position.x - transform.position.x) < float.Epsilon) 83 84 //If the y coordinate of the target's (player) position is greater than the y coordinate of this enemy's position set y direction 1 (to move up). If not, set it to -1 (to move down). 85 yDir = target.position.y > transform.position.y ? 1 : -1; 86 87 88 //If the difference in positions is not approximately zero (Epsilon) do the following: 89 else 90 //Check if target x position is greater than enemy's x position, if so set x direction to 1 (move right), if not set to -1 (move left). 91 xDir = target.position.x > transform.position.x ? 1 : -1; 92 93 //Call the AttemptMove function and pass in the generic parameter Player, because Enemy is moving and expecting to potentially encounter a Player 94 AttemptMove<Food>(xDir, yDir); 95 96 } 97 98 private void OnTriggerEnter2D(Collider2D other) 99 { 100 if(other.tag == "Food") 101 { 102 other.gameObject.SetActive(false); 103 } 104 } 105 106 protected override void OnCantMove<T>(T component) 107 { 108 109 } 110} 111
C#
1#pragma warning disable 0414 2using System.Collections; 3using System.Collections.Generic; 4using UnityEngine; 5using UnityEngine.UI; 6 7public class Statistics : MonoBehaviour 8{ 9 Text targetText; 10 11 int Level;//レベル 12 string Ability;//特性 13 public int HP; 14 int Attack;//こうげき 15 int Defense;//ぼうぎょ 16 int Sp_Atk;//とくこう 17 int Sp_Def;//とくぼう 18 public int Speed;//すばやさ 19 int Evasion;//回避 20 int Accuracy;//命中 21 string Gender;//性別 22 int Exp;//経験値 23 int Individual_Value;//個体値 24 string ATKorSPATK; 25 26 int OK = 0; 27 bool OK_Click = true; 28 29 Text SpeciesText; 30 string Text; 31 Image targetImage; 32 33 GameObject targetObj; 34 35 // ラジアン変数 36 private float rad; 37 // 現在位置を代入する為の変数 38 private Vector2 Position; 39 40 public Vector2 speed = new Vector2(0.01f, 0.01f); 41 42 private void Awake() 43 { 44 SpeciesText = GameObject.Find("SpeciesText").GetComponent<Text>(); 45 Text = "Species:"; 46 SpeciesText.text = Text; 47 targetImage = GameObject.Find("SpeciesImage").GetComponent<Image>(); 48 targetText = GameObject.Find("StatsText").GetComponent<Text>(); 49 Generate_Stats(); 50 targetText.enabled = false; 51 } 52 53 private void Update() 54 { 55 targetText.text = "Level " + Level.ToString() + "\n" + "Ability " + Ability + "\n" + "Gender " + Gender + "\n" + "IV " + Individual_Value.ToString() + "\n" + 56 "HP " + HP.ToString() + "\n" + "Attack " + Attack.ToString() + "\n" + "Defense " + Defense.ToString() + "\n" + 57 "Sp_Atk " + Sp_Atk.ToString() + "\n" + "Sp_Def " + Sp_Def.ToString() + "\n" + "Speed " + Speed.ToString() + "\n" + 58 "Evasion " + Evasion.ToString() + "\n" + "Accuracy " + Accuracy.ToString() + "\n" + "Exp " + Exp.ToString() + "\n" + "ATK Type " + ATKorSPATK; 59 60 if (HP <= 0) 61 { 62 Enemy enemy = GetComponent<Enemy>(); 63 enemy.enabled = false; 64 GameObject obj = this.gameObject; 65 GameObject.Destroy(obj); 66 obj = null; 67 } 68 } 69//省略
Unity2dのローグライクチュートリアルを改造しているのですが、StatisticsスクリプトのUpdateで(HP <= 0)になったとき、EnemyスクリプトとStatisticsスクリプトがアタッチされているオブジェクトをdestoryするようにしました。
ですが、destoryすると、Enemyスクリプトの
if (Mathf.Abs(target.position.x - transform.position.x) < float.Epsilon)
という部分で
MissingReferenceException: The object of type 'Enemy' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
というエラーが出て来てしまいます。
抽象クラスをいまいち理解出来ていないので、どうやればdestoryしたときに、エラーを回避出来るかが分かりませんでした。
出来ればエラーを回避する方法を教えていただきたいです。
回答お願いします。
回答2件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。