Initial Unity project
This commit is contained in:
@@ -0,0 +1,27 @@
|
||||
using UnityEngine;
|
||||
|
||||
// 왼쪽 끝으로 이동한 배경을 오른쪽 끝으로 재배치하는 스크립트
|
||||
public class BackgroundLoop : MonoBehaviour {
|
||||
private float width; // 배경의 가로 길이
|
||||
|
||||
private void Awake() {
|
||||
// 가로 길이를 측정하는 처리
|
||||
|
||||
BoxCollider2D backgroundCollider = GetComponent<BoxCollider2D>();
|
||||
width = backgroundCollider.size.x;
|
||||
}
|
||||
|
||||
private void Update() {
|
||||
// 현재 위치가 원점에서 왼쪽으로 width 이상 이동했을때 위치를 리셋
|
||||
if(transform.position.x <= -width)
|
||||
{
|
||||
Reposition();
|
||||
}
|
||||
}
|
||||
|
||||
// 위치를 리셋하는 메서드
|
||||
private void Reposition() {
|
||||
Vector2 offset = new Vector2(width * 2f, 0);
|
||||
transform.position = (Vector2) transform.position + offset;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ad1460fb9aea94c0398043cfb654e4a9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,59 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
using TMPro;
|
||||
|
||||
// 게임 오버 상태를 표현하고, 게임 점수와 UI를 관리하는 게임 매니저
|
||||
// 씬에는 단 하나의 게임 매니저만 존재할 수 있다.
|
||||
public class GameManager : MonoBehaviour {
|
||||
public static GameManager instance; // 싱글톤을 할당할 전역 변수
|
||||
|
||||
public bool isGameover = false; // 게임 오버 상태
|
||||
public TextMeshProUGUI scoreText; // 점수를 출력할 UI 텍스트
|
||||
public GameObject gameoverUI; // 게임 오버시 활성화 할 UI 게임 오브젝트
|
||||
|
||||
private int score = 0; // 게임 점수
|
||||
|
||||
// 게임 시작과 동시에 싱글톤을 구성
|
||||
void Awake() {
|
||||
// 싱글톤 변수 instance가 비어있는가?
|
||||
if (instance == null)
|
||||
{
|
||||
// instance가 비어있다면(null) 그곳에 자기 자신을 할당
|
||||
instance = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
// instance에 이미 다른 GameManager 오브젝트가 할당되어 있는 경우
|
||||
|
||||
// 씬에 두개 이상의 GameManager 오브젝트가 존재한다는 의미.
|
||||
// 싱글톤 오브젝트는 하나만 존재해야 하므로 자신의 게임 오브젝트를 파괴
|
||||
Debug.LogWarning("씬에 두개 이상의 게임 매니저가 존재합니다!");
|
||||
Destroy(gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
void Update() {
|
||||
// 게임 오버 상태에서 게임을 재시작할 수 있게 하는 처리
|
||||
if(isGameover && Input.GetMouseButtonDown(0))
|
||||
{
|
||||
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
|
||||
}
|
||||
}
|
||||
|
||||
// 점수를 증가시키는 메서드
|
||||
public void AddScore(int newScore) {
|
||||
|
||||
if(!isGameover)
|
||||
{
|
||||
score += newScore;
|
||||
scoreText.text = "Score : " + score;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 플레이어 캐릭터가 사망시 게임 오버를 실행하는 메서드
|
||||
public void OnPlayerDead() {
|
||||
isGameover = true;
|
||||
gameoverUI.SetActive(true);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d0a745ad4e51e495cad65585c3073da6
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,35 @@
|
||||
using UnityEngine;
|
||||
|
||||
// 발판으로서 필요한 동작을 담은 스크립트
|
||||
public class Platform : MonoBehaviour {
|
||||
public GameObject[] obstacles; // 장애물 오브젝트들
|
||||
private bool stepped = false; // 플레이어 캐릭터가 밟았었는가
|
||||
|
||||
// 컴포넌트가 활성화될때 마다 매번 실행되는 메서드
|
||||
private void OnEnable() {
|
||||
// 발판을 리셋하는 처리
|
||||
|
||||
stepped = false;
|
||||
|
||||
for( int i = 0; i < obstacles.Length; i++)
|
||||
{
|
||||
if(Random.Range(0,3) == 0)
|
||||
{
|
||||
obstacles[i].SetActive(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
obstacles[i].SetActive(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OnCollisionEnter2D(Collision2D collision) {
|
||||
// 플레이어 캐릭터가 자신을 밟았을때 점수를 추가하는 처리
|
||||
if(collision.collider.tag == "Player" && !stepped)
|
||||
{
|
||||
stepped = true;
|
||||
GameManager.instance.AddScore(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f975ef653abb48238f62061ebab1c23
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,69 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
// 발판을 생성하고 주기적으로 재배치하는 스크립트
|
||||
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() {
|
||||
// 변수들을 초기화하고 사용할 발판들을 미리 생성
|
||||
platforms = new GameObject[count];
|
||||
|
||||
for(int i = 0; i < count; i++)
|
||||
{
|
||||
platforms[i] = Instantiate(platformPrefab, poolPosition, Quaternion.identity);
|
||||
}
|
||||
|
||||
// 마지막 배치 시점 초기화
|
||||
lastSpawnTime = 0f;
|
||||
|
||||
// 다음번 배치까지의 시간 간격을 0으로 초기화
|
||||
timeBetSpawn = 0f;
|
||||
}
|
||||
|
||||
void Update() {
|
||||
// 순서를 돌아가며 주기적으로 발판을 배치
|
||||
if(GameManager.instance.isGameover)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if(Time.time >= lastSpawnTime + timeBetSpawn)
|
||||
{
|
||||
lastSpawnTime = Time. time;
|
||||
|
||||
timeBetSpawn = Random.Range(timeBetSpawnMin, timeBetSpawnMax);
|
||||
|
||||
float yPos = Random.Range(yMin, yMax);
|
||||
|
||||
platforms[currentIndex].SetActive(false);
|
||||
platforms[currentIndex].SetActive(true);
|
||||
|
||||
platforms[currentIndex].transform.position = new Vector2(xPos, yPos);
|
||||
|
||||
currentIndex++;
|
||||
|
||||
if(currentIndex >= count)
|
||||
{
|
||||
currentIndex = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf3925495abad4c798bedcc50b89dc29
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,86 @@
|
||||
using UnityEngine;
|
||||
|
||||
// PlayerController는 플레이어 캐릭터로서 Player 게임 오브젝트를 제어한다.
|
||||
public class PlayerController : MonoBehaviour {
|
||||
public AudioClip deathClip; // 사망시 재생할 오디오 클립
|
||||
public float jumpForce = 700f; // 점프 힘
|
||||
|
||||
private int jumpCount = 0; // 누적 점프 횟수
|
||||
private bool isGrounded = false; // 바닥에 닿았는지 나타냄
|
||||
private bool isDead = false; // 사망 상태
|
||||
|
||||
private Rigidbody2D playerRigidbody; // 사용할 리지드바디 컴포넌트
|
||||
private Animator animator; // 사용할 애니메이터 컴포넌트
|
||||
private AudioSource playerAudio; // 사용할 오디오 소스 컴포넌트
|
||||
|
||||
private void Start() {
|
||||
// 게임 오브젝트로부터 사용할 컴포넌트들을 가져와 변수에 할당
|
||||
playerRigidbody = GetComponent<Rigidbody2D>();
|
||||
animator = GetComponent<Animator>();
|
||||
playerAudio = GetComponent<AudioSource>();
|
||||
}
|
||||
|
||||
private void Update() {
|
||||
if(isDead)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// 마우스 왼쪽 버튼을 눌렀으면 && 최대 점프 횟수(2)에 도달하지 않았다면
|
||||
if(Input.GetMouseButtonDown(0) && jumpCount < 2)
|
||||
{
|
||||
jumpCount++;
|
||||
|
||||
// 점프 직전에 속도를 순간적으로 제로(0, 0)으로 변경
|
||||
playerRigidbody.linearVelocity = Vector2.zero;
|
||||
|
||||
// 리지드바디에 위쪽으로 힘을 주기
|
||||
playerRigidbody.AddForce(new Vector2(0, jumpForce));
|
||||
playerAudio.Play();
|
||||
}
|
||||
else if(Input.GetMouseButtonUp(0) && playerRigidbody.linearVelocityY > 0)
|
||||
{
|
||||
// 마우스 왼쪽 버튼에서 손을 떼는 순간 && 속도의 y값이 양수라면(위로 상승중)
|
||||
// 현재 속도를 절반으로 변경
|
||||
playerRigidbody.linearVelocity = playerRigidbody.linearVelocity * 0.5f;
|
||||
}
|
||||
|
||||
animator.SetBool("Grounded", isGrounded);
|
||||
}
|
||||
|
||||
private void Die() {
|
||||
// 애니메이터의 Die 트리거 파라미터를 셋
|
||||
animator.SetTrigger("Die");
|
||||
|
||||
playerAudio.clip = deathClip;
|
||||
|
||||
playerAudio.Play();
|
||||
|
||||
playerRigidbody.linearVelocity = Vector2.zero;
|
||||
|
||||
isDead = true;
|
||||
|
||||
GameManager.instance.OnPlayerDead();
|
||||
}
|
||||
|
||||
private void OnTriggerEnter2D(Collider2D other) {
|
||||
if(other.tag == "Dead" && !isDead)
|
||||
{
|
||||
Die();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCollisionEnter2D(Collision2D collision) {
|
||||
// 어떤 콜라이더와 닿았으며, 충돌 표면이 위쪽을 보고 있으면
|
||||
if(collision.contacts[0].normal.y > 0.7f)
|
||||
{
|
||||
isGrounded = true;
|
||||
jumpCount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnCollisionExit2D(Collision2D collision) {
|
||||
// 바닥에서 벗어났음을 감지하는 처리
|
||||
isGrounded = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 85f08caec5cd247478bf53a4b7819f3d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,14 @@
|
||||
using UnityEngine;
|
||||
|
||||
// 게임 오브젝트를 계속 왼쪽으로 움직이는 스크립트
|
||||
public class ScrollingObject : MonoBehaviour {
|
||||
public float speed = 10f; // 이동 속도
|
||||
|
||||
private void Update() {
|
||||
// 게임 오브젝트를 왼쪽으로 일정 속도로 평행 이동하는 처리
|
||||
if(!GameManager.instance.isGameover)
|
||||
{
|
||||
transform.Translate(Vector3.left * speed * Time.deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 649efa25ad21f497fb803a5b36ada1e8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user