유니티 - 정리 전

박상원·2024년 2월 13일

메모

목록 보기
8/8

스크립트 파일에서 public 변수로 선언하면 유니티 내에서 값을 수정할 수 있다.
그러나 private로 설정하면 유니티 내에서 값 수정 불가능. 따라서 직접 코드파일을 열어 수정해야 함
ex) hiyoko의 메인카메라의 Cannon 스크립트에서 prefab과 power를 public으로 선언한 것

어떠한 방향을 구하고 싶을땐 물체끼리 빼면 된다.
ex) 히요코의 Objmove 스크립트에서
Vector3 direction = target.transform.position - transform.position;
이 문장은 히요코의 데스존으로의 방향을 direction 변수에 대입하는것이다


Static변수는 용도에 따라
1. 정적변수
2. 공유변수
3. 클래스 변수
가 있다
공유변수는 전역변수나 멤버변수와 비슷한 개념인데, 스타의 마린을 예로 들면
각 마린들의 체력상태는 각각 다르다. (누구는 풀피인데 누구는 공격받아서 피가 깎였다거나)
그런데 마린들의 방어력, 공격력은 모두 같다. 또한 업그레이드를 해도 마린 한개만 업글이 된다거나 하지않고
모든 마린이 똑같이 업그레이드 된다. 마린의 공격력 방어력 같이 모든 마린이 공유하는 변수를 공유변수라 한다.
히요코 프로젝트에서 Score스크립트에서 static으로 int타입 변수 score를 선언했는데,
HiyokoCreator 스크립트의 Score.score++; 문장에서,
Score스크립트에서 선언한 변수를 여기서 가져다 쓰고있다.
HiyokoCreator 스크립트에서 선언한 변수가 아님에도 쓸수있는 이유는 Score스크립트에서 score변수를 static으로 선언했기 때문이다.

클래스변수는 클래스.변수 또는 클래스.메소드 <-이와 같은 형태로 쓰이는건 모두 static으로 선언된것 이다.
예를들어 Time.abc 이런 형태가 있다면 abc변수는 static abc <- 이렇게 static으로 선언된 변수인것
원래는 객체를 생성할때 메모리에 객체 크기만큼 할당이 된다.
그런데 static을 쓰면 객체를 생성하기 전에 이미 메모리에 할당이 된다.
예를들어 마린의 공격력 방어력은 마린을 생성하기 전부터(배럭에서 생성되기 전부터)이미 정해져있다.
따라서 공격력 방어력 변수는 static을 써서 선언된 변수이다. 또한 모든 마린이 공격력과 방어력을 공유하므로 공유변수이기도 하다
또다른 예로 만약 static을 안쓰면
Score scr = new Score();
scr.score++;
이렇게 써야하는데, static을 쓰면 new Score 이 부분(객체생성부분)이 필요없이 바로 Score.score++; 로 쓸 수 있다.


충돌검사 방식은 크게 두가지가 있다. OnCollision와 OnTrigger방식이다.
collision은 두 물체가 충돌했을때 물리적인 현상(튕겨나간다거나)을 발생시킬때 쓰고,
trigger방식은 물체가 부딪혔는지 아닌지 검사만 한다거나, 두 물체를 서로 통과시킬때 사용한다.
추가로 trigger방식을 쓸때는 Box Collider 컴포넌트의 Is Trigger를 체크해주어야 한다.

히요코 프로젝트의 충돌검사 방식에서, OnTriggerEnter(Collider other)에서 other에는, 이 스크립트가 적용될 오브젝트와 충돌한
오브젝트의 정보가 담긴다. 이 스크립트는 데스존에 적용되었으니 데스존과 충돌한 히요코 오브젝트의 정보를 가져온다.
그런데 충돌검사는 해당 오브젝트와 충돌한 모든 오브젝트의 정보를 가져온다.
따라서 히요코가 충돌했을때만 작동하게 하기위해 if (other.GameObject.tag == "Hiyoko") <- 이문장으로
부딪힌 오브젝트의 태그가 Hiyoko일때, 즉 히요코일때만 스크립트가 작동하게 했다.

OnCollision과 OnTrigger의 마지막에 Enter, Stay, Exit 중 뭐가 붙느냐에 따라 다른데,
Enter는 충돌이 시작되는 순간 호출,
Stay 는 충돌이 되고 있을때 매 프레임마다 호출,
Exit 은 충돌이 끝날때 호출이다.


히요코에서 gameover텍스트와 재시작 버튼을 활성화, 비활성화 할때 enabled와 SetActive를 썼다.
text.enabled = false;
button.SetActive(false)
↑요건 비활성화

text.enabled = true;
button.SetActive(true);
↑요건 활성화

enabled과 SetActive의 차이점은
enabled는 컴포넌트를 비활성화 할 때 쓴다. 이것은 Hierarchy에서 오브젝트를 선택하고 inspector의 컴포넌트 창에서
체크박스를 해제하는 것과 같은 효과이다.

SetActive는 오브젝트를 자체를 비활성화 할 때 쓴다. 이것은 Hierarchy에서 오브젝트를 선택하고 inspector의 제일 위에
오브젝트 이름옆에 체크박스를 해제하는 것과 같은 효과이다.


Update함수는 초당 수십번씩, 프레임마다 호출되는 함수로, 쉽게말해 항상 호출중인 함수이다.
게임의 핵심 로직을 작성한다.
항상 호출중이므로 주로 캐릭터의 이동이나, 사용자의 입력을 빠르게 감지하기 위해 사용된다.
컴퓨터 성능이나 상태에 따라 초당 호출되는 횟수가 달라진다.

Start는 생성자처럼 초기화를 해주는 함수이다.

awake 는 start와 비슷하지만, start는 스크립트가 활성화 될때 한번만 실행되지만 awake는 활성화 되든 안돼든 실행된다

GameObject는 게임내에서 생성된 오브젝트를 가리킨다.
ex) hiyoko에서 ball은 사용자가 화면을 누르면 생겨나는 gameobject이다.

transform
원래 컴포넌트를 가져오려면 getComponent를 해야하지만 transform을 쓰면 자동으로 컴포넌트를 가져온다.

Time.deltaTime은 현재 update함수가 호출된 시간과 바로 이전에 update함수가 호출된 시간의 간격을 나타낸다.
만약 0.1초마다 update가 호출된다면 Time.deltaTime은 0.1이 되는것이다.

FixedUpdate는 주로 물리엔진을 사용하는 경우에 시간 간격으로 힘을 가할때 사용한다. 발생하는 주기가 0.02초당 한번으로 일정하다


컴포넌트의 audio source는 음악을 재생하는 컴포넌트이며
audio listener는 audio source와 오디오리스너의 거리에 따라서 음악의 소리크기를 조절해준다
거리에 따라 소리가 조절되는 정도는 audio source의 spatial blend로 조절 가능


빌드방법
file -> build setting -> 씬 추가(순서대로) -> 플랫폼 선택 -> 빌드


마우스 고정시키기
1. Locked : 마우스의 커서를 윈도우 정중앙에 고정시킨 후 보이지 않게 해주는 코드. FPS 게임에 유용.
코드 사용 예시 : Cursor.lockState = CursorLockMode.Locked;

  1. Confined : 마우스의 커서가 게임 윈도우 밖으로 벗어나지 않게 함.
    코드 사용 예시 : Cursor.lockState = CursorLockMode.Confined;

  2. None : Locked 또는 Confined 되었던 커서를 원래대로 돌려줌.
    코드 사용 예시 : Cursor.lockState = CursorLockMode.None;

마우스 보이게/안보이게 하기
Cursor.visible=false; <-false로 하면 안보이게한다.
Cursor.visible=true; <-true로 하면 보이게 한다.


씬 다시시작
using UnityEngine.SceneManagement; <-using하기

SceneManager.LoadScene("씬이름");


Time.timeScale 은 시간이 어떤 속도로 흘러가는지를 설정한다.
Time.timeScale = 0; <-이렇게 0으로 설정하면 모든 게임 오브젝트가 정지한다. (즉 게임 일시정지 효과를 만들 수 있다)
Time.timeScale = 1; <-이렇게 1로 설정하면 원래대로 돌아간다.


오브젝트의 좌표 구하기
Vector3 변수;
변수 = this.gameObject.transform.position;
변수.x <- x좌표
변수.y <- y좌표
변수.z <- z좌표


함수 실행 지연 시키기
void Start(){ Invoke("함수이름", 지연시간); } <- 이렇게 하면 시간이 지연시간(초 단위) 만큼흐른뒤 함수를 실행한다.
ex) Invoke("Func", 5f); 시간초는 float형으로 해야함(직접 값 입력하는것이 아니라 변수를 넣을때)

일정 시간마다 반복적으로 실행시키기
void Start(){ InvokeRepeating("함수이름", 지연시간, 반복주기); } <- 이렇게 하면 지연시간이 지난 후, 반복주기 마다 함수를 실행한다.
(시간은 마찬가지로 float자료형)

일정 횟수만 반복시키기
int count = 0;
void Start(){ InvokeRepeating("함수이름", 지연시간, 반복주기); }
void 반복할함수(){ count += 1; }
void Update(){
if(count >= 5){ CancleInvoke("함수이름");} <- 5번 반복후 CancleInvoke() 함수호출
}

CancleInvoke("함수이름") 은 InvokeRepeating("함수이름")을 취소시키는 함수이다.

일정 시간이 지난 후 오브젝트 파괴
Destroy(gameObject, 5f); <- 5초후 gameObject 파괴
gameObject는 이 스크립트가 적용된 오브젝트를 뜻한다. (GameObject랑 다른거임)

RigidBody의 이동방법에는 velocity와 addforce가있다.
addforce는 힘을 계속 누적하고, velocity는 아니다.

canvas에서 canvas sclaer의 UI scale Mode를 scale with screen size로 설정하면
해상도나 화면크기가 변경되어도 동일한 비율로 크기가 자동으로 변경된다.

객체의 inspector 화면에서 additional settings의 sorting layer로 레이어 효과를 적용할 수 있다.


클래스 내에 함수, 메소드에 virtual 있을 경우, 이 클래스를 자식이 상속받았을 때 virtual이 붙은 함수는 재정의해서 쓰도록 유도한다
ex)
class Unit{
public virtual void Attack(){
Debug.Log("공격한다");
}
}

class Marine : Unit{ //상속받을 땐 클래스 이름 옆에 : 부모 클래스(또는 인터페이스) 라고 쓴다
public override void Attack(){ //부모클래스인 Unit에 있는 Attack메소드를 자식 클래스인 마린에서 오버라이드로 재정의한다(virtual은 재정의를 유도하는 것이므로, 자식이 재정의 하지 않아도 에러는 나지 않는다)
Debug.Log("마린이 총을 쏜다");
}
}

class Tank : Unit{
public override void Attack(){
Debug.Log("탱크가 대포를 쏜다");
}
}

Unit unit1 = new Unit();
Unit unit2 = new Marine(); //이렇게 부모 클래스 객체를 생성할 때 자식 클래스를 넣어서 사용할 수 있다.
Unit unit3 = new Tank();
unit1.Attack();
unit2.Attack();
unit3.Attack();
결과>>> 공격한다
마린이 총을 쏜다
탱크가 대포를 쏜다
//Unit 객체로 생성하고 자식클래스가 가진 메소드를 가져다가 사용했다. 따라서 Attack메소드를 쓰면 자식클래스의 Attack메소드가 실행된다.

또는
Unit [] unit = new Unit[3];
unit [0] = new Unit();
unit [1] = new Marine();
unit [2] = new Tank();
for (int i=0; i<unit.Length; i++){
unit[i].Attack();
}
결과>>> 공격한다
마린이 총을 쏜다
탱크가 대포를 쏜다
//이렇게 배열로 생성하고 for문으로 Attack을 사용할수도 있다.

이렇게 부모 클래스로 객체를 생성해도, 자식 클래스를 연결해 줌으로써 자식클래스의 메소드나 변수등을 가져다가 쓸 수 있다.

ex) 또다른 예제
class Unit{
public virtual void Attack(){
Debug.Log("공격한다");
}
public void SomethingAttack(Unit unit){ //Unit타입의 객체를 매개변수로 받는다
unit.Attack(); //매개변수로 받은 Unit타입 객체로 Attack메소드를 사용
}
}

class Marine : Unit{ //상속받을 땐 클래스 이름 옆에 : 부모 클래스(또는 인터페이스) 라고 쓴다
public override void Attack(){ //부모클래스인 Unit에 있는 Attack메소드를 자식 클래스인 마린에서 오버라이드로 재정의한다(virtual은 재정의를 유도하는 것이므로, 자식이 재정의 하지 않아도 에러는 나지 않는다)
Debug.Log("마린이 총을 쏜다");
}
}

class Tank : Unit{
public override void Attack(){
Debug.Log("탱크가 대포를 쏜다");
}
}

Unit unit = new Unit();
Unit unit2 = new Marine();
unit.SomethingAttack(unit2); //SomethingAttack은 Unit타입의 객체를 매개변수로 받는데, 여기선 Unit객체에 Marine클래스를 넣은 것을 매개변수로 넣었다.
결과>>>마린이 총을 쏜다
공격을 한다
//Marine클래스 객체를 매개변수로 넣어도 정상 작동하며, 마린 클래스의 어택과 Unit클래스의 어택 두개가 실행된다.

Tank unit3 = new Tank();
unit.SomethingAttack(unit3); //이번엔 탱크클래스로 선언한 객체를 매개변수로 넣었다
결과>>> 탱크가 대포를 쏜다
공격을 한다
//Tank클래스 객체를 매개변수로 넣어도 정상 작동한다

unit.SomethingAttack(new Marine());
결과>>> 마린이 총을 쏜다
공격을 한다
//이렇게 마린 객체를 생성하지 않고 메소드 사용할때 바로 넣어서 쓸수도 있다.

만약
public static void SomethingAttack(Unit unit){ //SomethingAttack에 static을 붙였을 경우
unit.Attack();
}

Unit.SomethingAttack(new Unit()); //static을 붙이면 이렇게 객체를 생성하지 않아도 메소드를 호출해서 사용 가능하다

※이런 다형성을 사용할 때 주의할점은 부모클래스를 상속받은 자식 클래스를 사용해야 한다
부모에게 상속받지 않은 일반 클래스를 사용하면 안된다.


델리게이트

void square(int n){
print(n*n);
}

void cube(int n){
print(nnn);
}

delegate void Numdele(int n);
Numdele Del; //Numdele타입의 객체 생성

Del = square; //Del객체에 square함수를 대입
Del(10) //Del실행 square함수에 매개변수가 있으므로 Del(10)과 같이 호출
Del = cube;
Del(10)
결과>>>100
1000

Del += square; //Del에 square를 대입하는게 아니라 더한다.
Del += cube;
Del(10)
결과>>>100 //Del에 추가했던 square와 cube 두 개 함수가 실행됨
1000

델리게이트 하나에 함수 여러개를 등록해서 한번에 실행할 수 있다.

Action : 반환 타입이 없는 델리게이트
Func : 반환타입이 있는 델리게이트

ex)
System.Action Del; //using System; 하면 Action Del과 같이 System생략가능
square와 cube가 매개변수로 int를 받으니 를 붙임
Del += square;
Del += cube;
Del(10);
결과>>>100
1000

ex)
*Del1클래스파일*
void func1(){
print("func1실행");
}

public static Action Del; //Del을 다른 클래스에서 접근할 수 있도록 하기위해 public static 붙임
Del += func1;

*Del2클래스파일****
void func2(){
print("func2실행");
}

Del1.Del += func2; //Del1클래스의 Del에 접근해서 Del2클래스에 있는 func2를 추가함
Del1.Del(); //Del실행
결과>>>func1실행 //Del1에 있는 func1과 Del2에 있는 func2모두 실행됨
func2실행

※tip
Del1.Del += () => print("익명메소드"); //한줄짜리 실행식은 이렇게 익명 메소드로 등록 가능

Del1 파일에서, public static Action Del; 이부분을 public static event Action Del; 이렇게 event를 붙이면
Del이 있는 Del1클래스에서만 Del();을 이용해 실행을 할 수 있다.
다시 말해 Del1에서 event를 붙여서 Del을 생성하면, Del2클래스에서는 함수를 Del에 등록할 수는 있지만 Del을 실행시킬 수는 없다

2D에서 애니메이션을 적용할때 Sprite를 적용할 사진이 sprite mode가 single이면 해당 사진 한개 전체를 뜻하고
multiple일 경우 하나의 사진을 여러개로 잘라서 사용한다.

rigidbody 2D에서 collision Detection을 continuous로 설정하면 충돌이 일어나도 특정축을 기준으로 고정시킬 수 있다.

animator 컨트롤러 에서 우클릭 후 make transiton으로 애니메이션의 순서를 설정한다.(화살표) any state는 어떤 상태든지 특정조건을 달성하면 해당 애니메이션을 실행하라는 것이다.
entry에서 시작할때 어떤 애니메이션을 최초로 시작할건지를 설정한다.
has Exit time은 실행중인 애니메이션이 끝난 후 다음 애니메이션을 실행할건지 아님 실행중이던것을 끊고 다음 애니메이션을 실행할건지 설정한다.
(끊고 다음걸 실행하면 애니메이션이 끊이는 현상이 있을 수 있다)
animator 컨트롤러의 parameters에서 변수를 추가한 후, 화살표를 선택하고 conditions을 추가하면 변수의 값에 따라 이 애니메이션을 실행하도록 설정할 수 있다.

애니메이션 클립에서 loop time을 체크하면 반복적으로 애니메이션을 실행하는것이고 체크를 해제하면 한번만 실행된다.
(Die애니메이션은 죽을 때 한번만 실행 하므로 체크해제, 점프와 달리기는 계속해서 실행되므로 체크)

animator의 layer는 객체에서 애니메이션을 부위별로 따로 적용시킬때 사용한다.

int i;
float j;
가 있을때, i = j 는 에러가 나지만 j = i는 가능하다.
float은 int보다 더 큰 값을 저장할 수 있으므로 float에 int를 넣으면 암시적 형변환이 되지만
int에 float을 넣을 순 없다.
마찬가지로 vector3에 vector2를 넣을 순 있지만, vector2에 vector3를 넣을 순 없다.

씬이 변경되거나 현재 씬을 다시 로드할 때 static으로 선언된 변수는 초기화 되지 않는다.
다른 변수들은 초기화됨

*Start, Awake, OnEnable, OnDisable, Update**
Awake : 대상이 GameObject이다. 게임오브젝트가 활성화 될 때 딱 한번만 호출됨, component가 활성/비활성화 되있는것과 상관 없음
OnEnable, OnDisable : 대상이 Component(MonoBehaviour) 다. Component의 Enable 조건은 GameObject-On & Component-On 일 때이고, 둘 중 하나라도 Off 면 Disable 이다.
Start : 대상이 Component(MonoBehaviour) 다. Component가 Enable 이고 최초 tick을 받아서 Update가 호출될 때 Update 보다 먼저 한 번만 호출된다.
Update : 대상이 Component(MonoBehaviour) 다. Component 가 Enable 일 때, tick 을 받을 때마다 호출된다

****다른 스크립트의 변수, 메소드에 접근하는 방법*
●해당 메소드나 변수를 static으로 선언
●싱글톤 사용
●GetComponent 사용
▶ex)
GameObject uzi = GameObject.Find("Player Character/Uzi"); //먼저 해당 스크립트가 적용된 오브젝트를 찾는다
uzi.GetComponent().Damage = 100; //오브젝트.GetComponent<스크립트명>().변수또는메소드 <- 이 형태로 메소드나 변수를 불러온다
int a = uzi.GetComponent().Damage;

ex)
public PlayerInputScript p;
p = GetComponent();

ex)Rigidbody, Animator등의 컴포넌트도 가져올 수 있다
public Rigidbody pp;
pp = GetComponent();

**익명함수, 화살표함수*
●화살표함수 ex)
void Hi() => Debug.Log("안녕");
●익명함수 ex)

*스크립트에서 오브젝트의 하이어라키 순서 변경***
●Transform.SetAsLastSibling
해당 오브젝트의 순위를 마지막으로 변경(가장 나중에 출력되므로 겹쳐졋을 경우 앞으로 나옵니다.)

●Transform.SetAsFirstSibling
해당 오브젝트의 순위를 처음으로 변경(가장 처음 출력되므로 겹쳐졋을 경우 가려집니다.)

●Transform.SetSiblingIndex(int nIndex)
nIndex를 매개변수를 넣어서 순위를 지정합니다.(0이 처음입니다.)

●Transform.GetSiblingIndex()
해당 오브젝트의 순위를 얻어옵니다.

인덱스는 0일수록 밑에 있는것이고 클수록 위에 있다. (숫자가 클수록 위로 나온다)

*import 해온 오브젝트의 회전축을 바꾸고 싶으면**
빈 오브젝트를 생성 후, 회전축을 바꾸고 싶은 오브젝트를 빈 오브젝트의 자식으로 넣는다.
그리고 회전 스크립트를 빈 오브젝트에 붙인다.

***UI크기를 화면 크기에 맞춰 자동적으로 변경되게 하고싶으면***
canvas의 canvas scalar컴포넌트에서 UI Scale Mode를 Scale with Screen Size로 설정

프로퍼티 교재592P 참고

1.프로퍼티, 델리게이트, 이벤트
2.코루틴
3.싱글톤패턴/오브젝트풀
4.다형성, 추상화

profile
주니어 개발자

0개의 댓글