GURU_unity_2주차 슈팅 게임 제작4

2023. 7. 5. 17:42SWU_프로젝트/GURU - unity

오늘 학습할 내용은 다음과 같다.

 

7. 점수 추가
8. 저장 & 불러오기

 

7. 점수 추가

 

현재점수 UI생성

Hierarchy에서 + 버튼을 눌러 [UI – Text] 를 하나 만들어 준다.

이름을 CurrentScore 로 변경한다.

text를 추가하면 위 사진과 같이 Canvas와 EventSystem이 함께 생겨난다.

현재점수가 있는 위치를 바꿔주고 싶다.

 

유니티에서는 UI 엘레먼트(Element) 의 앵커를 편하게 작업할 수 있도록 앵커프리셋(Anchor Preset) 을 제공하고있다.

앵커프리셋은 UI 가 어느 곳을 기준으로 배치가 될 것인지를 정하는 기능을 담당하는데  CurrentScore UI 는 그림처럼 좌측(Left) 상단(Top) 을 기준으로 정렬한다.

CurrentScore 게임오브젝트를 선택하고 Rect Transform 의 값을 아래 그림처럼 설정한다.

그리고 Text내용과 Font Size, Horizontal Overflow, Color(White)등을 아래 그림처럼 수정해준다.

현재점수를 만들었으니, 최고점수도 만들어볼 것이다.

ctrl+D를 해서 그대로 복제한다.

이름을 BestScore로 변경해주고 Text에 최고점수로 수정해주고 나머지는 현재점수와 동일하게 설정하면 된다.

 

짜란~!

 

이제 점수판은 만들어졌으니 점수가 실제로 매겨지게끔 만들어볼 것이다.

우선 Hierarchy 창에서 Create Empty를 만들어주고 이름을 ScoreManager로 변경해준다.

그리고 마찬가지로 Project에서 Script를 생성해 ScoreManager 라고 이름을 변경해준 후 드래그해서 넣어준다.

 

이제 스크립트를 작성해볼 것이다.

 

목표 : 에너미를 잡을 때마다 현재 점수 표시하고 싶다.

필요속성 : 현재점수 UI, 현재점수 기억

맨 위에 Using UnityEngine.UI; 를 추가하지않으면 오류가 발생하니까 꼭 넣어주자.

속성 추가

 

유니티 UI 를 사용하기 위해 UI 네임스페이스(Namespace) 를 추가,

현재 점수와 관련된 필요한 속성 currentScoreUI 와 currentScore 두개를 선언 한다.

일단 위 그림처럼 코드를 추가해주었다.

위 그림처럼 만들어진 속성에 기존에 만들어놓은 것을 드래그해서 넣어준다.

이제 Enemy.cs에 코드를 추가해줄 것이다.

void OnCollisionEnter(Collision other)
{
GameObject smObject = GameObject.Find("ScoreManager")
//2.폭발 효과 공장에서 폭발 효과를 하나 만들어야 한다.
GameObject explosion = Instantiate(explosionFactory);
//3.폭발 효과를 발생(위치) 시키고 싶다.
explosion.transform.position = transform.position;
Destroy(other.gameObject);
Destroy(gameObject); }
}

저 위에 GameObject.Find("ScoreManager") 에서 Find매서드는 충돌이 일어날 때마다 매번 호출을 해오게 된다.

그래서 게임의 퍼포먼스를 저하시킬 수 있으므로 좋은 방법은 아닐 수 있다.( 참고하자 )

이 처럼 코드를 추가해서 넣어주었다.

이제 최고점수도 만들어보자.

ScoreManager에서 위 그림처럼 Public Text BestScoreUI와 Public int BestScore 를 추가해준다.

마찬가지로 만들어진 속성에 BestScore를 끌어다넣어준다.

 

순서 : 1. 현재 점수가 최고 점수 보다 크니까

          2. 최고 점수가 갱신 시킨다.

          3. 최고 점수 UI 에 표시

public class Enemy : MonoBehaviour
{ . . . (생략) . . .
private void OnCollisionEnter(Collision collision)
{ . . . (생략) . . .
if(sm.currentScore > sm.bestScore)
{
//2.최고 점수가 갱신 시킨다.
sm.bestScore = sm.currentScore;
//3.최고 점수 UI 에 표시
sm.bestScoreUI.text = "최고점수 : " + sm.bestScore; }
. . . (생략) . . . }
}

이렇게 최고점수를 위한 코드를 추가해준다.

짜라란!

 

8. 저장 & 불러오기

 

PlayerPrefs 를 이용한 저장

public class Enemy : MonoBehaviour
{ . . . (생략) . . .
private void OnCollisionEnter(Collision collision)
{ . . . (생략) . . .
if(sm.currentScore > sm.bestScore)
{ . . . (생략) . . .
sm.bestScoreUI.text = "최고점수 : " + sm.bestScore;
// 목표 : 최고점수를 저장 하고싶다.
PlayerPrefs.SetInt("Best Score", sm.bestScore); }
. . . (생략) . . . }
}
  • PlayerPrefs 객체는 값을 키(Key) 와 값(Value) 형태로 저장
  • 저장할 수 있는 자료형은 int, float, string 을 제공하고 있으며 각각 쌍으로 Get 함수와 Set 함수를 API 로 지원한다.
  • 최고 점수는 정수형 데이터인 int 를 사용하기 때문에 SetInt 를 사용하여 저장 한다. 
  • 최고 점수 갱신 시점에 저장 로직을 삽입한다.

PlayerPrefs 를 이용한 불러오기

. . . (생략) . . .
public class ScoreManager : MonoBehaviour
{ . . . (생략) . . .
void Start()
{ // 목표 : 최고점수 불러와서 bestScore 변수에 할당하고 화면에 표시한다.
// 순서 : 1. 최고점수 불러와서 bestScore 에 넣어주기
bestScore = PlayerPrefs.GetInt("Best Score", 0);
// 2. 최고점수 화면에 표시하기
bestScoreUI.text = "최고점수 : " + bestScore; }
}
  • ScoreManager 객체가 태어날 때 해당 내용을 넣어주어 화면에 최고점수가 있으면 불러와서 뿌려주도록 한다.
  • 태어날때의 라이프사이클 함수가 Start 이기 때문에 Start 함수안에 불러오기 및 UI 표시코드를 작성한다.  PlayerPrefs.GetInt 함수는 인자에 키 값을 넣어주면 저장된 값을 넘겨주나, 저장된 값이 없을 경우 받을 값을 뒤에 지정해 줄 수 있다.

 

캡슐화처리(Get/Set 함수 만들기)

public class ScoreManager : MonoBehaviour
{ . . . (생략) . . .
// currentScore 에 값을 넣고 화면에 표시하기
public void SetScore(int value)
{
} // currentScore 값 가져오기
public int GetScore()
{
return currentScore; }
}

ScoreManager에 SetScore 함수와 GetScore 함수를 만드는 코드를 추가해준다.

 

캡슐화처리 (접근지시자 변경)

public class ScoreManager : MonoBehaviour
{
// 필요속성 : 점수 UI, 현재점수, 최고점수
// 현재 점수
UI public Text currentScoreUI;
// 현재 점수
private int currentScore;
// 최고 점수
UI public Text bestScoreUI;
// 최고 점수
private int bestScore; }
}

캡슐화를 위해 ScoreManager의 currentScore, bestScore 변수의 접근지시자를 private 로 바꿔준다.

 

캡슐화처리 (구현부 이동)

  • 다음 Enemy.cs 코드의 일부분을 잘라내기 하여 ScoreManager.cs 의 SetScore 함수로 이동 시킨다.
  • Enemy 클래스에 있던 내용을 ScoreManager 로 옮겼기 때문에 굳이 이제 ScoreManager 객체를 얻어서 처리할 필요가 없다.
  • sm 변수로 참조해서 사용하는 부분은 코드에서 삭제한다.
public class Enemy : MonoBehaviour
{
private void OnCollisionEnter(Collision collision)
{
// 에너미를 잡을 때마다 현재 점수 표시하고 싶다.
// 1. 씬에서 ScoreManager 객체를 찾아오자
GameObject smObject = GameObject.Find("ScoreManager");
// 2. ScoreManager 게임오브젝트에서 얻어 온다
ScoreManager sm = smObject.GetComponent();
// 3. ScoreManager 의 Get/Set 함수로 수정
sm.SetScore(sm.GetScore() + 1);
//2.폭발 효과 공장에서 폭발 효과를 하나 만들어야 한다.
GameObject explosion = Instantiate(explosionFactory);
//3.폭발 효과를 발생(위치) 시키고 싶다.
explosion.transform.position = transform.position;
Destroy(collision.gameObject);
Destroy(gameObject); }
}

Enemy 클래스에서 이 Get/Set 함수를 호출 하는 것으로 수정한다.

 

 

Enemy.cs 코드를 아래와 같이 수정했다.

ScoreManager.cs 코드를 아래와 같이 수정했다.

캡슐화를 통해 특별히 기능이 달라진 건 없고, 가독성이 좋게하기위한 작업인 것 같다.

 

이제 거의 완성이 되어간다. !! 뿌듯