1. 변수(Variable)의 정의 및 역할
변수란 데이터를 저장하기 위해 할당된 메모리 공간에 붙여진 이름을 의미합니다. 변수에 저장된 값은 프로그램 실행 중에 변경될 수 있다는 특징을 가집니다. 변수는 다음과 같은 주요 역할을 수행합니다.
- 데이터 저장: 숫자, 문자열, 객체 등 다양한 종류의 데이터를 임시 또는 영구적으로 저장합니다.
- 상태 추적: 게임 오브젝트의 위치, 플레이어의 체력, 점수 등 시간에 따라 변하는 상태 정보를 관리합니다.
- 계산 및 처리: 연산의 중간 결과나 최종 값을 저장하여 로직을 수행하는 데 사용됩니다.
모든 변수는 특정 데이터 타입(예: int
, float
, string
, GameObject
)을 가지며, 이는 해당 변수가 저장할 수 있는 데이터의 종류와 허용되는 연산을 결정합니다.
2. 변수 선언 및 초기화
C#에서 변수를 사용하기 위해서는 먼저 선언(Declaration) 과정을 거쳐야 합니다. 변수 선언은 컴파일러에게 특정 타입의 데이터를 저장할 메모리 공간을 확보하도록 지시하는 것입니다. 선택적으로 선언과 동시에 초기화(Initialization)를 통해 변수에 초기값을 할당할 수 있습니다.
[문법]
// 변수 선언
데이터타입 변수이름;
// 변수 선언과 동시에 초기화
데이터타입 변수이름 = 초기값;
[예시 코드]
using UnityEngine;
public class VariableExample : MonoBehaviour
{
// 멤버 변수 (필드) 선언
public int playerScore; // public 접근 제한자로 선언된 정수형 변수
private float speed = 5.0f; // private 접근 제한자, 선언과 동시에 초기화된 실수형 변수
[SerializeField] private string playerName; // private이지만 Inspector에 노출되는 문자열 변수
void Start()
{
// 지역 변수 선언 및 초기화
int initialHealth = 100; // Start 메서드 내에서만 유효한 지역 변수
bool isActive = true;
// 변수 값 변경
playerScore = 0;
speed = CalculateInitialSpeed();
Debug.Log("플레이어 이름: " + playerName);
Debug.Log("초기 체력: " + initialHealth);
}
float CalculateInitialSpeed()
{
// 지역 변수
float baseSpeed = 3.0f;
float speedModifier = 2.0f;
return baseSpeed * speedModifier; // 계산 결과를 반환
}
void Update()
{
// Update 메서드 내에서 변수 값 사용 및 변경
transform.Translate(Vector3.forward * speed * Time.deltaTime);
// playerScore += CalculateScore(); // 점수 업데이트 등
}
}
3. 상수(Constant)의 정의 및 특징
상수(Constant)는 변수와 유사하게 데이터를 저장하는 이름 붙은 메모리 공간이지만, 초기화된 이후에는 그 값을 절대로 변경할 수 없다는 중요한 차이점을 가집니다. 상수의 값은 반드시 컴파일 타임(Compile Time)에 결정되어야 합니다. 상수는 다음과 같은 특징과 장점을 제공합니다.
- 불변성(Immutability): 프로그램 실행 중 값이 변경되지 않아 안정성을 보장합니다.
- 가독성 향상: 의미를 알 수 없는 리터럴 값(Magic Number/String) 대신 의미 있는 이름을 부여하여 코드 이해도를 높입니다. (예:
3.14159
대신PI
) - 유지보수 용이성: 여러 곳에서 사용되는 고정 값을 상수로 정의하면, 값 변경 필요시 상수 선언부 한 곳만 수정하면 됩니다.
4. 상수 선언 및 사용
C#에서 상수는 const
키워드를 사용하여 선언하며, 선언과 동시에 반드시 값을 초기화해야 합니다.
[문법]
// [접근제한자] const 데이터타입 상수이름 = 컴파일 타임 상수 값;
public const int MaxConnectionAttempts = 5;
private const float GravityScale = 9.81f;
[예시 코드]
public class ConstantExample
{
public const int MaxPlayers = 4; // 최대 플레이어 수
private const string DefaultSceneName = "MainMenu"; // 기본 씬 이름
public void CheckPlayerCount(int currentPlayers)
{
if (currentPlayers >= MaxPlayers)
{
Debug.Log("최대 플레이어 수에 도달했습니다.");
}
}
public void LoadDefaultScene()
{
// SceneManager.LoadScene(DefaultSceneName); // 예시: 씬 로드에 상수 사용
Debug.Log(DefaultSceneName + " 씬을 로드합니다.");
}
}
상수는 그 자체로 static
멤버처럼 취급되어 클래스 인스턴스 없이 클래스명.상수명
형태로 접근 가능합니다 (단, 접근 제한자에 따라 접근 범위는 달라짐).
5. 읽기 전용 필드 (readonly)
const
와 유사하게 값을 한 번 할당하면 변경할 수 없지만, 초기화 시점에서 차이가 있는 readonly
키워드가 존재합니다.
const
(상수):- 값은 컴파일 타임에 결정되어야 합니다.
- 선언 시 반드시 초기화해야 합니다.
- 정적(static) 멤버로 취급됩니다.
readonly
(읽기 전용 필드):- 값은 런타임에 결정될 수 있습니다.
- 선언 시 또는 생성자(Constructor) 내에서 단 한 번 초기화될 수 있습니다.
static
으로 선언하지 않으면 인스턴스 멤버가 됩니다 (객체마다 다른readonly
값을 가질 수 있음).
readonly
는 객체가 생성될 때 결정되는 고정 값(예: 설정 파일에서 읽어온 값, 생성 시 부여된 고유 ID)을 저장하는 데 유용합니다.
[예시 코드]
public class ReadOnlyExample
{
public readonly int CreationTimeTicks; // 생성 시점의 시간을 저장할 읽기 전용 필드
private readonly string uniqueID;
public static readonly float DefaultGravity; // 정적 읽기 전용 필드
// 정적 생성자 (static readonly 필드 초기화)
static ReadOnlyExample()
{
DefaultGravity = 9.81f; // 런타임에 초기화될 수 있음 (예: 설정 파일 로드 등)
}
// 인스턴스 생성자 (인스턴스 readonly 필드 초기화)
public ReadOnlyExample(string id)
{
CreationTimeTicks = (int)System.DateTime.Now.Ticks; // 객체 생성 시점의 값으로 초기화
this.uniqueID = id; // 생성자 매개변수로 초기화
// 생성자 이후에는 readonly 필드 값 변경 불가
// CreationTimeTicks = 0; // 컴파일 오류 발생
}
public string GetID()
{
return uniqueID;
}
}
6. const vs. readonly 비교 (const vs. readonly Comparison)
const
와 readonly
는 모두 초기화된 후에는 값을 변경할 수 없다는 공통점이 있지만, 초기화 시점, 사용 가능한 타입, 멤버 종류 등에서 중요한 차이점을 가집니다. 이를 명확히 이해하는 것은 상황에 맞는 키워드를 선택하는 데 필수적입니다.
특징 구분 (Feature) | const (상수) |
readonly (읽기 전용 필드) |
---|---|---|
초기화 시점 (Init. Time) | 컴파일 타임 (Compile Time) (컴파일 시 값이 확정되어야 함) | 런타임 (Runtime) (객체 생성 시점 등 런타임에 값 결정 가능) |
초기화 위치 (Init. Location) | 선언 시 반드시 초기화 | 선언 시 또는 생성자(Constructor) 내에서만 초기화 가능 |
저장되는 값 (Value Type) | 컴파일 타임 상수 (코드 내에서 리터럴 값으로 대체될 수 있음) | 런타임에 결정된 값 (메모리에 일반 필드처럼 존재) |
정적/인스턴스 (Static/Instance) | 암묵적으로 정적(Static) (클래스 이름으로 접근) | 인스턴스 멤버 (기본) (static readonly 로 선언 시 정적 멤버) |
참조 타입 사용 (Ref. Type Use) | string 리터럴과 null 외 참조 타입 사용 불가 |
제한 없음 (단, 참조 대상 객체의 내부 상태는 변경 가능, 참조 자체만 변경 불가) |
성능 (Performance) | 컴파일 시 값이 대체되어 약간의 성능 이점 가능성 (미미함) | 일반 필드 접근과 거의 동일 |
주 사용 목적 (Main Purpose) | 절대 변경되지 않는 진정한 상수 값 (예: 수학 상수 PI , 최대값 MaxHp ) |
객체 생성 시 또는 특정 시점에 단 한 번 결정되어 변경되지 않아야 하는 값 (예: 객체 고유 ID, 설정 값) |
요약:
const
: 컴파일 시점에 값이 완전히 결정되어야 하는 진정한 상수에 사용합니다. 값은 코드 전체에서 절대 변하지 않습니다.readonly
: 객체가 생성될 때(또는 정적 생성 시) 값이 결정되고, 그 이후에는 변경되지 않아야 하는 읽기 전용 필드에 사용합니다. 객체마다 다른 값을 가질 수 있습니다.
7. Unity에서의 변수 및 상수 활용
- 변수(Variables):
- 게임 상태 관리: 플레이어 체력(
float health
), 점수(int score
), 위치(Vector3 position
), 활성화 여부(bool isAlive
) 등 게임 진행에 따라 변하는 모든 데이터를 저장합니다. 스크립트 내 멤버 변수로 선언하여 사용합니다. - Inspector 연동:
public
으로 선언하거나[SerializeField]
어트리뷰트를 붙인 변수는 Unity Inspector 창에 노출되어 에디터에서 값을 쉽게 조정할 수 있습니다. (예:public float moveSpeed;
,[SerializeField] private GameObject playerPrefab;
) - 임시 데이터: 메서드 내에서 계산 중간 결과나 임시 상태를 저장하기 위해 지역 변수를 사용합니다.
- 게임 상태 관리: 플레이어 체력(
- 상수(Constants):
- 고정 설정 값: 최대 레벨(
const int MaxLevel = 99
), 물리 계수(const float PlayerDrag = 0.5f
), UI 문자열(const string GameOverText = "Game Over";
) 등 변경되지 않는 고정 값을 정의하여 코드의 명확성을 높입니다. - 수학/물리 상수: 원주율(
Mathf.PI
), 중력 가속도 등 널리 사용되는 상수 값을 정의합니다.
- 고정 설정 값: 최대 레벨(
- 읽기 전용 필드(Read-Only Fields):
- 런타임 초기화 고정 값: 게임 시작 시 설정 파일에서 읽어온 값, 객체 생성 시 부여되는 고유 식별자(
readonly Guid instanceId
) 등 객체별로 다르지만 생성 후에는 변하지 않는 값을 저장하는 데 적합합니다.
- 런타임 초기화 고정 값: 게임 시작 시 설정 파일에서 읽어온 값, 객체 생성 시 부여되는 고유 식별자(
8. 변수/상수 명명 규칙 및 범위
- 명명 규칙(Naming Conventions): 코드의 가독성을 위해 표준 C# 명명 규칙을 따르는 것이 권장됩니다.
- 지역 변수, private/protected 필드:
camelCase
(예:playerHealth
,moveSpeed
) - public 필드, 상수(
const
), 읽기 전용 필드(readonly
), 속성(Property), 메서드:PascalCase
(예:MaxScore
,PlayerName
,CalculateDamage()
) - 이름은 변수/상수의 역할을 명확히 나타내도록 의미 있게 작성합니다.
- 지역 변수, private/protected 필드:
- 범위(Scope): 변수나 상수가 유효한 코드 영역을 의미합니다.
- 지역(Local) 범위: 특정 메서드나 코드 블록(
{}
) 내에서 선언된 변수는 해당 영역 내에서만 접근 가능하며, 영역을 벗어나면 소멸됩니다. - 클래스(Class/Member) 범위: 클래스 내부에 선언된 멤버 변수(필드)는 해당 클래스의 모든 메서드에서 접근 가능합니다(접근 제한자에 따라 다름). 객체가 존재하는 동안 메모리에 유지됩니다.
- 지역(Local) 범위: 특정 메서드나 코드 블록(
결론
변수는 프로그램의 동적인 상태와 데이터를 관리하는 핵심 요소이며, 상수는 변경되지 않는 고정 값을 명확하게 표현하여 코드의 안정성과 가독성을 높이는 중요한 도구입니다. const
와 readonly
의 차이를 명확히 이해하고 상황에 맞게 사용하는 것 또한 중요합니다. Unity C# 개발에서 변수와 상수를 올바르게 선언하고 활용하며, 일관된 명명 규칙과 범위(Scope) 개념을 적용하는 것은 효율적이고 유지보수가 용이한 코드를 작성하기 위한 기본적인 역량입니다. 이러한 기초를 충실히 다지는 것이 복잡한 게임 시스템을 성공적으로 구축하는 데 기여할 것입니다.