+24-08-13 수정(참고 링크 추가)
Vector3 MousePosToGridPos(Vector2 clickPos)
{
Ray ray = HandleUtility.GUIPointToWorldRay(clickPos);
var floorPosition = editTilemap.transform.position + (Vector3.up * floorIndex);
Plane plane = new Plane(Vector3.up, floorPosition);
if (plane.Raycast(ray, out float enter))
{
Vector3 rayPoint = ray.GetPoint(enter);
rayPoint.x = Mathf.Round(rayPoint.x);
rayPoint.y = Mathf.Round(rayPoint.y);
rayPoint.z = Mathf.Round(rayPoint.z);
return rayPoint;
}
return Vector3.negativeInfinity;
}
Event.current.mousePosition을 매개변수로 받아서 사용한다.
에디터 클릭 이벤트
👀 https://tistory.wonsorang.com/m/979
Plane을 사용해 클릭 좌표를 계산했다. Event.current.mousePoint를 직접 변환해서 계산하는 방법을 시도했었는데 좌표계에 대한 이해가 부족해서인지 쉽지 않았다.
격자 칸의 정중앙에 오브젝트를 생성해야 하기 때문에 Mathf.Round()를 사용했다.
참고
👀 plane 사용법 : https://m.blog.naver.com/happybaby56/221365696057
void GetGridPosition(Event e)
{
switch (e.type)
{
case EventType.MouseDown:
if (e.button == 0) // 좌클릭
{
if (editTilemap == null) return;
gridPos = MousePosToGridPos(e.mousePosition);
if (!IsValidPos(gridPos)) return;
if (drawTile == null) return;
CreateTile(gridPos);
}
else if (e.button == 1) // 우클릭
{
if (editTilemap == null) return;
gridPos = MousePosToGridPos(e.mousePosition);
if (!IsValidPos(gridPos)) return;
RemoveTile(IsExistAt(gridPos)); // 🐸
}
break;
}
}
void CreateTile(Vector3 position)
{
RemoveTile(IsExistAt(position)); // 🐸
GameObject tile = (GameObject)PrefabUtility.InstantiatePrefab(drawTile);
tile.transform.SetParent(editFloor.transform);
tile.transform.position = position;
// *** rotate
// *** replace
editFloor.GetComponent<CustomFloor>().tiles.Add(tile);
}
생성한 타일 오브젝트는 해당 층의 정보를 저장하고 있는 CustomFloor 클래스 안에서 tiles라는 이름의 리스트로 관리한다.
void RemoveTile(int index) // 🐸
{
List<GameObject> tiles = editFloor.GetComponent<CustomFloor>().tiles;
if (index != -1)
{
DestroyImmediate(tiles[index]);
tiles.RemoveAt(index);
}
}
tiles 리스트에서 position 값이 클릭한 좌표와 일치하는 오브젝트가 있을 경우 제거한다.
🐸
int IsExistAt(Vector3 position) { List<GameObject> tiles = editFloor.GetComponent<CustomFloor>().tiles; for (int i = 0; i < tiles.Count; ++i) { if (tiles[i].transform.position == position) return i; } return -1; }
나중에, 타일을 생성하고자 하는 위치에 타일이 존재할 때
1) 지우고 그리기
2) 그리지 않기
의 옵션을 추가하기 위해 해당 위치에 타일이 존재하는지 검사하는 로직을 분리했다.
bool IsValidPos(Vector3 position)
{
int halfVal = gridSize / 2;
if (gridSize % 2 == 0)
{
float x = position.x;
float z = position.z;
if ((x > 0 && x > halfVal)
|| (x < 0 && x <= -halfVal)
|| (z > 0 && z > halfVal)
|| (z < 0 && z <= -halfVal))
return false;
}
else
{
float x = Mathf.Abs(position.x);
float z = Mathf.Abs(position.z);
if (x > halfVal || z > halfVal)
return false;
}
if (position == Vector3.negativeInfinity)
return false;
return true;
}
Plane을 사용해 좌표를 구했기 때문에 Grid 밖의 영역을 클릭해도 오브젝트가 생성 되는 문제가 발생했다. 👉 Plane의 영역은 무한함
처음엔 막연히 좌표의 절대값을 구해 gridSize 크기의 절반 값(halfVal) 보다 크면 그리지 않도록 처리했는데, 그렇게 되자 gridSize가 짝수일 때 문제가 생겼다.
👉 Grid의 왼쪽과 아래쪽 바깥 한줄씩이 처리 되지 않음
결국 gridSize가 짝수일 때와 홀수일 때를 분리해서 처리했다.
참고
👀 https://velog.io/@gold715/Map-tool-%EA%B5%AC%ED%98%841
👀 https://junwe99.tistory.com/39
👀 https://bloodstrawberry.tistory.com/1063
👀 https://assetstore.unity.com/packages/tools/level-design/fabgrid-level-editor-175642