8년차 모션그래픽디자이너의 고군분투

[Unity/메타버스 게임] 로그인 할 때마다 캐릭터 정보 가져오기 | MongoDB | PhotonNetwork | 몽고디비 | 포톤네트워크 본문

코자이너/Unity

[Unity/메타버스 게임] 로그인 할 때마다 캐릭터 정보 가져오기 | MongoDB | PhotonNetwork | 몽고디비 | 포톤네트워크

쓰리디사람3Dperson 2024. 6. 20. 12:21
반응형

안녕하세요 오늘은 로그인 할 때마다 캐릭터 정보 가져오는 스크립트를 공유하겠습니다.

현재 제가 만들고 있는 게임에는 로그인 창이 있고 아이디와 비밀번호를 입력하면 로그인이 됩니다.

로그인 하는 방법에 대해서는 해당 포스팅으로 올려두었습니다.

[코자이너/Unity] - [Unity] 유니티에서 몽고DB 연결해서 사용하기 | MongoDB | 로그인 창에서 아이디 확인하기 | 자동 로그인 설정 값 | PlayerPrefs | Hashtable

 

[Unity] 유니티에서 몽고DB 연결해서 사용하기 | MongoDB | 로그인 창에서 아이디 확인하기 | 자동 로

안녕하세요 오늘은 로그인창에서 '아이디, 비밀번호를 몽고디비에서 체크하고 아이디와 비밀번호가 있다면' 의 조건문을 쓰기 위한 몽고디비 코드를 공유하고 또한 자동 로그인 하는 방법에 대

3dperson1.tistory.com

 

로그인을 하고 난 뒤에는 남자와 여자를 고르는 버튼을 클릭하면 랜덤으로 캐릭터를 생성하게 되는데요.

자동로그인 기능을 구현하고 있기 때문에 자동 로그인이 될 때 캐릭터의 정보 값도 같이 와야 합니다.

로그인을 매번 할 때마다 캐릭터를 변경할 수는 없으니까요.

 

퍼스널 클래스에 캐릭터 인덱스라는 변수 명을 넣어놨었습니다.

using MongoDB.Bson.Serialization.Attributes;
using MongoDB.Bson;
using System;
using System.Collections.Generic;

public enum RememberID 
{
    Remember,
    Nope
}

[Serializable]
public class Personal
{
    [BsonId]
    public ObjectId Id;
    public RememberID Remember;
    [BsonElement("Name")]
    public string Name;
    public string Password;
    public int Coins;
    public int CharacterIndex;
}
[Serializable]
public class PersonalData
{
    public List<Personal> Data;

    public PersonalData(List<Personal> data)
    {
        Data = data;
    }
}

 

이 캐릭터 인덱스를 최초 로그인 할 때 저장하고 그 이후에 로그인 시도를 할 때마다 자동 로그인이 이루어지며 캐릭터 인덱스를 가져오는 방법에 대해서 설명하겠습니다.

 

PersonalManager.cs

using MongoDB.Driver;
using Photon.Pun;
using System.Collections.Generic;
using UnityEngine;
using Hashtable = ExitGames.Client.Photon.Hashtable;
public class PersonalManager : MonoBehaviour
{
    private List<Personal> _personal = new List<Personal>();
    public List<Personal> Personals => _personal;

    private IMongoCollection<Personal> _personalCollection;
    public static PersonalManager Instance { get; private set; }

    private string _cachedUserName;

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
            DontDestroyOnLoad(gameObject);
            Init();
        }
        else
        {
            Destroy(gameObject);
        }
    }
    
	// 시작하자마자 몽고디비 서버 접속
    public void Init()
    {
        string connectionString = "mongodb+srv://****************.mongodb.net/";
        MongoClient mongoClient = new MongoClient(connectionString);
        IMongoDatabase db = mongoClient.GetDatabase("Logins");
        _personalCollection = db.GetCollection<Personal>("Log");
    }

일단 인잇으로 서버에 접속을 합니다.

자동 로그인 하는 방법은 이전 포스팅에 있으니 참고 부탁드립니다.

똑같이 퍼스널매니저 스크립트에 작성합니다.

// 캐릭터 인덱스를 업데이트하는 메서드
// (나중에 상점에서 코인을 주면 캐릭터를 랜덤으로 바꿀수 있기 때문에 쓰는 함수)
public bool UpdateCharacterIndex(int characterIndex)
{
    // 사용자 이름을 캐시에서 가져옴
    string name = GetCachedUserName();
    
    // 사용자 이름이 비어 있거나 null이면 false를 반환
    if (string.IsNullOrEmpty(name)) return false;

    // 사용자 이름과 일치하는 필터를 생성
    var filter = Builders<Personal>.Filter.Eq(p => p.Name, name);
    
    // 캐릭터 인덱스를 업데이트하는 업데이트 정의를 생성
    var update = Builders<Personal>.Update.Set(p => p.CharacterIndex, characterIndex);

    // 필터에 맞는 문서를 업데이트하고 결과를 저장
    var result = _personalCollection.UpdateOne(filter, update);

    // 업데이트된 문서가 있고, 현재 로컬 플레이어가 로컬일 경우
    // 플레이어UI에서 캐릭터의 인덱스 값을 받아 성별을 정해야해서 바로 업데이트 되는 해시테이블 사용
    if (result.ModifiedCount > 0 && PhotonNetwork.LocalPlayer.IsLocal)
    {
        // 새로운 캐릭터 인덱스를 해시 테이블에 저장
        Hashtable characterindex = new Hashtable { { "CharacterIndex", characterIndex } };
        
        // 로컬 플레이어의 커스텀 속성을 업데이트
        PhotonNetwork.LocalPlayer.SetCustomProperties(characterindex);
    }

    // 업데이트된 문서가 있는지 여부를 반환
    return result.ModifiedCount > 0;
}

// 캐릭터 인덱스를 확인하는 메서드
public int CheckCharacterIndex()
{
    // 사용자 이름을 캐시에서 가져옴
    string name = GetCachedUserName();
    
    // 사용자 이름이 비어 있거나 null이면 -1을 반환
    if (string.IsNullOrEmpty(name)) return -1;

    // 사용자 이름과 일치하는 필터를 생성
    var filter = Builders<Personal>.Filter.Eq(p => p.Name, name);
    
    // 필터에 맞는 문서를 찾아서 첫 번째 문서를 가져옴
    var user = _personalCollection.Find(filter).FirstOrDefault();

    // 사용자가 없으면 -1을 반환
    if (user == null)
    {
        return -1;
    }

    // 사용자의 캐릭터 인덱스를 반환
    return user.CharacterIndex;
}

캐릭터 인덱스를 확인하는 함수는 체크캐릭터인덱스 함수입니다.

반응형

여기서부터 저희 게임이 좀 복잡하게 돌아가는데

일단 저희 메타버스게임은 로비(로그인) -> 로딩(포톤에 접속하기까지 기다리는 씬) -> 마을(포톤에 접속하면 바로 뜨는 씬)

이렇게 이루어져있습니다.

때문에 마을에 들어가기전까지는 포톤에 접속을 하지 않습니다. 즉, 포톤네트워크로 캐릭터를 생성하지 않고 리스트 형태로 가지고 있다가 캐릭터 인덱스 값을 받으면 해당 캐릭터의 게임오브젝트만 켜주면 되는 것 입니다.

또한 캐릭터 인덱스 값은 그대로 들고와서 로비씬->로딩씬을 그대로 거쳐야 하기 때문에 저는 로딩씬까지만 존재할 스크립트를 따로 만들어주었습니다.

using Photon.Pun;
using UnityEngine;
using Hashtable = ExitGames.Client.Photon.Hashtable;
public class PlayerSelection : MonoBehaviour
{
    public static PlayerSelection Instance;
    public PlayerType SelectedType;
    public int SelectedCharacterIndex;
    // 인덱스 값을 받아서 켜줄 캐릭터오브젝트
    private GameObject currentCharacter;
    // 리스트형으로 가지고 있는 캐릭터오브젝트
    public GameObject[] SelectedCharacter;

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
        }
        else
        {
            Destroy(gameObject);
        }
        // 전체 끄고
        for (int i = 0; i < SelectedCharacter.Length; i++)
        {
            SelectedCharacter[i].gameObject.SetActive(false);
        }
    }
	// 최초 로그인시 캐릭터 인덱스를 저장하려고 실행되는 함수
    public void CharacterSelection(PlayerType type)
    {
        if (currentCharacter != null)
        {
            Destroy(currentCharacter);
        }
        int index;
        if (type == PlayerType.Male)
        {
            index = Random.Range(13, 26);
        }
        else
        {
            index = Random.Range(1, 13);
        }
        // 리스트형이기 때문에 -1 해줘야 함
        currentCharacter = SelectedCharacter[index - 1];
        SelectedCharacterIndex = index;

        Debug.Log($"{SelectedCharacterIndex}");
        // 캐릭터 인덱스를 새로 저장하고
        PersonalManager.Instance.UpdateCharacterIndex(SelectedCharacterIndex);

        Hashtable characterindex = new Hashtable { { "CharacterIndex", SelectedCharacterIndex } };
        PhotonNetwork.LocalPlayer.SetCustomProperties(characterindex);

        SelectedType = type;
        // 해당 캐릭터를 켜준다
        currentCharacter.gameObject.SetActive(true);
    }
    // 자동 로그인시 캐릭터 인덱스를 받아 실행되는 함수
    public void ReloadCharacter()
    {
    	// 몽고디비에 저장되어있는 캐릭터 인덱스 값을 받아 옴
        int characterIndex = PersonalManager.Instance.CheckCharacterIndex();

        if (characterIndex != -1)
        {
            if (currentCharacter != null)
            {
                Destroy(currentCharacter);
            }
			// 해당 캐릭터를 켜준다.
            currentCharacter = SelectedCharacter[characterIndex - 1];
            currentCharacter.gameObject.SetActive(true);
        }
        else
        {
            Debug.LogError("캐릭터 인덱스를 가져오지 못했습니다.");
            return;
        }
    }
}

 

이제 마을 씬으로 진입할 때 포톤네트워크로 캐릭터를 생성해줘야 합니다.

using Photon.Pun;
using Photon.Realtime;
using System.Collections.Generic;
using UnityEngine;

public class VillageScene : MonoBehaviourPunCallbacks
{
    public static VillageScene Instance { get; private set; }
    public List<Transform> SpawnPoints;

    private bool localPlayerInitialized = false;

    private void Awake()
    {
        if (Instance == null)
        {
            Instance = this;
        }
        else
        {
            Destroy(gameObject);
        }
    }
    private void Start()
    {
    	// 포톤네트워크로 방에 잘 접속이 되었다면
        if (PhotonNetwork.InRoom && !localPlayerInitialized)
        {
            InitializePlayer(PhotonNetwork.LocalPlayer);
        }
    }
    public override void OnJoinedRoom()
    {
        base.OnJoinedRoom();
    }

    private void InitializePlayer(Photon.Realtime.Player player)
    {
        if (!player.IsLocal) return;
        Vector3 spawnPoint = GetRandomSpawnPoint();
		// 캐릭터 인덱스 값을 받아와서
        int characterIndex = PersonalManager.Instance.CheckCharacterIndex();
        string characterPrefab = characterIndex <= 0 ? $"Player {PlayerSelection.Instance.SelectedCharacterIndex}" : $"Player {characterIndex}";
		// 캐릭터 생성
        PhotonNetwork.Instantiate(characterPrefab, spawnPoint, Quaternion.identity);

        localPlayerInitialized = true; // 로컬 플레이어가 생성되었음을 표시
    }
	// 랜덤 위치에서 생성
    public Vector3 GetRandomSpawnPoint()
    {
        int randomIndex = Random.Range(0, SpawnPoints.Count);
        return SpawnPoints[randomIndex].position;
    }
}

 

이런식으로 만들어보았습니다.

도움이 되었으면 좋겠습니다. 감사합니다.

반응형
Comments