유니티3D 프로그래밍
Unity 6주차 2일 수업 내용 : 쿠키런 구현해보기 (21.04.13) 본문
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;
}
}
'Unity > 수업내용' 카테고리의 다른 글
Unity UGUI Test (21.04.20) (0) | 2021.04.20 |
---|---|
Unity 6주차 5일 수업 내용 : 다단계 Scene 구성 (21.04.06) (0) | 2021.04.16 |
Unity 6주차 3,4,5일 수업 내용 : Zombie (21.04.14) (0) | 2021.04.16 |
Unity 5주차 5일 수업 내용 : Dodge, Fov (21.04.09) (0) | 2021.04.09 |
Unity 5주차 4일 수업 내용 : Ray, 캐릭터 이동 (21.04.08) (0) | 2021.04.08 |