我正在开发战术RPG,但有一个名为Map的空游戏对象,该对象由36个图块组成。
Map对象附加了以下脚本:
using System.Collections.Generic;
using UnityEngine;
public class GridMap : MonoBehaviour
{
private GameObject[] MyVector = new GameObject[36];
public GameObject[,] GridMatrix = new GameObject[6,6];
public GameObject Map;
// Start is called before the first frame update
void Awake()
{
for (int i = 0; i < 36; i++)
{
try
{
MyVector[i] = Map.transform.GetChild(i).gameObject;
}
catch
{
print("Something is wrong!");
}
}
}
void Start()
{
int Counter = 0;
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 6; j++)
{
GridMatrix[i, j] = MyVector[Counter];
Counter;
}
}
}
// Update is called once per frame
void Update()
{
}
}
每个图块都有此脚本:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Tile : MonoBehaviour
{
public bool Current = false;
public bool Selectable = false;
public bool MouseOver = false;
public bool Clicked = false;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
}
void OnMouseOver()
{
MouseOver = true;
if (Clicked == false)
{
GetComponent<Renderer>().material.color = Color.red;
}
if (Input.GetMouseButton(0))
{
Clicked = true;
GetComponent<Renderer>().material.color = Color.green;
}
}
void OnMouseExit()
{
MouseOver = false;
Clicked = false;
GetComponent<Renderer>().material.color = Color.white;
}
private void OnTriggerStay(Collider other)
{
if (other.tag == "Player")
{
GetComponent<Renderer>().material.color = Color.magenta;
Current = true;
}
}
private void OnTriggerExit(Collider other)
{
GetComponent<Renderer>().material.color = Color.white;
Current = false;
}
}
就实例而言,我想检测玩家所在的图块:如果玩家位于矩阵中位置为0,0的图块中,我想在控制台中显示以下内容: “玩家的位置为0,0'。
我已经创建了此脚本并将其附加到播放器上,以获取其在地图(网格)中的位置,但是不起作用:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GetPlayerPosition : MonoBehaviour
{
private GameObject mapgrid;
GridMap map;
float tileX, tileY;
// Start is called before the first frame update
void Start()
{
mapgrid = GameObject.FindGameObjectWithTag("map");
map = mapgrid.GetComponent<GridMap>();
for (int i = 0; i < 6; i++)
{
for (int j = 0; j < 6; j++)
{
Tile tile = map.GridMatrix[i, j].GetComponent<Tile>();
if (tile.Current)
{
tileX = i;
tileY = j;
Debug.Log(tileX);
Debug.Log(tileY);
}
}
}
}
// Update is called once per frame
void Update()
{
}
}
我该怎么做才能解决这个问题? Print of the project. The black cylinder is the player
答案 0 :(得分:0)
首先,我要输入
private Tile[] MayVector = new Tile[36];
public Tile[,] GridMatrix = new Tile[6,6];
因此您可以避免所有昂贵的GetComponent<Tile>
通话,而只需拨打一次。
我也宁愿使用OnTriggerEnter
,它只调用一次,而不是OnTriggerStay
,每帧都调用一次。而OnMouseEnter
的第一部分是OnMouseOver
,因为仅需设置一次即可。
我将使用FindObjectOfType
或什至更好(如果可能)通过Inspector引用所有内容,而不是使用GameObject.FindGameObjectWithTag
和GetComponent
!
还应该填充GridMatrix
中的Awake
数组。否则,可能会在Start
的{{1}}方法之前之前执行GetPlayerPosition
的{{1}},因此请尝试在不存在的时候访问该数组。尚未填写,仅包含Start
个元素→ GridMap
!
我对null
和NullReferenceException
的一般经验法则:
Awake
:做所有不依赖他人的事情,设置自己的引用和值,使用Start
等来查找场景引用
Awake
:根据已设置的引用来执行操作。就像其他人的访问字段一样。
然后,我将使整个事件更多地受事件驱动,而不是让玩家一直在所有磁贴之间循环,而是让磁贴设置玩家的位置:
类似
GetComponent
然后在 GridMap 中告诉Start
他们的位置
public class Tile : MonoBehaviour
{
// maybe not needed anymore
public bool Current = false;
public bool Selectable = false;
public bool MouseOver = false;
public bool Clicked = false;
// Will be assigned by the GridMap script
// so every tile will know it's own position
// you could also assign this via the Inspector
// but maybe a lot overhead for 36 tiles ;)
public Vector2Int TilePosition;
// The player will register itself here
// you could even already reference this via the Inspector
// select all tiles and simply drag the player object here
public GetPlayerPosition getPlayerPosition;
// would even be better to already reference this via the Inspector
// but maybe a bit overhead for 36 tiles
// except this is a prefab (what it probably should be ;) )
[SerializeField] private Renderer renderer;
private void Awake ()
{
// do this only once
if(!renderer) renderer = GetComponent<Renderer>();
}
private void OnMouseEnter()
{
// do this only once .. no need to do it every frame
MouseOver = true;
renderer.material.color = Color.red;
}
private void OnMouseOver()
{
// skip further API calls if already Clicked
if(Clicked) return;
if (Input.GetMouseButton(0))
{
Clicked = true;
renderer.material.color = Color.green;
}
}
private void OnMouseExit()
{
MouseOver = false;
Clicked = false;
renderer.material.color = Color.white;
}
private void OnTriggerEnter(Collider other)
{
// do all these only once .. no need to do it every frame
if(other.tag != "Player") return;
renderer.material.color = Color.magenta;
// Tell the player it's current position
playerPosition.GridPosition = TilePosition;
// probably not needed anymore
Current = true;
}
private void OnTriggerExit(Collider other)
{
if(other.tag != "Player") return;
renderer.material.color = Color.white;
// probably not needed anymore
Current = false;
}
}
现在剩下的就是玩家必须注册到Tiles:
Tile