캐릭터가 올라갈 수 있는 움직이는 블록을 만들겠습니다. 다음같은 속성을 갖습니다.

  • 이동방향
  • 거리
  • 시간
  • 플레이어가 올라가면 움직이느냐?

움직이는 블록 게임 오브젝트 만들기

Assets>Images폴더내 block_move을 프로젝트 뷰에서 씬뷰로 배치해 게임 오브젝트를 만들고 이름은 MovingBlock으로 합니다.

인스펙트뷰에서 Layer를 Ground로 하고 Sprite Rendere의 Order in Layer의 값을  2로 설정하고 Box Collider 2D를 어태치합니다. 이동 블록은 물리동작을 따르지 않아 Rigidbody는 필요없습니다.

 

블록을 움직이는 스크립트 작성

MovingBlock 스크립트를 만들고 MovingBlock 게임오브젝트에 어태치해줍니다.

변수

public float moveX = 0.0f;          //X이동거리
public float moveY = 0.0f;          //Y이동거리
public float times = 0.0f;          //단방향 이동시간
public float weight = 0.0f;         //정지 시간
public bool isMoveWhenOn = false;   //올라 탓을 때 움직이기

public bool isCanMove = true;       //움직임
float perDX;                        //1프레임 당 X이동 값, 이동속도
float perDY;                        //1프레임 당 Y이동 값, 이동속도
Vector3 defPos;                     //초기 위치, 왕복시 돌아올 위치
bool isReverse = false;             //정방향 반대반향 여부

Start()

perDX = moveX / (1.0f / timestep * times);  //1 프레임의 X 이동 값 이다.

float timestep = Time.fixedDeltaTime; //1프레임에 이동하는 시간

1/timestep = 1초당 프레임수

moveX/프레임수 = 1초동안 인동할 때 한프레임당 이동거리

한프레임당 이동거리 / times = times초 이동시 한프레임 이동거리

결론은 perDX는 tiems초 동안 블록이 moveX거리를 이동할때 프레임당 이동거리이다. 간단한걸 엄청 복잡하게 써놨다.

그냥 perDX = moveX * Time.fixedDeltaTime * speed(1/ times)와 같다. ㅠㅠㅠ

만일 블록 특성이 isMoveWhenOn(올라타야 움직임) = true라면 isCanMove = false로 만들어 블록이 이동못하게 한다.

void Start(){
    defPos = transform.position;         //초기 위치
    float timestep = Time.fixedDeltaTime; //1프레임에 이동하는 시간 
    perDX = moveX / (1.0f / timestep * times);  //1 프레임의 X 이동 값
    perDY = moveY / (1.0f / timestep * times); //1 프레임의 Y 이동 값

    if (isMoveWhenOn){
        //처음엔 움직이지 않고 올라 타면 움직이기 시작
        isCanMove = false;
    }
}

FixedUpdate()

코드가 긴것 같은데 별것 없다. 위에서 정한 perDX값만큼 매 프레임 transform.Translate()만큼 움직여주면 된다. 그러다 moveX만큼 움직이거나 다시 원위치로 오면 잠시 쉬었다가 방향을 반전해 주면 된다.

 Vector3 v = new Vector3(perDX, perDY, defPos.z);
                transform.Translate(v);

원점에 도착하면 현재위치 transfor.position = defPos로 보정해줘 실수연산오차를 방지해준다.

private void FixedUpdate(){
        if (isCanMove) {
            //이동중
            float x = transform.position.x;
            float y = transform.position.y;
            bool endX = false;
            bool endY = false;
            if (isReverse){
                //반대 방향 이동
                //이동량이 양수고 이동 위치가 초기 위치보다 작거나
                //이동량이 음수고 이동 위치가 초기 위치보다 큰경우
                if ((perDX >= 0.0f && x <= defPos.x) || (perDX < 0.0f && x >= defPos.x)) {
                    //이동량이 +
                    endX = true;    //X 방향 이동 종료
                }
                if ((perDY >= 0.0f && y <= defPos.y) || (perDY < 0.0f && y >= defPos.y)) {
                    endY = true;    //Y 방향 이동 종료
                }
                //블록 이동
                transform.Translate(new Vector3(-perDX, -perDY, defPos.z));
            }else{
                //정방향 이동
                //이동량이 양수고 이동 위치가 초기 위치보다 큰거나
                //이동량이 음수고 이동 위치가 초기 + 이동거리 보다 작은 경우
                if ((perDX >= 0.0f && x >= defPos.x + moveX) || (perDX < 0.0f && x <= defPos.x + moveX)){
                    endX = true;    //X 방향 이동 종료
                }
                if ((perDY >= 0.0f && y >= defPos.y + moveY) || (perDY < 0.0f && y <= defPos.y + moveY)){
                    endY = true;    //Y 방향 이동 종료
                }
                //블록 이동
                Vector3 v = new Vector3(perDX, perDY, defPos.z);
                transform.Translate(v);
            }

            if (endX && endY){
                //이동 종료
                if (isReverse){
                    //위치가 어긋나는것을 방지하기 위해 정면 방향이동으로 돌아가기 전에 초기 위치로 돌림
                    transform.position = defPos;
                }
                isReverse = !isReverse; //값을 반전 시킴
                isCanMove = false;      //이동 가능 값을 false
                if (isMoveWhenOn == false){
                    //올라 탓을 때 움직이는 값이 꺼져있는 경우
                    Invoke("Move", weight);  // weight 만큼 지연 후 다시 이동
                }
            }
        }
    }

OnCollisionenter2D()

캐릭터가 블록위에 올라타면 블록의 자식으로 해서 같이 움직이게 해준다 캐릭터가 블록위에서 벗어나면 풀어준다. OnCollisionEnter와 Exit를 이용해서 구현한다.

private void OnCollisionEnter2D(Collision2D collision)  {
    if (collision.gameObject.tag == "Player") {
        //접촉한것이 플레이어라면 이동 블록의 자식으로 만들기
        collision.transform.SetParent(transform);
        if (isMoveWhenOn) {
            //올라탔을 때 움직이는 경우면 
            isCanMove = true;   //이동하게 만들기
        }
    }
}
//접촉 종료
private void OnCollisionExit2D(Collision2D collision) {
    if (collision.gameObject.tag == "Player") {
        //접촉한것이 플레이어라면 이동 블록의 자식에서 제외시킴
        collision.transform.SetParent(null);
    }
}

블록에 스크립트를 어태치합니다

블록을 프리팹으로 만들고 프리팹을 끌어 씬뷰에 하나더 배치합니다. 스크립트의 변수 설정이 둘다 비슷한데 하나는 IsMoveWhenOn이 체크되어 있어 게임 실행후는 멈춰있지만 올라타면 움직이고 내리면 멈춥니다.

MoveX는 자동으로 움직일 거리입니다.

Times는 자동으로 움직일 편도 시간입니다. 3이면 3초동안 진행합니다.

 

MovingBlock.cs
0.00MB

밝으면 죽는 대미지 블록을 만듭니다. 새로운 게임오브젝트를 만들어 "Dead" Tag를 붙여주면 됩니다.

  • 대미지 블록의 외관은 바늘
  • 양 옆에서 접축하면 대미지 없이 충돌
  • 위에서 접촉시만 대미지 (게임오버)

 

바늘 대미지 블록 만들기

대미지 블록을 위한 바늘 이미지는 에셋인 needle을 씬뷰나 하이라키고 드래그 드롭으로 추가합니다.

Sprite Render컴포넌트의 Order in Layer값을 2로 합니다.

인스펙터 뷰에서 Add Component>Physics 2D를 선택한 후 Box Collider 2D를 두개 어태치해 양옆으로 벽처럼 배치합니다.  플레이어의 진행을 벽처럼 막을 목적이므로 isTrigger는 체크하지 않습니다.(체크하면 통과해버립니다.)

하이라키뷰에서 needle의 자식으로 Create Empty한후 이름을 DeadZone으로 하고 BoxCollider 2D를 추가하고 isTrigger를 체크합니다. 범위는 가운데쪽으로 해서 위에서 떨어지는 접촉을 감지합니다.

needle 을 Prefab폴더로 끌어다 prefab으로 만듭니다.

 

낙하하는 대미지 블록 만들기

images폴더에서 block1x1을 씬뷰에 끌어다 이름을 GimmickBlock으로 변경합니다. Sprite Renderer컴포넌트의 Order in Layuers는 2로 변경, Layer값은 Ground로 해서 캐릭터가 올라탈수 있도록 합니다.

Box Collider 2D를 추가하고 아래쪽을 살짝 올려줍니다.

지면과의 접촉은 CircleCollider2D를 추가합니다. 지면과의 마찰을 줄여 매끄럽게 이동하기 위해서입니다.   플레이어가 밀수 있게 Rigidbody2D를 추가하고 넘어지지 않게 Freeze Rotation Z를 체크하고 25로 설정합니다.

떨어지다가 플레이어와의 접촉을 담당할 새로운 빈오브젝트를 만들어 이름을 DeadZone으로 바꾸고 GimmickBlock의 자식으로 만들고 Tag를 Dead로 설정합니다.  Box Collider 2D를 추가하고 위치를 아래로 약간 내리고 IsTrigger를 체크해서 플레이어의 검출을 담당합니다.

장애물 블록과 식별을 용이하게 하기 위해 컬러아이콘을 붙입니다. 인스펙터뷰 맨위좌측을 눌러보면 아이콘을 선택할 수 있습니다. 부탁후 씬쀼에서 이름을 확인할 수 있습니다. 게임중에는 표시되지 않습니다.

공중에 배치하면 낙하하고 플레이어와 충돌하면 게임 오버가 되면 지면에 배치하면 플레이어가 밀어서 움직일 수 있고 올라탈수 있는 블록이 완성되었습니다.

 

대미지 블록을 낙하시키는 스크립트 만들기

GimmickBlock에 다음 기능을 추가하는 스크립트를 추가해봅니다.

플레이어가 일정 거리 안에 들어가면 떨어진다.

낙하 후에는 점점 사라진다.(변수로 시간을 정의할 수 있음)

GimmickBlock.cs의 코드 입니다.

변수 : 낙하와 페이드아웃 시간을 정의하고 있습니다.

public float length = 0.0f;     // 자동 낙하 탐지 거리
public bool isDelete = false;   // 낙하 후 제거할지 여부

bool isFell = false;            // 낙하 플래그
float fadeTime = 0.5f;          // 페이드 아웃 시간

Start()  : 게임 시작시 낙하할 블록을 Static으로 만들어 못 움직이게 만듭니다.

void Start() {
    // Rigidbody2D 물리연동 정지
    Rigidbody2D rbody = GetComponent<Rigidbody2D>();
    rbody.bodyType = RigidbodyType2D.Static;
}

Update() : 플레이어와의 거리를 계산해서 bodyType을 Dynamic으로 바꿔 떨어지게 만듭니다.

블록이 바닥에 떨어져 있는 상태라면 faceTiem을 카운트다운하면서 서서히 투명도를 바꿔줍니다. 0이 되면 제거합니다.

void Update(){
        GameObject player = GameObject.FindGameObjectWithTag("Player"); // 플레이어 찾기
        if (player != null) {
            // 플레이어와의 거리 계산
            float d = Vector2.Distance(transform.position, player.transform.position);
            if (length >= d) {
                Rigidbody2D rbody = GetComponent<Rigidbody2D>();
                if (rbody.bodyType == RigidbodyType2D.Static) {
                    // Rigidbody2D물리 연동 시작
                    rbody.bodyType = RigidbodyType2D.Dynamic;
                }
            }
        }
        if (isFell){
            // 낙하
            // 투명도를 변경해여 페이드 아웃 효과
            fadeTime -= Time.deltaTime; // 이전 프레이과의 차이만큼 시간 차감
            Color col = GetComponent<SpriteRenderer>().color;   // 컬러 값 가져오기
            col.a = fadeTime;   // 투명도 변경
            GetComponent<SpriteRenderer>().color = col; // 컬러 값을 재설정
            if (fadeTime <= 0.0f){            
                Destroy(gameObject); // 0보다 작으면(투명)제거
            }
        }
    }

OnCollisionEnter2D() 충돌은 바닥과 생기므로 오브젝트 검사는 하지 않습니다. 바닥에 떨어지면 isFell이 true로 바꿔줍니다.

void OnCollisionEnter2D(Collision2D collision) {
    if (isDelete){
        isFell = true; // 낙하 플래그 true
    }
}

스크립트를 GimmickBlock에 어태치하고 Lengh를 2정도로 해줍니다. 플레이어와 블록의 거리가 2이하이면 떨어지게 만들어 줍니다. isDelete도 체크해줘 땅에 떨어지면 사라지게도 해봅니다. 이걸 안하면 화면이 스크롤 되면서 블록이 왼쪽에 부디치면 어색하게 밀립니다.

블록이 2이상 높이 배치되어 있을 경우 블록이 떨어지지 않습니다. 거리d를 x만 계산해서 높이가 높아도 x축으로 다가가면  떨어지게 만들어 봤습니다. 이건 게임의 상황에 따라 적절히 조절해보시면 됩니다.

float d = Mathf.Abs( transform.position.x- player.transform.position.x);

완성된 GimmickBlock을 프리팹으로 만들어 씬에 몇개더 배치해 봅니다. 

게임 스테이지를 전부 클리어했을때 표시할 엔딩장면을 만들어 봅시다. Result 라는 이름의 씬을 만들어 봅니다.

결과화면  UI 만들기 

배경 이미지 배치

+UI>Image를 추가하고 자동추가된 Canvas 컴포넌트의 Render Mode값을 ScreenSpace-Camera로 설정하고 Render Camara Main Camera를 선택해 줍니다.  tile_back이미지를 Image컴포넌트에 끌어다 놓습니다. 이미지 크기를 화면에 맞게 조정합니다. 하이라키에서 image를 선택하고Anchor Presets를 열어 ALT를 누른상태에서 stetch를 선택해도 됩니다.

 

타이틀로 돌아가는 버튼 배치

하이라키의+를 클릭해 UI>Legacy>Button을 추가합니다. 프로젝트뷰 Image폴더의 Button스프라이트를 Image컴포넌트의  Source에 끌어다 놓습니다. Preserve Aspect / SetNativeSize후 적당히 위치를 잡습니다.

자식으로 Text도 추가하고 타이틀로 돌아가기를 입력해줍니다. 사이즈는 48정도 입니다.

Button에 ChangeScene 스크립트를 끌어다 추가해주고 Scene Name은 Title로 설정해줍니다.

OnClick()에 +를 눌러 리스트를 하나 만들고 하이라키의 Button을 끌어다 연결후 None Function을 눌러 ChangeScene>Load()를 선택해줍니다.

 

점수표시용 UI만들기

하이라키의+를 클릭해 UI>Image을 추가합니다. 프로젝트뷰 Image폴더의 ScoreBoard스프라이트를 Image컴포넌트의  Source에 끌어다 놓습니다. Preserve Aspect / SetNativeSize후 적당히 위치를 잡습니다. 이름을 ScoreBoard 로 바꿉니다.

자식으로 Text도 추가하고 타이틀로 돌아가기를 입력해줍니다. 사이즈는 48정도 입니다. 이름을 ScoreText로 바꿉니다.

전체 점수를 표시할 스크립트 만들기

ResultManager스크립트를 만들어 Canvas에 어태치합니다.

ResultManager.cs
0.00MB

실행되면 GameManager의 totalScore를 ScoreBoard자식인 scoreText에 표시하는게 다입니다.

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

public class ResultManager : MonoBehaviour
{
    public GameObject scoreText;

    // Start is called before the first frame update
    void Start() {
        scoreText.GetComponent<Text>().text = GameManager.totalScore.ToString();
    }
}

 Canvas에 어태치된 ResultManager스크립트 컴포넌트의  scoreText변수에 ScoreText를 끌어다 스크립트에 연결해 줍니다.

시간처리를 위한 변수를 추가한다.

// +++ 시간 제한 추가 +++
public GameObject timeBar;          // 시간 표시 이미지 
public GameObject timeText;         // 시간 텍스트
TimeController timeCnt;             // TimeController 스크립트 참조

 

점수처를 위한 변수를 추가한다.

// +++ 점수 추가 +++
public GameObject scoreText;        // 점수 텍스트  
public static int totalScore;       // 점수 총합
public int stageScore = 0;          // 스테이지 점수

싱글톤정적변수인 gameState를 체크해 게임중이라면 player게임오브젝트의 playerController스크립트의 score변수가 0이 아니라면 stageScore를 추가해주고 0으로 변경한후 점수를 처리하기 위한 UpdateScore()를 호출한다.

else if (PlayerController.gameState == "playing")
    {
        // 게임 중
        GameObject player = GameObject.FindGameObjectWithTag("Player");
        // PlayerController 가져오기
        PlayerController playerCnt = player.GetComponent<PlayerController>();
        // +++ 시간 제한 추가 +++
        // 시간 갱신
        if(timeCnt != null)
        {
			~시간 종료 처리
        }
        // +++ 점수 추가 +++
        if (playerCnt.score != 0)
        {
            stageScore += playerCnt.score;
            playerCnt.score = 0;
            UpdateScore();
        }
    }

UpdateScore()에서는 public으로 연결된 scoreText게임오브젝트의 Text컴포넌트를 갱신해준다. 재미있는건 하이라키의 모든건 게임오브젝트라 Text마저도 GameObject이다. Text 내용을 변경하기 위해서는 귀찮아도 다시 GetComponent<Text>를 통해 test에 접근해야 한다 

void UpdateScore()
{
    int score = stageScore + totalScore;
    scoreText.GetComponent<Text>().text = score.ToString();
}

using UnityEngine.UI;  간 선언되어 있기 때문에  Text타입을 이용해 좀더 편하게 사용할 수도 있다.

public Text ScoreText;
ScoreText.text =  score.ToString();

시간은 TimeController에서 관리되여 있고 여기서는 시간을 표시하고 게임을 관리하기 위해서 사용한다. 소스를 읽어보면 이해할수 있으리라 믿습니다.

GameManager.cs
0.00MB

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI; // UI を使うのに必要

public class GameManager : MonoBehaviour
{
    public GameObject mainImage;        // 이미지를 담아두는 GameObject
    public Sprite gameOverSpr;          // GAME OVER 이미지
    public Sprite gameClearSpr;         // GAME CLEAR 이미지
    public GameObject panel;            // 패널
    public GameObject restartButton;    // RESTART 버튼
    public GameObject nextButton;       // NEXT 버튼
    Image titleImage;                   // 이미지를 표시하고있는 Image 컴포넌트

    // +++ 시간 제한 추가 +++
    public GameObject timeBar;          // 시간 표시 이미지 
    public GameObject timeText;         // 시간 텍스트
    TimeController timeCnt;             // TimeController

    // +++ 점수 추가 +++
    public GameObject scoreText;        // 점수 텍스트  
    public static int totalScore;       // 점수 총합
    public int stageScore = 0;          // 스테이지 점수

    // Start is called before the first frame update
    void Start()
    {
        // 이미지 숨기기
        Invoke("InactiveImage", 1.0f);
        // 버튼(패널)을 숨기기
        panel.SetActive(false);

        // +++ 시간 제한 추가 +++
        // TimeController 가져옴
        timeCnt = GetComponent<TimeController>();
        if(timeCnt != null)
        {
            if(timeCnt.gameTime == 0.0f)
            {
                timeBar.SetActive(false);   // 시간 제한이 없으면 숨김
            }
        }

        // +++ 점수 추가 +++
        UpdateScore();
    }

    // Update is called once per frame
    void Update()
    {
        if (PlayerController.gameState == "gameclear")
        {
            // 게임 클리어
            mainImage.SetActive(true); // 이미지 표시
            panel.SetActive(true); // 버튼(패널)을 표시
            // RESTART 버튼 무효화 
            Button bt = restartButton.GetComponent<Button>();
            bt.interactable = false;
            mainImage.GetComponent<Image>().sprite = gameClearSpr;
            PlayerController.gameState = "gameend";

            // +++ 시간 제한 추가 +++
            if (timeCnt != null)
            {
                timeCnt.isTimeOver = true; // 시간 카운트 중지

                // +++ 점수 추가 +++
                // 정수에 할당하여 소숫점 버림
                int time = (int)timeCnt.displayTime;
                totalScore += time * 10;        // 남은 시간을 점수에 더한다.
            }
            // +++ 점수 추가 +++
            totalScore += stageScore;
            stageScore = 0;
            UpdateScore();// 점수 갱신
        }
        else if (PlayerController.gameState == "gameover")
        {
            // 게임 오버
            mainImage.SetActive(true);      // 이미지 표시하기
            panel.SetActive(true);          // 버튼(패널)표시하기
            // NEXT 버튼 비활성
            Button bt = nextButton.GetComponent<Button>();
            bt.interactable = false;
            mainImage.GetComponent<Image>().sprite = gameOverSpr;
            PlayerController.gameState = "gameend";

            // +++ 시간 제한 추가 +++
            if (timeCnt != null)
            {
                timeCnt.isTimeOver = true; // 시간 카운트 중지
            }
        }
        else if (PlayerController.gameState == "playing")
        {
            // 게임 중
            GameObject player = GameObject.FindGameObjectWithTag("Player");
            // PlayerController 가져오기
            PlayerController playerCnt = player.GetComponent<PlayerController>();
            // +++ 시간 제한 추가 +++
            // 시간 갱신
            if(timeCnt != null)
            {
                if (timeCnt.gameTime > 0.0f)
                {
                    // 정수에 할당하여 소수점 이하를 버림
                    int time = (int)timeCnt.displayTime;
                    // 시간 갱신
                    timeText.GetComponent<Text>().text = time.ToString();
                    // 타임 오버
                    if (time == 0)
                    {
                        playerCnt.GameOver();   // 게임 오버
                    }
                }
            }
            // +++ 점수 추가 +++
            if (playerCnt.score != 0)
            {
                stageScore += playerCnt.score;
                playerCnt.score = 0;
                UpdateScore();
            }
        }
    }
    // 이미지 숨김
    void InactiveImage()
    {
        mainImage.SetActive(false);
    }
    // +++ 점수 추가 +++
    void UpdateScore()
    {
        int score = stageScore + totalScore;
        scoreText.GetComponent<Text>().text = score.ToString();
    }
}

 

시간을 계측하는 스크립트 만들기

카운트다운과 카운트업을 모두 할수 있는 스크립트를 만들고 이름을 TimeController로 합니다.

프로젝트뷰의 Prefab폴더에서 Canvs 프리팹을 더블클릭후 편집모드 상태에서 TimeController 스크립트를 어태치합니다.

분석을  해보면

변수

times가 시계다.

public bool isCountDown = true; // true= 카운트 다운으로 시간 측정
public float gameTime = 0;      // 게엠의 최대 시간
public bool isTimeOver = false; // true= 타이머 정지
public float displayTime = 0;   // 표시 시간
float times = 0;                // 현재 시간

Start()

최대게임시간을 displayTime으로 지정한다.

void Start(){
    if (isCountDown){
        // 카운트다운
        displayTime = gameTime;
    }
}

Update()

times를 업데이트해주고 이시간을 이용해 displayTime을 갱신한다.

void Update(){
    if (isTimeOver == false){
        times += Time.deltaTime;
        if (isCountDown){
            // 카운트다은
            displayTime = gameTime - times;
            }
        }else{
            // 카운트업
            displayTime = times;
        }
    }
}

스크립트를 Canvas에 어태치한후 인스펙트뷰의 GameTime값을 60으로 IsCount Down을 체크합니다.

TimeController.cs
0.00MB

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

public class TimeController : MonoBehaviour{
    public bool isCountDown = true; // true= 카운트 다운으로 시간 측정
    public float gameTime = 0;      // 게엠의 최대 시간
    public bool isTimeOver = false; // true= 타이머 정지
    public float displayTime = 0;   // 표시 시간

    float times = 0;                // 현재 시간

    // Start is called before the first frame update
    void Start(){
        if (isCountDown){
            // 카운트다운
            displayTime = gameTime;
        }
    }

    // Update is called once per frame
    void Update(){
        if (isTimeOver == false){
            times += Time.deltaTime;
            if (isCountDown){
                // 카운트다은
                displayTime = gameTime - times;
                if (displayTime <= 0.0f){
                    displayTime = 0.0f;
                    isTimeOver = true;
                }
            }else{
                // 카운트업
                displayTime = times;
                if (displayTime >= gameTime){
                    displayTime = gameTime;
                    isTimeOver = true;
                }
            }
            Debug.Log("TIMES: " + displayTime);
        }
    }
}

 

게임에 시간제한 UI 추가하기

Prefabs폴더의 Canvas를 선택하고 인스펙트뷰의 Open을 클릭한다.

하이라키의 +를 클릭해서 UI>Image를 2개 추가하고 이름을 TimeBar, Score로 한다 

 Images폴더에서 TimeBar, ScoreBoard를 선택해 인스펙트뷰의 Image컴포넌트의 Source Image에 끌어다 놓는다.

Preserve Aspect를 체크하고 Set NativeSize를 클릭후 적당히 사이즈를 조정한다.

위치는 Transform 의 Anchor Presets를 누르고 ALT를 눌러 상중과 상우를 선택해 적당해 배치한다.

TimeBar, Score Image자식으로 UI>Legacy>Text를 추가한다. 이름은 TimeText, ScoreText로 바꿔준다. Text는 000 Font Size는 48~64로 설정한다.

 

실행시 Text가 안보이는건 Text박스가 작아서이다. 하이라키에서 두 Text를 순서대로 골라서 박스사이즈를 맞춰준다.

아이템과 점수 만들기

Images폴더에 Item_color 스프라이트가 있다. 하나를 끌어다 씬뷰에 놓는다.

인스펙트뷰에서 CircleCollider2D를 추가해준다. Trigger를 체크해준다. 플레이어와 접촉을 감지하기 위해서다

Tag에서 ScoreItem를 추가로 만들어주고 지정해준다. 플레이어에서 Trigger가 발생했을때 Item인지 체크하기 위해서다.

ItemData.cs 스크립트를 작성에 어태치해준다. 단순히 플레이어가 먹었을때 올라가는 점수값 변수만 있다.

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

public class ItemData : MonoBehaviour {
    public int value = 0;       // 정수값을 설정할 수 있다
}

이제 이걸 프로젝트뷰 프리팹폴더로 끌어다  놓는다.

Ctrl-D로 3개 더 만든후 이름을 Item_blue, Item_green, Item_red, Item_white로 바꾸고

itemData 컴포넌트의 value를 blue:30, green:10, red:50, white:100으로 설정한다.

스프라이트 렌더러컴포넌트의 Sprite 검색◉을 누르고 이름에 맞는 스프라이트를 선택해준다.

실험삼아 아이템들을 씬뷰에 배치한다.

 

아이템 획득 스크립트

방금만든 아이템을 획등하는 스크립트를 PlayerController에 추가합니다.

Collider에서 Trigger가 발생시 OnTriggerEnter2D()에서 처리하므로 Tag가 "ScoreItem"이라면 충돌 게임오브젝트의 ItemData컴포넌트(스크립트)의 변수인 value값을 score로 설정한다. 이값은 나중에 GameManager에서 불리워져 점수로 추가된다.

PlayerController.cs
0.01MB

// 접촉 시작
private void OnTriggerEnter2D(Collider2D collision)
{
   if(collision.gameObject.tag == "Goal")  {
        Goal();        // 골
    }
    else if (collision.gameObject.tag == "Dead") {
        GameOver();     // 게임 오버
    }
    else if (collision.gameObject.tag == "ScoreItem"){
        // 점수 아이템
        // ItemData 가져오기
        ItemData item = collision.gameObject.GetComponent<ItemData>(); // 점수 얻기
        score = item.value;
        // 아이템 제거
        Destroy(collision.gameObject);
    }
}

 

 

+ Recent posts