안녕하세요, 게임 개발 여정에 다시 오신 것을 환영합니다! 👋 지난번 [유니티 설치 및 인터페이스 기초](이전 글 링크 삽입) 글에서 유니티라는 강력한 도구와 친해지는 시간을 가졌다면, 이제부터는 그 도구에 생명을 불어넣는 마법, 바로 C# 스크립팅의 세계로 함께 떠나보겠습니다.
유니티에서 C# 스크립트는 단순히 코드를 작성하는 것을 넘어, 여러분의 게임 오브젝트(캐릭터, 몬스터, 아이템 등)가 스스로 생각하고 움직이며 상호작용하게 만드는 핵심 열쇠입니다. 🔑 처음에는 조금 낯설 수 있지만, 이 글을 통해 C#의 기본 문법부터 유니티에서 실제로 활용하는 방법까지 차근차근 정복해 나갈 수 있도록 도와드릴게요. 자, 이제 코딩의 즐거움에 빠져볼 준비 되셨나요? 😉
1. C# 기본 문법 마스터하기: 게임 개발의 언어 배우기 💻
C#은 유니티가 공식적으로 지원하는 메인 스크립팅 언어입니다. 현대적이고 강력하며 배우기 비교적 쉬운 언어죠. 게임 개발에 필요한 기본적인 C# 문법 요소들을 먼저 살펴봅시다.
✅ 변수와 자료형: 데이터 보관함 만들기
- 변수(Variable): 데이터를 저장하는 '이름표가 붙은 상자'라고 생각하면 쉽습니다. 점수, 체력, 이름 등 게임 내 다양한 정보를 저장하는 데 사용됩니다.
- 자료형(Data Type): 변수라는 상자에 어떤 종류의 데이터를 담을지 지정하는 규칙입니다.
- int: 정수 (소수점 없는 숫자)를 저장합니다. 예: 플레이어 점수(int score = 100;), 남은 총알 수(int ammoCount = 30;)
- float: 소수점 있는 숫자를 저장합니다. 예: 이동 속도(float moveSpeed = 5.5f;), 캐릭터 체력(float currentHealth = 85.0f;) (값 뒤에 f를 붙여 float임을 명시합니다.)
- bool: 참(true) 또는 거짓(false) 값을 저장합니다. 예: 생존 여부(bool isAlive = true;), 문 열림 상태(bool isDoorOpen = false;)
- string: 문자열 (텍스트)을 저장합니다. 예: 플레이어 이름(string playerName = "용감한 개발자";), 아이템 설명(string itemDescription = "강력한 검입니다.";) (텍스트는 큰따옴표 ""로 감싸줍니다.)
- 왜 중요할까요? 정확한 자료형을 사용해야 메모리를 효율적으로 사용하고 예상치 못한 오류(예: 정수만 필요한 곳에 소수점 계산)를 방지할 수 있습니다.
✅ 연산자: 데이터 계산하고 비교하기
- 산술 연산자: 더하기(+), 빼기(-), 곱하기(*), 나누기(/), 나머지(%) 등 기본적인 수학 계산을 합니다. 예: score = score + 10;, totalDamage = attackPower * 1.5f;
- 비교 연산자: 두 값의 관계를 비교하여 true 또는 false 결과를 반환합니다. 같다(==), 같지 않다(!=), 크다(>), 작다(<), 크거나 같다(>=), 작거나 같다(<=). 예: if (health <= 0) { ... }, if (ammoCount == 0) { ... }
- 논리 연산자: 여러 조건을 조합할 때 사용합니다. 그리고(&&), 또는(||), 아니다(!). 예: if (isAlive && canMove) { ... } (살아있고 움직일 수 있다면), if (isGrounded || isJumping) { ... } (땅에 있거나 점프 중이라면)
✅ 조건문: 상황에 따라 다른 행동하기 (if, else if, else)
특정 조건이 참(true)일 때만 코드를 실행하거나, 조건에 따라 다른 코드를 실행하게 합니다.
int playerLevel = 5;
if (playerLevel >= 10) {
Debug.Log("고급 스킬 사용 가능!"); // Debug.Log는 유니티 콘솔에 메시지를 출력합니다. (잠시 후 자세히!)
} else if (playerLevel >= 5) {
Debug.Log("중급 스킬 사용 가능!");
} else {
Debug.Log("초급 스킬만 사용 가능합니다.");
}
// 출력 결과: "중급 스킬 사용 가능!"
✅ 반복문: 같은 일 반복하기 (for, while, foreach)
- for: 정해진 횟수만큼 코드를 반복 실행할 때 유용합니다. (예: 몬스터 5마리 생성)
- while: 특정 조건이 참(true)인 동안 코드를 계속 반복 실행합니다. (예: 게임 오버 상태가 아닐 동안 계속 게임 로직 실행)
- foreach: 배열이나 리스트 같은 데이터 집합의 모든 항목에 대해 코드를 반복 실행할 때 편리합니다. (예: 인벤토리의 모든 아이템 효과 적용)
// for문 예시: 0부터 4까지 5번 출력
for (int i = 0; i < 5; i++) {
Debug.Log("현재 숫자: " + i);
}
// while문 예시: (실제 게임에서는 Update 함수 등을 더 많이 사용)
bool isLoading = true;
float loadProgress = 0f;
while (isLoading) {
loadProgress += 0.1f;
Debug.Log("로딩 중... " + loadProgress * 100 + "%");
if (loadProgress >= 1.0f) {
isLoading = false; // 로딩 완료 조건
}
// 실제 게임에서는 프레임 대기 등 필요
}
✅ 함수 (메서드): 코드 묶음 만들고 재사용하기
특정 작업을 수행하는 코드 블록을 만들어 이름을 붙여두고, 필요할 때마다 이름만 불러서 실행할 수 있습니다. 코드 중복을 줄이고 프로그램을 구조화하는 데 필수적입니다.
// 함수 정의 (Definition)
void PrintPlayerInfo() { // void는 반환값이 없음을 의미
string playerName = "모험가";
int level = 3;
Debug.Log("이름: " + playerName + ", 레벨: " + level);
}
// 함수 호출 (Call) - 예시 (Start 함수 등에서 호출)
void Start() {
PrintPlayerInfo(); // 함수 이름으로 호출!
PrintPlayerInfo(); // 여러 번 재사용 가능
}
2. 유니티에서 C# 스크립트 사용하기: 엔진과 코드의 만남 🤝
이제 C# 기본 문법을 알았으니, 유니티 안에서 실제로 스크립트를 만들어 적용해 봅시다.
- 새 C# 스크립트 생성:
- 유니티 에디터의 프로젝트(Project) 창에서 마우스 오른쪽 클릭 > Create > C# Script 선택.
- 스크립트 이름을 지정합니다. (예: PlayerMovement) 주의: 이름 변경 시 유니티 에디터 내에서 변경해야 클래스 이름과 파일 이름이 일치합니다. 공백이나 특수문자는 피하는 것이 좋습니다.
- 스크립트를 게임 오브젝트에 연결 (컴포넌트 화):
- 스크립트는 그 자체로 실행되지 않고, **게임 오브젝트(GameObject)**에 컴포넌트(Component) 형태로 부착되어야 작동합니다.
- 하이어라키(Hierarchy) 창에서 스크립트를 적용할 게임 오브젝트를 선택합니다. (예: 'Player' 오브젝트)
- 프로젝트 창에서 생성한 C# 스크립트 파일을 드래그하여, 선택된 게임 오브젝트의 인스펙터(Inspector) 창으로 놓습니다.
- 또는, 인스펙터 창 하단의 Add Component 버튼을 누르고 스크립트 이름을 검색하여 추가할 수도 있습니다.
- 핵심: 이제 이 스크립트는 해당 게임 오브젝트의 '두뇌' 또는 '행동 지침서' 역할을 하게 됩니다! 🧠
- 유니티의 기본 이벤트 함수: Start와 Update
- 방금 생성한 스크립트를 열어보면 Start() 와 Update() 라는 함수가 미리 정의되어 있을 겁니다. 이것들은 유니티가 특정 시점에 자동으로 호출해주는 특별한 함수(이벤트 함수 또는 라이프사이클 함수)입니다.
- void Start(): 게임이 시작될 때 단 한 번 호출됩니다. 주로 변수 초기화, 다른 오브젝트 찾기 등 초기 설정 코드를 넣습니다.
- void Update(): 게임의 매 프레임마다 호출됩니다. (컴퓨터 성능에 따라 초당 수십~수백 번) 플레이어 입력 처리, 오브젝트 이동, 시간 경과에 따른 변화 등 지속적인 로직 처리에 사용됩니다. 매우 중요! ⭐
- 방금 생성한 스크립트를 열어보면 Start() 와 Update() 라는 함수가 미리 정의되어 있을 겁니다. 이것들은 유니티가 특정 시점에 자동으로 호출해주는 특별한 함수(이벤트 함수 또는 라이프사이클 함수)입니다.
- 디버깅의 필수! Debug.Log 사용하기:
- 코드에 문제가 있거나, 변수 값이 어떻게 변하는지 확인하고 싶을 때 Debug.Log() 함수를 사용합니다. 괄호 안의 내용을 유니티 에디터의 콘솔(Console) 창에 출력해줍니다.
- 예: Debug.Log("현재 체력: " + currentHealth);
- 개발자의 눈과 귀가 되어주는 고마운 기능이니 꼭 익숙해지세요! 👀👂
3. 변수와 속성: 데이터 관리와 외부 소통의 비밀 🔑
스크립트 안의 데이터를 어떻게 관리하고, 유니티 에디터(특히 인스펙터 창)와 어떻게 소통하는지 알아봅시다.
- 접근 제한자 (public vs private):
- public: '공개'를 의미합니다. 스크립트 외부에서도 접근 가능하며, 가장 큰 특징은 유니티 인스펙터 창에 해당 변수가 노출되어 값을 직접 수정할 수 있게 된다는 점입니다! 🎉 디자이너나 다른 개발자가 코드를 열지 않고도 쉽게 값을 조절할 수 있게 해주죠.
- private: '비공개'를 의미합니다. 해당 변수는 오직 그 스크립트 내부에서만 접근 가능하며, 인스PECTOR 창에 노출되지 않습니다. 기본적으로 변수는 private으로 선언하는 것이 코드의 안정성과 구조를 위해 권장됩니다 (캡슐화). 다른 곳에서 함부로 값을 바꾸는 것을 방지하죠.
- 아무것도 안 쓰면? 기본적으로 private으로 간주됩니다.
using UnityEngine; // 유니티 기능을 사용하기 위해 필요
public class PlayerStats : MonoBehaviour { // MonoBehaviour를 상속받아야 유니티 컴포넌트로 작동
public string playerName = "Hero"; // public: 인스펙터에 노출됨!
public float moveSpeed = 5.0f; // public: 인스펙터에서 속도 조절 가능
private int score = 0; // private: 외부 접근 불가, 인스펙터에 안 보임
private float health = 100f; // private
void Start() {
Debug.Log(playerName + "의 게임 시작!");
// score나 health는 이 스크립트 안에서만 사용
}
void Update() {
// 예시: 인스펙터에서 조정한 moveSpeed 값 사용
// transform.Translate(Vector3.forward * moveSpeed * Time.deltaTime);
}
}
- [SerializeField] 속성: private 변수를 인스펙터 창에 노출시키고 싶지만, 외부 스크립트에서의 직접 접근은 막고 싶을 때 사용합니다. private 앞에 [SerializeField]를 붙여주면 됩니다. 좋은 습관 중 하나! 👍
[SerializeField] private float attackPower = 10f; // private이지만 인스펙터에는 보임!
4. 함수 (메서드) 심화 활용: 코드 재사용과 게임 로직 구현 ⚙️
함수를 좀 더 유용하게 사용하는 방법을 알아봅시다.
- 매개변수(Parameter)를 받는 함수: 함수를 호출할 때 데이터를 전달하여, 함수가 그 데이터를 가지고 작업을 수행하게 합니다. 함수를 더욱 유연하게 만들어 줍니다.
public class Enemy : MonoBehaviour {
private float health = 50f;
// 데미지를 받는 함수 (매개변수로 받은 데미지 양만큼 체력 감소)
public void TakeDamage(float damageAmount) {
health -= damageAmount;
Debug.Log("적 체력: " + health);
if (health <= 0) {
Die(); // 체력이 0 이하면 죽는 함수 호출
}
}
private void Die() {
Debug.Log("적이 쓰러졌다!");
// 여기에 적 제거 로직 추가 (예: 오브젝트 비활성화)
// gameObject.SetActive(false);
}
}
// 다른 스크립트에서 이 함수를 호출하는 예시
// Enemy enemyScript = targetEnemy.GetComponent<Enemy>(); // 적 오브젝트에서 Enemy 스크립트 가져오기
// enemyScript.TakeDamage(20f); // 20만큼 데미지를 입힘
- 값을 반환(Return)하는 함수: 함수가 작업을 수행한 후, 그 결과를 호출한 곳으로 돌려줍니다. 함수의 계산 결과를 다른 곳에서 활용할 수 있게 해줍니다. (반환값이 없으면 void 사용)
public class GameController : MonoBehaviour {
private int score = 0;
private bool isGameOver = false;
public void AddScore(int amount) {
score += amount;
Debug.Log("점수 획득! 현재 점수: " + score);
}
// 현재 게임오버 상태인지 알려주는 함수 (bool 값 반환)
public bool IsGameOver() {
// 예시: 플레이어 체력이 0 이하면 게임오버라고 가정
// if (playerHealth <= 0) isGameOver = true;
return isGameOver; // isGameOver 변수의 현재 값을 반환
}
void Update() {
if (IsGameOver()) { // 반환된 bool 값으로 조건 확인
Debug.Log("게임 오버!");
// 게임 오버 처리 로직...
}
}
}
마무리하며 & 다음 단계 예고 🏁
와우! 여기까지 오셨다면 C#의 기본적인 문법부터 유니티에서 스크립트를 생성하고 게임 오브젝트에 적용하는 방법, 그리고 변수와 함수를 활용하는 핵심적인 내용까지 배우신 겁니다! 🎉 Debug.Log로 궁금한 점을 확인하고, public 변수를 인스펙터에서 조절하며 코드가 게임 세상과 상호작용하는 것을 직접 경험해보세요.
처음에는 모든 것이 낯설고 어렵게 느껴질 수 있지만, 작은 기능이라도 직접 만들어보는 것이 중요합니다. 예를 들어, 오늘 배운 내용으로 간단하게 "플레이어 체력 관리" 스크립트나 "클릭하면 점수가 오르는" 스크립트를 만들어보는 것은 어떨까요?
다음 시간에는 유니티 개발의 또 다른 핵심 축인 '게임 오브젝트와 컴포넌트'에 대해 더 깊이 파고들어 보겠습니다. 게임 오브젝트는 무엇이고, 컴포넌트는 어떻게 조합하여 원하는 기능을 만들어내는지 자세히 알아볼 예정이니 많이 기대해주세요! 😊
💬 오늘 배운 C# 문법으로 어떤 간단한 게임 기능을 만들어보고 싶으신가요? 댓글로 여러분의 아이디어를 공유해주세요!
'C#' 카테고리의 다른 글
[C#]🎮 유니티 게임 개발의 핵심: 움직임 구현과 사용자 입력 마스터하기 ✨ (7) | 2025.04.09 |
---|---|
[C#]🔧 유니티 핵심 완벽 이해: 게임 오브젝트, 컴포넌트, 프리팹 파헤치기 (feat. 트랜스폼 & 스크립트 제어) (5) | 2025.04.08 |
[C#]유니티, 게임 개발의 첫걸음! 설치부터 인터페이스 정복까지 (+꿀팁) 🚀 (5) | 2025.04.08 |
C# 성능 최적화 기법 🚀💪 (0) | 2024.12.18 |
C#으로 크로스 플랫폼 애플리케이션 개발하기 🌍💥 (2) | 2024.12.18 |