일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
- 전쟁-전투
- TiL
- anonymous page
- 연결리스트
- 다익스트라
- 크래프톤 정글 4기
- Unity
- 이벤트 함수 실행 순서
- BFS
- C
- 알고리즘
- 핀토스
- 파이썬
- 티스토리챌린지
- 백준
- 크래프톤 정글
- KRAFTON JUNGLE
- pintos
- project3
- User Stack
- 유니티
- 네트워크
- 크래프톤정글
- 추상클래스와인터페이스
- 크래프톤정글4기
- 알고리즘수업-너비우선탐색2
- c#
- kraftonjungle
- 오블완
- 4기
- Today
- Total
말감로그
[유니티 C# 스크립팅 마스터하기] - 3장 싱글턴과 정적 멤버, 게임 오브젝트와 월드 본문
이번 장은 유니티 스크립트를 능수능란하게 다루려면
씬과 오브젝트, 오브젝트 간의 통신이 어떻게 일어나는지에 대한 구조를 이해하는 것이 중요하다! 가 포인트이다.
어떻게 오브젝트 간에 통신이 이뤄지고 오브젝트를 만들고 이것이 옮겨질 때 데이터를 유지하도록 만들어주는 정적멤버와 싱글턴 등의 대해서도 알아보자.
게임 오브젝트
기본적인 단위나 씬 안의 개체 등 여러 가지 의미를 가진다.
컴포넌트는 기본적으로 MonoBehaviour에서 파생한 클래스로서 씬 안의 게임 오브젝트에 붙어 동작을 변화시킬 수 있다.
컴포넌트 상호작용
- GetComponent
데이터 형식을 알고 있는 특정한 컴포넌트 하나에 직접 접근할 때 사용.
게임오브젝트에 붙여진 컴포넌트 중 일치하는 첫번째 컴포넌트에 접근하도록 해준다.
Transform thisTransform = GetComponent<Transform>();
- GetComponents (여러 개의 컴포넌트에 접근)
전체 컴포넌트의 리스트나 특정 형식의 컴포넌트 리스트처럼 복수의 컴포넌트를 담은 리스트가 필요할 수 있다.
(비용이 많이 들어 Start나 Awake 와 같이 일회성 이벤트에서 호출)
void Start()
{
Component[] allComponents = GetComponents<Component>();
foreach (Component c in allComponents)
{
Debug.Log(C.ToString());
}
}
GetComponentsInChildren - 모든 자식에 존재하는 모든 컴포넌트 가져오기
GetComponentsInParent - 오브젝트의 부모에 존재하는 모든 컴포넌트 가져오기
게임 오브젝트와 월드
유니티의 또 다른 중추적인 기능으로 스크립트에서 씬 안의 오브젝트(특히 런타임에 인스턴스화된 오브젝트)를 검색하는 기능이 있다.
이 함수들은 유용하지만 호출 비용이 비싸므로 가능하면 Start나 Awake와 같은 일회성 이벤트에서 부르도록 해야 한다.
게임 오브젝트 찾기
- GameObject.Find -> 문자열 비교를 통해 오브젝트를 찾음
- GameObject.FindObjectWithTag -> 일치하는 태그를 가진 오브젝트를 찾음. 속도가 더 빠름
- GameObejct.FindObjectsWithTag -> 발견되는 모든 오브젝트를 배열로 반환
오브젝트 비교
두 오브젝트의 태그를 비교하고 싶은 경우 -> CompareTag
bool bMatch = gameObject.CompareTag(Obj_Y.tag);
두 오브젝트가 동일한 오브젝트인지 비교하고 싶지 않은 경우 -> GetInstanceID
// 일치하는 태그를 가진 오브젝트를 찾는다.
FoundObjects = GameObject.FindGameObjectsWithTag(TagName);
// 모든 오브젝트를 검색하고 자신은 제외한다.
foreach(GameObject obj in FoundObjects)
{
// 두 오브젝트가 동일한 오브젝트인 경우
if(obj.GetInstanceID() == gameObject.GetInstanceID())
continue; //반복문의 이번 순회를 생략한다.
}
가장 가까운 오브젝트 찾기 ( Vector3.Distance )
씬 안의 임의의 두 점 간의 최단거리를 구해 가장 가까운 오브젝트를 찾는 방법
float distance = Vector3.Distance(Vector3.a , Vector3.b);
지정한 형식의 오브젝트 모두 찾기( Object.FindObjectsOfType )
오브젝트가 비활성화되지 않은 이상, 씬 안에서 지정한 오브젝트의 모든 인스턴스 리스트를 얻을 수 있다.
void Start()
{
// 씬 안의 모든 충돌체 리스트를 얻는다.
Collider[] colls = Object.FindObjectsOfType<Collider>();
}
게임 오브젝트 간 경로 만들기
Physics.LineCast 함수를 이용하여, 플레이어와 적 캐릭터처럼 두 게임 오브젝트 간에 그리는 가상의 선을 통해 교차하는 충돌체가 있는지 검사하는 경로를 만드는 흔한 방법이다.
public GameObject Enemy;
// 선 검출을 제한하기 위한 레이어 마스크
// LayerMask 변수를 이용해 특정 레이어를 포함하거나 제외시킨다.
public LayerMask lm;
void Update()
{
// 오브젝트 사이에 빈 경로가 있는지 검사
if(!Physics.Linecast(transform.position, Enemy.transform.position, lm))
{
Debug.Log("Path clear");
}
}
오브젝트 계층에 접근
트랜스폼 컴포넌트를 통해 오브젝트를 다른 오브젝트의 자식으로 붙일 수 있는지 보여준다.
void Start()
{
GameObject child = GameObject.Find("Child");
GameObject parent = GameObject.Find("Parent");
child.transform.parent = parent.transform;
}
부모에 붙어있는 모든 자식을 순회하는 방법
void Start()
{
for (int i = 0; i < transform.childCount; i++)
{
Debug.Log(transform.GetChild(i).name);
}
}
월드/시간과 업데이트
유니티의 씬은 같은 3D 공간에 존재하면서 같은 시간을 공유하는 유한한 수의 게임오브젝트의 집합을 표시하는 개념이다.
애니메이션을 동기화 및 변경하기 위해 모든 게임엔 통일된 시간 개념을 정할 필요가 있다.
유니티에서 Time 클래스를 이용해 시간을 읽고 시간의 흐름을 알아낼 수 있다.
유니티의 모든 MonoBehaviour 클래스가 제공하는 세 가지 클래스 이벤트를 통해 프레임의 개념과 비슷한 방식으로 시간에 따라 지속적으로 업데이트되도록 구현할 수 있다.
- Update : 씬 안의 모든 활성화된 게임오브젝트의 모든 컴포넌트에 대해 프레임 당 한 번씩 이벤트가 불리게 된다.
반복적인 동작이나 업데이트, 키보드 눌림이나 마우스 클릭을 확인하는 등의 모니터링 기능이 필요할 때 유용하다.
다만, Update 이벤트가 모든 컴포넌트에 매 프레임마다 불려지는 것은 보장되지 않는다
- FixedUpdate : Update와 같이 매 프레임마다 여러번 불리게 되지만 고정된 시간 간격을 기반으로 규칙적으로 표준화되어 일어난다. 유니티의 물리 기능(Rigidbody)을 사용할 때 가장 널리 이용된다.
- LateUpdate : Update와 마찬가지로 매 프레임 호출되지만 언제나 Update와 FixedUpdate가 호출된 이후에 호출된다.
1인칭 카메라를 구현하는 경우 유용하게 이용된다.
- 규칙 1: 프레임은 소중한 것이다.
매 프레임마다 씬 안의 모든 활성화된 MonoBehaviour 컴포넌트에 Update 이벤트가 호출된다.
Update 이벤트 안에서 하는 일들이 매 프레임 해당 씬을 처리하는 계산 복잡도에 큰 영향을 미친다는 뜻이다.
신중한 코딩 계획을 통해 Updat 함수 안의 부하를 줄이지 않으면 많은 오브젝트와 컴포넌트를 가지는 큰 씬을 감당하기 어려워지기 때문에 Update나 프레임 기반으로 규칙적으로 호출되는 이벤트를 아껴 쓰는 것이 중요하다.
-> 이벤트 주도적 프로그래밍을 고려하는 것이 부하를 크게 줄이는데 도움이 될 것이다.
- 규칙 2: 움직임은 시간과 비례해야 한다.
프레임의 주기를 일정하게 보장할 수 없기 때문에, 게이머에게 일관된 경험을 제공하기 위해 매우 주위를 기울여 움직임을 코딩하고 변경해야 한다.
프레임은 가변적이지만 시간은 일정하기 때문에 Time 클래스의 멤버인 deltaTime 변수를 이용하면 일정한 움직임 구현이 가능해진다.
deltaTime 변수는 부동소수점 값으로서 항상 이전 Update 함수가 호출된 이후로 시간이 얼마나 지났는지를 초 단위로 표시한다.
싱글턴 오브젝트와 정적 멤버
하나의 클래스 인스턴스만 유일하게 존재하게 되며 절대 그보다 많은 인스턴스를 만들지 않는다. 하나보다 많은 인스턴스를 가지는 것은 모순적인 부분이 발생하거나 오브젝트의 역할을 망가뜨리고 어떤 면에서는 쓸모없어질 수도 있다.
이런 종류의 오브젝트를 싱글턴이라 부른다.
싱글턴으로 만드는 기본적인 요소는 항상 메모리에 클래스의 인스턴스가 하나만 존재한다는 것뿐이다.
public class GameManager : MonoBehaviour
{
// 싱글턴 인스턴스에 접근하기 위한 C# 프로퍼티
// get 접근자만 가지는 읽기 전용인 프로퍼티
public static GameManager Instance
{
// private 변수 instance의 참조를 반환한다.
get
{
return instance;
}
}
private static GameManager instance;
private void Awake()
{
// 씬에 이미 인스턴스가 존재하는지 검사한다.
// 존재하는 경우 이 인스턴스는 소멸시킨다.
if(instance)
{
DestroyImmdiate(gameObject);
return;
}
// 이 인스턴스를 유효한 유익 오브젝트로 만든다.
instance = this;
// 게임 매니저가 지속되도록 한다.
DontDestroyOnLoad(gameObject);
}
}
'Unity' 카테고리의 다른 글
[유니티C# 스크립팅 마스터하기] - 4장 이벤트 주도적 프로그래밍 (1) | 2025.01.07 |
---|---|
[유니티 C# 스크립팅 마스터하기] - 2장 디버깅 (0) | 2025.01.03 |
[유니티 C# 스크립팅 마스터하기] - 1장 유니티 C# 복습 (0) | 2025.01.02 |
[Unity] 시네머신으로 카메라 이동 제한하기 (1) | 2024.12.25 |
[Unity] Device Simulator (디바이스 시뮬레이터) (0) | 2024.12.23 |