23.12.25 TIL - Unity 미니 프로젝트 (3) : AudioListner

JJwoo·2023년 12월 25일
post-thumbnail

🎃 개발 초보자가 메모한 내용이라 틀린 내용이 많을 수 있습니다. 완벽한 정보가 아니니 조심 하십시오. 💀

오늘은 소리 on/off와 점수 계산 기능을 구현하기 위해 힘 썼음.

1. 사운드 On/Off 기능 ( AudioListner 조작 )

일단 전체 음량 OFF 기능 써보기로 했다.


우선 유니티에서 버튼 UI를 하나 만들었고, 놓고 싶은 위치에 배치했다.

그리고 스크립트를 하나 만들고

public void SoundToggle()
    {
        AudioListener.volume = AudioListener.volume == 0 ? 1 : 0;
    }

라는 함수를 입력 해주었다.

AudioListener -> 소리를 듣는 컴포넌트, 보통 플레이어 혹은 카메라에 부착됨

오디오 리스너 볼륨(현재값) =
오디오 리스너 볼륨(변경값) == 0(현재 볼륨이 0인지)

0? 1 : 0 : 삼항 조건 연산자, 볼륨이 0이라면 1을, 그렇지 않으면 0을 선택.

?는 조건이 참일때, :는 조건이 거짓일때 선택됨

한 줄 요약-> 현재 볼륨이 0이라면 1로, 그렇지 않으면 0으로 설정


2. 이미지 버튼 스왑 기능

소리 on/off 기능은 일단 구현이 되었고.. 이제 같은 버튼으로 이미지도 변했으면 좋겠다.

그래서 soundtoggleBtn 이라는 스크립트를 만들어서 밑과 같이 입력

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;


public class soundtoggleBtn : MonoBehaviour
{
    public Sprite[] sprites;  // Sprite 배열을 선언, (0,1) 2가지 상태!
    public bool isClicked; // bool 선언해서 버튼 클릭 여부 확인
    
    // Start is called before the first frame update
    void Start()
    {
        GameObject.Find("soundtoggleBtn").GetComponent<Image>().sprite = sprites[0]; 
        // 시작할때 ON 스프라이트 설정
    }

    // Update is called once per frame
    void Update()
    {
        
    }
    
    public void SoundToggle()
    {
        AudioListener.volume = AudioListener.volume == 0 ? 1 : 0; 
// 현재 오디오 리스너의 볼륨을 토글 볼륨이 0이면 1로, 1이면 0으로 설정

        isClicked = !isClicked;
        if (isClicked) // 클릭시 Image sprite 반전(변경)
        {
            GameObject.Find("soundtoggleBtn").GetComponent<Image>().sprite = sprites[0]; 
            //버튼이 클릭된 상태라면 버튼의 이미지를 ON 상태의 스프라이트로 변경.
        }
        else
        {
            GameObject.Find("soundtoggleBtn").GetComponent<Image>().sprite = sprites[1];
            // 아니면 OFF 상태로 변경
        }
    }
}

soundtoggleBtn에서 soundtoggleBtn 스크립트를 먹여주고

On Click에 위 스크립트 넣어주고 SoundToggle 함수를 연결

마지막으로 사진과 같이 인스펙터에 Sprites 이미지를 On/Off 2종류 추가 해줌.
잊지않고 is Clicked 체크

실행해보니 일단은 잘 된다!

하지만 더 간단한 방법이 없을까..


3. 남은 시간/ 성공 / 실패 / 점수로 환산하는 기능

1. 남은 시간(1) 마다 점수를 + 1, 유니티에서 timescoreTxt 라는 text에 표시되게 하고 싶음.

2. 카드 매칭을 성공했을 때 점수 +10, 유니티에서 matchscoreTxt라는 text에 표시되게 하고 싶음

3. 카드 매칭을 실패했을 때 점수 -1, 유니티에서 failscoreTxt라는 text에 표시되게 하고 싶음

4. 위의 모든 점수 방식을 참조하여, 점수로 환산하고 totalscoreTxt 라는 Text에 표시되게 하고 싶음.

이 놈들을 다 계산한 점수를, 게임 결과 점수판의 각각 만들어둔 Text에 표시 되게 하고 싶었다.

1번부터 예상해보면 시간 관련한 코드 함수에 엮으면 될 것 같고
2,3번은 매칭 관련 함수에,
마지막 종합 4번은 1,2,3 점수를 모아주는 함수를 만들어서 슥삭 마무리하면 될 듯 하다 생각했는데..

웬걸, 오늘도 온종일 들이박았다.


GamaManager 스크립트에

public Text timeScoreTxt;
public Text matchScoreTxt;
public Text failScoreTxt;
public Text totalScoreTxt;

private int timeScore = 0;
private int matchScore = 0;
private int failScore = 0;
private int totalScore = 0;

일단 선언은 했다.


3. 응 시행착오💣

  • 남은 시간당 점수 1점 기능 구현 -> 흐른 시간 당 점수 구현이 되버림!

필드에 private float TimeScoreUpdate = 0f; 선언후

void RunTime 함수 안에
 if (Time.time - TimeScoreUpdate >= 1.0f)
        {
            timeScore++;
            timeScoreTxt.text = "Time Score: " + timeScore.ToString();
            lastTimeScoreUpdate = Time.time;
        }

TimeScoreUpdate 변수를 사용하여 timeScore가 업데이트된 시간 기록,

현재 시간과 비교하여 1초가 경과한 경우에만 timeScore를 증가시키고 텍스트를 업데이트

이렇게 하면 실제로 1초마다 timeScore가 증가

-> 근데 이 방식은 남은 시간이 아니라 시간의 흐름에 따라 점수가 증가하는 시스템이라, 다른 팀원이 만든 실패시 시간이 일정 값 감소되는 스크립트와 호환이 안될 듯 하여..
스크립트 안의 gameTime()이라는 함수가 있으니 그걸 이용해보기로 했다..

  • True 남은 시간 당 점수 구현
void RunTime()으로 돌아와서

if고 

            timeScoreTxt.text = timeScore.ToString();    // 점수 업데이트
            timeScore = Mathf.RoundToInt(gameTime);  // 초당 1점 점수 계산

를 추가해주었다.   (다른 분이 만든 gameTime 함수 이용)

- Mathf ?

유니티의 수학 관련 함수들을 모아둔 클래스,

여기서 'Mathf.RoundToInt'는 소수를 반올림한다는 뜻인데,
gameTime 변수를 반올림해서 timeScore에 저장.
그 값을 문자열로 업데이트.

다행히 잘 작동 됨.

- 성공, 실패 횟수 점수 카운트 기능

Void Match()라는 함수가 이미 있기에

그 안의 if, else if 조건문 등을 통해서

        failScore--;
        failScoreTxt.text = failScore.ToString();  
        // 매칭 실패 시 failScore를 1 감소
        

한다거나

MatchSuccess() 라는 함수를 만들어서

  public void MatchSuccess()
{
    // 매칭 성공 시 matchScore를 10 증가
    matchScore += 10;
    matchScoreTxt.text =matchScore.ToString();

    Time.timeScale = 0;

    nameCard.SetActive(true);
    nameCard.GetComponent<Introduction>().matchName(
        firstCard.transform.Find("Back").GetComponent<SpriteRenderer>().sprite.name);

작동이 되었으면 했는데 안되더라.

튜터 님께도 물어보고 이유가 뭔가 했더니

match에 관한 함수가 2가지였다.

void Match() 와 IEnumerator Match2Co() 함수가 있었는데

void Match() 같은 경우 매칭 시도 횟수와 성공 실패 여부에 따라 gameTime을 조절하는 역할이었고

IEnumerator Match2Co()가 내가 원하는 카드 매칭 코드가 들어간 본체였던거 같다.

public void Match2() //카드 매칭
{
    StartCoroutine(Match2Co());
}

IEnumerator Match2Co()
{
    fullCard = true;
    countTime.SetActive(false);

    yield return new WaitForSeconds(0.8f);
    string firstName = firstCard.GetComponent<Card>().frontImage.GetComponent<Image>().sprite.name;
    string secondName = secondCard.GetComponent<Card>().frontImage.GetComponent<Image>().sprite.name;

    if (firstName == secondName)
    {
        audioSource.PlayOneShot(success);
        Debug.Log("Matched!");

        Destroy(firstCard);
        Destroy(secondCard);
        matchScore += 10; // Card match successful, 10 point
        matchScoreTxt.text = matchScore.ToString();

        Time.timeScale = 0f;
        nameCard.SetActive(true);
        nameCard.GetComponent<Introduction>().matchName(firstName);
    }
    else
    {
        audioSource.PlayOneShot(fail);
        Debug.Log("Not matched!");
        firstCard.GetComponent<Card>().CloseCard();
        secondCard.GetComponent<Card>().CloseCard();

        failCard.SetActive(true);
        Invoke("FailCard", 1f);
        StartCoroutine(PenaltyUi());
        gameTime -= penaltyTime;
        failScore--; // Card matched failed, -1 point
        failScoreTxt.text = failScore.ToString();
    }
    matchCardReset();
    TotalScore();// totalscore
}

그래서
if (firstName == secondName) 의 안에

matchScore += 10; // Card match successful, 10 point
matchScoreTxt.text = matchScore.ToString();

매칭 성공 점수 기능과

바로 밑의 else 안에

failScore--; // Card matched failed, -1 point
failScoreTxt.text = failScore.ToString();

실패 당 -1점 점수를,

마지막으로 조건문 밖에

TotalScore();// totalscore
  • 위의 점수 Total 기능
public void TotalScore()
{
    // timeScore, matchScore, failScore ++ total
    totalScore = timeScore + matchScore + failScore;
    totalScoreTxt.text = totalScore.ToString() + "점";
}

를 추가해주고 점수판도 불러올 수 있게 설정 해보니 잘 된다..

그리고 튜터님이 너무 잘 알려주셔서 감사했고 내가 모르는 부분이 너무 장황하여 죄송했다.

미니 프로젝트가 완성되어 제출하고 나면, 팀원들이 왜 이 코드를 이렇게 짰고 이게 무슨 기능을 하는 건지 다시 공부 해봐야겠다.


오늘의 간단 코드

  • 게임 오버시 등장하는 Panel
public GameObject endPanel; // 종료시 점수판 endPanel 팝업되게 하는 간단한 함수

public void gameOver()
{
    Time.timeScale = 0.0f; // 시간 0초 되면
    endPanel.SetActive(true);   // false 되어있던 점수판 팝업
}

오늘 같은 경우는 게임 종료 패널 팝업 기능을

다른 분이 만든 함수

void RunTime()

if (gameState == GameState.Start)
{
    gameTime -= Time.deltaTime;
    timeText.text = gameTime.ToString("N2");

    if (gameTime <= 0)   //게임 종료
    {
        gameState = GameState.GameOver;
        timeText.text = "0.00";
        Debug.Log("Game Over!");

        endPanel.SetActive(true);   <<<   // 여기다가 넣었다 !
    }
profile
개발 모코코

0개의 댓글