Initial Unity project

This commit is contained in:
jongjae0305
2026-06-05 11:26:57 +09:00
commit d0760eaa40
223 changed files with 108001 additions and 0 deletions
+27
View File
@@ -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;
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ad1460fb9aea94c0398043cfb654e4a9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+59
View File
@@ -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);
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d0a745ad4e51e495cad65585c3073da6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+35
View File
@@ -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);
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9f975ef653abb48238f62061ebab1c23
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+69
View File
@@ -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;
}
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bf3925495abad4c798bedcc50b89dc29
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+86
View File
@@ -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;
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 85f08caec5cd247478bf53a4b7819f3d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+14
View File
@@ -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);
}
}
}
+11
View File
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 649efa25ad21f497fb803a5b36ada1e8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: