feat: 캐릭터 스펙 정보 서버에 저장하도록 변경

This commit is contained in:
aube.lee
2025-03-09 20:46:25 +09:00
parent 9e3d3881da
commit 110dc3d86e
12 changed files with 188 additions and 103 deletions

View File

@@ -0,0 +1,114 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using BackEnd;
namespace TON
{
/// <summary>
/// 뒤끝 서버 유저 데이터 관리 담당 클래스
/// </summary>
public class BackendPlayerDataManager
{
// 테이블 이름 상수
private const string USER_TABLE = "USER_DATA";
// PlayerDataManager에서 플레이어 데이터 로드
public void LoadMyPlayerData(System.Action<PlayerData> onComplete)
{
PlayerData playerData = new PlayerData();
Backend.PlayerData.GetMyData(USER_TABLE, callback =>
{
if (callback.IsSuccess() == false)
{
Debug.Log("데이터 읽기 중에 문제가 발생했습니다 : " + callback.ToString());
Main.Singleton.SystemQuit();
return;
}
// 불러오기에는 성공했으나 데이터가 존재하지 않는 경우
if (callback.IsSuccess() && callback.FlattenRows().Count <= 0)
{
Debug.Log("데이터가 존재하지 않습니다");
onComplete.Invoke(null);
return;
}
// 정상적으로 플레이어 데이터를 불러온 경우
if (callback.FlattenRows().Count > 0)
{
playerData.type = callback.FlattenRows()[0]["type"].ToString();
playerData.name = callback.FlattenRows()[0]["name"].ToString();
playerData.level = int.Parse(callback.FlattenRows()[0]["level"].ToString());
playerData.experience = int.Parse(callback.FlattenRows()[0]["experience"].ToString());
playerData.hp = int.Parse(callback.FlattenRows()[0]["hp"].ToString());
playerData.mp = int.Parse(callback.FlattenRows()[0]["mp"].ToString());
playerData.attackPower = float.Parse(callback.FlattenRows()[0]["attackPower"].ToString());
playerData.defensivePower = float.Parse(callback.FlattenRows()[0]["defensivePower"].ToString());
playerData.critical = int.Parse(callback.FlattenRows()[0]["critical"].ToString());
onComplete?.Invoke(playerData); // 성공 시 데이터 반환
}
});
}
/// <summary>
/// 캐릭터 초기 생성 시 row 삽입
/// </summary>
public void CreateNewPlayer(PlayerData playerData, System.Action<bool> onComplete = null)
{
Param param = new Param();
param.Add("type", playerData.type);
param.Add("name", playerData.name);
param.Add("level", playerData.level);
param.Add("experience", playerData.experience);
param.Add("hp", playerData.hp);
param.Add("mp", playerData.mp);
param.Add("attackPower", playerData.attackPower);
param.Add("defensivePower", playerData.defensivePower);
param.Add("critical", playerData.critical);
Backend.PlayerData.InsertData(USER_TABLE, param, callback =>
{
if (callback.IsSuccess())
{
Debug.Log("캐릭터 생성 성공");
onComplete?.Invoke(true);
}
else
{
Debug.LogError("캐릭터 생성 실패: " + callback.ToString());
onComplete?.Invoke(false);
}
});
}
public void UpdatePlayerData(PlayerData playerData, System.Action<bool> onComplete = null)
{
Param param = new Param();
param.Add("level", playerData.level);
param.Add("experience", playerData.experience);
param.Add("hp", playerData.hp);
param.Add("mp", playerData.mp);
param.Add("attackPower", playerData.attackPower);
param.Add("defensivePower", playerData.defensivePower);
Backend.PlayerData.UpdateMyLatestData(USER_TABLE, param, (callback) =>
{
if (callback.IsSuccess())
{
Debug.Log("캐릭터 업데이트 성공");
onComplete?.Invoke(true);
}
else
{
Debug.LogError("캐릭터 업데이트 실패: " + callback.ToString());
onComplete?.Invoke(false);
}
});
}
}
}

View File

@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0eeb12a360b37e54c8dd15fae106c8c1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -58,8 +58,6 @@ namespace TON
public void Initialize()
{
// int playerIndex = PlayerPrefs.GetInt("SelectedPlayerIndex", 0);
PlayerDataManager.Singleton.SetCurrentUserData();
playerData = PlayerDataManager.Singleton.player;
currentHP = maxHP = playerData.hp;

View File

@@ -51,7 +51,7 @@ namespace TON
public void SetCurrentUserHeart()
{
characterId = PlayerPrefs.GetInt("SelectedPlayerIndex", -1);
characterId = 0;
if (characterId > -1 && heartDatas.Count > 0)
{
currentHeartData = heartDatas[characterId];

View File

@@ -1,3 +1,4 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
@@ -8,7 +9,6 @@ namespace TON
public class PlayerDataManager : SingletonBase<PlayerDataManager>
{
// 사용자가 생성해둔 플레이어 데이터를 싱글톤으로 전역 사용하기 위함
public List<PlayerData> playersData { get; private set; }
public PlayerData player { get; private set; }
public int goldAmount { get; private set; }
public int fishAmount { get; private set; }
@@ -20,11 +20,13 @@ namespace TON
[SerializeField] private int expVariable = 50; // 경험치 변수 (조정 가능)
[SerializeField] private float attackGrowthFactor = 50f; // 공격력 성장 변수 (조정 가능)
private BackendPlayerDataManager playerDataManager;
private BackendCashDataManager cashDataManager;
private BackendItemDataManager itemDataManager;
private void OnEnable()
{
playerDataManager = new BackendPlayerDataManager();
cashDataManager = new BackendCashDataManager();
itemDataManager = new BackendItemDataManager();
}
@@ -38,17 +40,11 @@ namespace TON
private void LoadPlayerData()
{
if (playersData != null)
// * 사용자 정보 서버에서 조회
playerDataManager.LoadMyPlayerData(player =>
{
playersData.Clear();
}
JSONLoader.SaveJsonToPersistentData("player");
playersData = JSONLoader.LoadJsonFromPersistentData<List<PlayerData>>("player");
if (playersData == null)
{
playersData = new List<PlayerData>();
}
SetPlayerData(player);
});
}
private void LoadPlayerCashData()
@@ -172,30 +168,25 @@ namespace TON
public void UpdatePlayerData()
{
Debug.Log($"player {player.level}: {player.attackPower}, {player.defensivePower}");
int index = playersData.FindIndex(x => x.id == player.id);
if (index > -1)
// 캐릭터 데이터 서버 업데이트
playerDataManager.UpdatePlayerData(player, isSuccess =>
{
playersData[index] = player;
Assert.IsTrue(JSONLoader.SaveUpdatedJsonToPersistentData(playersData, "player"));
Initalize();
}
if (isSuccess)
{
Initalize();
}
});
}
public void SetCurrentUserData()
public void SetPlayerData(PlayerData playerData)
{
if (playersData.Count > 0)
player = playerData;
// 사용자 정보가 있을때만 레벨업 필요 초기값 세팅
if (playerData != null)
{
// 현재 플레이어 1개만 사용하므로 0번째 인덱스의 플레이어 데이터를 사용
PlayerPrefs.SetInt("SelectedPlayerIndex", 0);
player = playersData[0];
// 현재 플레이어의 정보를 세팅하고, 레벨업 필요 경험치 정보를 세팅
requireLevelUpExp = GetRequiredExp(player.level);
}
else
{
Debug.LogError("유효하지 않은 캐릭터 정보 입니다.");
}
}
// 플레이어가 사망했을때 호출
@@ -209,5 +200,12 @@ namespace TON
UIManager.Show<GameWinUI>(UIList.GameWinUI);
}
public void CreateNewPlayer(PlayerData player, System.Action<bool> onComplete = null)
{
playerDataManager.CreateNewPlayer(player, isSuccess =>
{
onComplete?.Invoke(isSuccess);
});
}
}
}

View File

@@ -8,21 +8,14 @@ namespace TON
{
public static bool SpawnPlayerCharacter()
{
List<PlayerData> playerDatas = PlayerDataManager.Singleton.playersData;
// 저장된 인덱스 가져오기
int selectedIndex = PlayerPrefs.GetInt("SelectedPlayerIndex", 0);
// 인덱스가 범위를 벗어나지 않는지 확인
if (selectedIndex < 0 || selectedIndex >= playerDatas.Count)
{
Debug.LogError($"Invalid player index: {selectedIndex}");
return false;
}
string prefabName = playerDatas[selectedIndex].type == "b" ? "TON.Player_B" : "TON.Player_W";
PlayerData playerData = PlayerDataManager.Singleton.player;
string prefabName = playerData.type == "b" ? "TON.Player_B" : "TON.Player_W";
// Resources에서 프리팹 로드
GameObject characterPrefab = Resources.Load<GameObject>($"Player/{prefabName}");
if (characterPrefab == null)
{
Debug.LogError($"Failed to load character prefab: {playerDatas[selectedIndex].type}");
Debug.LogError($"Failed to load character prefab: {playerData.type}");
return false;
}
// TON.Player 오브젝트 찾기

View File

@@ -51,7 +51,6 @@ namespace TON
// UIManager.Show<IngameOptionUI>(UIList.IngameOptionUI);
// UIManager.Show<SkillSettingUI>(UIList.SkillSettingUI);
PlayerDataManager.Singleton.Initalize();
PlayerDataManager.Singleton.SetCurrentUserData();
// UIManager.Show<ControllerUI>(UIList.ControllerUI);
// ControllerUI.Instance.Initalize();
// UIManager.Show<IngameUI>(UIList.IngameUI);

View File

@@ -10,7 +10,6 @@ namespace TON
TitleUI, // 게임 시작 화면 UI
CharaterCreateUI, // 캐릭터 생성 UI
CharaterSelectUI,
ControllerUI, // 캐릭터 컨트롤러 UI
LobbyUI, // 게임 로비 UI
SkillSettingUI, // 스킬 세팅 팝업 UI

View File

@@ -7,39 +7,23 @@ namespace TON
[System.Serializable]
public class PlayerData
{
// 캐릭터 아이디
public string id;
// 캐릭터 이미지 타입 (w/b)
// 필드 선언 (외부 수정 방지)
public string type;
// 캐릭터 이름
public string name;
// 캐릭터 레벨
public int level;
// 캐릭터 경험치
public int experience;
// 캐릭터 체력
public int hp;
// 캐릭터 마나(스킬 포인트)
public int mp;
// 기본 공격력
public float attackPower;
// 기본 방어력
public float defensivePower;
// 캐릭터 크리티컬 수치
public int critical;
public int level = 1;
public int experience = 0;
public int hp = 100;
public int mp = 100;
public float attackPower = 50f;
public float defensivePower = 30f;
public int critical = 30;
public PlayerData(int i, string t, string n)
public PlayerData() : this("w", "") { }
public PlayerData(string t, string n)
{
id = $"P{i:000}";
type = t == "BlackCat" ? "b" : "w";
name = n;
level = 1;
experience = 0;
hp = 100;
mp = 100;
attackPower = 50f;
defensivePower = 30f;
critical = 30;
}
}

View File

@@ -19,7 +19,6 @@ namespace TON
yield return null;
}
PlayerDataManager.Singleton.SetCurrentUserData();
SkillDataManager.Singleton.Initalize();

View File

@@ -11,9 +11,8 @@ namespace TON
public class CharaterCreateUI : UIBase
{
[SerializeField] private Button cancelButton; // cancel 버튼 참조
[SerializeField] private Button confirmButton; // cancel 버튼 참조
[SerializeField] private Button confirmButton; // confirm 버튼 참조
[SerializeField] private Button createButton; // Create 버튼 참조
[SerializeField] private List<PlayerData> playerDatas;
[SerializeField] private TextMeshProUGUI nicknameCondition;
@@ -26,8 +25,6 @@ namespace TON
private void Start()
{
playerDatas = PlayerDataManager.Singleton.playersData;
// 처음에는 버튼을 비활성화
createButton.interactable = false;
@@ -68,9 +65,6 @@ namespace TON
return;
}
// 선택된 캐릭터 인덱스 정보를 저장 (다음 씬에서도 사용할 수 있도록)
PlayerPrefs.SetInt("SelectedPlayerIndex", 0);
// 캐릭터 이름 입력 모달 활성화
characterCreateUI_Modal.SetActive(true);
}
@@ -120,20 +114,24 @@ namespace TON
if (success)
{
// 생성한 캐릭터를 저장한다
PlayerData player = new PlayerData(playerDatas.Count, selectedCharacter, nickname);
playerDatas.Add(player);
Assert.IsTrue(JSONLoader.SaveUpdatedJsonToPersistentData(playerDatas, "player"));
PlayerData player = new PlayerData(selectedCharacter, nickname);
PlayerDataManager.Singleton.SetPlayerData(player);
PlayerDataManager.Singleton.SetCurrentUserData();
// 뒤끝 서버 데이터 저장 로직 적용
PlayerDataManager.Singleton.CreateNewPlayer(player, isSuccess =>
{
if (isSuccess)
{
// 하트 시스템을 생성한다
HeartDataManager.Singleton.CreateNewHeartSystem(0);
HeartDataManager.Singleton.SetCurrentUserHeart();
// 하트 시스템을 생성한다
HeartDataManager.Singleton.CreateNewHeartSystem(playerDatas.Count);
HeartDataManager.Singleton.SetCurrentUserHeart();
// 씬 변경
UIManager.Hide<CharaterCreateUI>(UIList.CharaterCreateUI);
Main.Singleton.ChangeScene(SceneType.Lobby);
}
});
// 씬 변경
UIManager.Hide<CharaterCreateUI>(UIList.CharaterCreateUI);
Main.Singleton.ChangeScene(SceneType.Lobby);
}
else
{

View File

@@ -6,7 +6,6 @@ namespace TON
{
public class TitleUI : UIBase
{
public CharaterSelectUI charaterSelectUI;
public void OnClickStartButton()
{
@@ -17,25 +16,18 @@ namespace TON
{
yield return new WaitForSeconds(0.2f); // 0.2초 대기
// Main.Singleton?.ChangeScene(SceneType.Ingame);
UIManager.Hide<TitleUI>(UIList.TitleUI);
// 플레이어가 가지고 있는 캐릭터들의 데이터 불러옴
List<PlayerData> players = PlayerDataManager.Singleton.playersData;
PlayerData player = PlayerDataManager.Singleton.player;
if (players == null || players.Count == 0)
if (player == null)
{
// 현재 가지고 있는 캐릭터가 없다면 CharaterCreateUI 를 보여주고
// 현재 가지고 있는 캐릭터가 없다면 캐릭터 생성 화면으로 이동
UIManager.Show<CharaterCreateUI>(UIList.CharaterCreateUI);
}
else
{
// 캐릭터가 있다면 내 캐릭터 목록에서 선택할 수 있도록 함
// UIManager.Show<CharaterSelectUI>(UIList.CharaterSelectUI);
// select 요소는 나중에 인게임 화면으로 바로 전환
PlayerPrefs.SetInt("SelectedPlayerIndex", 0);
PlayerDataManager.Singleton.SetCurrentUserData();
HeartDataManager.Singleton.SetCurrentUserHeart();
Main.Singleton.ChangeScene(SceneType.Lobby);
}