전제 조건

  • 첫번째 Scene에서 생성되어 게임이 실행되는 동안 계속 소유하고 있는 무언가가 있어야 함
    • 현재 쓰고 있는 구조에서는 App이라는 스크립트가 게임 시작부터 끝까지 존재
  • 각 Scene마다 소유하고 있는 스크립트가 존재해야 함
    • 현재 쓰고 있는 구조에서는 _Ruler(상속)라는 스크립트가 존재
      • 예) Ruler_Logo, Ruler_Lobby 등

방법

  1. (예외 처리 1) 첫번째 Scene으로 갈 지 안 갈 지를 판단
    • isGoToApp:Bool 라는 Inspector 상에서 보이는 변수를 _Ruler가 소유 중
    • 해당 isGoToApp이 True면 밑의 내용을 실행, False면 return
      • (예외 처리 2)
        • False일 때 App을 아예 생성해서 모든 작업들(데이터 로드 등)을 우선 진행한 후 이 Scene에 남아 있게 할 수도 있음
          • 이 Scene에서는 로드가 전부 될 때까지 지연 처리
        • 다만 그 경우 여러모로 각 씬 + 협업하는 사람이 합(데이터 로드는 무조건 한 곳)을 맞춰야 함
  2. _Ruler가 Awake될 때 App이라는 스크립트가 현재 화면 내에 존재하는 지 확인
  3. App이 없다면 바로 0번째 Scene을 로드
  4. 완료

생각해볼 것

  • 저런 처리(스크립트 존재) 없이 유니티 상에서 시작 시에 현재 Scene을 판단해서 어떤 항목의 ON/OFF에 따라 첫번째(0) Scene으로 갈 수 있지 않을까?
블로그 이미지

RIsN

,

  • Auto Simulation이 켜져 있는 지 확인
블로그 이미지

RIsN

,

[Unity] 가로 Swipe 판단

Unity 2023. 1. 22. 17:44

목표: 가로 Swipe를 토대로 캐릭터 카메라 회전

  • Event에 익숙해지기 위해서 Event 사용
    • Scene이 바뀌어도 딱히 문제 없이 사용하기 위함
private Coroutine iCoroutine_Input = null;
public void StartInput()
{
    this.iCoroutine_Input = this.StartCoroutine(this.IENInput());
}
public event System.Action<float> eSwipeHorizontal = null;
private IEnumerator IENInput()
{
    while (true)
    {
        // :: Swipe Horizontal
        // :: 처음 터치
        if (Input.GetMouseButtonDown(0))
        {
            // :: 터치 시작 위치
            Vector2 startPos = Input.mousePosition;
            // :: 터치 중
            while (Input.GetMouseButton(0))
            {
                // :: 터치 끝 위치
                Vector2 endPos = Input.mousePosition;
                // :: 터치 방향
                Vector2 swipe = endPos - startPos;
                // :: 터치 방향 이벤트
                this.eSwipeHorizontal?.Invoke(swipe.x);
                yield return null;
            }
        }
        yield return null;
    }
}
public void StopInput()
{
    if (this.iCoroutine_Input != null)
    {
        this.StopCoroutine(this.iCoroutine_Input);
        this.iCoroutine_Input = null;
    }
}

 

블로그 이미지

RIsN

,

목표: 게임의 레시피 UI가 카메라를 계속 바라볼 필요가 있음

  • 주의
    • 빈 게임 오브젝트를 만들고 거기에 스크립트를 부착할 필요가 있음.
    • 내부의 이미지나 글은 조금 각도 등이 수정이 가능한 형태로 만들어야 나중에 편해짐

예) 방식

using System.Collections;
using UnityEngine;

public class GearTool_LookAtCamera : _Gear
{
    public override void Init() { }

    // :: 따라갈 카메라 혹은 오브젝트
    [SerializeField] private Transform iCamera = null;

    // :: 쳐다보기
    void Update()
    {
        if (this.iCamera == null) this.iCamera = Camera.main.transform;

        this.transform.LookAt(
            this.transform.position + this.iCamera.rotation * Vector3.forward,
            this.iCamera.rotation * Vector3.up);
    }
}
  • _Gear는 현재 쓰고 있는 형식, MonoBehaviour로 사용하거나, 상황에 맞춰서 사용할 것
블로그 이미지

RIsN

,

목표: TextMeshPro에서 숫자가 바뀔 때마다 카운팅 하여 숫자를 집어 넣도록 처리

using System.Collections;

public static class ToolText
{
    public static void CountingTo(this TMPro.TMP_Text _targetText, int _goal)
    {
        // :: 코루틴을 실행할 녀석 확인
        // :: 지금 구조에서는 App이 모든 코루틴을 실행하고 관리할 예정
        App.oInstance.StartCoroutine(_targetText.IENCountingTo(_goal));
    }
    public static IEnumerator IENCountingTo(this TMPro.TMP_Text _targetText, int _goal)
    {
        // :: 현재 값
        int current = int.Parse(_targetText.text);

        // :: Up일 경우
        while (current < _goal)
        {
            if (current + 100 < _goal) current += 100;
            else if (current + 10 < _goal) current += 10;
            else current++;

            _targetText.text = string.Format("{0}", current);
            yield return null;
        }
        // :: Down일 경우
        while (current > _goal)
        {
            if (current - 100 > _goal) current -= 100;
            else if (current - 10 > _goal) current -= 10;
            else current--;

            _targetText.text = string.Format("{0}", current);
            yield return null;
        }

        // :: 마지막 재확인
        _targetText.text = string.Format("{0}", _goal);
    }
}
블로그 이미지

RIsN

,

목표: 3D 카메라로 바라보는 3D 오브젝트의 위치에 UI 카메라 상의 캔버스에 이미지를 표시
>> 사용 이유: 내가 선호하는 구조가 3D 카메라와 UI카메라의 복합적인 구조

using System;
using UnityEngine;

public static class ToolCamera
{
    public static Vector3 ConvertPosition3DTo2DLocal(this Camera _camera3D,
    Camera _camera2D, Canvas _canvas, Vector3 _position3D)
    {
        // :: 3D 카메라에서의 3D 위치를 3D 카메라에서의 2D 위치로 변경
        Vector3 position2Din3D = _camera3D.WorldToScreenPoint(_position3D);

        // :: 3D 카메라에서의 2D 위치를 UI(2D) 카메라에서의 2D 로컬 위치로 변경
        Vector2 result;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(
            _canvas.transform as RectTransform, position2Din3D, _camera2D, out result);

        // :: Z축은 0으로 고정
        return new Vector3(result.x, result.y, 0);
    }
}

 

블로그 이미지

RIsN

,

1. 애니메이터 컨트롤러 켜기

2. 2개의 레이어(행동, 표정)를 만들기
>> 마스크 등으로 행동 + 행동 등도 가능하지만, 우선 지금 필요한 건 행동 + 표정

3. 2개의 레이어(행동, 표정) 전부 weight 수치를 1로 설정

4. 실행시키면 동시에 애니메이션 2개(앉아서 움직임 + 눈 깜빡임)가 같이 실행되는 것을 확인 가능합니다.

 

블로그 이미지

RIsN

,

  • 해당 이미지의 Sprite Mode가 설정이 안되어 있는 경우가 있으며, 그럴 경우 해당 항목을 설정해줘야 합니다.
블로그 이미지

RIsN

,

1차 시도

  1. Assets에서 오른쪽 클릭, Play Service Resolver → Android Resolver → Resolve

결과: 실패

2차 시도

  1. Assets에서 오른쪽 클릭, Play Service Resolver → Android Resolver → Force Resolve

결과: 실패

3차 시도

  1. Project Settings에서 Player → Publishing Settings → Build
    1. Custom Main Gradle Template: Enable 처리
    2. Custom Gradle Properties Template: Enable 처리
  2. Assets에서 오른쪽 클릭, Play Service Resolver → Android Resolver → Resolve

결과: 실패

4차 시도(...끝을 보자)

  1. GPGS 설치 전 성공 Git 버전으로 회귀
  2. Assets, Packages, ProjectSettings 외 전부 제거
  3. API Level 32
  4. GPGS 설치
  5. Plugin의 Android 내부에 있는 파일 전부 제거
  6. Assets에서 오른쪽 클릭, Play Service Resolver → Android Resolver → Resolve

결과: 실패...

5차 시도

  1. 4차 시도
  2. Assets에서 오른쪽 클릭, Play Service Resolver → Android Resolver → Force Resolve

결과: 실패

6차 시도

  1. 왜 인지 성공한 컴퓨터가 있어서 그 파일을 그대로 비교해서 설정 적용

결과: 실패

7차 시도(새로 시작)

  1. GPGS 설치 전 성공 Git 버전으로 회귀
  2. 새 프로젝트를 Google Play Console에 제작
  3. 해당 프로젝트에 우선 성공 Git 버전 빌드(aab)해서 업로드
  4. 참고: https://docs.unity.com/authentication/SettingupGoogleSignin.html
  5. Google Play Games plugin for Unity v10.14 유니티에 Import
    • 이 시점에서 이미 빌드는 해결
  6. Play Games 설정
  7. 참고: https://young-94.tistory.com/225
  8. 해당 프로젝트 빌드(aab)

결과: 성공

블로그 이미지

RIsN

,

원본: https://github.com/Unity-Technologies/EntityComponentSystemSamples/blob/master/DOTS_Guide/ecs_tutorial/README.md

Step 9 - 카메라 추적(Camera follow)

런타임에서 ECS와 GameObjects의 간단한 상호작용.

  1. "Scripts/MonoBehaviours" 폴더에 "CameraSingleton.cs"이라는 이름의 새 C# 스크립트 파일을 만들고 다음 내용을 저장합니다:
  2. // 메인 카메라에 접근하는 방법은 여러 가지가 있지만, 
    // 싱글톤(여기서 사용하는 방식)을 사용하는 접근 방식은 모든 종류의 MonoBehaviour에서 작동됩니다.
    class CameraSingleton : UnityEngine.MonoBehaviour
    {
        public static UnityEngine.Camera Instance;
    
        void Awake()
        {
            Instance = GetComponent<UnityEngine.Camera>();
        }
    }
  3. "SampleScene"의 "Main Camera" 게임 오브젝트에 "CameraSingleton" MonoBehavior를 추가합니다.
  4. "Scripts/Systems" 폴더에 "CameraSystem.cs"이라는 이름의 새 C# 스크립트 파일을 만들고 다음 내용을 저장합니다:
  5. using Unity.Collections;
    using Unity.Entities;
    using Unity.Mathematics;
    using Unity.Transforms;
    
    // 이 시스템은 변환 시스템이 업데이트된 후 실행되어야 합니다. 
    // 그렇지 않으면 카메라가 탱크보다 한 프레임 뒤로 처져 흔들림이 발생합니다.
    [UpdateInGroup(typeof(LateSimulationSystemGroup))]
    partial class CameraSystem : SystemBase
    {
        Entity Target;
        Random Random;
        EntityQuery TanksQuery;
    
        protected override void OnCreate()
        {
            Random = Random.CreateFromIndex(1234);
            TanksQuery = GetEntityQuery(typeof(Tank));
            RequireForUpdate(TanksQuery);
        }
    
        protected override void OnUpdate()
        {
            if (Target == Entity.Null || UnityEngine.Input.GetKeyDown(UnityEngine.KeyCode.Space))
            {
                var tanks = TanksQuery.ToEntityArray(Allocator.Temp);
                Target = tanks[Random.NextInt(tanks.Length)];
            }
    
            var cameraTransform = CameraSingleton.Instance.transform;
            var tankTransform = GetComponent<LocalToWorld>(Target);
            cameraTransform.position = tankTransform.Position - 10.0f * tankTransform.Forward + new float3(0.0f, 5.0f, 0.0f);
            cameraTransform.LookAt(tankTransform.Position, new float3(0.0f, 1.0f, 0.0f));
        }
    }
  6. 플레이 모드로 들어가서 게임 뷰(이전과 같이 씬 뷰가 아님)를 보면 카메라가 탱크 중 하나를 따라가고 있음을 확인할 수 있습니다.  게임 뷰에 입력 포커스가 되어 있는지 확인하고(클릭해서) 스페이스바를 반복적으로 누릅니다. 카메라는 그 때마다 매번 다른 임의의 탱크로 전환되어야 합니다.
  7. 플레이 모드에서 나오세요.

축하합니다!

이 튜토리얼을 끝냈습니다! 가서 케이크 좀 사 와서 축하하세요!

블로그 이미지

RIsN

,