유니티 게임 프로젝트 5주차 작업 기록

박서영·2026년 2월 27일

2월 13일 작업로그

작업 현황

  1. 플레이어 식별화
  2. 플레이어 충돌 및 튀는 현상 제거

1. 플레이어 식별화

  • 플레이어 자기 자신을 구분하기 위해 닉네임 녹색으로 변경
  • PlayerController.cs에서 기존 색 설정하는 코드에서 PhotonView가 자기자신이면 초록색으로 변경하도록 설정
  • 아래에 ApplyKillerNameRed() 메소드에서 플레이어 이름 검정으로 설정하면 덮어쓰게돼서 해당 코드 삭제
    void Start()
        {
            ...
    
            if (photonView.Owner != null)
            {
                playerNameText.text = photonView.Owner.NickName;
                playerNameText.color = Color.black; //일반적으로는 검정색 설정
            }
    
            #region 맵 테스트용 임시 코드
            if (photonView.IsMine)
            {
                playerNameText.color = Color.green; //여기서 자기자신이면 초록색 설정
                CameraFollow cam = Camera.main.GetComponent<CameraFollow>();
                if (cam != null)
                {
                    cam.target = this.transform;
                }
    
                // 혹시 모르니 Start()에서 IsDead false로 저장.
                Hashtable startProps = new Hashtable();
                startProps.Add("IsDead", false);
                PhotonNetwork.LocalPlayer.SetCustomProperties(startProps);
            }
            #endregion
    
            ApplyKillerNameRed(); // 시작할 때 직업이 있을 수 있으니 여기서도 체크
        }
    void ApplyKillerNameRed()
        {
            object jobValue;
            if (photonView.Owner.CustomProperties.TryGetValue("Job", out jobValue))
            {
                string job = (string)jobValue;
    
                if (job == "Killer" && photonView.IsMine)
                {
                    playerNameText.color = Color.red; // 킬러면 빨간색
                }
                //일반인 닉네임 검정색 설정은 다른데에서 해서 + 초록색 설정 안 덮어쓰도록 이 부분은 삭제함
            }
        }
    

2. 플레이어 충돌 및 튀는 현상 제거

  • 어떻게 해결할까 고민을 했는데 애초에 플레이어를 그냥 겹치게하고, 충돌하지 않게 처리할거라, Player라는 레이어를 만들어 두 레이어 간의 물리 충돌을 꺼주어 충돌 자체를 막아버리고 → 이에 따라 충돌하지 않아서 포톤 등 네트워크 동기화 시에 튀는 현상이 없도록 하였다…
  • Player와 Player 간의 물리 충돌은 감지하지 않도록 처리
  • 이렇게 해서 해결이 안되면 다른 방법을 생각했어야했는데, 다행히도 문제가 없어서 플레이어 프리팹 Player(main)에 레이어를 Player로 설정하는 걸로 간단하게 해결이 됐음.
  • 대신에 메인씬에서도 Player라는 레이어를 추가해줘야하긴한다.. ⇒ 이거는 충돌 안나게 잘 처리해서 올려야 할듯함.

2월 14일 작업로그

작업 로그

  1. 게임 방법 초안 작업
  2. 사운드 작업

1. 게임 방법 초안 작업

UI 작업

  • 캔버스 아래에 패널 하나 만들어서 TMP로 게임 방법 쭉 작성하고 스크롤 할 수 있게 ScrollView 아래에 자식요소로 작성
  • 게임 방법 타이틀 + 닫는 창은 스크롤뷰 밖으로 빼서 고정되도록 작업
  • 좌우 스크롤바는 안보이게 삭제해버림
  • Scroll View Content에 Vertical Layout과 Contet Size Fitter 컴포넌트 추가해서 알아서 자식 요소들이 세로로 쌓이고, 너비나 높이가 크기에 맞게 잘 조절되도록 설정.

TMP 에셋 생성

  • 게임 방법에 들어갈 키(E키/ 스페이스 키)나 클릭 버튼 등을 TMPro의 Sprite Asset으로 만들어 타이핑 중간에 들어가도록 함

TitleUI.cs 스크립트 편집

  • 게임 방법 패널을 인스펙터에서 연결하고자 그냥 필드에 둠
  • 메소드 껍데기만 있던 부분에 패널을 키는 부분과, 초기화(Start()) 부분에 패널을 디폴트로는 꺼두는 스크립트 작성
  • 닫기 버튼 누를 때 호출할 패널 닫는 메소드도 해당 스크립트에 작성
  • Update() 메소드는 불필요한 것 같아서 삭제해둠
public class TitleUI : MonoBehaviour
{
    [Header("UI 연결")]
    [SerializeField] public GameObject gameRulePanel;

    void Start()
    {
        if (gameRulePanel != null) gameRulePanel.SetActive(false);
    }
    public void GoConnect()
    {
        SceneManager.LoadScene("Scene_Connect");
    }

    public void GoHowTo()
    {
        gameRulePanel.SetActive(true);
    }

    public void OffRulePanel()
    {
        gameRulePanel.SetActive(false);
    }
}
  • 이후에 인스펙터에서 캔버스 안에있는 RulePanel을 끌어다가 연결시켜주고, 닫기 버튼과 게임 방법 버튼의 OnClick 시의 액션에 TitleUI 오브젝트의, 해당 스크립트에 관련된 메소드가 실행되도록 연결.

⇒ 전체 테스트는 타이틀씬 복사해서 새로 판 씬에서 진행했고, RulePanel을 포함한 캔버스 자식 요소를 프리팹화해두고 나중에 타이틀씬의 캔버스 아래 자식 요소를 이 프리팹을 갈고 RulePanel 인스펙터에서 연결하고 버튼 클릭 이벤트 발생 시 호출 메소드만 잘 연결하면 진짜 타이틀씬에다가 연결도 끝. 결과물은 아래 사진.

2. 사운드 작업

  • 일단 사운드 파일을 Audio 폴더에 다 몰아서 넣고 유튜브에서 사운드 넣을 때는 SFXPlay() 메소드에 매개변수로 사운드 이름 + 사운드 AudioClip을 전달해서 재생했는데 이렇게 하면 그때그때 필요한 곳에서 이 함수에 인자만 잘 전달하면 편할 것 같아서 이걸 쓰려고함
  • 근데 작업하다 보니까 AudioClip을 각각 쓰는 곳에서 인스펙터에 연결해줘야하는 불편함이 생김 ⇒ 맨 처음 작업한게 FurnitureBox에서 서랍 열릴 때 나는 소리 붙이려고 했는데 그러면 최악에는 가구 인스펙터 마다 이걸 붙이고 있어야함
  • 그래서 결국은 딕셔너리 만들어서 string, audioclip을 매핑하는 방식을 생각하게됨. 이러면 매개변수로 string만 전달하면 되니까 필요한 데에서 소리 이름만 잘 적어주면 됨 → 이것도 조금 귀찮긴한데 현 상황에서 이게 제일 베스트.
  • 그런데 여기서 또 다른 의문은 이 딕셔너리 처음 초기화는 어떻게해야하는지? ⇒ 이걸 AI한테 물어봤더니 ScriptableObject로 만들라고해서 결국 작업 방식으로 결정.
  • ScriptableObject를 만들어서 리스트로 string + audioclip을 여기서 먼저 매핑
  • 이거 있으면 그때그때 여기서 찾아서 쓰면 되지 않나? 생각이 들어서 AI한테 딕셔너리 안만들고 이거 가져다 쓰면 되지 않냐고 했더니 시간복잡도 + 저거는 리스트고 이걸 딕셔너리로 만들면 string으로 바로 찾아 쓰는거니까 코드도 더 간결해짐 ⇒ 근데 SO에서 그럼 리스트가 아니라 딕셔너리를 만들면 안되나? 하는 의문이 이걸 적으면서 갑자기 들었다..흠
  • 위와 같이 작업해서 SoundManager 스크립트 초기화 (Awake)에 싱글톤으로 만들어주고 저 리스트를 딕셔너리로 만드는 것까지 추가해줬다.
using UnityEngine;
using System.Collections.Generic;

public class SoundManager : MonoBehaviour
{
    public static SoundManager instance;

    [Header ("사운드 연결")]
    [SerializeField] private SoundDataSO soundDataSO;
    private Dictionary<string, AudioClip> sfxDictionary = new Dictionary<string, AudioClip>();
    private AudioSource audioSource;

    private void Awake()
    {
        if (instance == null)
        {
            instance = this;
            audioSource = GetComponent<AudioSource>();
            DontDestroyOnLoad(instance);
        }
        else
        {
            Destroy(gameObject);
        }

        if (soundDataSO != null)
        {
            foreach (var entry in soundDataSO.soundEntries)
            {
                if (!sfxDictionary.ContainsKey(entry.name))
                {
                    sfxDictionary.Add(entry.name, entry.clip);
                }
            }
        }
    }

    public void SFXPlay(string sfxName)
    {
        if (sfxDictionary.TryGetValue(sfxName, out AudioClip clip))
        {
            audioSource.PlayOneShot(clip);
        }
        else
        {
            Debug.Log("Audio Clip이 없음");
        }
    }
}
  • SFXPlay는 이제 그때그때 필요한 곳에서, 예를 들면 버튼 클릭할 때 실행하는 메소드에서 ButtonClick 문자열만 전달해서 호출해주면 클릭 소리가 나는 식으로 사용할 수 있게 해두었다.

⇒ 문제는 플레이어 걸음 소리는 이렇게 처리가 안된다. 지금 생각으로는 State+애니메이션 관련 코드가 있으니까 거기에 잘 묶어서 처리하고…? 다른 플레이어 걸음 소리 문제도 있으니까 아마 PlayerController.cs 스크립트를 건드려야할 것 같다… 이건 추후에 작업

  • 현재 전체 씬에 연결된 클릭 관련 코드를 보면서 타이틀씬, 접속씬, 로비씬에 있는 버튼 관련 메소드 앞쪽에 SoundManager.instance.SFXPlay("ButtonClick");을 호출하도록 코드를 추가해놨고… 이건 그냥 단순반복노동..
  • 조합대에서 조합하기 클릭할 때도 버튼 클릭음 + 조합하는 소리 SFXPlay 호출하도록 설정 완료.
  • 인게임씬 가구 여는 소리는 작업 완료. ⇒ 이거는 코드가 그래도 잘 짜져있어서? 한 줄만 추가해서 다 처리할 수 있어서 좋았다.
  • 인게임씬 살인자가 스킬 쓸 때 나는 소리 작업 완료.
  • 인게임씬 조합된 아이템 드랍될 때 소리 작업 완료.
  • 폭죽 사용할 때 날 소리 작업 완료. ⇒ 이거 코드가 어디있는지 찾아야함 ⇒ 라고 생각해보니 이미 찾아서 붙여놨었다… 흠

해야할 작업

  • 인게임씬 버튼 클릭은 아직 작업 미완료.
  • 플레이어 죽을 때 날 소리 작업 미완료.
  • 투표 타이머 임박 소리 작업 미완료.
  • 하고 후에 게임 설정 관련해서 기획 + 구현하기ㅣ..

2월 15일 작업로그

1. 플레이어 발걸음 소리 작업

  • 플레이어 애니메이션에서 상하좌우 이동 모션마다 한 부분 씩 이벤트 연결 PlayFootStep() 함수를 연결
  • PlayerController.cs에 PlayFootStep 메소드를 작성해서 SoundManager.cs에 있는 딕셔너리의 Walking 소리 파일을 재생하도록 작업
public void PlayFootStep()
    {
        Dictionary <string, AudioClip> sfxDictionary = SoundManager.instance.sfxDictionary;

        if (sfxDictionary.TryGetValue("Walking", out AudioClip clip))
        {
            myAudioSource.Stop();
            myAudioSource.clip = clip;
            myAudioSource.Play();
        }
    }
  • 이때 사운드를 재생하기 위해 플레이어 프리팹에 AudioSource 컴포넌트를 추가하고 PlayerController.cs의 초기화(Awake()) 부분에서 해당 컴포넌트를 가져올 수 있도록 코드를 추가함
private AudioSource myAudioSource;

void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        spriteRenderer = GetComponent<SpriteRenderer>();
        myAudioSource =GetComponent<AudioSource>();
    }

회고
이때가 아마 각자 작업이 조금씩 밀려있었고...? 조금 번아웃? 올 느낌의 시기라 다들 바쁘고 일주일정도 쉬어가는 시간을 가지자고 했던 때여서 12일 목요일에 회의를 진행하고 그 전까지는 쉬었었다. 그런데 사실 팀원 다들 안 쉬고 각자 밀린 작업을 거의 완성시켜 와서 엄청 감사했던 주차..하하.:D 그리고 쉬면서 재정비하고 할 일도 싹 정리해서 최종 완성까지 해야할 일들을 정리할 수 있어서 며칠 쉬고 진행하는 선택이 정말 나쁘지 않은 선택이었던 것을 알 수 있었다. 애초에 완성까지 할 일이 그렇게 많이 남지 않아서 쉰다는 결정을 할 수 있었던 것도 있긴하다...

profile
이불 밖은 위험해.

0개의 댓글