본문 바로가기

유니티

[유니티]Firebase Database를 이용해서 유저들이 가입한 후 채팅하는 어플 만들기

회원가입과 로그인에 더 자세한 정보는 https://sharp2studio.tistory.com/36?category=884092

 

[유니티] Firebase Database를 이용한 회원가입, 로그인 구현

기본적인 세팅은 https://sharp2studio.tistory.com/32 이 글을 참고하면 된다. 왼쪽 빌드에서 Authentication에 들어가서 로그인 방법을 설정해준다. 여러개가 있지만, 가장 간단한 이메일로 구현을 해보겠다.

sharp2studio.tistory.com

이 포스팅에 정리했다. 

 

 


회원가입을 도와줄 SignUp 씬과, 로그인을 도와줄 SignIn 씬, 마지막으로 채팅창을 구현한 Main 씬 이렇게 3가지 씬을 만들것이다.

Project에서 우클릭 후 create-scene

기본적으로 어플이 켜지면, 회원가입 씬이 나오고 , 가입 성공시 로그인 씬, 로그인 성공시 Main씬으로 이동하겠다.

File-Build Settings 에 들어가서 SignUp 씬을 0번으로 고정시켜준다.

 

회원가입 씬은 이러한 씬을 만들어 줄것이다.

3개의 InputField와, 가입을 눌러줄 버튼,이미 계정이 있다면 로그인 씬으로 가는 버튼을 만들었다.

빈 오브젝트에 회원 가입을 도와줄 스크립트를 넣어주자.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using Firebase;
using Firebase.Database;
using Firebase.Extensions;
using Firebase.Auth;
using UnityEngine.SceneManagement;
public class SingUp : MonoBehaviour
{
    Firebase.Auth.FirebaseAuth firebaseAuth;
    DatabaseReference databaseReference;
    [SerializeField] TMP_InputField[] inputFields; //필드 0->이메일 1->패스워드 입력 필드 2->닉네임 입력 필드
    void Start()
    {
        databaseReference= FirebaseDatabase.DefaultInstance.RootReference;
        firebaseAuth = Firebase.Auth.FirebaseAuth.DefaultInstance;
        Debug.Log(firebaseAuth.CurrentUser.UserId);
        //초기값을 디폴트로
    }
  public void ClickSignUpButton() //버튼 클릭시 해당 함수를 발동해준다.
    {
        string email = inputFields[0].text;
        string password = inputFields[1].text;
        string nickname = inputFields[2].text;
        firebaseAuth.CreateUserWithEmailAndPasswordAsync(email, password).ContinueWith(task =>
        {
            if (task.IsFaulted||task.IsCanceled)
            {
                Debug.Log(task.Exception);
            }
            else {
                databaseReference.Child("user").Child(firebaseAuth.CurrentUser.UserId).Child("nickname").SetValueAsync(nickname);
           //접속된 유저의 uid를 키값으로, db에 넣어준다. 자식으로 닉네임을 추가해서 입력한 닉네임을 저장해준다.            
            SceneManager.LoadScene("SignIn");
           }
        });
        
    }
    public void GoSingInScene()
    {
        SceneManager.LoadScene("SignIn");
    }
}

위 ClickSingUpButton 함수를 버튼에 넣어주고,

GoSignInScene함수를 로그인 씬으로 갈 버튼에 넣어준다.

이러한 식으로 입력한 후 버튼을 눌러주면

위와같이 파이어베이스 Authentication과 realtime database에 원하는대로 저장이 됨을 볼 수 있다.

이제 로그인 화면을 구현할 건데, Sign Up 씬에서 닉네임 정하는 칸만 없애주면 된다.

또한 가입이 성공하면 SignIn씬으로 이동을 하게 된다.

 

똑같이, 로그인을 도와줄 스크립트를 완성시키면

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using Firebase.Auth;
using UnityEngine.SceneManagement;
public class SingIn : MonoBehaviour
{
    Firebase.Auth.FirebaseAuth firebaseAuth;
    [SerializeField] TMP_InputField[] inputFields; //필드 0->이메일 1->패스워드 입력 필드 
    void Start()
    {      
        firebaseAuth = Firebase.Auth.FirebaseAuth.DefaultInstance;
        //초기값을 디폴트로
    }

    public void ClickSignInButton() //버튼 클릭시 해당 함수를 발동해준다.
    {
        string email = inputFields[0].text;
        string password = inputFields[1].text;
        firebaseAuth.SignInWithEmailAndPasswordAsync(email, password).ContinueWith(task =>
        {
            if (task.IsFaulted || task.IsCanceled)
            {
                Debug.Log(task.Exception);
            }
            else
            {
                 SceneManager.LoadScene("Main");
            }
        });
    }
    public void GoSingUpScene()
    {
        SceneManager.LoadScene("SignUp");
    }
}

이렇게 짜주면 된다.

로그인 성공 시 Main씬으로 이동하게 된다.

 

Main 씬은 이렇게 구성할 것이다

하나하나 천천히 보도록 하자.

먼저,가장 위에는 내 닉네임을 표시한 공간을 만들어 준다.

가운데에는 Scroll View를 활용해서 채팅창을 만들어 줄 것이며,

세로로만 이동이 가능하게 Horizontal 체크 표시, 또한 하이어라키에서 Scrollbar Horizon도 없애준다.

Scroll View 밑 객체로 Content라는 오브젝트가 있을텐데, 이 공간이 내가 원하는 오브젝트들을 놓을 공간이다.

오브젝트들은 채팅이겠고, 세로로 쭉 이어질 것이기 때문에 Vertical Layout Group속성을 추가해줘서 Padding과 Spacing을 원하는 크기로 조정해준다.

또한 Content Size Fitter를 추가해, 오브젝트가 추가되면 자동으로 Height가 변화되게 위에처럼 설정을 해주면 된다.

다음으로 채팅 오브젝트에 대해 알아보자.

기본적으로 채팅 오브젝트는 이러한 식으로 구성할 예정이다. 채팅의 개수가 3개인 예시이다.

내가 보낸 채팅은 자동적으로 오른쪽으로, 다른 사람이 보낸 채팅은 왼쪽으로 정렬되게 할것이며, 이 형태를 프리팹으로 만들어서 채팅이 추가될 때마다 프리팹을 Instiate하는 방식으로 구현할것이다.

Chat이라는 TextMeshPro 오브젝트를 만들어주며, 이 오브젝트 또한 텍스트의 길이에 따라서 Height가 자동으로 변하게 Content Size Fitter를 넣어준다.

또한 채팅 생성시, 내 채팅인지 아닌지 구분하며,위치를 바꿔줄 스크립트를 만들어 줄 것이다.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
public class Chat : MonoBehaviour
{
    TextMeshProUGUI tmp;
    public void MakeChat(string nickname,string content,bool mine)//내 채팅이면 mine이 true
    {
        tmp = GetComponent<TextMeshProUGUI>();
        if (mine)
        {
            tmp.alignment = TextAlignmentOptions.TopRight;
            nickname = "나";
        }
        tmp.text = nickname + ":\n" + content;
    }
}

이 스크립트를 Chat에 넣어주고, 프리팹화 시켜준다.

 

마지막으로 가장 하단에 있는 메세지 Input Field 와 전송 버튼이다.

 

UI구성은 이렇게 해주고, 이제 서버에 메시지를 보내줄 스크립트를 만들어주자.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using TMPro;
using Firebase;
using Firebase.Database;
using Firebase.Extensions;
using Firebase.Auth;
using UnityEngine.SceneManagement;

public class ChatManager : MonoBehaviour
{
    Firebase.Auth.FirebaseAuth firebaseAuth;
    DatabaseReference databaseReference;
    [SerializeField]Transform scrollviewContent;
    [SerializeField] TMP_InputField msgInputFields; //메시지 인풋 필드
    [SerializeField] TextMeshProUGUI nicknameTmp;
    [SerializeField] GameObject chatPrefeb;
    string myNickname;
    int counter;
    void Start()
    {
        databaseReference = FirebaseDatabase.DefaultInstance.GetReference("chat");
        firebaseAuth = Firebase.Auth.FirebaseAuth.DefaultInstance;
        SetNickname();
        databaseReference.ValueChanged += ValueChanged;   //데이터가 바뀔 때 감지
    }
    void ValueChanged(object data, ValueChangedEventArgs args)
    {      
        if (args.DatabaseError != null)
        {
            Debug.Log(args.DatabaseError.Message);
        }
        else
        {
            counter++; //chat에 하위 데이터가 변화할때 coutner를 늘려준다.
            // 기본적으로 nickname값,content값 두 데이터가 들어와야 채팅을 생성하기에, 2의 배수에만 반응하게 해준다.
            if (counter % 2 == 1) return;         
            FirebaseDatabase.DefaultInstance.GetReference("chat")
             .GetValueAsync().ContinueWithOnMainThread(task =>
             {
                 if (task.IsFaulted)
                 {
                     Debug.Log(task.Exception);
                 }
                 else if (task.IsCompleted)
                 {
                     DataSnapshot snapshot = task.Result;
                     string nickname = snapshot.Child((task.Result.ChildrenCount - 1).ToString()).Child("nickname").Value.ToString();
                     string content = snapshot.Child((task.Result.ChildrenCount - 1).ToString()).Child("content").Value.ToString();
                    //가장 최근 채팅은 채팅 개수-1의 번호를 가지고 있다.
                     bool mychat = false;
                     if (nickname == myNickname) mychat = true; //내 닉네임과 동일하면 나로 인식
                     //만약 닉네임 중복을 허용한다면, UID로 나인지 아닌지를 판단할 수 있음
                     GameObject newChat = Instantiate(chatPrefeb, scrollviewContent);
                     newChat.GetComponent<Chat>().MakeChat(nickname, content, mychat);
                 }
             });

        }
    }

    void SetNickname()
    {//초기에 내 닉네임을 화면에 띄우고, 스크립트에 내 닉네임을 저장하기 위함
        FirebaseDatabase.DefaultInstance.GetReference("user")
          .GetValueAsync().ContinueWithOnMainThread(task =>
          {
              if (task.IsFaulted)
              {
                  Debug.Log(task.Exception);
              }
              else if (task.IsCompleted)
              {
                  DataSnapshot result = task.Result;
                  myNickname= result.Child(firebaseAuth.CurrentUser.UserId).Child("nickname").Value.ToString();
                  nicknameTmp.text = "내 닉네임: " + myNickname;
              }
          });
    }
    public void SendMsg() //서버에 메시지를 보내는 함수
    {
        string content=msgInputFields.text;
        FirebaseDatabase.DefaultInstance.GetReference("chat")
           .GetValueAsync().ContinueWithOnMainThread(task =>
           {
               if (task.IsFaulted)
                {
                   Debug.Log(task.Exception);
               }
               else if (task.IsCompleted)
               {
                   int childCount = (int)task.Result.ChildrenCount;
                   databaseReference.Child(childCount.ToString()).Child("nickname").SetValueAsync(myNickname);
                   databaseReference.Child(childCount.ToString()).Child("content").SetValueAsync(content);
                   //데이터가 바뀌는 작업을 총 두번함.
                   msgInputFields.text = ""; //전송을 하면 인풋필드를 초기화 시켜준다
               }
           }
           );
    }
  
}

 

위 ChatManager를 빈 오브젝트에 넣어주고, [SerializeField] 로 선언한 변수들에 각각 적당한 오브젝트를 넣어주면 된다.


시연 화면

모바일 기기에서

 

 

유니티 빌드 화면에서

 

이런식으로 통신이 가능하며, 2명이상이서 하는 것도 가능하다.

 

이상 유니티와 파이어베이스 데이터베이스를 이용해 채팅앱을 구현해봤다.