전체 글 (114)

01
15

 

우리는 평소 디버깅할 때 Debug.Log로 데이터 값을 찍어내곤했습니다.

하지만 여러명이 서로 다른 스크립트 위치에서 Debug.Log를 찍어대면 콘솔창이 어지러워집니다.

 

이럴 때 그냥 OnGUI로 화면에 GUI를 그려 데이터값을 가시화하는게 조금 더 좋다고 생각합니다.

사용법은 간단합니다.

 

디버깅하려고 하는 스크립트에서 OnGUI() 함수 하나만 추가하시면 됩니다.

public class MeleeAttack : Attack
{
	public int attackStack = 0; // attackStack을 디버깅 할 예정입니다.

	private void OnGUI() {
        GUIStyle style =  new GUIStyle();
        style.fontSize = 54;
        style.normal.textColor = Color.green;

        GUI.Label(new Rect(5,525,Screen.width,20), "공격 스택" + attackStack.ToString(), style);
	}
}

위 코드 예시에서는 제 MeleeAttack.cs 파일에다가 해봤는데 MonoBehaviour만 상속하면 다 작동 가능합니다.

그냥 간단한 변수를 가시화한 코드입니다.

 

OnGUI() 함수는 Update문 처럼 매 프레임마다 호출됩니다.

이 때 함수 내에 구성한 그래픽대로 화면에 찍어주는 그래픽 코드입니다.

또한 중요한 점이 Update처럼 해당 오브젝트(스크립트)가 활성화될 때만 계속 호출됩니다.

따라서 오브젝트(스크립트)를 끄면 비활성화되서 GUI를 더이상 안그려서 화면에 그린게 사라집니다.

 

툴팁이 있어서 여러분도 간단하게 구성가능하지만 몇가지 예시를 알려드리겠습니다.


버튼 그리기

 

using UnityEngine;
using System.Collections;

public class GUITest : MonoBehaviour {
            
    void OnGUI () {
        // 배경 박스 만들기
        GUI.Box(new Rect(10,10,100,90), "Loader Menu");
    
        // 버튼 하나 만들고 클릭시 true가되어 함수 호출
        if(GUI.Button(new Rect(20,40,80,20), "Level 1")) {
            //Application.LoadLevel(1);
        }
    
        // 두번 째 버튼 만들기
        if(GUI.Button(new Rect(20,70,80,20), "Level 2")) {
            //Application.LoadLevel(2);
        }
    }
}

보시다시피 GUI.Box를 호출하면 인자로 Rect 위치 좌표와 입력 테스트를 넣어주면 됩니다.

해당 박스는 제일 먼저 그렸으므로 아래에 잘 배치가 됩니다.

순서 바꾸고 싶으면 GUI.Box 코드를 버튼 코드들 밑으로 내리면 됩니다.

 

Rect()에는 인자로 Rect 좌표뿐 아니라 가로 세로 길이도 포함됩니다.

 


깜빡이는 버튼 만들기

using UnityEngine;
using System.Collections;

public class GUITest : MonoBehaviour {
            
    void OnGUI () {
	if (Time.time % 2 < 1) {
            if (GUI.Button (new Rect (10,10,200,20), "2초마다 깜빡이는 버튼")) {
                print ("클릭");
            }
        }
    }
}

위 코드는 2초마다 깜빡이는 버튼을 GUI에 그렸습니다.

Time.time은 선언하는 순간 카운트가 되기 시작하므로 이를 나머지 2 해서 딱 떨어지면 2초가 지나간 것으로 간주해서 2초를 카운팅 가능한 방식입니다.

그리고 2초마다 GUI.Button을 그리는 것입니다.


아이콘 그리기

using UnityEngine;
using System.Collections;

public class GUITest : MonoBehaviour {
    public Texture2D icon; // 아이콘 이미지

    void OnGUI () {
        GUI.Box (new Rect (10,10,100,50), new GUIContent("텍스트 내용", icon));
    }
}

GUIContent에는 텍스트와 Texture이 들어가는데 이를 통해 이미지를 띄울 수 있습니다.


위치 Position

지금까지 Rect()로 GUI 위치를 정했습니다.

각각 x, y, 가로, 세로 를 뜻하는 인자였습니다.

이 값들은 모두 픽셀 값 int로 설정됩니다.

 

원점은 테스트해보시면 아시겠지만 좌측 상단이 원점입니다.

이걸 Screen.width, Screen.height 프로퍼티를 활용하면 각 화면 모서리 위치도 구할 수 있습니다.

using UnityEngine;
using System.Collections;

public class GUITest : MonoBehaviour {
            
    void OnGUI(){
        GUI.Box (new Rect (0,0,100,50), "Top-left");
        GUI.Box (new Rect (Screen.width - 100,0,100,50), "Top-right");
        GUI.Box (new Rect (0,Screen.height - 50,100,50), "Bottom-left");
        GUI.Box (new Rect (Screen.width - 100,Screen.height - 50,100,50), "Bottom-right");
    }

}

 

더 자세한 내용은 메뉴얼에 있습니다.

https://docs.unity3d.com/kr/530/Manual/gui-Basics.html

 

IMGUI 기본 사항 - Unity 매뉴얼

이 섹션에서는 Unity의 IMGUI(Immediate Mode GUI) 시스템을 사용하여 Controls 를 스크립팅해야 하는 필요성에 대해 설명합니다.

docs.unity3d.com

 

COMMENT
 
12
26

에디터 설정

우선 모든 팀원들의 에디터 버전이 동일해야합니다.

만약 버전이 다르다면 재설치하셔서 일치시켜주세요.

 

그리고 나서 Edit → Project Settings에 가셔서 직렬화 설정을 해주세요.

 

Project Settings → Editor → Asset Serialization → Mode → Force Text

유니티에서 직렬화하는 방식을 텍스트로 바꾸셔야 문제가 생기지 않습니다.

 

 

⭐메타 파일⭐

유니티에는 보다시피 각 파일마다 대응하는 meta파일이 있습니다.

이 meta파일은 각 파일을 대응하기 위해 고유 ID가 있습니다.

 

이러한 meta 파일 속의 guid를 에디터에서는 서로 참조할 때 사용합니다.

예를 들어 prefab에 cs 파일을 붙여준다면 prefab 내에 cs파일에 해당하는 guid를 참조하게 됩니다.

 

이 meta 파일에는 주의할 점이 있습니다. ( 꼭 염두해두시고 커밋해주세요 )

  1. 만약 해당 cs파일의 위치를 에디터가 아닌 윈도우 탐색기에서 다른 폴더로 옮기거나 이름을 바꾸게 된다면 prefab에서는 참조를 잃어버리게 됩니다. 그러면 prefab에서는 해당 파일이 삭제되었다고 생각하고 meta 파일을 하나 더 생성하게 됩니다. 따라서 뭔가 옮기실 땐 꼭 알려주세요.
  2. 새로운 이미지 소스를 넣고 싶어서 파일 탐색기에서 Asset폴더에 직접 접근해서 넣었다고 칩시다. 그러면 에디터에서는 아직 인식이 안되었기 때문에 meta 파일을 생성 안한 상태입니다. 이 상태에서 커밋해버리시면 같이 작업하시는 다른 팀원 각각의 에디터에서 해당 파일에 대응하는 meta 파일을 생성하게 됩니다. 그러니 뭔가 새로운 자료나 파일을 넣고 싶다면 꼭 에디터에 인식하는 과정을 통해 무조건 meta 파일을 같이 커밋해주세요.
  3. meta 파일에 해당하는 원본 파일(cs 파일)이 없으면 meta파일이 삭제 되므로 원본파일 삭제 시 meta 파일 삭제 된 변경사항도 같이 커밋해주세요

meta 파일에 대해 더 알고싶다면 ↓

에셋 메타데이터 - Unity 매뉴얼

COMMENT
 
12
12


프로그래밍 언어에서 리터럴(literal)이란
소스 코드 상에서 고정된 값을 가지는 것을 일컫습니다.
특히, C 언어의 경우 큰 따옴표(`"`) 로 묶인 것들을 문자열 리터럴(string literal) 이라 부릅니다.

'그냥 개발글 > C++' 카테고리의 다른 글

오버로딩 (Overloading)  (0) 2023.12.12
레퍼런스 (참조)  (0) 2023.12.12
동적 할당 new, delete  (0) 2023.12.12
클래스  (0) 2023.12.12
COMMENT
 
12
12

오버로딩은 말 그대로 과적, 과부하로 같은 이름의 함수가 여러 개가 존재하여 과부화 걸린다고 보시면 됩니다.

오버로딩에는 함수의 오버로딩(Overloading) , 연산자 오버로딩(Operator Overloading)이 있습니다.

함수의 오버로딩(Overloading)

가장 기본적인 함수의 오버로딩부터 봅시다.

void Function(int a)
{
    std::cout << "a";
}

void Function(char b)
{
    std::cout << "b";
}

int main()
{
    Function('b');
    return 0;
}

코드를 보시면 똑같은 이름의 Function 함수가 있습니다.
둘의 차이점은 int형 a와 char형 b로 인자만 다릅니다.

 

이렇게 두 개 이상의 동일한 이름의 함수에서 다른 인자 사용(인자 유형, 인자 수 등)하는 걸 오버로딩이라 부릅니다.
Using different arguments in a function of the same name (Type of arguments, number of arguments, …)

 

위의 상황에서 main()에서 보시면 Function('b')로 인자에 char형 'b'를 전달하였습니다.
실제 출력해보면 b가 출력이 됩니다.

 

이렇게 오버로딩은 인자에 따라 함수가 실행됩니다.
The function is executed depending on the arguments

 

만약 Funtion(1) 로 호출했으면 int a 인자의 Funtion함수로 실행이 되어 a가 출력 될 것입니다.

주의점

만약 아래 코드처럼 short형 변수가 인자로 들어가면 어떻게 될까요?

short s = 1;
Function(s);

이럴 땐 인자가 정확히 일치하는 함수가 없기 때문에 아래와같이 최대한 비슷한 함수를 찾게 됩니다.

 

만약 위의 방식으로도 일치하는 함수가 없다면 더 포괄적인 형변환으로 함수를 찾게 됩니다.

연산자 오버로딩(Operator Overloading)

연산자도 사실 하나의 함수로 취급됩니다.
따라서 연산자 또한 오버로딩이 가능합니다. 함수니깐요

 

사용법은 간단합니다.

(리턴 타입) operator(연산자) (연산자가 받는 인자)

 

예를 들어 Apple 클래스가 있으면 (리턴 타입)으로 Apple를 사용할 수 있습니다.
이 Apple을 덧셈에 사용하고 싶으시면 (연산자) 부분에 +를 사용해주시면 됩니다.
Apple operator+ (연산자가 받는 인자)
이런식으로 말이죠.

 

인자는 말그대로 연산할 때 연산할 대상을 가져오는 것입니다.
Apple operator+ (const Apple& a)
보통 const 키워드를 붙여주는데 인자의 값이 함수 내부에서 바뀌지 않는 다고 확신할 수 있으면 const 붙여주면 됩니다.

주의점

오버로딩된 연산자의 출력은 닫혀 있어야 합니다.
The output of the overloaded operator must be closed
다시 말해, 출력(결과)은 같은 클래스의 객체여야 합니다.
예를 들어 Apple 라는 클래스가 있으면 Apple + Apple 의 결과는 Apple 클래스 타입이여야한다는 식이죠.

 

그럼 만약 첫 번째 피연산자가 객체가 아닌 연산자를 어떻게 오버로드할 수 있을까요?
How can we overload an operator whose first operand is not an object?
예를 들어 객체가 아닌 정수같은 것들이랑 연산을 하는 것입니다.
Apple + 3 이런 느낌으로요.

#include <iostream>

class Apple{
    private:
        int value;
    public:
        Apple(int val) : value(val) {}
        int getValue() const {
            return value;
        }
};

// MyClass 객체와 정수를 더하는 '+' 연산자 전역 함수로 오버로딩
Apple operator+(const Apple& A, int value)
{
    int result = A.getValue() + value;
    return Apple(result);
}
int main() {
    Apple apple(5);
    Apple result = apple + 5;
    std::cout << "결과는 : " << result.getValue();
}

위의 코드 처럼 객체가 아닌 정수랑 연산할 땐 '+' 연산자를 전역 함수로 오버로딩하면 됩니다.
이러면 피연산자가 클래스 객체 아니라도 연산이 됩니다.

출처

C++ 조교님 수업 자료
모두의 코드 - 씹어먹는 C++ - <4 - 2. 클래스의 세계로 오신 것을 환영합니다. (함수의 오버로딩, 생성자)>
https://modoocode.com/173
모두의 코드 - 씹어먹는 C++ - <5 - 1. 내가 만든 연산자 - 연산자 오버로딩>
https://modoocode.com/202

'그냥 개발글 > C++' 카테고리의 다른 글

리터럴(literal)  (0) 2023.12.12
레퍼런스 (참조)  (0) 2023.12.12
동적 할당 new, delete  (0) 2023.12.12
클래스  (0) 2023.12.12
COMMENT