[SKKU DT] 41일차 -유니티 개인 프로젝트(2) (경기 스타트업 캠퍼스 디지털 트윈) -HDRI 적용, 플레이어 이동/회전(3인칭 이동), 로그인 적용

2023. 12. 27. 22:29SKKU DT

728x90
반응형
 

[SKKU DT] 40일차 -유니티 개인 프로젝트1 (경기 스타트업 캠퍼스 디지털 트윈) -기획, 건물 모델링, U

기획 기획 -디지털 트윈 구현이 가능한가? 게임 + 디지털 트윈 합칠 수 있는 방법? 내가 가져왔던 로봇 팔 아니면 다른 오픈 fbx를 가져와서 캐릭터가 돌아다니면서 해당 로봇과 상호작용 또는 특

lightbakery.tistory.com


HDRI 적용

전체적인 빛 색감을 잡기 위해서 HDRI부터 적용한다.

뒤에 산이 있으므로 나무가 있는 HDRI를 배치하였다.

 

 


 

 

교실 내부 에셋 채우기

내부 에셋은 모델링 할 시간이 없으므로 무료 에셋으로 채운다.

https://assetstore.unity.com/packages/3d/environments/low-poly-office-props-lite-131438

 

Low Poly Office Props - LITE | 3D 주변환경 | Unity Asset Store

Elevate your workflow with the Low Poly Office Props - LITE asset from RRFreelance. Find this & other 주변환경 options on the Unity Asset Store.

assetstore.unity.com

대략적으로 공간이 채워진 느낌이 든다.

**건물을 포함한 모든 에셋들은 Static 설정을 한다.

 

 


 

 

캐릭터 가져오기

https://assetstore.unity.com/packages/3d/characters/humanoids/casual-1-anime-girl-characters-185076

 

Casual 1 - Anime Girl Characters | 3D 휴머노이드 | Unity Asset Store

Elevate your workflow with the Casual 1 - Anime Girl Characters asset from Lukebox. Find this & other 휴머노이드 options on the Unity Asset Store.

assetstore.unity.com

메테리얼 오류는 URP-Lit으로 바꾸고 Transparent로 투명도를 주었고,

Alpha Clipping을 체크하여 투명해진 파트가 보이지 않게 만들었다.

Scale은 1.5배로 설정하여 환경과 맞추었다.

 

 


 

 

플레이어 이동 / 카메라 회전

3인칭 카메라 시점으로 플레이어를 이동하게 만들 예정이다.

Player 캐릭터에 Character Contoller 추가,

Cinemachine 설치

 

PlayerMovement 스트립트 추가

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

public class PlayerMove : MonoBehaviour
{
    CharacterController characterController;
    private new Transform transform;
    private new Camera camera;

    //플레이어 이동 속도
    public float movespeed = 10f;

    //플레이어 카메라 회전
    public float rotSpeed = 200f;

    //회전값 변수
    float mx = 0;
    void Start()
    {
        characterController = GetComponent<CharacterController>();
        transform = GetComponent<Transform>();
        camera = Camera.main;
    }
    void Update()
    {
        Move();
        Turn();
    }

    float h => Input.GetAxis("Horizontal");
    float v => Input.GetAxis("Vertical");

    void Move()
    {
        //카메라 설정
        Vector3 cameraForward = camera.transform.forward;
        Vector3 cameraRight = camera.transform.right;
        cameraForward.y = 0;
        cameraRight.y = 0;
        Vector3 moveDir = (cameraForward * v) + (cameraRight * h);
        moveDir.Set(moveDir.x, 0.0f, moveDir.z);
        characterController.SimpleMove(moveDir * movespeed);
    }

    void Turn()
    {
        float horizontal = Input.GetAxis("Mouse X");
        mx += horizontal * rotSpeed * Time.deltaTime;
        transform.eulerAngles = new Vector3(0, mx, 0);
    }
}

 

 

CharacterController의 속성 때문에 실행을 하면 캐릭터가 밑으로 떨어진다. 바닥에 Mesh Collider를 설정하고 Convex Mesh를 체크한다.

 

캐릭터의 Capsule Collider가 잘 안맞아서 공중부양해서 돌아다니길래 콜라이더를 캐릭터 몸에 맞게 수정하였다.

 

이제 씨네머신 Virtual 카메라를 적용하여 카메라가 캐릭터를 따라다니게 한다.

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

public class PlayerMove : MonoBehaviour
{
    CharacterController characterController;
    private new Transform transform;
    private new Camera camera;

    //플레이어 이동 속도
    public float movespeed = 10f;

    //플레이어 카메라 회전
    public float rotSpeed = 200f;

    //회전값 변수
    float mx = 0;

    //시네머신 가져오기
    CinemachineVirtualCamera virtualCamera;
    void Start()
    {
        characterController = GetComponent<CharacterController>();
        transform = GetComponent<Transform>();
        camera = Camera.main;

        //virtualCamera 가져오기
        virtualCamera = GameObject.FindObjectOfType<CinemachineVirtualCamera>();

        virtualCamera.Follow = transform;
        virtualCamera.LookAt = transform;
    }
    void Update()
    {
        Move();
        Turn();
    }

    float h => Input.GetAxis("Horizontal");
    float v => Input.GetAxis("Vertical");

    void Move()
    {
        //카메라 설정
        Vector3 cameraForward = camera.transform.forward;
        Vector3 cameraRight = camera.transform.right;
        cameraForward.y = 0f;
        cameraRight.y = 0f;
        Vector3 moveDir = (cameraForward * v) + (cameraRight * h);
        
        moveDir.Set(moveDir.x, 0.0f, moveDir.z);
        characterController.SimpleMove(moveDir * movespeed);
    }

    void Turn()
    {
        float horizontal = Input.GetAxis("Mouse X");
        mx += horizontal * rotSpeed * Time.deltaTime;
        transform.eulerAngles = new Vector3(0, mx, 0);
    }
}

 

위와 같은 상황에서는 내 카메라로 내 캐릭터를 볼 수가 없어서, 카메라가 돌아갈 때 캐릭터가 같이 돌아가지는 않게 수정해야 할 것 같다. 수 많은 시도 끝에 Cinemachine 컴포넌트 수정으로 비슷한 구현까지 했다!

Virtual Camera의 Body는 [Orbital Transposer]로, Aim은 [Composer]로 설정했다.

[Orbital Transposer]의 [Follow Offset] 수정은 원하는 만큼 하면 된다.

 

 

Virtual Camera의 Recenter는 꺼야 시간 지나도 다시 제자리로 가지 않는다. Input Axis Value에 Invert를 체크 해제하면 마우스가 가는 방향대로 시야가 회전되어 더 직관적이다.

 

 

원하고자 했던 플레이어 무브를 구현하였다. 카메라가 비추는 방향 쪽으로 플레이어가 이동하며 상하좌우 키를 입력하면 플레이어가 해당 방향으로 몸을 튼다. [Lock To Target On Assign]을 해서 플레이어가 이동 중 방향을 틀어도 카메라는 그 자리를 유지하도록 설정하였다.

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

public class PlayerMove : MonoBehaviour
{
    CharacterController characterController;
    private new Transform transform;
    private new Camera camera;

    //플레이어 이동 속도
    public float movespeed = 10f;

    //플레이어 카메라 회전
    public float rotSpeed = 200f;

    //회전값 변수
    float mx = 0;

    //시네머신 가져오기
    CinemachineVirtualCamera virtualCamera;

    //플레이어 움직임 true/false
    bool isMoving = false;
    void Start()
    {
        characterController = GetComponent<CharacterController>();
        transform = GetComponent<Transform>();
        camera = Camera.main;

        //virtualCamera 가져오기
        virtualCamera = GameObject.FindObjectOfType<CinemachineVirtualCamera>();
    }
    void Update()
    {
        Move();
    }

    float h => Input.GetAxis("Horizontal");
    float v => Input.GetAxis("Vertical");

    void Move()
    {
        //카메라 설정
        Vector3 cameraForward = camera.transform.forward;
        Vector3 cameraRight = camera.transform.right;
        cameraForward.y = 0f;
        cameraRight.y = 0f;
        Vector3 moveDir = (cameraForward * v) + (cameraRight * h);

        moveDir.Set(moveDir.x, 0.0f, moveDir.z);
        characterController.SimpleMove(moveDir * movespeed);

        

        if (Input.GetKey("w"))
        {
            transform.forward = cameraForward;
        }
        if (Input.GetKey("a"))
        {
            transform.right = cameraForward * 90;
        }
        if (Input.GetKey("s"))
        {
            transform.forward = -cameraForward;
        }
        if (Input.GetKey("d"))
        {
            transform.right = cameraForward * -90;
        }

    }
}

 

 


 

 

파이어 베이스를 이용한 로그인 구현

 

[SKKU DT] 30일차 -유니티 네트워크 -파이어베이스(Firebase) Authentication 로그인, 익명 로그인

Firebase란? -Google에서 제공하는 클라우드 기반의 개발 플랫폼. 사용자 인증(로그인 서비스), 실시간 데이터베이스, 분석, 파일 스토리지 등을 포함한 많은 기능을 지원한다. -WhatsApp, Snapchat, Airbnb, U

lightbakery.tistory.com

 

 

 

[XR 전문 인력 과정] 유니티 타워디펜스 만들기(5) -프로젝트 최적화, 추가 기능 넣기(로비/로그인

https://create.unity.com/performance-optimization-e-book-console-PC?ungated=true Optimize your console and PC game performance Country AfghanistanÅland IslandsAlbaniaAlgeriaAmerican SamoaAndorraAngolaAnguillaAntarcticaAntigua and BarbudaArgentinaArmeniaAr

lightbakery.tistory.com

앞서 했던 파이어베이스(Firebase)를 이용한 로그인 구현과 동일하게 진행할 예정이다.

 

 

Other Settings에서 Bundle Identifier 확인

 

 

Firebase에서, 유니티 프로젝트로 앱추가를 한다.

가운데 하이픈은 되지 않아서 아예 프로젝트 이름에서 지웠다.
json을 받아 [Assets] - [StreamingAssets] 폴더를 만들어서 다운 받은 json을 추가한다.
다운 받은 zip 파일 중 FirebaseAuth.unitypackage를&nbsp; [Assets] - [Import Package] - [Custom Package...]로 import 한다.
위쪽 오류 클릭해서 경로 찾아서 Inspector 전부 체크 해제하고 Apply
그 아래 오류는 파일 경로 찾아서 "UNITY_IOS" 입력하고 Apply

FirebaseAuthManager 스크립트 생성

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Firebase.Auth;
using TMPro;


public class FirebaseAuthManager : MonoBehaviour
{
    private FirebaseAuth auth; //인증을 위한 변수 선언
    public TMP_InputField email;
    public TMP_InputField password;
    void Start()
    {
        auth = FirebaseAuth.DefaultInstance;
    }

    public void Create() //계정 생성
    {
        auth.CreateUserWithEmailAndPasswordAsync(email.text, password.text).ContinueWith(task => //람다식, 결과는 task가 나온다.
        {
            if (task.IsFaulted) //계정을 만들지 못했을 경우,
            {
                Debug.Log("계정 생성 실패");
                return;
            }
            if (task.IsCanceled) //계정 생성을 실패했을 경우(네트워크 장애, 도중 취소)
            {
                Debug.Log("계정 생성 취소");
                return;
            }
            FirebaseUser newUser = task.Result.User; //계정을 만들지 못하거나 실패했을 경우가 아닐 경우
        });
    }

    public void LogIn() //로그인 함수 계정 생성과 동일한 코드 복붙, 수정
    {
        auth.SignInWithEmailAndPasswordAsync(email.text, password.text).ContinueWith(task => //람다식, 결과는 task가 나온다.
        {
            if (task.IsFaulted) //로그인을 못했을 경우,
            {
                Debug.Log("로그인 실패");
                return;
            }
            if (task.IsCanceled) //로그인을 실패했을 경우(네트워크 장애, 도중 취소)
            {
                Debug.Log("로그인 취소");
                return;
            }
            Debug.Log("로그인 성공");
        });
    }

    public void LogOut() //로그아웃 함수
    {
        auth.SignOut();
        Debug.Log("로그아웃"); //로그아웃 확인
    }
}

 

로그인 씬 만들기 -InputField와 Button 배치

 

빈 오브젝트 또는 EventSystem에 만든 FirebaseAuthManager 스크립트 넣기

버튼에 함수 매핑
Build Settings에 씬 전환을 위해서 로그인 씬, 메인 씬 추가

 

씬 이동을 위한 LogIn 함수 수정. SceneManager.LoadScene(1); 추가하였다. 비동기 함수이기 때문에 아래와 같이 수정한다. 이전 글 참조.

public async void LogIn() //로그인 함수 계정 생성과 동일한 코드 복붙, 수정
{
    try
    {
        var signInTask = await auth.SignInWithEmailAndPasswordAsync(email.text, password.text);
        Debug.Log("로그인 성공");
        SceneManager.LoadScene(1);
    }
    catch (System.Exception e)
    {
        Debug.Log($"로그인 실패: {e.Message}");
    }
}

 

public으로 TextMeshPro 하나 가져와서 로그인 실패 메시지 출력

public async void LogIn() //로그인 함수 계정 생성과 동일한 코드 복붙, 수정
{
    try
    {
        var signInTask = await auth.SignInWithEmailAndPasswordAsync(email.text, password.text);
        Debug.Log("로그인 성공");
        SceneManager.LoadScene(1);
    }
    catch (System.Exception e)
    {
        Debug.Log($"로그인 실패: {e.Message}");
        loginFailedtext.text = "Login Failed";
    }
}

 

완성, 전체 코드

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Firebase.Auth;
using TMPro;
using UnityEngine.SceneManagement;

public class FirebaseAuthManager : MonoBehaviour
{
    private FirebaseAuth auth; //인증을 위한 변수 선언
    public TMP_InputField email;
    public TMP_InputField password;
    public TMP_Text loginFailedtext;
    void Start()
    {
        auth = FirebaseAuth.DefaultInstance;
    }

    public void Create() //계정 생성
    {
        auth.CreateUserWithEmailAndPasswordAsync(email.text, password.text).ContinueWith(task => //람다식, 결과는 task가 나온다.
        {
            if (task.IsFaulted) //계정을 만들지 못했을 경우,
            {
                Debug.Log("계정 생성 실패");
                return;
            }
            if (task.IsCanceled) //계정 생성을 실패했을 경우(네트워크 장애, 도중 취소)
            {
                Debug.Log("계정 생성 취소");
                return;
            }
            FirebaseUser newUser = task.Result.User; //계정을 만들지 못하거나 실패했을 경우가 아닐 경우
        });
    }

    public async void LogIn() //로그인 함수 계정 생성과 동일한 코드 복붙, 수정
    {
        try
        {
            var signInTask = await auth.SignInWithEmailAndPasswordAsync(email.text, password.text);
            Debug.Log("로그인 성공");
            SceneManager.LoadScene(1);
        }
        catch (System.Exception e)
        {
            Debug.Log($"로그인 실패: {e.Message}");
            loginFailedtext.text = "Login Failed";
        }
    }

    public void LogOut() //로그아웃 함수
    {
        auth.SignOut();
        Debug.Log("로그아웃"); //로그아웃 확인
    }
}

로그인 구현 완료

 


아직 남은 과제

-플레이어 애니메이션 넣기

-포톤 적용

728x90
반응형