Project/Unity 게임 제작

[4] C# 스크립트 (3)

gapsoo 2023. 6. 30. 03:28

 

[4].1 메서드 만들기
[4].2 클래스 만들기
[4].3 Vector 클래스 사용하기

 


[4].1 메서드 만들기

 

>> 메서드

  • 스크립트가 끝없이 길어질 때, 길어진 처리를 의미가 있는 처리 블록으로 분해하고 이름을 붙이는 구조를 만든다.
  • 이렇게 분해한 각 처리를 메서드(또는 함수)라고 함

메서드

 

  • 메서드의 역할: 처리를 기능 단위로 묶는 역할 외에도 메서드에 값을 전달해서 계산하거나 계산 결과를 돌려받을 수 있도록 함
  • 인수: 메서드로 건네는 값, 반환값: 메서드에서 돌려받는 값
  • 인수는 여러 개 건넬 수 있지만 반환값은 한 개로 정해져 있음

인수와 반환값

 

🔍내가 찾아본 내용

  • 메서드는 일련의 문을 포함하는 코드 블록입니다.
  • 일련의 코드를 하나의 이름 아래 묶은 것
  • 메소드(메서드)는 C/C++에서는 함수, 파스칼에서는 프로시져 등으로 부름

 

 

 

>> 메서드를 만드는 방법

Add 메서드 예

  • 반환값의 데이터 형에는 호출자의 메서드로 반환하는 값의 데이터 형을 지정함
  • 지정할 데이터 형은 변수의 데이터 형과 같음
  • 값을 반환하지 않는 메서드에는 void를 지정함
  • void의 의미: '반환값이 없음'
  • 인수는 호출자의 메서드에서 받은 값임
  • 메서드는 인수 값을 사용해서 처리를 실행함
  • 인수를 갖지 않는 메서드도 있는데 이때는 메서드명 뒤에 붙는 괄호 안을 공백으로 비움
  • 호출하는 메서드명에 이어 괄호 안에 전달하는 인수를 기술함
  • 인수가 여러 개면 쉼표(,)로 구분함

메서드의 서식

 

 

 


 

 

>> ⭐① 인수도 반환값도 없는 메서드⭐

  • 코드: Console 창에 Hello를 출력하는 메서드
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
	void SayHello()
	{
		Debug.Log("Hello");
	}

	void Start()
	{
		SayHello();
	}
}

\ 출력 결과 /

Hello

 

 

 

>> 메서드 작성 방법

  • 7~10번 줄이 Console 창에 문자를 출력하는 SayHello 메서드임
  • 이 메서드는 Console 창에 문자를 출력할 뿐 호출자의 값을 반환하지 않으므로(반환값을 갖지 않음), 반환값의 데이터 형에 void를 지정함
  • 인수가 없으므로 메서드명 뒤에 붙는 괄호 안을 공백으로 비움
  • 계속해서 중괄호 안에 실행할 처리를 작성함
  • 여기서는 Debug.Log를 사용해서 Console 창에 Hello를 출력함
  • SayHello 메서드를 사용할 위치는 Start 메서드를 벗어나더라도 Test 클래스의 중괄호 안(7~15번 줄)이라면 어디든 상관없음

반환값도 인수도 갖지 않는 메서드

 

 

 

 

>> 메서드 호출 방법

  • Start 메서드에서 SayHello 메서드를 호출함(14번 줄)
  • 메서드를 호출하려면 메서드명에 이어 전달하고 싶은 인수를 씀
  • 이 예제에서는 SayHello 메서드에 인수가 없으므로 괄호 안을 공백으로 비움

메서드 호출 흐름

  • 여기서 작성한 SayHello 메서드는 Start 메서드가 Update 메서드에서 호출될 때까지는 처리가 실행되지 않음
  • 작성한 메서드는 호출해서 사용한다는 것을 기억해두자

 

 


 

 

>> ⭐② 인수가 있는 메서드

  • 코드: 인수를 출력하는 메서드
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
	void CallName(string name)
	{
		Debug.Log("Hello" + name);
	}

	void Start()
	{
		CallName("Tom");
	}
}

\ 출력 결과 /

Hello Tom 

 

 

 

>> 메서드 작성 방법

  • 10번 줄이 CallName 메서드임
  • CallName 메서드에는 반환값이 없으므로 void를 지정함
  • 문자열을 인수로 받으므로 메서드명에 이어 괄호 안에 string형의 name 변수를 선언함

반환값은 없지만 인수가 있는 메서드

 

 

 

>> 메서드 호출 방법

  • 14번 줄에서 CallName 메서드를 호출함
  • 메서드명 CallName에 이어 괄호 안에 메서드로 전달하는 이름(문자열)을 씀

인수가 있는 메서드 호출 흐름

  • CallName 메서드를 호출하면 인수의 문자열인 "Tom"이 자동으로 메서드 안의 name 변수에 대입됨
  • name 메서드는 메서드에서 변수처럼 쓸 수 있으므로 Debug.Log를 써서 name 변수 값을 출력함

 

 

 

>> 인수 형에 주의한다!

  • 14번 줄에서 인수를 지정하지 않고 CallName();으로 메서드를 호출하면 오류가 발생함
  • 기본적으로 인수 수는 호출되는 쪽과 호출하는 쪽이 일치해야 함

 

 


 

 

>> ⭐③ 인수와 반환값이 있는 메서드

  • 이번에 살펴볼 예제는 인수로 변수를 두 개 받고, 두 변수의 합계를 반환하는 Add 메서드임
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
	int Add(int a, int b)
	{
		int c = a + b;
		return c;
	}

	void Start()
	{
		int answer;
        answer = Add(2, 3);
		Debug.Log(answer);
	}
}

\ 출력 결과 /

5

 

 

 

 

>> 메서드 작성 방법

  • 7~11번 줄은 이번에 작성한 Add 메서드임
  • 메서드의 반환값은 int형 인수를 합한 것이므로 int형으로 지정함
  • Add 메서드는 인수가 두 개이므로 각 인수를 쉼표(,)로 구분해 선언함

반환값과 인수가 있는 메서드

  • 10번 줄에서 인수의 합계를 반환값으로 돌려줘야 하므로 return 문을 씀
  • return 문 뒤에 공백을 두고 변수명을 적으면 그 변수 값을 메서드를 호출한 곳으로 반환할 수 있음

 

 

 

>> 메서드 호출 방법

  • Add 메서드를 호출하는 흐름을 정리하면 다음과 같음

인수가 여러 개 있고 반환값이 있는 메서드 호출 흐름

  • 메서드를 호출하는 쪽에서는 메서드명에 이어 인수를 두 개(2와 3) 전달함
  • 메서드 호출과 동시에 a와 b 변수에는 각각 2와 3이 대입됨
  • a와 b 변수에는 메서드를 호출하는 곳에서 지정한 순서대로 값이 대입됨
  • Ad(2, 3)이 아닌 Add(3, 2)를 쓰면 a 변수에 3이 대입되고 b 변수에 2가 대입됨
  • 메서드에서는 a와 b 변수를 합한 값을  c 변수에 대입하고 return 문을 사용해서 합계를 호출한 곳으로 반환함
  • 메서드를 실행한 후에는 메서드의 호출 부분이 반환값으로 바뀌는 형태임
  • Add(2, 3) 부분이 반환값 c 값으로 바뀌기 때문에 answer = Add(2, 3);은 answer = c;이 되고 answer에 c 값이 대입됨

 

 

 


[4].2 클래스 만들기

>> 클래스

  • 메서드 : 처리를 모아 둔 것
  • 클래스 : 메서드와 변수를 모아 둔 것
  • 유니티로 게임을 만들려면 플레이어, 적, 무기, 아이템 등 물체마다 그 움직임을 정의하는 스크립트를 작성해야 함
  • 이때는 '처리 단위'보다는 '물건 단위'로 스크립트를 작성하는 것이 편리함

클래스는 물체 단위

  • 변수와 메서드를 하나로 합치지 않고 따로따로 구현하면 어느 변수와 메서드가 연결되어 있는지 알기 어려움
  • 클래스를 사용하면 관계가 있는 변수와 메서드를 하나로 합칠 수 있으므로 스크립트를 관리하기 쉬움
  • class 키워드 다음에 클래스명을 쓰고, 그 안에 클래스에서 사용하는 변수와 메서드를 씀
  • 클래스에서 사용한 변수를 멤버 변수, 클래스에서 사용한 메서드를 멤버 메서드라고 함

  • 작성한 클래스는 int나 string 등 데이터 형으로 사용할 수 있음
  • 즉. Player 클래스를 만들면 Player형을 사용할 수 있게 됨
  • int num;을 쓰면 int형의 num 변수를 만들 수 있음
  • Player myPlayer;을 쓰면 Player형의 myPlayer 변수를 만들 수 있음
  • 이 상태에서 myPlayer 변수의 상자 안은 비어 있음
  • int형의 num 변수에는 2나 1500 같은 숫자를 대입함
  • Player형의 myPlayer 변수에는 플레이어의 실체를 대입함 ⭐
  • 이 실체를 인스턴스라고 함 ⭐

값과 인스턴스

  • myPlayer 변수가 가진 멤버 메서드나 멤버 변수를 사용하려면 myPlayer;멤버 메서드명(또는 멤버 변수명)을 씀
  • 앞으로 마침표(.)로 연결된 형태가 자주 나옴
  • OO.xx가 나오면 OO 클래스가 갖는 xx 메서드(또는 변수)를 사용한다고 이해해 두자

멤버 변수의 사용 방법

 

 

 

>> 유니티가 제공하는 클래스도 있다!

  • 직접 클래스를 만들 수도 있지만 유니티가 처음부터 제공하는 클래스도 있음
  • Vector 클래스와 로그 표시를 할 때 쓰는 Debug 클래스 등이 유니티가 제공하는 클래스임
  • 유니티를 사용하려면 클래스 개념을 제대로 이해하는 것이 중요함

 

 

 


[4].2 클래스 만들기

 

>> 클래스 작성하기

  • 지금까지 써 온 Test 스크립트(Test.cs)에 Player 클래스를 추가함
  • Player 클래스는 Test 클래스 외부에 추가하는 것에 주의함

 

🖥️ 코드: Player 클래스 구현하기

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
 
public class Player
{
	private int hp = 100;
	private int power = 50;

	public void Attack()
	{
		Debug.Log(this.power + "데미지를 입혔다");
	{
	public void Damage(int damage)
		this.hp -= damage;
		Debug.Log(damage + "데미지를 입었다");
	}
}

public class Test : MonoBehaviour
{
	void Start()
	{
		Player myPlayer = new Player();
		myPlayer.Attack();
		myPlayer.Damage(30);
	}
}

\ 출력 결과 /

50 데미지를 입혔다
30 데미지를 입었다

✏️ (5번 줄) Player 클래스는 public 선언을 했기 때문에 외부 클래스에서 사용할 수 있음

✏️ 만약 public을 붙이지 않으면 private가 자동으로 설정되기 때문에 public을 사용하고 싶을 때는 꼭 붙여준다!

✏️ (7, 8번 줄) private 선언을 했기 때문에 외부 클래스에서는 hp와 power라는 변수에 접근을 할 수 없게 되고, 만약 접근하려고 하면 에러가 발생함, Player 클래스 안에서만 접근 가능

✏️ (10번 줄) Attack 앞에 public을 붙여주었기 때문에 다른 클래스에서도 사용 가능함

✏️ 

 

  • 5~20번 줄이 이번에 작성한 Player 클래스임
  • 클래스 구성을 간단히 살펴보면 5번 줄에서 Player 클래스를 선언함
  • 7~8번 줄에서 플레이어의 HP를 나타내는 멤버 변수(power)를 선언함
  • 10~19번 줄에서는 공격하는 멤버 메서드(Attack)와 데미지를 받는 멤버 메서드(Damage)를 작성함

 

 

 

>> 클래스를 사용하는 방법

  • 코드 2~29의 Start 메서드에 있는 26~28번 줄에서는 방금 작성한 Player 클래스의 인스턴스를 만들어 사용함
  • 먼저 26번 줄의 왼쪽에 Player myPlayer를 써서 Player형의 myPlayer 변수를 선언함
  • 이 단계에서는 Player형의 상자를 만들었을 뿐이므로 Player형의 실체인 인스턴스를 작성해 대입해야 함
  • 인스턴스를 만들려면 new 키워드 다음에 클래스 이름()을 씀(26번 줄의 오른쪽)
  • Player 클래스의 인스턴스가 만들어지고 이것을 myPlayer 변수 안에 대입함

  • 27번 줄에서는 인스턴스를 가진 Attack 메서드를 myPlayer.Attack()인 변수명.멤버 메서드명() 형태로 호출함
  • 마찬가지로 28번 줄에서는 Damage 메서드를 호출함
  • 실행 도구를 클릭해 Console 창에 무엇이 출력되는지 확인함

 

 

 

>> 접근 수식자

  • 코드 2~29를 보면 Player 클래스의 멤버 변수와 멤버 메서드 앞에 public이나 private 키워드가 붙어 있음
  • 이것을 접근 수식자라고 하는데, OO.xx라고 썼을 때 다른 클래스에서 멤버로 접근 가능한지 여부를 나타냄
  • public이 붙어 있는 멤버는 다른 클래스에서도 호출할 수 있지만, private가 붙어 있는 멤버는 다른 클래스에서 호출할 수 없음
  • Attack 메서드에는 public이 붙어 있으므로 myPlayer. Attack()이라고 써서 Attack 메서드를 호출할 수 있음
  • hp 변수에는 private가 붙어 있으므로 myPlayer.hp라고 써도 hp 변수에 접근할 수 없음

 

  • private을 쓰는 이유는 다른 사람이 자신이 만든 클래스를 사용할 때 'private 메서드는 사용하지 마세요, private 변수는 변경하지 마세요'라는 의사 표시를 할 수 있기 때문임
  • 즉, 다른 사람이 만든 클래스를 쓸 때는 public이 붙은 변수와 메서드만 써야 함

클래스가 public인지 확인하고 사용하기

 

  • 접근 수식자를 생략하면 private으로 간주되므로 공개하고 싶은 변수와 메서드가 있다면 public 수식자를 붙이는 것이 좋음

접근 수식자

 

 

 

>> this 키워드

  • this는 자신의 인스턴스를 가리키는 키워드임
  • this.power는 자신의 인스턴스가 가진 power 변수(Player 클래스의 인스턴스가 가진 power 변수)를 나타냄
  • 사실 this를 붙이지 않아도 자기 클래스의 멤버 변수를 사용할 수 있음
  • '코드: Player 클래스 구현하기' 의 Attack 메서드에서 다음과 같이 멤버 변수와 동일한 이름의 로컬 변수 (power)를 선언했다고 할 때, power라고만 쓰면 로컬 변수의 값이 우선해서 사용됨
  • 멤버 변수를 쓸 때는 명시적으로 this를 붙여야 오류를 막을 수 있음

 

 

 

>> 상속

  • Test 클래스의 선언 부분(코드 2~29의 22번 줄) 뒤에 붙은 MonoBehaviour는 상속이라고 함
  • 이 부분은 유니티가 미리 준비한 MonoBehaviour 클래스의 기능을 Test 클래스에 집어넣겠다고 선언하는 과정임
  • MonoBehaviour 클래스는 게임 오브젝트를 구성하는 기본 기능을 멤버 변수와 멤버 메서드로 준비한 클래스임
  • 게임 오브젝트에 붙여 실행하는 스크립트는 MonoBehaviour 클래스 (또는 MonoBehaviour를 바탕으로 한 클래스)를 상속해야 함

 

 

 

>> Debug.Log는 인스턴스 없이 사용할 수 있을까?

  • Player 클래스의 인스턴스를 만들고 '인스턴스 변수명.멤버 메서드명' 형태로 멤버 메서드를 직접 호출함
  • 한편 계속해서 쓰고 있는 Debug.Log 메서드는 '클래스명.멤버 메서드명' 형태로 멤버 메서드를 직접 호출함
  • Debug.Log가 static 메서드(인스턴스를 만들지 않고도 쓸 수 있는 메서드)로 선언되기 때문

 

 

 


[4].3 Vector 클래스 사용하기

 

>> Vector

  • 3D 게임을 만들려면 공간에서 오브젝트를 어디에 둘지, 어느 쪽으로 옮길지, 어디르 힘을 보낼지 등을 정해야 하므로 float형의 x, y, z 값 세 개를 씀

Vector형 사용 방법

  • C#에는 이러한 값을 하나로 합쳐 다룰 수 있는 Vector3 클래스(정확히는 구조체라고 한다)가 준비되어 있음
  • 반면 2D 게임용에는 float형의 x, y 값을 갖는 Vectort2 클래스가 있음
  • Vector3 클래스의 구조는 다음과 같음

  • Vector3 클래스에는 x, y, z 멤버 변수가 있고, Vector2 클래스는 x, y 멤버 변수가 있음
  • 둘 다 좌표나 벡터로 쓸 수 있음
  • x = 3, y = 5를 좌표로 쓰면 오브젝트가 (3, 5) 위치에 배치되었다는 것을 뜻함
  • 한편 벡터로 쓰면 현재 위치에서 'X 방향으로 3', 'Y 방향으로 5' 움직였다는 것을 뜻함

좌표로써 Vector2와 벡터로써 Vector2

 

 

 

>>  Vector 클래스를 사용하는 방법

  • 코드: Vector2 클래스의 멤버 변수에 숫자 더하기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
	void Start()
	{
		Vector2 playerPos = new Vector2(3.0f, 4.0f);
		playerPos.x += 8.0f;
		playerPos.y += 5.0f;
		Debug.Log(playerPos);
	}
}

\ 출력 결과 /

(11.0, 9.0)

 

  • 9번 줄 왼쪽에 Vector2 클래스의 playerPos 변수를 선언함
  • 이 과정은 Vector2형의 상자를 만드는 과정이므로 대입할 수 있는 인스턴스를 이어서 작성해야 함
  • new Vector2(3.0f, 4.0f)를 써서 Vector2 클래스의 인스턴스를 작성해 대입함
  • new 클래스명()으로 클래스 인스턴스를 작성할 수 있음
  • 클래스 부분에서 설명한 대로 멤버 변수인 x와 y값에 접근하려면 변수명x, 변수명y라고 씀
  • 이것을 이용해서 10~11번 줄에서 플레이어가 있는 X좌표를 8, Y좌표를 5 증가시킴

Vector2 멤버 변수로 더하기

  • Vector2 클래스 변수를 게임 오브젝트의 좌표로 사용하는 경우에는 값을 증가시키면 화면의 게임 오브젝트가 양수 방향(오른쪽 혹은 위)으로 이동함
  • 반대로 값을 감소시키면 음수 방향(왼쪽 혹은 아래)으로 이동함

 

🖥️ 코드: Vector 클래스끼리 뺄셈하기

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Test : MonoBehaviour
{
	void Start()
	{
		Vector2 startfos = new Vector2(2.0f, 1.0f);
		Vector2 endfos = new Vector2(1.0f, 5.0f)
		Vector2 dlr = endfos - startfos;
		Debug.Log(dlr);

		float len = dlr.magnitude;
		Debug.Log(len);
	}
}

\ 출력 결과 /

(6.0, 4.0)
7.211102
  • 이 예제에서는 startPos에서 endPos로 향하는 dlr 벡터를 구함
  • 두 점의 좌표에서 벡터를 구하기 때문에 11번 줄의 endPos에서 startPos를 뺌
  • 이처럼 Vector2 클래스끼리 뺄셈을 할 수 있음

Vector2 클래스끼리 뺄셈하기

  • 14번 줄에서는 startPos부터 endPos까지 거리를 구함
  • 이 거리는 dlr 벡터 길이와 같으므로 Vector2 클래스가 갖는 magnitude 멤버 변수를 사용해서 dlr 벡터의 길이를 구함

 

 

 

>> Vector 클래스 응용하기

  • Vector 클래스는 가속도, 힘, 이동 속도 같은 물리 수치로도 사용할 수 있음

Vector2를 좌표로 사용하기

 

 

 

>> Visual Studio 동작

  • 때때로 Visual Studio의 intellisense 기능을 사용할 수 없고 스크립트 전체가 빨간색 물결선으로 표시될 때가 있음
  • 이때는 Visual Studio를 다시 실행해보자

'Project > Unity 게임 제작' 카테고리의 다른 글

[6] 슈팅 게임 제작 (2)  (2) 2023.07.06
[5] 슈팅 게임 제작 (1)  (6) 2023.07.04
[3] C# 스크립트 (2)  (6) 2023.06.29
[2] C# 스크립트 (1)  (6) 2023.06.28
[1] 유니티 설치 & 조작법 - (3) 오브젝트 다루기  (6) 2023.06.27