본문 바로가기
2D 콘텐츠 제작 개발일지 (mario)

마리오 개발 3일차(포탈이동/UI)

by 노재두내 2023. 9. 15.

오늘 할 일 

<오전>

씬 2 ,3 구성

벽돌 깨면 아이템 나오기(어제 못한거), 포탈타면 씬 이동 

<오후>

UI에 시간감소, 맵이름 , 아이템 획득에 따른 점수 증가 표시, 동전 개수


1.씬2 구성 

+ 포탈(굴뚝) 에 collider 추가

+ 뭔가 빈틈이 있어서 찾아보니 타일맵 에디터로 씬을 만들수 있어서 타일맵 에디터를 이용하여 다시 만들었다.

타일맵 에디터로 만드는데 문제점. 내가 가진 이미지의 크기가 너무 컸다-> 타일맵의 스케일을 줄이니 해결됨

타일맵으로 만들어도 선같은게 생김 찾아보니 경계선이라고 한다. => material 을 새로 생성하여

pixel snap 체크 -> 타일맵의 새로운 material을 적용 시킴

훨씬 자연스러워진 모습

 

2. 씬3 구성

씬 3도 1과 마찬가지로 길게 구성하였다.


1. 포탈 타면 씬 이동하기 

먼저 File-> build settings -> scene 추가

첫번째 씬에서는 포탈의 위에 마리오가 올라가 아래 방향키를 누르면 씬2로 전환/

씬2에서는 마리오가 포탈 앞에서 오른쪽 방향키를 누르면 씬 3로 전환이기 때문에 처음에는 portalController를 만들어서 오른쪽 화살표를 누르거나 아래 화살표를 누르면 전환하려고 했다.

생각해보니 그러면 언제 어떤씬으로 전환하는지 알기 어렵다 .

 

=>  MarioController에서 하면 될 것 같다고 생각

private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.gameObject.tag == "coin")
        {
            Destroy(other.gameObject);
        }
        if (other.gameObject.tag == "portal"|| Input.GetKey(KeyCode.DownArrow))
        {
            SceneManager.LoadScene("Map2Scene");
        }
        if (other.gameObject.tag == "portal" || Input.GetKey(KeyCode.RightArrow))
        {
            SceneManager.LoadScene("Map3Scene");
        }
    }

위쪽에서만 가능하기 때문에 마찬가지로 edge collider 2d를 추가해서 위쪽에 위치하게 하였다.

문제점1. 첫번째 포탈에서 마리오 위치를 이동하려고 오른쪽 방향키를 누르면 씬3으로 전환 =>  tag를 두개한다.

문제점2. trigger하자마자 씬 이동됨 => ||가 아니라 && 이어야함 , 수정

문제점3. &&로 했는데 씬이 이동되지 않음 -> onTriggerEnter말고 onCollisionEnter로 바꿈 -> 그래도 이동안됨 -> 

테스트 해보니 씬2에서는 정상적으로 이동됨 -> 점프해서 닿는 순간에 아래버튼을 눌러야만 이동이 됨

=>

onCollisionEnter2D: 두 객체가 충돌 시 호출

onCollisionStay2D: 두 객체가 충돌하는 동안 호출

private void OnCollisionStay2D(Collision2D collision)
    {
        if (collision.gameObject.tag == "portal" && Input.GetKey(KeyCode.DownArrow))
        {
            SceneManager.LoadScene("Map2Scene");
        }
        if (collision.gameObject.tag == "portal2" && Input.GetKey(KeyCode.RightArrow))
        {
            SceneManager.LoadScene("Map3Scene");
        }
    }


1. UI 구성

씬1->씬2->씬3로 씬 전환해도 UI가 유지되어야 한다 .->  찾아보기 -> DontDestroyOnLoad 사용하기

 

<폰트적용 및 위치잡기>

textMesh를 이용하였다. 

UIDirector 만들기

< 동전 먹으면 50점 추가, 시간 감소, 코인먹으면 숫자 1씩 증가>

찾아본점: 점수는 총 6자리로 표현 빈 앞자리는 0으로 채우기 

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

public class UIDirector : MonoBehaviour
{
    [SerializeField]
    private Text txtScore;
    [SerializeField]
    private Text txtCoin;
    [SerializeField]
    private Text txtTime;
    public Text txtMapName;

    private float time = 400f;
    private int score = 0;
    private int coin = 0;
    // Start is called before the first frame update
    void Start()
    {
        this.txtMapName.text=string.Format("WORLD\n1-1");
        this.UpdateUI();
    }

    // Update is called once per frame
    void Update()
    {
        this.time -= Time.deltaTime;
        this.txtTime.text = this.time.ToString("F0");//정수로 표현
        this.txtTime.text = string.Format("TIME\n{0}", this.txtTime.text);
    }

    public void UpdateUI()
    {
        this.txtScore.text = string.Format("MARIO\n{0:D6}", score);//총 6자리로 앞에 0으로 채우기
        this.txtCoin.text = string.Format("X {0}", this.coin);
        
    }
    public void IncreaseScore(int score)
    {
        this.score += score;
    }
    public void IncreaseCoin()
    {
        this.coin += 1;
    }

}
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.SceneManagement;

public class MarioController : MonoBehaviour
{
    private Rigidbody2D rBody2D;
    private float jumpForce = 500f;
    private float moveForce = 60f;
    private Animator anim;
    private bool isJump=false;
    private bool isLongJump = false;
    [SerializeField]
    private UIDirector uiDirector;


    // Start is called before the first frame update
    void Start()
    {
        this.rBody2D = this.GetComponent<Rigidbody2D>();
        this.anim = this.GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        //jump
        if (Input.GetKeyDown(KeyCode.Space))
        {
            if (this.rBody2D.velocity.y == 0)
            {
                this.rBody2D.AddForce(Vector2.up * this.jumpForce);
                if (this.isJump == false)
                    this.isJump = true;
            }
        }


        int dirX = 0;

        if (Input.GetKey(KeyCode.LeftArrow))
        {
            dirX = -1;
        }
            
        if (Input.GetKey(KeyCode.RightArrow))
        {
            dirX = 1;
        }
        float speedX = Mathf.Abs(this.rBody2D.velocity.x);//절대값(속도는 음수 나오면 안됨), 가속도

        if (speedX < 5f)//가속도 제한 
        {
            this.rBody2D.AddForce(new Vector2(dirX, 0) * this.moveForce);
        }

        //움직이는 방향으로 쳐다보기 
        if (dirX != 0)//달리고 있다면?
        {
            this.transform.localScale = new Vector3(dirX * 0.5f, 0.5f, 1);
        }
      
        this.anim.speed = speedX / 2.0f;

        //길게 누르면 높은 점프 짧게 누르면 낮은 점프
        if (Input.GetKey(KeyCode.Space))
        {
            isLongJump = true;
        }
        else if (Input.GetKeyUp(KeyCode.Space))
        {
            isLongJump = false;
        }
    }
    private void FixedUpdate()
    {
        if (isLongJump && this.rBody2D.velocity.y > 0)
        {
            this.rBody2D.gravityScale = 1.3f;
        }
        else
        {
            this.rBody2D.gravityScale = 2.5f;
        }
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        if (other.gameObject.tag == "coin")
        {
            Destroy(other.gameObject);
            this.uiDirector.IncreaseScore(50);
            this.uiDirector.IncreaseCoin();
        }
        this.uiDirector.UpdateUI();

    }
    private void OnCollisionStay2D(Collision2D collision)
    {
        if (collision.gameObject.tag == "portal" && Input.GetKey(KeyCode.DownArrow))
        {
            SceneManager.LoadScene("Map2Scene");
        }
        if (collision.gameObject.tag == "portal2" && Input.GetKey(KeyCode.RightArrow))
        {
            SceneManager.LoadScene("Map3Scene");
        }
    }
}

<UI유지하기+ 맵 이름 변경>

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

public class DontDestroyOnLoad : MonoBehaviour
{
    private static DontDestroyOnLoad instance = null;
    // Start is called before the first frame update
    private void Awake()
    {
        if (instance)
        {
            DestroyImmediate(this.gameObject);
            return;
        }
        instance = this;
        DontDestroyOnLoad(this.gameObject);
    }
}

스크립트 생성해서 파괴하고 싶지 않은 오브젝트(나같은 경우에는 UI(canvas)에다가 적용

 private void OnCollisionStay2D(Collision2D collision)
    {
        if (collision.gameObject.tag == "portal" && Input.GetKey(KeyCode.DownArrow))
        {
            SceneManager.LoadScene("Map2Scene");
            this.uiDirector.txtMapName.text = string.Format("WORLD\n1-2");
        }
        else if (collision.gameObject.tag == "portal2" && Input.GetKey(KeyCode.RightArrow))
        {
            SceneManager.LoadScene("Map3Scene");
            this.uiDirector.txtMapName.text = string.Format("WORLD\n2-1");
        }
    }

=> 문제점 1. 씬이 이동하면서 마리오 controller에 할당할 UIDirector가 없음 -> mario에게도 dontdestroyonLoad를 적용했더니 

마리오가 여기에 들어가면서 오류가 남

=> UI를 prefab으로 만들기 

프리팹으로 만들고-> 동적 생성하고 정보 불러오기 ?

(비동기 씬 로드 공부하기)

https://notyu.tistory.com/33 참고하기 

layer 랑 tag는 ctrl+s 로 저장안됨 , save project로 저장해야함