EasyCastleUNITY

HeroShooter 씬 전환 시에 변화 본문

유니티 심화

HeroShooter 씬 전환 시에 변화

EasyCastleT 2023. 8. 24. 18:19

튜토리얼 -> 특정 위치에 가면 문이 열리며, 포탈이 생성된다

생성된 포탈 근처에 가면, 페이드 인/아웃 하고 다음 씬으로 넘어간다. 

DoorController -> 말 그대로 문을 제어, 코루틴과 slerp를 사용하여, 문을 여는 애니메이션처럼 연출

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

public class DoorController : MonoBehaviour
{
    [SerializeField] private Transform rightDoor;
    [SerializeField] private Transform leftDoor;
    
    public void OpenDoor()
    {
        StartCoroutine(this.CoOpenDoor());
        Debug.Log("문 개방!");
    }

    private IEnumerator CoOpenDoor()
    {
        while (true)
        {
            this.rightDoor.localRotation = Quaternion.Slerp(this.rightDoor.localRotation, Quaternion.Euler(0, -100, 0), Time.deltaTime);
            this.leftDoor.localRotation = Quaternion.Slerp(this.leftDoor.localRotation, Quaternion.Euler(0, 100, 0), Time.deltaTime);
            yield return null;
            if (this.rightDoor.localRotation == Quaternion.Euler(0,-100,0) &&
                this.leftDoor.localRotation == Quaternion.Euler(0,100,0))
            {
                break;
            }
        }
        
        //yield return null;
    }
}

PlayerController 

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

public class PlayerController : MonoBehaviour
{
    public enum eControlType
    {
        KeyBoard,Joystick
    }
    [SerializeField] private FloatingJoystick joystick; //조이스틱
    [SerializeField] private eControlType controlType; //플레이어 이동 타입
    [SerializeField] private float moveSpeed = 1.0f; //플레이어 이동 속도

    [SerializeField] private Transform target; //튜토리얼에서의 특정위치
    [SerializeField] private float radius = 1.0f; //플레이어가 자기 주변을 인식하는 반경

    private GameObject portal;
    private GameObject targetMonster;

    public System.Action onPortal; //튜토리얼 포탈
    public System.Action onTarget; //튜토리얼 타겟

    private float h = 0;
    private float v = 0;

    public float H
    {
        get { return h; }
    }
    public float V
    {
        get { return v; }
    }
    public GameObject Portal
    {
        set { this.portal = value; Debug.Log("설정완료"); }
    }

    public GameObject TargetMonster
    {
        get { return this.targetMonster; }
    }
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if(this.controlType == eControlType.Joystick)
        {
            h = this.joystick.Direction.x;
            v=  this.joystick.Direction.y;
        }
        else if(this.controlType==eControlType.KeyBoard)
        {
            h = Input.GetAxisRaw("Horizontal");
            v = Input.GetAxisRaw("Vertical");
        }
        Vector3 direction = new Vector3(h, 0, v);
        float angle =Mathf.Atan2(direction.x,direction.z) * Mathf.Rad2Deg;
        //이동
        this.transform.Translate(direction * this.moveSpeed * Time.deltaTime,Space.World);
        //회전
        this.transform.localRotation = Quaternion.AngleAxis(angle, Vector3.up);
        this.OnTarget();
        this.OnPortal();
        this.SearchMonster();
        
    }
    //튜토리얼에서 특정 위치 가면 실행되는 메서드
    private void OnTarget()
    {
        if(this.target != null)
        {
            float distance = Vector3.Distance(this.transform.position, target.position);
            //Debug.LogFormat("distance:{0}", distance);
            if (distance < 1.6f) //목표위치에 도착
            {
                this.onTarget(); //대리자 호출
            }
        }
    }
    //튜토리얼에서 포탈의 위치에 가면 실행되는 메서드 
    private void OnPortal()
    {
        if(this.portal != null)
        {
            float distance = Vector3.Distance(this.transform.position,
                this.portal.transform.position);
            if(distance < 4.8f)
            {
                //다음 씬으로 이동
                this.onPortal();
            }
        }
    }
    //주변에 있는 몬스터를 검색하여 선택하는 메서드
    private void SearchMonster()
    {
        float distance= 0.0f;
        int layerMask = 1 << LayerMask.NameToLayer("Monster");
        Collider[] colls = Physics.OverlapSphere(this.transform.position, radius, layerMask);
        foreach(Collider coll in colls)
        {
            this.targetMonster = coll.gameObject;
            Debug.LogFormat("<color=yellow>타겟 선택 targetMonster:{0}</color>",
                this.targetMonster.name);   
        }
        if(this.targetMonster != null)
        {
            distance = Vector3.Distance(this.transform.position,
            this.targetMonster.transform.position);
            this.transform.LookAt(this.targetMonster.transform.position);
        }
        if(distance > this.radius)
        {
            this.targetMonster = null;
            Debug.Log("<color=red>선택해제</color>");
        }

    }
    //주변에 몬스터가 있다면 공격하는 메서드
    private void Attack()
    {

    }

    private void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawWireSphere(this.transform.position, radius);
    }
}

PortalGenerator 포탈을 생성

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

public class PortalGenerator : MonoBehaviour
{
    [SerializeField] private GameObject PortalPrefab;
    public GameObject PortalGenerate(Transform transform)
    {
        Vector3 pos = new Vector3(0, 1.5f, 30f);
        GameObject go =Instantiate(PortalPrefab, pos, transform.rotation);
        return go;
        //this.StartCoroutine(CoPortalCreate(transform));
    }
    
}

TutorialMain -> 튜토리얼 전체를 제어

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using static UnityEngine.GraphicsBuffer;

public class TutorialMain : MonoBehaviour
{
    [SerializeField]
    private PortalGenerator portalGenerator;
    [SerializeField]
    private PlayerController playerController;
    [SerializeField] private GameObject door;
    [SerializeField] private Transform target;
    [SerializeField] private GameObject fadeOut;

    private Transform doorTransform;

    private GameObject portal;

    public GameObject Portal
    {
        get { return this.portal; }
    }

    // Start is called before the first frame update
    void Start()
    {
        this.doorTransform = this.door.transform;
        this.playerController.onPortal = () => {
            Debug.Log("<color=yellow>포탈위치에 도착</color>");
            //Debug.LogError("!");//error pause용
            this.fadeOut.SetActive(true);
            //씬전환
        };
        this.playerController.onTarget = () => {
            Debug.Log("<color=yellow>목표위치에 도착</color>");
            Destroy(target.gameObject);

            if (this.door != null)
            {
                this.doorTransform.position = new Vector3(this.door.transform.position.x, -0.24f, this.door.transform.position.z);
                this.portal = this.portalGenerator.PortalGenerate(this.doorTransform);
                this.playerController.Portal = this.portal; //포탈 설정
                this.door.GetComponent<DoorController>().OpenDoor();
            }
        };
    }
}

포탈에 도착하면 fadeout 하고 다음 씬으로 전환

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class FadeOutMain : MonoBehaviour
{
    [SerializeField] private Image dim;

    private System.Action onFadeOutComplete;
    // Start is called before the first frame update
    void Start()
    {
        Image image =this.dim.GetComponent<Image>();
        image.enabled = true;
        this.onFadeOutComplete = () => {
            SceneManager.LoadScene("StageOne");
        };
        this.StartCoroutine(this.FadeOut());
    }

    private IEnumerator FadeOut()
    {
        Color color = this.dim.color;
        //어두어짐
        while(true)
        {
            color.a += 0.01f;
            this.dim.color = color;

            if(this.dim.color.a >= 1)
            {
                break;
            }
            yield return null; 
        }
        Debug.Log("FadeOut Complete!");
        this.onFadeOutComplete();
    }

}

다음 씬에서 fadein 실행

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

public class FadeInMain : MonoBehaviour
{
    [SerializeField]
    private GameObject StageOneMain;
    [SerializeField] private Image dim;

    private System.Action onFadeInComplete;
    // Start is called before the first frame update
    void Start()
    {
        this.onFadeInComplete = () => {
            Debug.Log("FadeIn complete!");
            //this.StageOneMain.SetActive(true);
            Image image = this.dim.GetComponent<Image>();
            image.enabled = false;
            Destroy(this.gameObject,1.0f);
        };  
        this.StartCoroutine(this.FadeIn());
    }

   private IEnumerator FadeIn()
    {
        Color color = this.dim.color;

        while (true)
        {
            color.a -= 0.01f;
            this.dim.color = color;

            if(this.dim.color.a <= 0)
            {
                break;
            }
            yield return null;
        }
        this.onFadeInComplete();
    }
}