using UnityEngine;
using TMPro;
public class DebugText : MonoBehaviour)
{
public TMP_Text tmpT;
public TextMeshProUGUI tmpUgui;
tmpT.text = "원하는 텍스트 적어넣기";
tmpUgui.text = "원하는 텍스트 적어넣기2";
}
Data 영역 : Static, Const 프로그램/어플리케이션 전반에 필요한 데이터 저장
생성 시점 : 프로그램/어플리케이션 실행시 삭제 시점 : 프로그램/어플리케이션 종료시
Heap 영역 : 참조 데이터(객체) 저장
생성 시점 : new(C#), Instaniate(Unity) 삭제 시점 : GC(가비지컬렉터) 동작 시점 가비지는 해당 데이터가 사용하지 않는 시점 (참조가 끊긴 시점)에 GC에 수집됨
p.s Unity Editor의 Destroy()라는 오브젝트를 삭제해주는 메서드가 있는데 이것도 눈에 보이는 오브젝트가 삭제된거지 Heap영역에 있는 Data들은 가비지 데이터가 되어버린다.
Stack 영역 : 로컬 변수,매개 변수 저장 프로그램/어플리케이션 실행순서에 필요한 데이터 보관
생성 시점 : 함수 내에서 선언시, 변수 할당시 생성 종료 시점 : 함수가 종료될때
priavte void Start()
{
int x = 10;
int y = x;
x = 5;
}
해당 코드가 있을때 x,y의 최종 데이터는 어떡해 되는가?
x = 5 , y = 10이 될것이다.
class Person()
{
public int Age;
public string Name;
}
private void Start()
{
Person personA = new Person(32,"BirdHead");
Person personB = personA;
personA.Age++;
}
해당 코드에서 PersonA와 PersonB의 Age의 데이터는 몇인가?
결과는 둘다 33 이다.
Q.왜 위의 코드와 아래의 코드의 데이터는 왜 다른식으로 저장돼?
A.
로컬 변수(지역변수) 및 매개변수는 Stack영역에 첫 메모리부터 저장되기 시작한다.
해당 데이터에 접근하기 위해 0000 0000 주소값을 가져오는게 아닌 변수 x로 이름을 대체하여 사용하게 되는것이다.
해당 변수(주소 이름)을 호출하여 그 안에 데이터를 꺼내서 사용하는 것이다.
해당 코드는 Class로 객체 A,B를 생성하고 A의 Age 데이터를 1 증가시키는 코드이다.
1번 : 객체(인스턴스)는 Stack 영역에 저장되고 객체의 데이터들은 Heap영역으로 저장된다.
이때Heap의 저장된 Data는 Stack에 참조 되어 있는 상태라고 표현한다.
2번 : B 객체에 A를 대입 하게되면 , 객체인 B는 Stack 영역에 저장되고 B 객체의 데이터는 A에 참조되어 데이터를 사용하게 된다.
3번 : A 객체의 Age 데이터를 호출할때 Stack 영역의 A객체에 접근 후 참조된 데이터값에 접근하여 수정 할 수 있다.
이런 과정을 걸치면 B도 기존의 A데이터 Heap영역에 참조되어있기에 데이터가 변경되면 B도 같이 변경되는 모습을 볼 수 있다.
Q.객체를 삭제하게 되면 Heap영역의 Data는 어떡해 돼?
A.
Stack 영역의 객체만 삭제되고 , Heap영역의 Data는 참조가 끊기며 사용하지 않는 데이터가 된다.
즉, 가비지(쓰레기)데이터가 되어 메모리 누수를 발생시킨다.
하지만 C#에서는 이런 가비지 데이터들을 수집하여 처리해주는 GC(가비지 컬렉터)가 존재한다.
AND : 1000 & 0001 = 0000 OR : 1000 & 0001 = 1001 XOR : 1000 & 0001 = 1001 NOT : 1000 -> 0111
0010 << 1 = 0100
0010 >> 1 = 0001
(<< , >> 이동시 처음과 끝 bit 는 0으로 채워진다.)
Q.비트연산자는 왜 쓰는거야?
A.
효율적이고 빠른 데이터 처리와 메모리 절약이 목적
Unity에서는 레이어마스크 처리 할 때 사용이 됨
사용하는 이유를 정확히 설명하면
1.메모리 효율성 :하나의 정수 값으로 각각의 비트를 개별적인 상태로 관리 할수 있기 때문에
예를 들이 32bit 정수 (4byte = int)는 32개의 서로 다른 상태를 한번에 표현 할 수 있기 때문
2.빠른 성능 : 비트연산은 CPU에 최적화 된 연산이며 덧셋,곱셈 보다 비트 연산이 더 빠르게 수행되기 떄문에
그래픽 처리시 매우 높은 최적화 효율을 보인다.
3.복잡한 조건을 단순하게 표현 : 메모리 효율성과 좀 겹치는 내용이지만, 32개의 정수 단일값으로 다중 상태를 관리하기에 가독성이 매우 좋아짐
Q.레이어마스크는 뭐야?
A.
Unity의 레이어를 비트마스크(Bit Mask)를 사용하여 여러 레이어를 하나의 값으로 표현하는 방식
p.s 비트마스크?
bit의 이진수 표현을 활용하여 나타내는 방법
Q.레이어마스크는 왜 쓰는거야?
A.
일반적으로 내 공격이 나한테 맞거나 , 적의 공격이 적에 맞거나 하는건 게임에서는 적용되면 않된다.
(물론 적용되는 게임들도 있다) 이러한 문제를 대처하기 위해 레이어마스크를 사용하는것이다 .
1.충돌 검사 : 비트 마스크를 사용하여 특정 레이어에 속한 오브젝트만을 대상으로 충돌 검사 수행이 가능
즉, 태그,이름(문자열)로 검색할 필요가 없으니 최적화에 도움이 됨
2.레이캐스팅 제어 : 레이캐스트가 특정 레이어의 오브젝트에만 반응하도록 비트마스크를 설정 할 수 있음
예시1)
객체에서 레이(빛)을 쏴서 부딪히는 객체를 탐지할때 ,장애물 오브젝트는 무시하고 탐색을 하고 싶을때
해당 장애물의 레이어를 제외하여 레이가 해당 장애물 오브젝트에 부딪힐때 투과해서 쏠수 있게 하는기능
해당 내용을 코드로 작성하면
public int ObstcalseLayer = 5;
public int PeopleLayer = 8;
LayerMask layerMask = 1 << ObstcalseLayer; //장애물(5번레이어)를 비트마스크로 생성후 레이어마스크에 초기화
raycastObj = ~raycastObj; //반전비트를 이용하여 장애물 레이어를 0으로 변경
//레이캐스트에 layerMask를 인자값으로 넣어 장애물 레이어를 투과하여 레이캐스트를 발사
Physics.Raycast (transform.position, transform.TransformDirection (Vector3.forward), hit, Mathf.Infinity, layerMask);
이렇게 작성된다.
3.카메라 렌더링 설정 : 카메라가 특정 레이어의 오브젝트를 렌더링하도록 설정하여, 게임의 시각적 요소를 세밀하게 제어를 가능하게 한다.
Q.레이어마스크를 어떡해 쓰는거야?
A.우선 오브젝트에 있는 레이어를 코드내에서 사용하기위해 비트마스크로 생성해야한다.
1 << n // 1을 n번째 비트 위치로 시프트(이동)한다는 의미
//즉 n은 레이어(0~32 layer정수값을 의미), n번쨰 레이어를 나타내는 비트마스크로 생성한다는 의미
//예시
//충돌된 객체의 게임오브젝트에서 레이어를 초기화
int layer = collision.gameObject.layer;
1 << layer; //호출받아온 레이어를 비트마스크로 생성하여 사용
해당 코드처럼 1 << n 을 사용하여 비트마스크로 생성하는것이다.
그럼 비트마스크로 생성까지 완료했으면 그 이후에는 어떡해 해야되나?
해당 비트마스크를 이용하여 검사를 진행하면된다.
위에서 설명한 논리 연산자들을 활용하는 것이다.
AND (&): 특정 레이어의 존재 여부 확인할떄 사용 OR (|): 새로운 레이어를 추가할 때 사용 XOR (^): 두 레이어의 차이를 찾을떄 사용 ( 비교하는 대상이 다르면 1 ) NOT (~): 특정 레이어를 제외시킬때 사용 ( 모든비트 반전 )
보통 이 논리연산자들 이 특징들을 사용한다.
public LayerMask levelCollisonLayer; //비교할 기준 레이어
private void OnTriggerEnter2D(Collider2D collision)
{
//LayerMask의 value 프로퍼티는 해당레이어의 비트마스크를 십진수를 반환해준다.
if (IsLayerMatched(levelCollisonLayer.value, collision.gameObject.layer))
{
//레이어가 일치하면 true
}
//레이어가 불일치하면 false
}
private bool IsLayerMatched(int value, int layer)
{
//value는 비트마스크이기 때문에 그대로 사용 , layer는 비트마스크로 생성
//(value | 1 << layer) : | 연산자로 기준 레이어(value)와 객체와 충돌한 레이어(layer) OR연산
//OR 연산된 비트마스크 가 기준 레이어와 일치할경우 True
return value == (value | 1 << layer);
}
해당 코드는 OR 연산을 충돌된 객체 레이어가 기준 레이어와 일치할 경우 동작하는 코드이다.
OR 연산은 레이어를 추가할때 사용 하는데 , 이런식으로도 원하지 않는 레이어는 제외할수 있게 구성 할 수도 있다.