⚓문제
paper.io 2에서는 유저가 맵 위를 이동한 궤적을 고유의 색으로 흔적으로 남기는 요소가 있다.
그리고 이 흔적에 다른 유저 또는 자기 자신이 닿을 경우 흔적의 주인은 파괴된다.
⚓접근
1. 고유의 색으로 흔적으로 남기는 요소
- 단색뿐만 아니라 이미지가 흔적에 그려질 수 있기 때문에 텍스처를 넣을 수 있는 컴포넌트를 사용
- 객체의 매프레임 이동에 따라 부드러운 선을 그려야 하기 때문에 LineRenderer 사용한다.(좀 더 화려한 옵션을 위해서 파티클도 고려할 수 있겠지만 빠른 구현을 위해 LineRenderer로 진행)
2. 흔적에 닿을 때 흔적의 주인이 파괴
2.1) 방법 1(폐기)
- 유저가 밟고 있는 현재 위치가 점유된 좌표인지 점유되지 않은 좌표인지 확인하는 법이 관건이다.
- 유저들은 모두 동일한 맵 위를 이동한다.
- 따라서, 유저가 맵 좌표의 점유현황을 확인하는 데이터도 1개로 구현할 수 있다.
(단계)
2-a) 유저가 밟은 위치를 맵 텍스처의 픽셀좌표로 전환하는 방법을 알아낸다.
2-b) 맵 텍스처의 해상도 크기와 같은 배열을 만들고 유저가 밟은 위치에 유저의 정보를 입력한다.
2-c) 매프레임마다 유저가 밟은 위치를 배열로 확인해서 점유된 상태면 주인 객체를 파괴한다.
2.1) 방법 2
- 맵 해상도와 동일한 1024x1024 배열로 흔적과 영역 데이터를 GameManager에서 관리하고자 했으나 월드좌표에서 Creature가 움직이는 좌표는 소수점 단위로 정교하기 때문에 데이터가 실제와 오차가 생기는 버그가 있다.
- 예를 들어, Creature의 흔적의 경우 코너를 돌 때 실제 자취를 벗어나는 픽셀도 흔적 데이터를 남긴다.
- 그리고 영역의 경우에도 픽셀은 정수이기 때문에 곡선 영역의 경계를 완벽히 데이터로 저장하지 못 하고 근사치로 저장한다.
- 위 문제를 보완하기 위해서 LineRenderer의 Point에서 Ray를 y방향으로 쏴서 Creature가 감지되면 흔적의 주인 Creature가 파괴되도록 구현하기로 했다.
(단계)
2-a) CheckPixelType() 함수를 통해 현재 위치가 Area/None을 체크한다.
2-b) None일 경우 흔적을 남기는 TraceOnLand() 함수를 호출한다.
2-c) 자취인 Points에서 Ray를 쏴서 Creature가 있는지 감지한다.
2-d) Creature가 감지되면 A는 ObjectManager의 Despawn 함수를 호출해 자신을 파괴한다.
⚓구현
2-a) CheckPixelType() 함수를 통해 현재 위치가 Area/None을 체크한다.
//Creature.cs
private void FixedUpdate()
{
switch (CheckPixelType())
{
case EPixelType.None:
{
print("None!!");
isClosed = false;
TraceOnLand();
break;
}
case EPixelType.Area:
{
if (isClosed == false && Vertices.Count > 3)
{
isClosed = true;
Managers.Map.UpdateArea(this);
Vertices.Clear();
lineRenderer.positionCount = Vertices.Count;
}
print("Area!!");
break;
}
}
CreatureMove();
}
2-b) None일 경우 흔적을 남기는 TraceOnLand() 함수를 호출한다.
//Creature.cs
void TraceOnLand()
{
Vector3 point = transform.position;
Vertices.Add(point);
lineRenderer.positionCount = Vertices.Count;
lineRenderer.SetPosition(Vertices.Count - 1, point);
DetectOnTrace();
}
2-c) 자취인 Points에서 Ray를 쏴서 Creature가 있는지 감지한다.
//Creature.cs
void DetectOnTrace()
{
foreach (Vector3 point in Vertices)
{
if (Physics.Raycast(point, Vector3.up, 1.0f, 1 << CreatureMask))
{
print("Detect!!");
Managers.Object.Despawn<Creature>(data.DataId);
return;
}
}
}
2-d) Creature가 감지되면 A는 ObjectManager의 Despawn 함수를 호출해 자신을 파괴한다.
//ObjectMaangers.cs
private Dictionary<int, Creature> creatures = new Dictionary<int, Creature>();
public void Despawn<T>(int key) where T : Creature
{
T creature = creatures[key] as T;
Managers.Resource.Destroy(creature.gameObject);
creatures.Remove(key);
}
2-a) 유저가 밟은 위치를 맵 텍스처의 픽셀좌표로 전환하는 방법을 알아낸다.
public Vector2 WorldToPixelPosition(RaycastHit hit)
{
Vector2 uvPos = hit.textureCoord;
float u = uvPos.x * texture.width;
float v = uvPos.y * texture.height;
return new Vector2(u, v);
}
- hit.textureCoord : 레이캐스트가 충돌한 위치의 uv좌표를 반환(0~1 범위)
- uv 좌표에 텍스처의 가로, 세로 길이를 곱해주면 픽셀의 위치를 구할 수 있다.
2-b) 맵 텍스처의 해상도 크기와 같은 배열을 만들고 유저가 밟은 위치에 유저의 정보를 입력한다.
2-c) 매프레임마다 유저가 밟은 위치를 배열로 확인해서 점유된 상태면 주인 객체를 파괴한다.
public void DrawCircleOnTexture(int centerX, int centerY, Define.CreatureType creatureType, Color circleColor)
{
if (centerX >= 0 && centerY < texture.width && centerX >= 0 && centerY < texture.height)
{
if (tiles[centerX, centerY] > 0 && tiles[centerX, centerY] != (byte)creatureType)
Managers.Object.Despawn<Creature>(tiles[centerX, centerY]);
tiles[centerX, centerY] = (byte)creatureType;
}
texture.Apply();
}
- tiles는 텍스처의 해상도와 같은 크기의 배열.
- CreatureType은 enum 형식으로 유저객체마다 고유하게 들고있음.
- Object 객체는 Manager의 일종으로 객체를 생성하거나 삭제하고 현재 게임에 로드된 객체정보를 들고있음.
⚓결과
2.
1. (폐기)
'Unity > Paper.io 2' 카테고리의 다른 글
[유니티-Paper.io2] 닫힌 영역에서 메시 생성 (0) | 2024.12.16 |
---|---|
[유니티-paper.io2] 프레임 단위 이동과 흔적 남기기(폐기) (0) | 2024.12.15 |