[멋쟁이사자처럼 부트캠프 TIL회고] 75일차
using UnityEngine;
public static class UserInformations
{
private const string HEART_COUNT = "HeartCount";
// 하트 수
public static int HeartCount
{
get
{
return PlayerPrefs.GetInt(HEART_COUNT, 5);
}
set
{
PlayerPrefs.SetInt(HEART_COUNT, value);
}
}
}
오늘 배운 것
1. 퀴즈 게임 만들기
2. 자투리 지식(추가 공부)
01. 퀴즈 게임 만들기
패널
게임은 보통 이런 순서로 진행됨.
저장을 종료시에만 한다면 ? 오류가 떴을 때, 혹은 강제종료 되었을 때 어떻게 할 것인가 생각해야함.
using UnityEngine;
public static class UserInformations
{
private const string HEART_COUNT = "HeartCount";
// 하트 수
public static int HeartCount
{
get
{
return PlayerPrefs.GetInt(HEART_COUNT, 5);
}
set
{
PlayerPrefs.SetInt(HEART_COUNT, value);
}
}
}
이런식으로 데이터를 저장하고 불러올 수 있다.
PlayerPref 관련해서는 따로 알아볼 예정.
GetInt는 Heart_Count를 가져오고 없으면 기본값인 5를 가져온다.
using UnityEngine;
public static class UserInformations
{
private const string HEART_COUNT = "HeartCount";
private const string LAST_STAGE_INDEX = "LastStageIndex";
// 하트 수
public static int HeartCount
{
get
{
return PlayerPrefs.GetInt(HEART_COUNT, 5);
}
set
{
PlayerPrefs.SetInt(HEART_COUNT, value);
}
}
// 스테이지 클리어 정보
public static int LastStageIndex
{
get
{
return PlayerPrefs.GetInt(LAST_STAGE_INDEX, 0);
}
set
{
PlayerPrefs.SetInt(LAST_STAGE_INDEX, value);
}
}
}
이렇게 하트 카운트와 마지막 스테이지(어디까지 풀었는지 정보)를 저장하면
PlayerPrefs가 동작해 다음과 같이 동작된다.
오늘 만든 코드의 전문은 다음과 같다.
public class GamePanelController : MonoBehaviour
{
private GameObject _firstQuizCardObject;
private GameObject _secondQuizCardObject;
private List<QuizData> _quizDataList;
private int _lastGeneratedQuizIndex;
private int _lastStageIndex;
private void Start()
{
_lastStageIndex = UserInformations.LastStageIndex;
InitQuizCards(_lastStageIndex);
}
private void InitQuizCards(int stageIndex)
{
_quizDataList = QuizDataController.LoadQuizData(stageIndex);
_firstQuizCardObject = ObjectPool.Instance.GetObject();
_firstQuizCardObject.GetComponent<QuizCardController>()
.SetQuiz(_quizDataList[0], 0, OnCompletedQuiz);
_secondQuizCardObject = ObjectPool.Instance.GetObject();
_secondQuizCardObject.GetComponent<QuizCardController>()
.SetQuiz(_quizDataList[1], 1, OnCompletedQuiz);
SetQuizCardPosition(_firstQuizCardObject, 0);
SetQuizCardPosition(_secondQuizCardObject, 1);
// 마지막으로 생성된 퀴즈 인덱스
_lastGeneratedQuizIndex = 1;
}
private void OnCompletedQuiz(int cardIndex)
{
if (cardIndex >= Constants.MAX_QUIZ_COUNT - 1)
{
// TODO: 스테이지 클리어 연출
_lastStageIndex += 1;
InitQuizCards(_lastStageIndex);
UserInformations.LastStageIndex = _lastStageIndex;
return;
}
ChangeQuizCard();
}
private void ChangeQuizCard()
{
if (_lastGeneratedQuizIndex >= Constants.MAX_QUIZ_COUNT) return;
var temp = _firstQuizCardObject;
_firstQuizCardObject = _secondQuizCardObject;
_secondQuizCardObject = ObjectPool.Instance.GetObject();
if (_lastGeneratedQuizIndex < _quizDataList.Count - 1)
{
_lastGeneratedQuizIndex++;
_secondQuizCardObject.GetComponent<QuizCardController>()
.SetQuiz(_quizDataList[_lastGeneratedQuizIndex], _lastGeneratedQuizIndex, OnCompletedQuiz);
}
SetQuizCardPosition(_firstQuizCardObject, 0);
SetQuizCardPosition(_secondQuizCardObject, 1);
ObjectPool.Instance.ReturnObject(temp);
}
}
private void Start()
{
_lastStageIndex = UserInformations.LastStageIndex;
InitQuizCards(_lastStageIndex);
}
시작할 때, UserInformations에서 마지막 스테이지 정보를 가져와 그 스테이지의 퀴즈들로 카드를 세팅한다.
private void InitQuizCards(int stageIndex)
{
_quizDataList = QuizDataController.LoadQuizData(stageIndex);
_firstQuizCardObject = ObjectPool.Instance.GetObject();
_firstQuizCardObject.GetComponent<QuizCardController>()
.SetQuiz(_quizDataList[0], 0, OnCompletedQuiz);
_secondQuizCardObject = ObjectPool.Instance.GetObject();
_secondQuizCardObject.GetComponent<QuizCardController>()
.SetQuiz(_quizDataList[1], 1, OnCompletedQuiz);
SetQuizCardPosition(_firstQuizCardObject, 0);
SetQuizCardPosition(_secondQuizCardObject, 1);
// 마지막으로 생성된 퀴즈 인덱스
_lastGeneratedQuizIndex = 1;
}
현재 퀴즈 카드의 순번이, 정해둔 Max보다 높지 않으면 한 장씩 넘긴다.
private void ChangeQuizCard()
{
if (_lastGeneratedQuizIndex >= Constants.MAX_QUIZ_COUNT) return;
var temp = _firstQuizCardObject;
_firstQuizCardObject = _secondQuizCardObject;
_secondQuizCardObject = ObjectPool.Instance.GetObject();
if (_lastGeneratedQuizIndex < _quizDataList.Count - 1)
{
_lastGeneratedQuizIndex++;
_secondQuizCardObject.GetComponent<QuizCardController>()
.SetQuiz(_quizDataList[_lastGeneratedQuizIndex], _lastGeneratedQuizIndex, OnCompletedQuiz);
}
SetQuizCardPosition(_firstQuizCardObject, 0);
SetQuizCardPosition(_secondQuizCardObject, 1);
ObjectPool.Instance.ReturnObject(temp);
}
매 번 넘길 때마다 마지막 장인지체크하고, 마지막 장이라면 다음 스테이지로 이동한다.
마지막 장이 아니라면 한 장을 넘긴다.
private void OnCompletedQuiz(int cardIndex)
{
if (cardIndex >= Constants.MAX_QUIZ_COUNT - 1)
{
// TODO: 스테이지 클리어 연출
_lastStageIndex += 1;
InitQuizCards(_lastStageIndex);
UserInformations.LastStageIndex = _lastStageIndex;
return;
}
ChangeQuizCard();
}
02. 자투리 지식
PlayerPrefs 관련
https://docs.unity3d.com/kr/530/ScriptReference/PlayerPrefs.html
UnityEngine.PlayerPrefs - Unity 스크립팅 API
Stores and accesses player preferences between game sessions.
docs.unity3d.com
이런 PlayerPrefs는 레지스트리 편집기에 가서 그 정보를 확인하고 바꿀 수 있음
(Windows 키 - regedit 입력)
저장 관련
ios는 Root - Application - 폴더이름 -게임실행파일 - Documents 안에 데이터를 저장함.
(앱이 데이터를 저장할 수 있는 위치가 정해져 있음)
ios가 접근 제한이 상대적으로 많고 심사가 까다롭다.
또한 모바일 기기는 특정 데이터 타입에 대한 지원이 제한될 수 있음
기능적 제약 등도 고려야 함.
앱의 생명주기 ( Application Lifecycle)
유니티로 게임을 만들고 출시할 때, 앱이 실행, 일시 정지, 백그라운드 이동, 종류 등의 상태를 거치게 됨.
이를 이용해 게임 데이터를 적절히 저장하고 불필요한 리소스를 해체하는 등의 최적화 작업이 가능함.
앱의 주요 상태
- Not Running(비실행)
: 앱이 완전히 종료된 상태(실행X) , 프로세스가 메모리에서 완전히 제거, 실행시 Foreground로 진입 - Foreground(전면 실행)
: 앱이 실행되는 중, 일반적인 플레이 상태 - Background(백그라운드)
: 홈 버튼 OR 다른 앱 전환, ios는 Background상태 시 몇 초 뒤 Suspended로 전환, 안드로이드는 시간 or 메모리로 앱 종료 가능 - Suspended(중단)
: ios에만 존재, 다시 활성화되면 Foreground로 복귀 - Terminated(완전 종료)
: 강제 종료하거나, 메모리 확보를 위한 앱 종료 상태. 다시 실행시 NotRunning에서 시작
UI 관련 작은 팁
각각의 버튼들을 묶어 놓은 것은 Horizontal LayoutGroup으로 ,
버튼들은 Vectical Layout 그룹으로 배치한 후 버튼들을 묶어놓은 것을 SetActive (true/false)로 정렬하면서 동시에
펼쳐서 볼 수 있다.
Anchor 관련
이렇게 앵커를 하나씩 옮길 때 4000, -4000인 이유. 기준점에서 얼마나 떨어졌냐를 기준으로 보기 때문에 보인다.
즉 left가 4000인 이유는 앵커의 left 기준으로 오른쪽으로 4000만큼 떨어져 있다는 것을 의미하고,
right가 -4000인 이유는 앵커의 right을 기준으로 오른쪽으로 4000만큼 떨어져 있따는 것을 의미한다.
왜 부호가 다르냐고 하면
라고 한다.
증감 연산자
int index = 0;
Init(index++); // index의 현재 값(0)을 사용하여 Init 함수를 호출하고, index 값을 1 증가시킴
// Init 함수가 호출된 후 index 값은 1이 됩니다.
지금까지 후위 증감 연산자와 전위 증감 연산자의 차이를 확실히 알지못했는데, 이런 경우에 다르게 쓰일 수 있다는 것을 알았다. 더해서, 전위 연산자가 후위 연산자보다 살짝 빠르다는 사실도 알았다.
타이머 제작
백그라운드 이미지와 , 필 이미지 // 피그마를 이용해 그리고 간단한 코드들로 기능하게 함.
(아직 전부 구현하진 않음)
Wrapping && OverFlow
Wrapping(줄바꿈)
- Disable : 텍스트가 영역을 넘어가도 줄 바꿈 없이 한 줄로 표시
- 지정된 영역 안에서 설정된 방식에 따라 줄 바꿈
OverFLow(넘침 처리)
- Visible : 그대로 표시
- Hidden : 잘려서 보이지 않음
- Ellipsis : '...' (줄임표) 표시
- Truncate : 자랄냄
- Scroll Rect : 스크롤 가능하게 만듬
- Masking : 영역을 넘어가는 부분을 마스크로 가려서 보이지 않게 함
- Page : 여러 페이지로 나뉘어서 표시, 넘기기 기능 구현됨
- Linked : 여러개의 TMP Text 컴포넌트에 연결되어 표시
linked의 정확한 예시를 아직 모르겠다.
오늘의 목표
1. 프로그래머스 5문제 풀기
2. 스레드 관련 내용 정리