유니티3D 프로그래밍

Unity 6주차 2일 수업 내용 : 쿠키런 구현해보기 (21.04.13) 본문

Unity/수업내용

Unity 6주차 2일 수업 내용 : 쿠키런 구현해보기 (21.04.13)

tjdgus9955 2021. 4. 13. 14:25

1. 배경 구현

 

 

2. 캐릭터 애니메이션 구현

 

 

Run : 달리는 모션

Jump : 1단 점프

Jump2 : 2단 점프

sliding : 슬라이딩

Landing : 착지 모션

Die : 죽을때 모션

 

 

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

public class PlayerController : MonoBehaviour
{
    public Button btn;
    //점프 함
    public float jumpForce;
    //누적 점프 횟수
    private int jumpCount = 0;
    //바닥에 닿았는지 나타냄
    private bool isGrounded = false;
    //사망 상태
    private bool isDie = false;
    //달리는 상태
    public bool isRun = false;
    //사용할 리지드바디 컴포넌트
    private Rigidbody2D playerRigidbody;
    //사용할 애니메이터 컴포턴트
    private Animator animator;
    // Start is called before the first frame update
    void Start()
    {
        this.playerRigidbody = this.GetComponent<Rigidbody2D>();
        this.animator = this.GetComponent<Animator>();
    }

    // Update is called once per frame
    void Update()
    {
        if (this.isDie) return;

        
        
        //애니메이터의 Grounded파라메터를 isGrounded값을 생산(애니메이션 플레이)
        this.animator.SetBool("Grounded", this.isGrounded);
    }
    public void Jump()
    {
        //마우스 왼쪽 버튼을 눌렀고 최대 점프 횟수 (2)에 도달하지 않았다면
        if (this.jumpCount < 2)
        {
            //점프 횟수 증가
            this.jumpCount++;
            //점프 직전에 속도를 순간적으로 0.0으로 변경
            playerRigidbody.velocity = Vector2.zero;

            //리지드바디에 위쪽 힘주기
            this.playerRigidbody.AddForce(new Vector2(0, this.jumpForce));
            if (jumpCount == 2)
            {
                this.animator.SetTrigger("Jump2");
            }
        }
    }

    public void Slide()
    {
        this.animator.SetTrigger("Slide");
    }

    public void Run()
    {
        this.animator.SetTrigger("Run");
    }
    public void Die()
    {
        if(isRun)
        {
            //사망처리
            //애니메이터의 Die 트리거 마라메터 설정
            this.animator.SetTrigger("Die");
            //속도를 0으로 변경
            this.playerRigidbody.velocity = Vector2.zero;
            //사망 상태 변경
            this.isDie = true;

            //게임 매니저의 게임오버 처리 실행
            GameManager.instance.OnPlayerDead();
        }
        
    }
    private void OnTriggerEnter2D(Collider2D collision)
    {
        //트리거 콜라이더를 가진 장애물과의 충돌감지
        if (collision.tag == "Dead" && !this.isDie)
        {
            //충돌한 상대방의 태그가 Dead고 아직 죽지 않았다면
            this.Die();
        }
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        //바닥에 닿았음을 감지하는 처리
        //어떤 콜라이더와 닿았으며 충돌 표면이 위쪽을 보고있으면
        if (collision.contacts[0].normal.y > 0.7f)
        {
            //isGrounded를 true로 변경하고, 누적 점프 횟수를 0으로 리셋
            isGrounded = true;
            isRun = true;
            jumpCount = 0;
        }
    }

    private void OnCollisionExit2D(Collision2D collision)
    {
        //바닥에 벗어났음을 감지하는 처리
        isGrounded = false;
        isRun = false;
    }


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

public class GameManager : MonoBehaviour
{
    public static GameManager instance; // 싱글턴을 할당할 전역 변수

    public bool isGameover = false; // 게임오버 상태
    public Text scoreText; //점수를 출력할 UI 텍스트
    public GameObject gameoverUI; // 게임 오버 시 활성화 할 UI 게임 오브젝트

    private int score = 0; // 게임 점수

    //게임 시작과 동시에 싱글턴 구성
    void Awake()
    {
        //싱글턴 변수 instance가 비어있는가?
        if(instance == null)
        {
            //instance가 비어있다면 (null) 그곳에 자기 자신을 할당
            instance = this;
        }
        else
        {
            //instance에 이미 다른 GameObject가 할당되어 있는 경우

            //씬에 두개 이상의 GameManager 오브젝트가 존재한다는 의미
            //싱글턴 오브젝트는 하나만 존재해야 하므로 자신의 게임 오브젝트를 파괴
            Debug.LogWarning("씬에 두 개 이상의 게임 매니저가 존재합니다!");
            Destroy(gameObject);
        }
    }


    // Update is called once per frame
    void Update()
    {
        
    }

    public void GameRestart()
    {
        //게임 오버 상태에서 게임을 재시작 할 수 있게하는 처리
        if (isGameover)
        {
            //게임오버 상타에서 마우스 왼쪽 버튼을 클릭하면 현재 씬 재시작
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
    }

    //점수를 장가시키는 메서드
    public void AddStore(int newStore)
    {
        if(!isGameover)
        {
            //점수를 증가
            score += newStore;
            scoreText.text = "Score : " + score;
        }
    }

    //플레이어 캐릭터 사망 시 게임오버를 실행하는 메서드
    public void OnPlayerDead()
    {
        //현재 상태를 게임오버 상태로 변경
        isGameover = true;
        //게임오버 UI를 활성화
        gameoverUI.SetActive(true);
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Platfrom : MonoBehaviour
{
    public GameObject[] obstacles; // 장애물 오브젝트들
    private bool stepped = false; // 플레이어 캐릭터가 밟았는가

    //컴포넌트가 활성화될 때마다 매번 실행되는 메서드
    private void OnEnable()
    {
        //밟힘 상태를 리셋
        stepped = false;

        //장애물 수 만큼 루프
        for(int i = 0; i < obstacles.Length; i++)
        {
            //현재 순번의 장애물을 1/3의 확률로 활성화
            if (Random.Range(0, 3) == 0)
            {
                obstacles[i].SetActive(true);
            }
            else
            {
                obstacles[i].SetActive(false);
            }
        }
    }

    private void OnCollisionEnter2D(Collision2D collision)
    {
        //충돌한 상대방의 태그가 Player이고 이전에 플레이어 캐릭터가 밟지 않았다면
        if(collision.collider.tag == "Player" && !stepped)
        {
            //점수를 추가하고, 밟힘 상태를 참으로 변경
            stepped = true;
            GameManager.instance.AddStore(1);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlatformSpawner : MonoBehaviour
{
    public GameObject platformPrefab;   //생성할 발판의 원본 프리랩
    public int count = 3; //생성할 발판 수

    public float timeBetSpawnMin = 1.25f; // 다음 배치까지의 시간 간격 최솟값
    public float timeBetSpawnMax = 2.25f; // 다음 배치까지의 시간 간격 최댓값
    private float timeBetSpawn; // 다음 배치까지의 시간 간격

    public float yMin = -3.5f;   // 배치할 위치의 최소 y 값
    public float yMax = 1.5f;    // 배치할 위치의 최대 y 값
    private float xPos = 20f;    // 배치할 위치의 x 값

    private GameObject[] platforms; //미리 생성한 발판들
    private int currentIndex = 0; // 사용할 현재 순번의 발판

    //초반에 생성한 발판을 화면 밖에 숨겨둘 위치
    private Vector2 poolPosition = new Vector2(0, -25);
    private float lastSpawnTime; // 마지막 배치 시점

    void Start()
    {
        // count만큼의 공간을 가지는 새로운 발판 배열 생성
        platforms = new GameObject[count];

        // count만큼 루프하면서 발판 생성
        for(int i = 0; i < count; i++)
        {
            // platformPrefab을 원본으로 새 발판을 poolPosition 위치에 복제 생성
            // 생성된 발판을 platform 배열에 할당
            platforms[i] = Instantiate(platformPrefab, poolPosition, Quaternion.identity);
        }

        // 마지막 배치 시점 초기화
        lastSpawnTime = 0f;
        // 다음번 배치까지의 시간 간격을 0으로 초기화
        timeBetSpawn = 0;
    }

    // Update is called once per frame
    void Update()
    {
        // 게임오버 상태에서는 동작하지 않음
        if (GameManager.instance.isGameover) return;

        // 마지막 배치 시점에서 timeBetSpawn 이상 시간이 흘렀다면
        if(Time.time >= lastSpawnTime + timeBetSpawn)
        {
            // 기록된 마지막 배치 시점을 현재 시점으로 갱신
            lastSpawnTime = Time.time;

            // 다음 배치까지의 시간 간격을 timeBetSpawnMin, timeBetSpawnMax 사이에서 랜덤으로 설정
            timeBetSpawn = Random.Range(timeBetSpawnMin, timeBetSpawnMax);

            // 배치할 위치의 높이를 yMin과 yMax 사이에서 랜덤 설정
            float yPos = Random.Range(yMin, yMax);

            // 사용할 현재 순번의 발판 게임 오브젝트를 비활성화 하고 즉시 다시 활성화
            // 이때 발판의 Platform 컴포넌트의 OnEnable 메서드가 실행됨
            platforms[currentIndex].SetActive(false);
            platforms[currentIndex].SetActive(true);

            // 현재 순번의 발판을 오른쪽에 재배치
            platforms[currentIndex].transform.position = new Vector2(xPos, yPos);
            // 순번 넘기기
            currentIndex++;

            // 마지막 순번에 도달했다면 순번을 리셋
            if(currentIndex >= count)
            {
                currentIndex = 0;
            }
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ScrollingObject : MonoBehaviour
{
    public float speed = 10f;

    // Update is called once per frame
    void Update()
    {
        if (!GameManager.instance.isGameover)
        {
            // 초당 speed의 속도로 왼쪽으로 평행이동
            transform.Translate(Vector3.left * speed * Time.deltaTime);
        }
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class BackgroundLoop : MonoBehaviour
{
    private float width; // 배경의 가로 길이

    private void Awake()
    {
        //BoxColider2D 컴포넌트의 Size 필드의 x 값을 가로 길이로 사용
        BoxCollider2D backgroundCollider = GetComponent<BoxCollider2D>();
        width = backgroundCollider.size.x;
    }

    // Update is called once per frame
    void Update()
    {
        //현재 위치가 원점에서 왼쪽으로 width 이상 이동했을 때 위치를 재배치
        if(transform.position.x <= -width * 3f)
        {
            Reposition();
        }
    }

    private void Reposition()
    {
        //현재 위치에서 오른쪽으로 가로 길이 * 2만큼 이동
        Vector2 offset = new Vector2(width * 6f, 0);
        transform.position = (Vector2)transform.position + offset;
    }
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FlatformLoop : MonoBehaviour
{
    private float width; // 배경의 가로 길이

    private void Awake()
    {
        //BoxColider2D 컴포넌트의 Size 필드의 x 값을 가로 길이로 사용
        BoxCollider2D flatformGroundCollider = GetComponent<BoxCollider2D>();
        width = flatformGroundCollider.size.x;
    }

    // Update is called once per frame
    void Update()
    {
        //현재 위치가 원점에서 왼쪽으로 width 이상 이동했을 때 위치를 재배치
        if (transform.position.x <= -width)
        {
            Reposition();
        }
    }

    private void Reposition()
    {
        //현재 위치에서 오른쪽으로 가로 길이 * 2만큼 이동
        Vector2 offset = new Vector2(width * 2f, 0);
        transform.position = (Vector2)transform.position + offset;
    }
}