Snow Boarder - 3 (42강-완)

2025. 9. 25. 15:37·유데미/C# Unity 2D

1. 모먼트 튜닝

레벨을 꾸밀 때가 왔다

적당히 귀엽게 꾸몄다...

나무는 귀찮아서 좀 덜 심었긴하다

 

2. FindObjectOfType 사용

우리는 이제껏 GetCompnent를 통해 인스펙터에 있는 걸 사용할 수 있었다.

다른 스크립트나 오브젝트에는 어떻게 접근할까? 바로 FindObjetOfType이다.

이 코드는 장면 안에 해당 대상이 하나만 있을 때 효율적이다

 

우리는 레벨이라는 오브젝트가 하나만 있으므로 Surface Effector 2D도 하나만 존재한다

(이 방법은 해당 대상이 여러 개가 있다면 작동하지 않음)

 

따라서 적당히 작동할 것이다.

그렇다면 먼저 PlayerController스크립트로 간다

SurfaceEffector2D 변수를 하나 만들고 FindObjectOfType을 사용한다(Objects로 된 것도 있으니 주의)

 

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

public class PlayerController : MonoBehaviour
{
    [SerializeField] float torqueAmount = 1f;
    [SerializeField] float boostSpeed = 30f;
    [SerializeField] float baseSpeed = 20f;

    Rigidbody2D rb2d;
    SurfaceEffector2D surfaceEffector2D;
 
    void Start()
    {
        rb2d = GetComponent<Rigidbody2D>();
        surfaceEffector2D = FindObjectOfType<SurfaceEffector2D>();
    }


    void Update()
    {
        RotatePlayer();
        RespondToBoost();
    }

    void RotatePlayer()
    {
        if (Input.GetKey(KeyCode.A))
        {
            rb2d.AddTorque(torqueAmount);
        }
        else if (Input.GetKey(KeyCode.D))
        {
            rb2d.AddTorque(-torqueAmount);
        }
    }

    void RespondToBoost()
    {
        if (Input.GetKey(KeyCode.W))
        {
            surfaceEffector2D.speed = boostSpeed;
        }
        else
        {
            surfaceEffector2D.speed = baseSpeed;
        }
    }
}

이제서야 깨달은건데 인스펙터에 있는 사항들은 .으로 할 수 있는 것 같다

 

3. OnCollisionExit2D 사용하기

OnCollisionEnter2D는 콜라이더를 통과할 때고 나가면 OnCollisionExit2D가 된다

이 게임의 경우 바닥에 붙어있으면 Enter2D고 위로 점프하면 Exit2D가 되는 것이다

다음과 같이 코드를 작성한 후 Barry에 Particle을 만들어 붙여줬다

그리고 적용도 했다!

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

public class DustTrail : MonoBehaviour
{
    [SerializeField] ParticleSystem dustParticles;

    void OnCollisionEnter2D(Collision2D other)
    {
        if (other.gameObject.tag == ("Ground"))
        {
            dustParticles.Play();
        }
    }

void OnCollisionExit2D(Collision2D other)
    {
        if (other.gameObject.tag == ("Ground"))
        {
            dustParticles.Stop();
        }
    }
}

 

4. 사운드 이펙트 적용

사운드 이펙트를 적용하기 위해서는 오디오 리스너가 필요하다

소리를 받아들이는 마이크 같은 것이다(물론 실제는 아님, 어떤 소리가 나는지 듣는 역할)

주로 카메라에 위치하게 된다

또 오디오 소스도 있는데, 장면에서 내고 싶은 소리 크기를 조정하는 것 같은 것이다

오디오 클립은 재생할 소리이다.

 

finish line을 잠깐 캐릭터 옆으로 가져가서 편하게 설정을 조정할 수 있도록 하고

add component를 이용해 Audio Source를 추가한다

Audio Clip이 재생할 소리임으로 Finish SFX를 넣어주면 된다

 

중요한 건 플레이어가 지나갈 때만 소리가 나야하기 때문에 Play on awake(게임 시작시 소리남)을 꺼준다

 

이제 FinishLine 코드에 들어가서

GetComponent<AudioSource>().Play();

을 입력하는데

아직 코드의 의미가 헷갈려서 AI에게 다시 질문해보았다

Unity에서 GetComponent<T>()는 그 오브젝트에 붙어 있는 컴포넌트를 찾아서 가져오는 메서드예요.
🔎 GetComponent<AudioSource>() 의 의미
  • 현재 스크립트가 붙어 있는 GameObject에서
    AudioSource라는 컴포넌트를 찾아서 가져오라는 뜻이에요.
  • 만약 AudioSource가 붙어 있지 않으면 null을 반환해요.
📝 코드 해석
  1. GetComponent<AudioSource>() → 현재 오브젝트에서 AudioSource 컴포넌트 찾기
  2. .Play() → 찾은 AudioSource에 있는 재생 함수 실행
즉, “이 오브젝트에 붙어 있는 오디오 소스를 재생해라” 라는 의미예요.
⚡ 특징 (중요!)
  1. 제네릭 함수
    • <AudioSource> 부분에 다른 컴포넌트를 넣으면 그 컴포넌트를 가져올 수 있어요.
      예: GetComponent<Rigidbody2D>()
  2. 실행 중에 탐색
    • Unity가 그 오브젝트 안에서 컴포넌트를 찾아줘요.
    • 하지만 자주 호출하면 성능에 부담이 될 수 있어요 (매 프레임 호출은 비효율적).
  3. 자주 쓰는 패턴
  4. AudioSource audio; void Start() { audio = GetComponent<AudioSource>(); // 미리 찾아두기 } void Update() { if (Input.GetKeyDown(KeyCode.Space)) audio.Play(); // 매번 GetComponent 안 써도 됨 }
👉 정리하자면,
코드 GetComponent<AudioSource>().Play();는
“현재 게임오브젝트에 붙은 오디오 소스를 찾아서, 그걸 바로 재생한다” 라는 뜻이에요.


정리하자면 GetComponent는 <> 안에 있는 걸 가져오는 제네릭 함수라는 것이고,

바로 .Play()를 붙이면 이걸 재생하라는 뜻 같다.

 

좀 더 복잡하게 한다면 캐릭터의 상호작용에 따라 소리를 다르게 할 건데,

add Component로 일단 Auido Source를 추가한다음에... 바로 재생할 소리를 넣진 않는다

왜냐면 때에 따라서 (충돌시에, 달릴 때 등) 소리가 다르게 나기 때문에

코드를 통해 바꿔야한다.

 

 [SerializeField] float loadDelay = 0.5f;
    [SerializeField] ParticleSystem crashEffect;
    [SerializeField] AudioClip crashSFX;
    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.tag == "Ground")
        {
            crashEffect.Play();
            GetComponent<AudioSource>().PlayOneShot(crashSFX);
            Invoke("ReloadScene", loadDelay);
        }
    }

중요한 건 형광펜 쳐져있는 추가된 코드인데,

먼저 SerializeField를 통해 AuidoSource를 집어넣을 수 있는 공간을 만들고

GetComponet와 PlayOneShot(Play와 유사)를 통해 crashSFX를 가져온다

 

...

근데 쓰면서도 모르겠는게 많아서 다시 물어봤다

🎵 사운드 크기(볼륨) 조정하는 방법

Unity에서 오디오 볼륨은 AudioSource나 AudioClip 재생 시점에서 조정할 수 있어요.
  1. AudioSource 자체 볼륨 조절
    → 이 AudioSource를 통해 나는 모든 소리에 적용돼요.
  2. PlayOneShot 시 개별 볼륨 조절
    → 이 한 번의 효과음에만 적용돼요.
    → 예: 부드럽게 나야 하는 효과음은 0.3f, 크게 나야 하는 건 1.0f로 조절.

🤔 왜 AudioClip을 따로 두고 PlayOneShot을 쓰나요?

  1. 여러 사운드를 상황별로 재생할 수 있어서
    • 예: jumpSFX, crashSFX, boostSFX … 다 다른 클립으로 재생 가능
    • 오브젝트에 AudioSource 하나만 붙여도 다양한 효과음 재생 가능해요.
  2. 소리가 겹쳐서 동시에 나올 수 있어서
    • AudioSource.Play()는 재생 중이면 덮어쓰기 돼요. (소리가 끊김)
    • PlayOneShot()은 이미 소리가 나고 있어도 겹쳐서 같이 재생 가능해요.
    • 예: 연속 충돌, 총알 발사 소리 같은 경우에 유용하죠.
  3. AudioSource에 고정하지 않고 유연하게 관리
    • AudioSource에 직접 Clip을 넣으면, 한 종류의 소리만 재생 가능.
    • 지금처럼 Clip을 변수로 받아두면, 코드에서 상황에 맞게 바꿀 수 있음.
👉 정리하자면,
  • 볼륨 조절은 AudioSource.volume이나 PlayOneShot(clip, volumeScale)로 할 수 있어요.
  • AudioClip을 따로 두고 PlayOneShot을 쓰는 이유는
    • 다양한 소리를 상황별로 쉽게 재생할 수 있고
    • 소리가 겹쳐도 끊기지 않게 하기 위함이에요.

 

5. 공용 액세스 한정자 public (퍼블릭 액세스 모디파이어)

게임을 플레이해보면 알겠지만 머리를 부딪힌 다음에도 사실 움직일 수 있다...

우선 이걸 막아보자 (대충 부딪히면 이제 못 움직인다는 console)

 

기본적으로 private이기때문에 private는 이제껏 쓰지 않고 지워왔었는데, 

private를 설명하자면 그 중괄호 밖에서는 안의 것을 사용할 수 없게 된다

반면 완전 밖에서 설정하면 어디서든 사용할 수 있었다

public을 붙이면 private와는 다르게 밖에서도 컨트롤할 수 있게 된다 (다른 스크립트나 클래스에서 건들일 수 있다)

그리고 inspector에서 조회도 가능하다! (SerializedField랑 비슷)

그치만 그렇게 하지 않은 이유는 다른 스크립트/클래스에서 수정 가능하다는 건, 실수가 일어날 가능성도 높기 때문이다

 

6. 멀티 플레이 막기 (효과 겹침 막기)

5번과 동일하게 가면 된다...

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class CrashDetector : MonoBehaviour
{
    [SerializeField] float loadDelay = 0.5f;
    [SerializeField] ParticleSystem crashEffect;
    [SerializeField] AudioClip crashSFX;
    bool hasCrashed = false;

    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.tag == "Ground" && !hasCrashed)
        {
            FindObjectOfType<PlayerController>().DisableControls();
            crashEffect.Play();
            GetComponent<AudioSource>().PlayOneShot(crashSFX, 0.3f);
            Invoke("ReloadScene", loadDelay);
        }
    }

    void ReloadScene()
    {
        SceneManager.LoadScene(0);
    }
}

 

'유데미 > C# Unity 2D' 카테고리의 다른 글

Quiz Master - 2 (7강- 완 )  (0) 2025.11.06
Quiz Master - 1 (1강 - 6강)  (0) 2025.10.28
Snow Boarder - 2 (35-41강)  (1) 2025.08.31
Snow Boarder - 1 (29-34강)  (0) 2025.08.22
Delivery Driver - 3 (21-강의 완)  (3) 2025.08.20
'유데미/C# Unity 2D' 카테고리의 다른 글
  • Quiz Master - 2 (7강- 완 )
  • Quiz Master - 1 (1강 - 6강)
  • Snow Boarder - 2 (35-41강)
  • Snow Boarder - 1 (29-34강)
피까츄
피까츄
프로그래밍 마스터가 될테야
  • 피까츄
    프로그래밍 마스터
    피까츄
  • 전체
    오늘
    어제
    • 분류 전체보기 (87)
      • 컴퓨터가 이상해요 모음집 (5)
      • 프로그래밍 (0)
      • 회고 (1)
      • 1학년 (21)
        • 명품 HTML+CSS+JS (10)
        • 쉽게 배우는 C언어 Express (2)
        • R언어 (9)
      • 2학년 (3)
        • C언어로 쉽게 풀어쓴 자료구조 (1)
        • 프로그래밍 언어론 (2)
      • 개인공부 (25)
        • 백준 (17)
        • 코드트리 JS (7)
        • 코테 공부 (1)
      • 챌린지 (1)
        • Do it C++ 코테 6주 챌린지 (1)
      • 교재 (14)
        • 이것이 C++이다 (3)
        • 이것이 JAVA다 (0)
        • 혼자 공부하는 컴퓨터구조 + 운영체제 (1)
        • 혼자 공부하는 데이터통신 (0)
        • 코어 자바스크립트 (8)
        • OpenGL로 배우는 3차원 컴퓨터 그래픽스 (2)
      • 유데미 (11)
        • 100일 코딩 챌린지 (3)
        • C# Unity 2D (8)
      • 기타 (0)
        • 24주 게임 프로그래밍 챌린지 (5)
  • 블로그 메뉴

    • 방명록
    • 그림블로그
    • 3D 블로그
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    복습
    작업표시줄클릭안됨
    0x80370102오류코드
    vscode자동완성
    프로그래밍언어론
    가상현실 설정
    js #자바스크립트_기초
    the package javax.swing is not accessible
    HTML5+CSS3+Javascript 웹 프로그래밍 #연습문제 #이론문제 #실습문제 #풀이 #정답
    우분투C
    우분투java
    윈도우 기능 켜기
    우분투 설치 오류
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
피까츄
Snow Boarder - 3 (42강-완)
상단으로

티스토리툴바