반응형
안녕하세요!
이번 글은 제가 어디서든 볼려고 작성하는 글로 저는 늘 프로젝트 만들 때, 기본 세팅으로 깔아놓고 시작하는 코드들이 있습니다. 바로 관리자 스크립트인데요. 음악, 글자, scene 등 관리하는 스크립트와 싱글톤 패턴 사용을 위한 스크립트, 모바일 화면 비율을 세팅해주기 위한 스크립트, 마지막으로 버튼 effect 를 간편하게 사용하기 위해 컴포넌트 형식으로 만들어논 코드를 공유해드릴까 합니다.
하지만 자세히 정리하지 않아서 직접 보시고 활용하시길 추천드립니다.
1. SingleTon
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SingleTon<T> : MonoBehaviour where T : MonoBehaviour {
private static T _instance;
public static T Instance {
get {
if(_instance == null) {
_instance = FindObjectOfType<T>();
DontDestroyOnLoad(_instance.gameObject);
}
return _instance;
}
}
protected void Awake() {
if(_instance != null) {
if(_instance != this) {
Destroy(gameObject);
}
return;
}
_instance = GetComponent<T>();
DontDestroyOnLoad(gameObject);
}
}
2. CS_SceneManager
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
public class CS_SceneManager : SingleTon<CS_SceneManager>
{
/* States */
private SceneData.SceneType curScene = SceneData.SceneType.None;
public void LoadScene(SceneData.SceneType type) {
if(curScene != type) {
StartCoroutine(unloadScene(SceneData.GetSceneName(curScene), ()=>{
StartCoroutine(loadScene(SceneData.GetSceneName(type), ()=>{
curScene = type;
SwitchActiveScene(type);
}));
}));
}
}
IEnumerator loadScene(string sceneName, Action callback) {
if(sceneName != SceneData.GetSceneName(SceneData.SceneType.None)) {
AsyncOperation asyncOp = SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive);
while(!asyncOp.isDone) {
yield return null;
}
}
callback();
}
IEnumerator unloadScene(string sceneName, Action callback) {
if(sceneName != SceneData.GetSceneName(SceneData.SceneType.None)) {
AsyncOperation asyncOp = SceneManager.UnloadSceneAsync(sceneName);
while(!asyncOp.isDone) {
yield return null;
}
}
callback();
}
public void SwitchActiveScene(SceneData.SceneType type)
{
SceneManager.SetActiveScene(
SceneManager.GetSceneByName(SceneData.GetSceneName(type))
);
}
}
public static class SceneData {
public enum SceneType {
None = -1,
Main_Community = 0,
Main_Seagrass = 1,
Test =2
}
public static string GetSceneName(SceneType type) {
switch (type) {
case SceneType.None:
return "None";
case SceneType.Main_Community:
return "Main_Community";
case SceneType.Main_Seagrass:
return "Main_Seagrass";
case SceneType.Test:
return "Test";
default:
return "None";
}
}
}
3. CS_GameSoundManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Audio;
public enum BGM
{
Main_Community = 0,
Main_Seagrass = 1
}
public enum SFX
{
TrashClick = 0,
TrashSucess = 1,
CoinGet = 2
}
public class CS_GameSoundManager : SingleTon<CS_GameSoundManager>
{
[Header("[Object Setting]")]
[SerializeField] private AudioMixer audioMixer;
private AudioSource audioSource;
[Header("[BGM]")]
[SerializeField] private AudioClip[] bgmSources;
[Header("[SFX]")]
[SerializeField] private AudioSource[] sfxSource;
private Coroutine fadeOutCoroutine;
private bool isPause = false;
public bool IsPause { get { return isPause; } }
private BGM bgmCur = BGM.Main_Community;
private float audioVolume;
private float audioVolumeCur = 0;
// 0 ~ 1
public void SetAudioMixer(float value)
{
if (value < 0.0001)
{
audioMixer.SetFloat("Master", -80);
}
else
{
audioMixer.SetFloat("Master", Mathf.Log10(value) * 20);
}
}
public void SfxPlay(SFX sfx)
{
sfxSource[(int)sfx].Play();
}
public void BgmPlay()
{
if (!audioSource.isPlaying)
{
if (isPause)
{
isPause = false;
audioSource.UnPause();
}
else
{
audioSource.clip = bgmSources[(int)bgmCur];
audioSource.Play();
}
}
else
{
if (fadeOutCoroutine != null)
{
StopCoroutine(fadeOutCoroutine);
}
fadeOutCoroutine = StartCoroutine(FadeOut());
}
}
// 1sec
private IEnumerator FadeOut()
{
audioVolumeCur = audioVolume;
float minIntervalTime = Time.deltaTime;
while (true)
{
if (audioVolumeCur > 0)
{
audioVolumeCur -= audioVolume * minIntervalTime;
audioSource.volume = audioVolumeCur;
yield return new WaitForSeconds(minIntervalTime);
}
else
{
break;
}
}
audioSource.clip = bgmSources[(int)bgmCur];
audioSource.Play();
audioSource.volume = audioVolume;
}
public void BgmPause()
{
if (audioSource.isPlaying)
{
audioSource.Pause();
isPause = true;
}
}
public void BgmSet(BGM index)
{
bgmCur = index;
}
private new void Awake()
{
audioSource = GetComponent<AudioSource>();
audioVolume = audioSource.volume;
}
}
4. CS_SaveLoadManager
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using System;
[System.Serializable]
public class StoryInfo
{
public List<bool> isStoryOpened;
public StoryInfo()
{
isStoryOpened = new List<bool>();
for (int i = 0; i < 3; i++)
{
isStoryOpened.Add(false); //초기값 false
}
}
public void openStory(int index) { isStoryOpened[index] = true; } //스토리 해금
}
[System.Serializable]
public class GameData
{
public int high_score;
public int coin;
public List<int> upgrade;
public int heart;
public bool isGameFirst;
public List<StoryInfo> unlockedMemory;
public float bgmSound;
public float sfxSound;
public int playCount;
public bool haptic;
public GameData()
{
high_score = 0;
coin = 0;
upgrade = new List<int>();
for (int i = 0; i < 3; i++) upgrade.Add(0);
heart = 5;
isGameFirst = false;
//10개의 스테이지
unlockedMemory = new List<StoryInfo>();
for (int i = 0; i < 10; i++) unlockedMemory.Add(new StoryInfo());
bgmSound = 0;
sfxSound = 0;
playCount = 0;
haptic = true;
}
}
public class CS_SaveLoadManager : SingleTon<CS_SaveLoadManager>
{
private string savePath;
private GameData _gameData;
public GameData GameData
{
get
{
if(_gameData == null)
{
_gameData = LoadData();
SaveData();
}
return _gameData;
}
}
private void Start()
{
// Application.persistentDataPath는 각 플랫폼에 따라 저장될 수 있는 영구적인 데이터 경로를 제공합니다.
savePath = Path.Combine(Application.persistentDataPath, "GameData.json");
Debug.Log(Application.persistentDataPath);
}
private GameData LoadData()
{
Debug.Log(savePath);
if (File.Exists(savePath))
{
// 파일에서 JSON 데이터 읽기
string jsonData = File.ReadAllText(savePath);
// JSON 데이터를 클래스로 변환
GameData loadedData = JsonUtility.FromJson<GameData>(jsonData);
return loadedData;
}
else
{
Debug.Log("새로운 파일 생성");
GameData gameData = new GameData();
return gameData;
}
}
public void UpgradeHP() { GameData.upgrade[0]++; } //호출 시 upgrade_hp 1 증가
public void UpgradeEnergy() { GameData.upgrade[1]++; } //호출 시 upgrade_energy 1 증가
public void UpgradeJelly() { GameData.upgrade[2]++; } //호출 시 upgrade_jelly 1 증가
public int GetUpgradeHP() { return GameData.upgrade[0]; } //upgrade_hp 반환
public int GetUpgradeEnergy() { return GameData.upgrade[1]; } //upgrade_energy 반환
public int GetUpgradeJelly() { return GameData.upgrade[2]; } //upgrade_jelly 반환
public void PlusCoin(int coin) { GameData.coin += coin; } //Coin 더하기
public void MinusCoin(int coin) { GameData.coin -= coin; } //Coin 빼기
public int GetCoin() { return GameData.coin; } //DB에 있는 Coin 반환
public void SetHighScore(int high_score) { GameData.high_score = GameData.high_score > high_score ? GameData.high_score : high_score; } //최대 점수 설정
public int GetHighScore() { return GameData.high_score; } //최대 점수 반환
public int GetHeart() { return GameData.heart; } //하트 반환
public void PlusHeart() { GameData.heart++; } //하트 하나 더하기
public void SubtractHeart() { GameData.heart--; } //하트 하나 빼기
public bool GetIsGameFirst() { return GameData.isGameFirst; } //처음 시작 여부 반환
public void SetIsGameFirst() { GameData.isGameFirst = true; } //처음 시작 완료 설정
public List<StoryInfo> GetUnlockedMemory() { return GameData.unlockedMemory; } //먹은 기억의 조각 반환
public void SetBgmSound(float sound) { GameData.bgmSound = sound; } //bgm 소리 저장
public float GetBgmSound() { return GameData.bgmSound; } //bgm 소리 반환
public void SetSfxSound(float sound) { GameData.sfxSound = sound; } //sfx 소리 저장
public float GetSfxSound() { return GameData.sfxSound; } //sfx 소리 반환
public void ReadStory(int concept, int index) { GameData.unlockedMemory[concept].openStory(index); } //스토리를 읽은 상태로 설정
public void PlusPlayCount() { GameData.playCount++; } //플레이 횟수 + 1
public int GetPlayCount() { return GameData.playCount; } //플레이 횟수 반환
public bool ToggleHaptic() //Toggle haptic
{
GameData.haptic = !GameData.haptic;
return GameData.haptic;
}
public bool GetHaptic() { return GameData.haptic; }
public void SaveData()
{
// 데이터를 JSON 형식으로 변환
string jsonData = JsonUtility.ToJson(_gameData);
// JSON 데이터를 파일에 쓰기
File.WriteAllText(savePath, jsonData);
Debug.Log("저장 완료");
}
void OnApplicationQuit()
{
SaveData();
}
}
5. SafeArea
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class SafeArea : MonoBehaviour
{
public GameObject safeAreaPanel;
private void Start()
{
// SafeArea 설정
Rect safeArea = Screen.safeArea;
Vector2 newAnchorMin = safeArea.position;
Vector2 newAnchorMax = safeArea.position + safeArea.size;
newAnchorMin.x /= Screen.width;
newAnchorMax.x /= Screen.width;
newAnchorMin.y /= Screen.height;
newAnchorMax.y /= Screen.height;
RectTransform rect = safeAreaPanel.GetComponent<RectTransform>();
rect.anchorMin = newAnchorMin;
rect.anchorMax = newAnchorMax;
}
}
6. ButtonEffect
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.Events;
using UnityEngine.EventSystems;
public class ButtonEffect : MonoBehaviour, IPointerDownHandler, IPointerUpHandler
{
[Header("Default")]
[SerializeField] private bool onClickChangeScale = true;
[SerializeField] private bool onClickChangeColor = true;
[SerializeField] private Image[] btnImages;
[SerializeField] private Button button;
[Header("Custom Color")]
[SerializeField] private bool isUseCustomColor = false;
[SerializeField] private Color customColor = new Color(200 / 255f, 200 / 255f, 200 / 255f, 255 / 255f);
/* Const Values */
private readonly Color NORMAL_COLOR = new Color(255 / 255f, 255 / 255f, 255 / 255f, 255 / 255f);
private readonly Color PRESSED_COLOR = new Color(229 / 255f, 51 / 255f, 137 / 255f, 255 / 255f);
private readonly Vector3 NORMAL_SCALE = Vector3.one;
private readonly Vector3 PRESSED_SCALE = new Vector3(1.15f, 1.15f, 1.15f);
public void OnPointerUp(PointerEventData eventData)
{
OnButtonUp();
}
public void OnPointerDown(PointerEventData eventData)
{
OnButtonDown();
}
private void OnButtonDown()
{
if (onClickChangeColor)
{
if (!isUseCustomColor)
{
foreach (var btnImage in btnImages)
{
btnImage.color = PRESSED_COLOR;
}
}
else
{
foreach (var btnImage in btnImages)
{
btnImage.color = customColor;
}
}
}
if (onClickChangeScale)
{
foreach (var btnImage in btnImages)
{
btnImage.rectTransform.localScale = PRESSED_SCALE;
}
}
}
private void OnButtonUp()
{
if (onClickChangeColor)
{
foreach (var btnImage in btnImages)
{
btnImage.color = NORMAL_COLOR;
}
}
if (onClickChangeScale)
{
foreach (var btnImage in btnImages)
{
btnImage.rectTransform.localScale = NORMAL_SCALE;
}
}
}
}
반응형
댓글