파티클 생성

플레이어 하위에 Effects - Particle System을 생성한다.

 

적당히 꾸며준다.

  • Duration : 얼마나 실행할 것인가
  • Looping : 반복 실행
  • Start Lifetime : 생존 시간
  • Start Speed : 시작 속도
  • Start Size : 파티클 사이즈
  • Simulation Space : 어느 곳에서 애니메이션화할지(오브젝트, 월드, 커스텀 등)

Emission

  • Rate over Time : 시간 당 방출량

Shape

  • Shape : 방출 모양
  • Radius : 뿜어져 나오는 범위

Limit Velocity over Lifetime

  • Speed : 파티클 속도
  • - Dampen : 감소 속도, 저항

Color over Lifetime : 생존 동안의 색상 변화Size over Lifetime : 생존 동안의 크기 변화

Collision

  • Dampen : 감소 속도, 저항
  • Bounce : 탄성

Renderer

  • Material : 재질
  • Order in Layer : 레이어 순서

 

스크립트를 만들어 플레이어가 움직일 때마다 생성되도록 애니메이터가 있는 공간에 달아준다.

[SerializeField] private bool createDustOnWalk = true;
    [SerializeField] private ParticleSystem dustParticleSystem;

    public void CreateDustParticles()
    {
        if (createDustOnWalk)
        {
            dustParticleSystem.Stop();
            dustParticleSystem.Play();
        }
    }

 

동작할 때마다 파티클을 달아줄 애니메이션을 선택하여 Animation Event를 달아준다. 애니메이션 이벤트는 같이 설정되어있는 곳에 애니메이션이 있어야 호출할 수 있다.

 

투사체 소멸 효과도 만들어준다. 파티클을 만들어서 달아준 뒤, ProjectileManager에 스크립트를 추가한다.

투사체가 적이나 벽에 닿았을 때, 파티클이 터지는 코드인데 이 부분은 솔직히 이해 못해서 다시 봐야할 것 같다.

public void CreateImpactParticlesAtPostion(Vector3 position, RangedAttackData attackData)
{
    _impactParticleSystem.transform.position = position;
    ParticleSystem.EmissionModule em = _impactParticleSystem.emission;
    em.SetBurst(0, new ParticleSystem.Burst(0, Mathf.Ceil(attackData.size * 5)));
    ParticleSystem.MainModule mainModule = _impactParticleSystem.main;
    mainModule.startSpeedMultiplier = attackData.size * 10f;
    _impactParticleSystem.Play();
}

 

원거리 투사체 스크립트 부분도 수정한다.

private void DestroyProjectile(Vector3 position, bool createFx)
{
    if (createFx)
    {
        _projectileManager.CreateImpactParticlesAtPostion(position, _attackData);
    }
    gameObject.SetActive(false);
}

 

 

사운드 컨트롤

사운드 매니저 스크립트를 만든다.

싱글톤화 시킨 후, 사운드 이펙트에 맞춘 볼륨, 이펙트 볼륨, 배경음악 볼륨과 오브젝트 풀, 오디오소스와 실제로 오디오를 가지고 있는 오디오클립을 준비한다.

public static SoundManager instance;

    [SerializeField][Range(0f, 1f)] private float soundEffectVolume;
    [SerializeField][Range(0f, 1f)] private float soundEffectPitchVariance;
    [SerializeField][Range(0f, 1f)] private float musicVolume;
    private ObjectPool objectPool;

    private AudioSource musicAudioSource;
    public AudioClip musicClip;

    private void Awake()
    {
        instance = this;
        musicAudioSource = GetComponent<AudioSource>();
        musicAudioSource.volume = musicVolume;
        musicAudioSource.loop = true;

        objectPool = GetComponent<ObjectPool>();
    }

    private void Start()
    {
        ChangeBackGroundMusic(musicClip);
    }

    public static void ChangeBackGroundMusic(AudioClip music)
    {
        instance.musicAudioSource.Stop();
        instance.musicAudioSource.clip = music;
        instance.musicAudioSource.Play();
    }

    public static void PlayClip(AudioClip clip)
    {
        GameObject obj = instance.objectPool.SpawnFromPool("SoundSource");
        obj.SetActive(true);
        SoundSource soundSource = obj.GetComponent<SoundSource>();
        soundSource.Play(clip, instance.soundEffectVolume, instance.soundEffectPitchVariance);
    }

 

SoundSource는 사운드 클립을 컨트롤 하기 위해 만든 것이다. Play를 걸면 해당 클립을 설정한 볼륨과 피치로 재생시킨다. Invoke는 지연 실행으로, 노래가 끝난 2초 뒤에 끝낸다.

private AudioSource _audioSource;

    public void Play(AudioClip clip, float soundEffectVolume, float soundEffectPitchVariance)
    {
        if (_audioSource == null)
            _audioSource = GetComponent<AudioSource>();

        CancelInvoke();
        _audioSource.clip = clip;
        _audioSource.volume = soundEffectVolume;
        _audioSource.Play();
        _audioSource.pitch = 1f + Random.Range(-soundEffectPitchVariance, soundEffectPitchVariance);

        Invoke("Disable", clip.length + 2);
    }

    public void Disable()
    {
        _audioSource.Stop();
        gameObject.SetActive(false);
    }

 

유니티에서 SoundManager와 SoundSource를 만들어준 뒤, 각각 스크립트를 연결시킨다.

SoundSource에 Audio Source를 달아주고 프리팹화 시킨다. SoundManager 역시 Audio Source와 배경음악을 달아준다.

 

Shooting 소리나 데미지를 입었을 때 등 효과음을 넣어주기 위해 스크립트에 AudioClip을 부른 뒤, 해당 조건에 재생되도록 한다.

public AudioClip shootingClip;

----------------- 생략 ----------------- 
if (shootingClip)
        SoundManager.PlayClip(shootingClip);

 

 

UI

UGUI를 사용하여 UI를 구현하기 위해 Canvas를 생성하고 Scale을 Scale With Screen Size로 바꿔준 뒤, 16:9로 변경한다. Scale With Screen Size 화면이 커질수록 UI 요소도 커져서 멀티 해상도에 대응이 가능하다. 반대로 Constant Physical Size는 화면 크기와 해상도에 관계없이 UI 요소가 동일한 물리적인 크기로 유지된다.

 

UI 배치는 큰 묶음과 앵커에 신경쓰면 좋다.

앵커를 기준으로 크기와 좌표를 정한다.

현재 앵커가 중앙에 걸려있으므로 화면 사이즈가 변할 때, 중앙을 기준으로 위치가 유지된다.

 

Wave를 띄우기 위해 Canvas 하위에 빈 오브젝트를 생성해서 image를 추가하여 앵커로 위치를 조정한다.

 

생성한 캔버스를 꽉 채우기 위해서는 alt + 클릭으로 stretch를 선택하면 된다.

 

UI를 적당히 꾸며준 뒤, UI를 처리하는 스크립트를 GameManager에서 처리한다.

플레이어의 체력을 불러와서 %로 계산해준 뒤, Silder UI에 반영한다.

GameOver가 되면 GameOver UI가 실행되도록 하고, 버튼을 눌렀을 때 각각 게임 Scene화면을 다시 불러오고 어플리케이션을 종료시킨다. 예전에는 Application.LoadScene로 씬을 불러왔는데 이제는 사용되지 않기 때문에 SceneManager로 build Setting에 걸려있는 인덱스 번호로 불러온다.(Scene 이름으로 불러올 수도 있다.)

using TMPro;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

private HealthSystem playerHealthSystem;

[SerializeField] private TextMeshProUGUI waveText;
[SerializeField] private Slider hpGaugeSlider;
[SerializeField] private GameObject gameOverUI;

private void Awake()
{
    instance = this;
    Player = GameObject.FindGameObjectWithTag(playerTag).transform;

    playerHealthSystem = Player.GetComponent<HealthSystem>();
    playerHealthSystem.OnDamage += UpdateHealthUI;
    playerHealthSystem.OnHeal += UpdateHealthUI;
    playerHealthSystem.OnDeath += GameOver;

    gameOverUI.SetActive(false);
}

private void UpdateHealthUI()
{
    hpGaugeSlider.value = playerHealthSystem.CurrentHealth / playerHealthSystem.MaxHealth;
}

private void GameOver()
{
    gameOverUI.SetActive(true);    
}

private void UpdateWaveUI()
{
    // waveText.text = 
}

public void RestartGame()
{
    SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}

public void ExitGame()
{
    Application.Quit();
}

 

유니티로 돌아와서 GameManager와 버튼에 필요한 것들을 연결해준다.

 

 

'부트캠프 > Study' 카테고리의 다른 글

<Unity> UI  (0) 2023.12.14
<Unity> 숙련 - 2D 게임 개발(8)  (0) 2023.12.13
<Unity> 숙련 - 2D 게임 개발(6)  (1) 2023.12.12
ToString() 메서드  (1) 2023.12.11
<Unity> 숙련 - 2D 게임 개발(5)  (0) 2023.12.10

+ Recent posts