[SKKU DT] 50일차 -유니티 프로젝트 GitHub 충돌, repository, 게임 수학과 이동(삼각함수/구면좌표), Light Probe

2024. 1. 11. 18:25SKKU DT

728x90
반응형

GitHub 충돌

GitHub에서 충돌이 난다면, 충돌 메시지가 뜨게 되고, [Open in Visual Studio Code] 버튼을 선택하면 코드를 볼 수 있다. 변경된 점의 위쪽에 Accept Current Change, Accept Incoming Change, Accept Both Changes, Compare Changes 4개의 선택을 고를 수 있다.

 

해결 되었다면 충돌이 없어지고 Continue merge 하면 된다.

 

 


 

 

내가 기존에 가지고 있는 파일들을 기반으로 GitHub 리포지토리를 만들기

먼저, 대충 폴더 하나에 폴더랑 코드파일을 하나 만든다.

 

폴더 안에 텍스트 새로 하나 만들고 .gitignore로 만들기. 기존에 .txt 확장자도 지우기

 

 

.gitignore를 채우기 위해서 아래의 사이트를 들어가서 Unity를 입력하여 생성한다.

 

gitignore.io

Create useful .gitignore files for your project

www.toptal.com

 

 

위의 내용을 메모장에 붙여넣기.

 

 

새 텍스트 하나 만들어서 README.md를 만들어도 된다.

 

 


 

 

repository는 README와 .gitignore를 해제하고 만든다.

 

 

리포지토리를 만들면 Quick setup 내용이 나온다.

 

 

Git Bash를 켠다. Quick setup의 아래 내용을 따라가면 된다.

 

 

먼저, cd 명령어를 이용해서 Git Bash에서 내 리포지토리로 이동한다.

 

 

ls 명령어를 입력하면 내용을 볼 수 있다.

 

 

ls -a하면 숨겨진 파일도 볼 수 있다.

 

 

다른 방법으로는, 리포지토리에서 [마우스 오른쪽 클릭] - [터미널에서 열기]가 있지만 명령어가 조금 다르다.

 

 

다시 Git Bash로 돌아와서, "git init" 입력하면 .git 폴더가 만들어진다.

User@SKKU-31 MINGW64 ~/Documents/PleaseDeleteThis
$ git init
Initialized empty Git repository in C:/Users/User/Documents/PleaseDeleteThis/.git/

User@SKKU-31 MINGW64 ~/Documents/PleaseDeleteThis (master)
$ ls -a
./  ../  .git/  .gitignore  DeleteThis.cs  Library/  README.md

 

 

"git add ." 입력하면 모든 것을 add 하고 싶다는 뜻이다. 특정 파일만 하려면 "git add README.md" 같이 쓰면 된다.

"git commit -m "first commit" 커밋한다.

"git branch -M main" 깃의 마스터를 main으로 바꾼다.

"git remote add origin https://github.com/---/test.git" 깃 허브 url 정보 등록

"git push -u origin main" 내 컴퓨터 main에 있는 내용을 origin에 push 해라

User@SKKU-31 MINGW64 ~/Documents/PleaseDeleteThis (master)
$ git add .

User@SKKU-31 MINGW64 ~/Documents/PleaseDeleteThis (master)
$ git commit -m "first commit"
[master (root-commit) d9718d2] first commit
 3 files changed, 78 insertions(+)
 create mode 100644 .gitignore
 create mode 100644 DeleteThis.cs
 create mode 100644 README.md

User@SKKU-31 MINGW64 ~/Documents/PleaseDeleteThis (master)
$ git branch -M main

User@SKKU-31 MINGW64 ~/Documents/PleaseDeleteThis (main)
$ git remote add origin https://github.com/---/test.git

User@SKKU-31 MINGW64 ~/Documents/PleaseDeleteThis (main)
$ git push -u origin main
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 16 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (5/5), 1023 bytes | 1023.00 KiB/s, done.
Total 5 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/Unity-SeungwooLee/test.git
 * [new branch]      main -> main
branch 'main' set up to track 'origin/main'.

 

 

GitHub에서도 동일하게 뜨는 것을 볼 수 있다.

 

 

폴더에서 AccountManager.cs를 하나 만들면 GitHub에는 아래와 같이 뜨고, GitBash에도 뜬다.

 

 

 

git commit -a를 하면 아래 화면이 나온다. i나 esc를 누르고 주석을 입력할 수 있고, ":"로 명령어 입력, wq를 입력하면 write and quit이다. 이후 push까지 하면 끝.

 

 


 

 

Git Bash를 쓰지 않고 GitHub를 이용해서 기존 폴더를 리포지토리로 만들기

GitHub에서, [File] - [New repository...], Create repository를 누른다. 이후 나오는 Publish Repository까지 하면 쉽게 할 수 있다.

 

 


 

 

유니티 게임 수학과 이동

두 Sphere를 만들고 작은 Sphere가 큰 Sphere 주변을 원 궤도로 3초에 한 바퀴 돌도록 구현해보자.

 

 

방법 1. EarthManager 지구와 달이 같이 돈다.

public class EarthManager : MonoBehaviour
{
    float euler;
    
    void Update()
    {
        euler += Time.deltaTime;
        transform.localRotation = Quaternion.Euler(0f, euler * 100f, 0f);
    }
}

 

 

방법 2. transform.RotateAround 지구에서는 달의 한 면만 볼 수 있다.

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class Orbit : MonoBehaviour
{
    
    [SerializeField] GameObject earth;
    
    void Start()
    {
       
    }
    void Update()
    {
        transform.RotateAround(earth.transform.position, Vector3.up, Time.deltaTime * 100);
    }
}

 

 

방법 3. 삼각함수를 사용하는 방법. 달이 한쪽 방향을 유지한 채로 주위를 돈다.

using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;

public class Orbit : MonoBehaviour
{
    float euler;
    
    void Update()
    {
        euler += Time.deltaTime;
        transform.position = GetPosition(euler * 100, 3);
    }

    Vector3 GetPosition(float angle, float radius)
    {
        float x = Mathf.Cos(Mathf.Deg2Rad * angle) * radius;
        float z = Mathf.Sin(Mathf.Deg2Rad * angle) * radius;

        return new Vector3 (x, 0, z);
    }
}

 

 

위에서 내려다보면 일반적인 x, y축이 유니티에서는 x, z축이 된다. 따라서 x축 좌표는 cosine 값에 변화하고 z축 좌표는 sine 값에 변화한다. 그리고 각도는 degree가 아닌 radian 값을 사용한다.

 

 

 

구를 하나더 추가해서 조금 다른 값을 주면 아래처럼 움직인다. 태양계도 만들 수 있을 것 같다.

 

 


 

 

Capsule Wave

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CapsuleManager : MonoBehaviour
{
    [SerializeField] GameObject capsule1;
    [SerializeField] GameObject capsule2;
    [SerializeField] GameObject capsule3;

    float value = 0f;
    void Update()
    {
        value += Time.deltaTime * 50f;

        float sinWave = Mathf.Sin(Mathf.Deg2Rad * value);
        float cosWave = Mathf.Cos(Mathf.Deg2Rad * value);

        capsule1.transform.position = new Vector3(capsule1.transform.position.x, sinWave, capsule1.transform.position.z);
        capsule2.transform.position = new Vector3(capsule2.transform.position.x, cosWave, capsule2.transform.position.z);
    }
}

 

 

맨 오른쪽 캡슐에 Abs로 절대값을 씌우면 아래처럼 나온다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CapsuleManager : MonoBehaviour
{
    [SerializeField] GameObject capsule1;
    [SerializeField] GameObject capsule2;
    [SerializeField] GameObject capsule3;

    float value = 0f;
    void Update()
    {
        value += Time.deltaTime * 100f;

        float sinWave = Mathf.Sin(Mathf.Deg2Rad * value) * 3;
        float cosWave = Mathf.Cos(Mathf.Deg2Rad * value) * 3;

        capsule1.transform.position = new Vector3(capsule1.transform.position.x, sinWave, capsule1.transform.position.z);
        capsule2.transform.position = new Vector3(capsule2.transform.position.x, cosWave, capsule2.transform.position.z);
        capsule3.transform.position = new Vector3(capsule3.transform.position.x, Mathf.Abs(sinWave), capsule3.transform.position.z);
    }
}

 

 


 

 

좌표의 각도 구하기 -마우스 포인터로 탱크 머리 돌리기

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TankManager : MonoBehaviour
{
    [SerializeField] GameObject tank;

    float newAngle = 0f;
    private void Update()
    {
        if (Input.GetMouseButtonDown(0)) //마우스 왼쪽 버튼을 클릭했을 때,
        {
            Debug.Log($"Mouse Position x: {Input.mousePosition.x}, y:{Input.mousePosition.y}"); //마우스의 x, y 좌표 출력

            Vector3 tankScreenPoint = Camera.main.WorldToScreenPoint(tank.transform.position); //카메라 메인의 함수를 이용해서 월드 좌표를 스크린 좌표계로 바꾸었다.

            Debug.Log($"Tank Position x: {tankScreenPoint.x}, y:{tankScreenPoint.y}");

            Vector3 diff = Input.mousePosition - tankScreenPoint;

            float angle = Mathf.Atan2(diff.y, diff.x) * Mathf.Rad2Deg; //함수의 결과값은 rad 값으로 나오기 때문에 deg로 바꾸어야 한다.
            newAngle = 90 - angle;
        }

        tank.transform.eulerAngles = new Vector3(0f, Mathf.LerpAngle(tank.transform.eulerAngles.y, newAngle, Time.deltaTime * 4f), 0f);
    }
}

 

 


 

 

구면좌표계를 이용한 물체 위치 표현 -큐브 주변을 도는 카메라

SphericalCoordinate 클래스를 만들어서 구면좌표와 데카르트좌표를 변환하는 코드를 만들었다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SphericalCoordinates //구면좌표 연산만을 위한 클래스이므로 상속 필요없다.
{
    //반지름
    float radius;
    //방위각
    float azimuth;
    //앙각
    float elevation;

    public SphericalCoordinates(Vector3 cartesianCoordiates) //데카르트 좌표계를 입력하면, 구면좌표계로 바꿔주는 생성자이다.

    {
        //반지름
        radius = cartesianCoordiates.magnitude;

        //방위각
        azimuth = Mathf.Atan2(cartesianCoordiates.z, cartesianCoordiates.x); //아크탄젠트 특성상 두 길이를 알면 각도를 알 수 있다.

        //양각
        elevation = Mathf.Asin(cartesianCoordiates.y / radius);
    }

    public Vector3 ToCartesian //프로퍼티 생성
    {
        get //요청하면 get 부분 실행
        {
            float a = radius * Mathf.Cos(elevation);
            return new Vector3(a * Mathf.Cos(azimuth), radius * Mathf.Sin(elevation), a * Mathf.Sin(azimuth)); //각각 계산되어서 x, y, z에 들어간다.
        }
    }

    public SphericalCoordinates Rotate(float newAzimuth, float newElevation) //회전시키기
    {
        azimuth += newAzimuth;
        elevation += newElevation;
        return this;
    }
}

 

카메라의 CameraController 스크립트는 아래와 같다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CameraController : MonoBehaviour
{
    [SerializeField] Transform target; //큐브가 타겟
    SphericalCoordinates sphericalCoordinates;

    float rotateSpeed = 1f;
    float scrollSpeed = 200f;

    void Start()
    {
        //구면좌표
        sphericalCoordinates = new SphericalCoordinates(transform.position); //카메라의 포지션을 구면좌표로 바꿈
        transform.position = sphericalCoordinates.ToCartesian + target.position; //데카르트 좌표로 변환해서 타겟 포지션을 더해줌. 타겟이 움직일 경우 카메라가 타겟을 따라서 위치를 고정함.
    }

    void Update()
    {
        float h, v;
        h = Input.GetAxis("Horizontal");
        v = Input.GetAxis("Vertical");

        transform.position = sphericalCoordinates.Rotate(h * rotateSpeed * Time.deltaTime, v * rotateSpeed * Time.deltaTime).ToCartesian + target.position;

        transform.LookAt(target.position);
    }
}

 

실행하면, 타겟을 바라본 상태로 가상의 구면을 돈다.

 

 


 

 

클릭한 지점으로 큐브 이동 -RayCast 사용

RayCast는 콜라이더가 있는 물체에 적용된다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CubeManager : MonoBehaviour
{
    public float speed;
    Vector3 targetPosition;

    private void Start()
    {

    }

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if(Physics.Raycast(ray, out hit))
            {
                targetPosition = hit.point;
                Debug.Log("Target Position: " + targetPosition);
            }
        }

        Vector3 dir = targetPosition - transform.position;

        dir.Normalize();
        dir = new Vector3(dir.x, 0, dir.z);
        dir *= speed * Time.deltaTime;

        transform.position += dir;
    }
}

 

 


 

 

Tank 게임 프로젝트

아래의 무료 Tanks! 에셋을 받아서 import 한다.

 

Tanks! Tutorial | 자습서 | Unity Asset Store

Get the Tanks! Tutorial package from Unity Technologies and speed up your game development process. Find this & other 자습서 options on the Unity Asset Store.

assetstore.unity.com

 

 

Directional Light가 2개라서 하나를 비활성화 했고, [Realtime]에서 [Baked] 라이트 모드로 바꾸었다.

 

 

물체가 Lightmap에서 구워지려면 모델 설정에서 Generate Lightmap UVs가 체크되어있어야 한다.

 

 

움직이지 않는 모든 물체들을 잡고 Static을 체크한다. Yes, change children까지. Static만 라이트 굽는 대상이 된다.

 

 

[Window] - [Rendering] - [Lighting] 메뉴를 꺼내고 New로 새로 라이트 세팅 만든다. 아래의 사진에 따라 세팅해본다.

 

 

이후 Generate Lighting 누르면 라이트가 구워진다. 구워지는 중....

 

 

다 구워지면 Baked Lightmaps에 구워진 결과물들이 보인다.

 

 

탱크를 올려보면, 현재 dynamic 물체는 라이트를 받지 않기 때문에 어색해보인다. Light Probe를 사용해야한다.

 

 

Light Probe Group을 생성해서 씬에 배치한다.

 

 

다시 베이킹하면 dynamic 물체에도 라이트가 비추어지는 것 처럼 보인다.

 

 


 

 

MyTank 스크립트 생성

using System.Collections;
using System.Collections.Generic;
using UnityEditor.Rendering;
using UnityEngine;

public class MyTank : MonoBehaviour
{
    [SerializeField] private Transform turret;
    Transform tr;

    private void Start()
    {
        tr = transform;
    }

    IEnumerator Move() //코루틴으로 Move 함수 만들기
    {
        Vector3 targetPos = new Vector3(tr.position.x, tr.position.y, tr.position.z);

        while (Vector3.Distance(tr.position, targetPos) >= 0.01f)
        {
            tr.position = Vector3.MoveTowards(tr.position, targetPos, 0.1f);
            yield return null;
        }
    }

    IEnumerator TurnTurret(float rotateY, float duration) //터렛 돌리는 코루틴 생성
    {
        float startTime = Time.time;
        float initTime = Time.time - startTime;
        Quaternion turretRot = turret.localRotation;

        while(initTime <= duration)
        {
            turret.localRotation = Quaternion.Slerp(turretRot, Quaternion.Euler(0, rotateY, 0), initTime / duration);
            initTime = Time.time - startTime;
            yield return null;
        }
    }

    IEnumerator StartTank()
    {
        while(true)
        {
            yield return StartCoroutine(Move());
        }
    }
}
728x90
반응형