반응형

 

 

포톤 에셋을 받은 후, 비주얼 스튜디오로 작업을 하게되면 한번씩 다음과 같은 에러를 본다.

 

  • CS0246 형식 또는 네임스페이스 이름을 찾을 수 없습니다. using 지시문 또는 어셈블리 참조가 있는지 확인하세요.

실수로라도 포톤에셋의 코드들을 건드릴일이 없는데 CS0246에러를 만나면 성가시기 짝이없다.

물론 무시하고 사용해도 기능적으로 문제가 생긴다거나 하지는 않지만, 참조를 못하는 상황이니 자동완성으로 편하게 코딩은 불가능하다.

 

 

해결방법

1. 유니티 프로젝트와 비주얼 스튜디오를 닫는다.

2. 유니티 프로젝트 폴더에서 .csproj.sln확장자의 파일을 모두 삭제한다. (유니티를 다시 실행하면 자동으로 생성이 되니 안심하고 지우면 된다.)

3. 유니티를 재실행한다.

 

 

 

반응형
반응형

 

 

 

유니티 스크립트를 편집하려할 때, 유니티 스크립팅 API에 대한 자동완성이 되지 않을때가 있다.

 

원인

- 유니티 프로젝트에서 .csproj.sln파일 생성이 안되서 발생하는 문제이다.

- 유니티 프로젝트 폴더를 열어보면 다음과 같이 유니티 프로젝트 관련 폴더만 보이고 비주얼스튜디오 관련 파일은 보이지 않는것을 확인할 수 있다. (비주얼 스튜디오의 솔루션 탐색기에서도 확인이 가능하다.)

 

 

 

 

해결방법

1. EditPreferenceExternal ToolsExternal Script Editor에서 비주얼 스튜디오를 선택한다.

 

2. 비주얼 스튜디오를 재시작하면 프로젝트 폴더에서 .csproj와 .sln 파일이 생성되는것을 확인할 수 있다.

 

 

 

 

반응형
반응형

여태 기회가 닿지를 않아 포톤을 깊게 파보지를 않았는데, 작년 플랙프라이데이에 구매한 포톤 상품이 곧 만료라(11월까지 ㅠㅠ..) 이번 기회에 깊게 파보려고 이 일지 작성을 시작하게 되었다.

 

포톤에 붙일 게임도 프로토타입으로 한번 만들어보긴했는데, 동작관련 문제를 아직 해결하지 못해서 시스템 먼저 만들어보게 되었다. 그래서 만들기 시작한것이 로비, 방 구현이다.

 

이 일지에 작성된 로비, 방 스타일은 옛날에 서비스를 했던 서바이벌 프로젝트에서 가져왔다.

어릴때 했던 게임중 가장 재미있게 했었던 게임이고, 시스템 자체도 꽤 괜찮다고 판단해서 작업을 시작하게되었다.

 

작업은 저번달 22일부터 조금씩 진행하기 시작해서 짬짬히 작업을 해왔다.

 

1. 입장

입장을 시작하게 되면, 로비 화면이 노출된다.

하단의 화살표 버튼과 우측 버튼들은 아직 기능구현이 되지 않았다.

포톤 콜백을 통해 방이 생성되면 파티클이 없어지고 방에 대한 옵션을 프리뷰 형태로 볼 수 있다.

 

2. 방 만들기

방을 생성하고 싶으면 비어있는 방들(파티클들)을 클릭하면 방 생성창이 열린다.

일단 시험삼아 커뮤니티, 팀, 서바이벌모드와 인원을 선택해서 방을 생성 할 수 있다.

 

3. 생성된 방의 프리뷰 확인

다른 클라이언트가 방을 생성하면 포톤 콜백을 통해 생성된 방의 리스트를 갱신해 로비에 있는 유저에게 생성된 방의 옵션 등을 프리뷰로 볼 수 있다. (방의 모드, 입장한 유저의 캐릭터 정보, 팀 정보 확인 가능)

 

4. 방 입장 및 캐릭터, 팀 선택

생성되어 있는 방을 누르면 입장이 시작되며, 캐릭터 선택이 가능하고, 팀 모드에서는 팀 선택이 가능하다.

상대랑 같은 슬롯을 선택할 경우를 대비해서 마스터 클라이언트에서 정보를 받아 슬롯정보를 다른 클라이언트에게 뿌려주고 일반 클라이언트들은 갱신만 하게되는 형태로 했다.

(ExpectedValues를 써볼까 고민하긴 했지만, 위와 같은 형태에선 괜히 코드만 더 복잡해질거같아서 배제했다.)

 

이 작업을 거의 20일간 했는데, 그래픽 리소스 문제도 그렇고 포톤 콜백이나 함수 활용에 대해 일일히 로그 찍고 확인하다보니 생각보다 많은 시간이 소요됨... 그래도 나름 형태도 어느정도 잡혔고, 다음 작업은 로비 쪽의 구현하지 못한 기능 완성과 방의 기능 완성을 할 예정이다!

반응형
반응형

어느날 지인에게 메쉬를 생성하는법을 알려달라고 연락이 왔다.

해본적은 없지만(메쉬 개념도 없었다...) 재미있을거같아서 한번 시도해보았다.

 

1. 메쉬 생성(vertices, uv) : vertices만 알면 되는거같아서 uv 설정은 하지 않음.

2. Raycast를 이용해서 vertices 값이 유동적으로 바뀔수 있어야한다.

3. Circle 형태여야 함.

 

연락받았을 당시, 어몽어스에서 그림자가 표현되는 것을 상상했다.

그래서 코드를 2D로 만들었다가, 나중에 3D로 만들어야 된다고 뒤늦게 들어서.. 안타깝게도 코드가 2D와 3D가 섞인 코드가 됐다.

 

※※ 메쉬에 대한 개념은 구글링하면 바로나오니 패스한다.


  • 코드
using UnityEngine;
using UnityEngine.Rendering;

public class MeshCreater : MonoBehaviour
{
    public Material meshMaterial;

    private Mesh mesh;
    private MeshFilter meshFilter;
    private MeshRenderer meshRender;

    private void Start()
    {
        GameObject meshGameObject = new GameObject("Mesh", typeof(MeshFilter), typeof(MeshRenderer));
        meshFilter = meshGameObject.GetComponent<MeshFilter>();
        meshRender = meshGameObject.GetComponent<MeshRenderer>();

        meshRender.material = meshMaterial;

        mesh = new Mesh();
        meshFilter.mesh = mesh;
    }

    private void Update()
    {
        CalculateMesh();
    }

    //Calculate vertex vector(circle)
    private Vector3 ConvertAngleToVector(float _angle)
    {
        var rad = _angle * Mathf.Deg2Rad;
        return new Vector3(Mathf.Cos(rad), Mathf.Sin(rad));
    }

    //*** Mesh vertices point : local position of gameObject
    //recalculate vertices for vertices of mesh
    private void CalculateMesh()
    {
        float targetAngle = 360f;
        int rayCount = 360;
        float angleIncrease = targetAngle / rayCount;
        float angle = 0f;
        float dist = 2f;
        
        //Arr Length : ray counts + cneter point
        Vector3[] vertices = new Vector3[rayCount + 1];
        //Triangles : Multiple of 3
        int[] triangles = new int[rayCount * 3];

        //Center point is always Vector3.zero
        Vector3 centerPoint = Vector3.zero;
        //Set the center point to vertices[0] (triangle index 0)
        vertices[0] = centerPoint;

        int vertexIndex = 1;
        int triangleIndex = 0;
        for (int i = 0; i < vertices.Length; i++)
        {
            if (vertexIndex < vertices.Length)
            {
                Vector3 vertex = ConvertAngleToVector(angle);
                RaycastHit hit;

                //Get vertex points
                if (Physics.Raycast(meshRender.transform.position, vertex, out hit, dist))
                {
                    //Recalculate mesh point(local position)
                    //Set the local position(vertices), after Subtract the meshRender position from hit point.
                    vertices[vertexIndex] = hit.point - meshRender.transform.position;
                }
                else
                {
                    vertices[vertexIndex] = vertex * dist;
                }
            }

            //Set triangles
            if (vertexIndex > 1)
            {
                triangles[triangleIndex] = 0;
                triangles[triangleIndex + 1] = vertexIndex - 1;
                triangles[triangleIndex + 2] = vertexIndex < vertices.Length ? vertexIndex : 1;

                triangleIndex += 3;
            }

            vertexIndex++;
            angle -= angleIncrease;
        }

        //Apply mesh info
        mesh.vertices = vertices;
        mesh.triangles = triangles;
    }
}

 

※※ ConvertAngleToVector(float)는 삼각비를 이용해서 각도로 좌표를 구하는 함수다. (Raycast 함수의 direction 값이라 거리값은 필요가 없음.)

※※ 위 함수가 이해가 안간다면 다음글 참고

링크 : [유니티] 삼각비를 이용해 각도로 좌표구하기

 

[유니티] 삼각비를 이용해 각도로 좌표구하기.

삼각비 삼각비는 직각 삼각형에서 각 A에 대해 세 변의 길이가 이루는비가 일정한걸 말한다. 위와 같은 삼각형에서 빗변(r), 대변(y), 이웃변(x)로 확인해보자. 여기서 각 A가 동일하면 다음과 같은

srdeveloper.tistory.com


  • 결과 보기

 

일단 개념을 잡는 쪽에 맞춰둔 코드라, 활용이나 최적화 작업은 목적에 따라 바뀔것 같다.

추가로 빛으로 활용하기 위한 참고 사이트 링크도 올려둠.

 

2d Visibility

The next step is to keep track of which walls the sweep ray passes through. Only the nearest wall is visible. How do you figure out which wall is nearest? The simplest thing is to calculate the distance from the center to the wall. However, this approach d

www.redblobgames.com

 

반응형
반응형

※ 해당 글은 삼각비를 이해해야 적용이 가능하니 혹시 삼각비를 모르시는 분들은 검색해서 알아보시거나, 아래 링크를 참고해주세요~!

링크 : [유니티] 삼각비를 이용해 각도로 좌표구하기

 

[유니티] 삼각비를 이용해 각도로 좌표구하기.

삼각비 삼각비는 직각 삼각형에서 각 A에 대해 세 변의 길이가 이루는비가 일정한걸 말한다. 위와 같은 삼각형에서 빗변(r), 대변(y), 이웃변(x)로 확인해보자. 여기서 각 A가 동일하면 다음과 같은

srdeveloper.tistory.com


 

 

위의 글에서 우리는 삼각비를 통해서 극축과의 각도(θ)와 반지름(r)을 알면 좌표를 구할수 있다는것을 알았다.

그럼 이제 이 원리를 이용해서 유니티로 3D 카메라의 좌표를 구해보도록 하자.

 

  • 구면좌표계

구면좌표계는 2D 극좌표계에서 축이 하나 더 생긴 3D 극좌표계를 말한다. 그림을 보면서 확인해보자.

 

위 그림에서와 같이 극으로 부터 떨어진 점 P의 좌표를 (r, θ, Φ)라고 한다.

방위각(Azimuth)는 말 그대로 방위의 각이고, 앙각(Elevation)은 고도를 말한다. 유니티 좌표계를 기준으로 XZ축이 방위가 되고, Y축이 고도가 된다.

 

그럼 삼각비를 이용해서 점 P의 직교좌표를 구해보자.

위 그림을 기준으로 우리는 2개의 삼각형을 얻을 수 있다.

왼쪽 삼각형은 앙각을 끼고있는 삼각형이고 오른쪽은 방위각을 끼고있는 삼각형이다.

여기서 우리가 제일 먼저 알아야할 값은 빗변(t)의 길이이다. 일단 r값과 Φ을 이용하여 t를 구하게되면,

 

sinΦ = t / r → t = r sinΦ

 

가 되는것을 확인할 수 있다. 이제 t의 값을 구했으니 t와 θ값을 이용해서 x와 z값을 구해보자.

 

x값 : cosθ = x / t → x = t cosθ → x = r sinΦ cosθ

z값 : sinθ = z / t → z = t sinθ → z = r sinΦ sinθ

 

나머지 y값은 y = r cosΦ로 확인할 수 있다.

삼각비를 제대로 이해했고 여기까지 설명을 봤으면 다 이해했다고 믿는다!

 


 

  • 구면좌표계를 이용해서 캐릭터를 중심으로 움직이는 3D카메라 좌표 계산하기.

이젠 코드와 함께 캐릭터를 중심으로 움직이는 카메라의 3D 좌표를 구해볼 차례이다. 코드를 작성하기 전에 코드에 참고한 예시는 다음 그림과 같다.

위 그림을 기준으로 새로 식을 작성해 보면

 

x = r cosΦ cosθ

y = r sinΦ

z = r cosΦ sinθ

 

으로 확인할 수 있다. (여기까지 이해했다면 당신은 좀 더 진화된 수포자다.)

 

위에서의 설명과 다른점이 하나 있는데, 우리는 카메라의 시작 좌표와 반지름(r)을 지정하여 각도를 먼저 구할것이다.

즉, (x, y, z)값을 지정해서 각 축의 값으로 역함수를 이용하여 θ와 Φ의 각도를 구할것이다.

 

※ 역함수로 직각삼각형의 두 변의 길이를 이용하여 극축과의 각도를 구할 수 있다.

 

우리는 (x, y, z)값과 r값을 알고있기 때문에, 방위각(θ)는 역함수 atan으로 구할것이고, 앙각(Φ)은 역함수 asin으로 구한다.

float Azimuth = Mathf.Atan2(_camCoordinate.z, _camCoordinate.x);
float Elevation = Mathf.Asin(_camCoordinate.y / radius);

위와 같이 작성하게되면 우리는 방위각(Azimuth)과 앙각(Elevation)을 얻을 수 있다. 이렇게 각까지 알아냈다면 나머지는 우리가 가진 값들로 직교좌표를 구하면 되는것이다.

 


 

  • 코드
[System.Serializable]
public class SphericalCoordinates
{
    private float radius, azimuth, elevation;

    public float Azimuth
    {
        get { return azimuth; }
        private set
        {
            azimuth = Mathf.Repeat(value, maxAzimuth_Rad - minAzimuth_Rad);
        }
    }

    public float Elevation
    {
        get { return elevation; }
        private set
        {
            elevation = Mathf.Clamp(value, minElevation_Rad, maxElevation_Rad);
        }
    }

    //Azimuth range
    public float minAzimuth_Deg = 0f;
    private float minAzimuth_Rad;

    public float maxAzimuth_Deg = 360f;
    private float maxAzimuth_Rad;

    //Elevation rages
    public float minElevation_Deg = -20f;
    private float minElevation_Rad;

    public float maxElevation_Deg = 40f;
    private float maxElevation_Rad;

    public SphericalCoordinates(Vector3 _camCoordinate, float _radius)
    {
        //방위각 라디안 값(최대, 최소)을 구한다.
        minAzimuth_Rad = Mathf.Deg2Rad * minAzimuth_Deg;
        maxAzimuth_Rad = Mathf.Deg2Rad * maxAzimuth_Deg;
        //앙각 라디안 값(최대, 최소)을 구한다.
        minElevation_Rad = Mathf.Deg2Rad * minElevation_Deg;
        maxElevation_Rad = Mathf.Deg2Rad * maxElevation_Deg;

        radius = _radius;
        //역함수로 방위각과 앙각을 구한다.
        Azimuth = Mathf.Atan2(_camCoordinate.z, _camCoordinate.x);
        Elevation = Mathf.Asin(_camCoordinate.y / radius);
    }

    public Vector3 toCartesian
    {
        get
        {
            //camera position = (r cosΦ cosθ, r sinΦ, r cosΦ sinθ)
            float t = radius * Mathf.Cos(Elevation);
            return new Vector3(t * Mathf.Cos(Azimuth), 
                radius * Mathf.Sin(Elevation), t * Mathf.Sin(Azimuth));
        }
    }

    public SphericalCoordinates Rotate(float newAzimuth, float newElevation)
    {
        Azimuth += newAzimuth;
        Elevation += newElevation;
        return this;
    }
}

public class CamCtrl : MonoBehaviour
{
    private Vector3 lookPosition;
    private Vector3 targetCamPos = new Vector3(0, 1.5f, -4);

    public Transform PlayerTr;
    public SphericalCoordinates sphericalCoordinates;

    void Start()
    {
        //카메라 위치 계산을 위해 x, y, z좌표와 반지름 r값을 넘겨준다.
        sphericalCoordinates = new SphericalCoordinates(targetCamPos, Mathf.Abs(targetCamPos.z));
        transform.position = sphericalCoordinates.toCartesian + PlayerTr.position;
    }

    void Update()
    {
        float horizontal = Input.GetAxis("Mouse X") * -1;
        float vertical = Input.GetAxis("Mouse Y") * -1;

        //플레이어 위치에서 조금더 위쪽으로 자리잡게 만든다.
        lookPosition = new Vector3(PlayerTr.position.x, 
        PlayerTr.position.y + targetCamPos.y, PlayerTr.position.z);

        //플레이어 중심으로 구한 구면좌표를 카메라 위치에 적용
        transform.position = sphericalCoordinates.Rotate
            (horizontal * Time.deltaTime, vertical * Time.deltaTime).toCartesian + lookPosition;

        //목표지점으로 카메라를 보게함
        transform.LookAt(lookPosition);
    }
}

 

※※ 여기서 반지름(radius)값을 조절하면 마우스 스크롤을 통한 카메라 줌인 줌아웃 기능도 추가가 가능하다.

※※ 방위각(Azimuth)와 앙각(Elevation)에 제한을 설정하고 싶다면 minAzimuth_Deg, maxAzimuth_Deg, minElevation_Deg, maxElevation_Deg 값들을 설정해두면 된다.

반응형

+ Recent posts