[패스트캠퍼스 수강 후기] 올인원 패키지 : 유니티 포트폴리오 완성 100% 환급 챌린지 40회차 미션 시작합니다.

04. 배틀로얄 - 25, 26 번을 진행합니다.




저번 시간에 이어 ThirdPersonOrbitCam 스크립트를 지속 작성합니다.

우선 Unity Script의 이벤트 함수 실행 순서는 반드시 숙지해야 하는 내용입니다.

Unity 매뉴얼 최신 URL은 다음과 같습니다.

docs.unity3d.com/kr/2020.2/Manual/ExecutionOrder.html

 

이벤트 함수의 실행 순서 - Unity 매뉴얼

Unity 스크립트를 실행하면 사전에 지정한 순서대로 여러 개의 이벤트 함수가 실행됩니다. 이 페이지에서는 이러한 이벤트 함수를 소개하고 실행 시퀀스에 어떻게 포함되는지 설명합니다.

docs.unity3d.com

 

그래도 정리된 Flowchart를 첨부합니다. 정리가 아주 죽입니다. ㅎㅎ



일단 Camera의 위치가 어떻게 위치하게 되는지 Update() 함수를 임시로 작성하여 확인해 봅니다.
위와 같이 작성후 플레이를 해보면 다음과 같이 오른쪽 어깨 위쯤에서 약간 위를 보는 듯한 시선으로 처리되는 것을 확인할 수 있습니다.



Update() 내용은 모두 지우고 ThirdPersonOrbitCam 스크립트를 계속 작성합니다.


[RequireComponent(typeof(Camera))] // Camera 컴포넌트 있어야 구동.
public class ThirdPersonOrbitCam : MonoBehaviour
{
    // 저번 시간 작성한 변수들..
    
    private void Awake() {
        // 캐싱
        cameraTransform = transform;
        myCamera = cameraTransform.GetComponent<Camera>();
        // 카메라기본 포지션 세팅
        cameraTransform.position = player.position + Quaternion.identity * pivotOffset + Quaternion.identity * camOffset;
        cameraTransform.rotation = Quaternion.identity;
        
        // 카메라의 플레이어간의 상대 벡터, 충돌체크에 사용하기 위함
        relCameraPos = cameraTransform.position - player.position;
        relCameraPosMag = relCameraPos.magnitue - 0.5f; // 플레이어 충돌을 피하기 위한 Offset
        
        // 기본 세팅
        smoothPivotOffset = pivotOffset;
        smoothCamOffset = camOffset;
        defaultFOV = myCamera.fieldOfView;
        angleH = player.eulerAngles.y;
        
        ResetTargetOffsets();
        ResetFOV();
        ResetMaxVerticalAngle();
    }
    
    public void ResetTargetOffsets() {
        targetPivotOffset = pivotOffset;
        targetCamOffset = camOffset;
    }
    
    public void ResetFOV() {
        targetFOV = defaultFOV;
    }
   
    public void ResetMaxVerticalAngle() {
        targetMaxVerticalAngle = maxVerticalAngle;
    }
    
    public void BounceVertical(float degree) {
        recoilAngle = degree;
    }
    
    public void SetTargetOffset(Vector3 newPivotOffset, Vector3 newCamOffset) {
        targetPivotOffset = newPivotOffset;
        targetCamOffset = newCamOffset;
    }
    
    public void SetFOV(float customFOV) {
        targetFOV = customFOV;
    }
    
    bool ViewingPosCheck(Vector3 checkPos float deltaPlayerHeight) {
        Vector3 target = player.position + (Vector3..up * deltaPlayerHeight);
        if (Physics.SphereCast(checkPos, 0.2f, target - checkPos, out RaycastHit hit, relCameraPosMag)) {
            if (hit.transform != player && !hit.transform.GetComponent<Collider>().isTrigger)
                return false;
        }
        return true;
    }
    
    bool ReverseViewingPosCheck(Vector3 checkPos, float deltaPlayerHeight, float maxDistance) {
        Vector3 origin = player.position + (Vector3.up * deltaPlayerHeight);
        if (Physics.SphereCast(origin, 0.2f, checkPos - origin, out RaycastHit hit, maxDistance) {
            if (hit.transform != player & hit.transform != transform && !hit.transform.GetComponent<Collider>().isTrigger)
                return false;
        }
        return true;
    }
    
    bool DoubleViewingPosCheck(Vector3 checkPos, float offset) {
        float playerFocusHeight = player.GetComponent<CapsuleCollider>().height * 0.75f;
        return ViewingPosCheck(checkPos, playerFocusHeight) && ReverseViewingPosCheck(checkPos, playerFocusHeight, offset);
    }
   
    void Update() {
        // 마우스 이동 값..
        angleH += Mathf.Clamp(Input.GetAxis("Mouse X"), -1f, 1f) * horizontalAimingSpeed;
        angleV += Mathf.Clamp(Input.GetAxis("Mouse Y"), -1f, 1f) * verticalAimingSpeed;
        // 수직 이동 제한
        angleV = Mathf.Clamp(angleV, minVerticalAngle, targetMaxVerticalAngle);
        // 수직 카메라 바운스
        angleV = Mathf.LerpAngle(angleV, angleV + recoilAngle, 10f * Time.deltaTime);
        
        // 카메라 회전
        Quaternion camYRotation = Quaternion.Euler(0.0f, angleH, 0.0f);
        Quaternion aimRotation = Quaternion.Euler(-angleV, angleH, 0.0f);
        cameraTransform.rotation = aimRotation;
        
        // Set FOV
        myCamera.fieldOfView = Mathf.Lerp(myCamera.fieldOfView, targetFOV, Time.deltaTime);
        
        Vector3 baseTempPosition = player.position + camYRotation * targetPivotOffset;
        Vector3 noCollisionOffset = targetCamOffset; // 조준할 때 카메라의 오프셋값, 조준할때와 평소때가 다르다.
        for (float zOffset = targetCamOffset.z; zOffset <= 0f; zOffset += 0.5f) {
            noCollisionOffset.z = zOffset;
            if (DoubleViewingPosCheck(baseTempPosition + aimRotation * noCollisionOffset, Mathf.Abs(zOffset)) || zOffset == 0f) {
                break;
            }
        }
        
        // Reposition Camera
        smoothPivotOffset = Vector3.Lerp(smoothPivotOffset, targetPivotOffset, smooth * Time.deltaTime);
        smoothCamOffset = Vector3.Lerp(smoothCamOffset, noCollisionOffset, smooth * Time.deltaTime);
        
        cameraTransform.position = player.position + camYRotation * smoothPivotOffset + aimRotation * smoothCamOffset;
        
        if (recoilAngle > 0.0f) {
            recoilAngle -= recoilAngleBounce * Time.deltaTime;
        }
        else if (recoilAngle < 0.0f) {
            recoilAngle += recoilAngleBounce * Time.deltaTime;
        }
        
        public float GetCurrentPivotMagnitude(Vector3 finalPivotOffset) {
            return Mathf.Abs((finalPivotOffset - smoothPivotOffset).magnitue);
        }
    }
}




위와 같이 하고 컴파일 에러가 없는 것을 확인 후, 플레이를 해보면 마우스 움직임에 따라 카메라 시점이 변경되는 것을 확인할 수 있습니다.







이제 플러거블 동작 시스템을 제작합니다.
우선 플러거블 동작 시스템에 대한 설명입니다. 우선 플러거블 패턴을 사용하지 않았을 때의 문제점에 대해 간략히 설명합니다.





나쁜 코드에 대한 예입니다. 하나의 Update()에서 특정 키를 누를 때 무얼하고 무엇하고, 그런데 이럴때는 예외처리를 하고 등을 넣고 하다보면 Update()가 엄청나게 길어지고 복잡한 코드로 만들어지는 것을 볼 수 있습니다. 이러한 문제가 발생한다는 것이지요.


[7]



디아블로 시간에 설명되었던 Transition에 대한 설명입니다 ^^~
그리고 이것을 구현하는 디자인 패턴 방법이 Pluggable Pattern인 것입니다.



캐릭터를 하나 가져다 놓고, Rigidbody와 CapsuleCollider를 추가하여 대략적인 세팅을 해줍니다.


다음 시간에는 Pluggable Pattern을 하나씩 만들어 보게 되겠네요 ^^~






<위의 코드들은 제가 보면서 주요한 함수, 코드를 확인하기 위해 타이핑한 용도로, 전체 소스코드가 아님에 주의해 주세요. 전체 코드는 교육 수강을 하면 완벽하게 받으실 수가 있답니다 ^^>

패스트캠퍼스 - 올인원 패키지 : 유니티 포트폴리오 완성 bit.ly/2R561g0

 

유니티 게임 포트폴리오 완성 올인원 패키지 Online. | 패스트캠퍼스

게임 콘텐츠 프로그래머로 취업하고 싶다면, 포트폴리오 완성은 필수! '디아블로'와 '배틀그라운드' 게임을 따라 만들어 보며, 프로그래머 면접에 나오는 핵심 개념까지 모두 잡아 보세요!

www.fastcampus.co.kr

 

[패스트캠퍼스 수강 후기] 올인원 패키지 : 유니티 포트폴리오 완성 100% 환급 챌린지 39회차 미션 시작합니다.

04. 배틀로얄 - 23, 24 번을 진행합니다.


저번 시간에 이어서 SoundTool 스크립트를 지속 작성합니다 ^^


public void FadeTo(Soundclip clip, float time, Interpolate.EaseType ease) {
    if (currentPlayingType == MusicPlayingType.None) {
        FadeIn(clip, time, ease);
    }
    else if (IsDifferentSound(clip)) {
    


캡쳐 화면을 넣을 것이 부족하여 중간중간 화면 캡쳐라도 해서 넣고 있습니다 ^^ 였는데, 오늘은 뒤에 가니 많네요 ㅎㅎ

        if (currentPlayingType == MusicPlayingType.SourceA) {
            PlayAudioSource(fadeB_audio, currentSound, 0.0f);
            currentPlayingType = MusicPlayingType.AtoB;
        }
        else if (currentPlayingType == MusicPlayingType.SourceB) {
            PlayAudioSource(fadeA_audio, currentSound, 0.0f);
            currentPlayingType = MusicPlayingType.BtoA;
        }
        if (currentSound.HasLoop()) {
            isTicking = true;
            DoCheck();
        }
    }
}

public void FadeTo(int index, float time, Interpolate.EaseType ease) {
    FadeTo(DataManager.SoundData().GetCopy(index), time, ease);
}




public void PlayBGM(int index) {
    SoundClip clip = DataManager.SoundData().GetCopy(index);
    PlayBGM(clip);
}

public void PlayUISound(SoundClip clip) {
    PlayAudioSource(UI_audio, clip, clip.maxVolume);
}

public void PlayEffectSound(SoundClip clip) {
    bool isPlaySuccess = false;
    for (int i = 0; i < EffectChannelCount; i++) {
        if (effect_audios[i].isPlaying == false) {
            PlayAudioSource(effect_audios[i], clip, clip.maxVolume);
            effect_PlayStartTime[i] = Time.realtimeSinceStartup;
            isPlaySuccess = true;
        }
        else if (effect_audios[i].clip == clip.GetClip()) {
            effect_audios[i].Stop();
            PlayAudioSource(effect_audios[i], clip, clip.maxVolume);
            effect_PlayStartTime[i] = Time.realtimeSinceStartup;
            isPlaySuccess = true;
        }
    }
    
    if (isPlaySuccess == false) {
        float maxTime = 0.0f;
        int selectIndex = 0;
        for (int i = 0; i < EffectChannelCount; i++) {
            if (effect_PlayStartTime[i] > maxTime) {
                maxTime = effect_PlayStartTime[i];
                selectIndex = i;
            }
        }
        PlayAudioSource(effect_audios[selectIndex], clip, clip.maxVolume);
    }
}

 


PlayEffectSound()와 거의 유사한데, PlayAudioSource() -> PlayAudioSourceAtPoint()로 변경해주면 됩니다.
대신 isPlaySuccess가 실패시 maxTime 체크하던 부분은 필요없이 바로 함수 호출만 해주면 됩니다.


public void PlayOneShotEffect(int index, Vector3 position, float volume) {
    if (index == (int)SoundList.None) return;
    SoundClip clip = DataManager.SoundData().GetCopy(index);
    if (clip == null) return;
    PlayEffectSound(clip, position, volume);
}



public void Stop(bool allStop = false) {
    if (allStop) {
        fadeA_audio.Stop();
        fadeB_audio.Stop();
    }
    
    FadeOut(0.5f, Interpolate.EaseType.Linear);
    currentPlayingType = MusicPlayingType.None;
    StopAllCoroutines();
}

여기까지가 SoundTool의 구현이 끝입니다 ^^~ 수고하셨습니다.
지금까지는 무언가 싶지만 Player나 Monster 작업을 할 때 지금 만들어놓은 것들이 힘을 발휘하게 됨을 볼 수 있습니다.
자세한 설명들도 직접 적용하는 시점에 하기 위해 코딩에 집중하였다고 하네요.. 어쩐지 너무 타이핑 따라하기 느낌어어서 ㅠ.,ㅜ; 설명도 없고.. ㅎㅎ 무언지 알것은 같은데 사용처를 모르니.. 쩝..
이제부터는 3D GameObject를 가지고 움직이는 기능 구현을 시작합니다.






PluggableBehaviour Pattern을 적용하여 플레이어를 적용할 예정입니다.
우선 카메라 제작을 시작합니다.




배틀그라운드나 바이오해저드와 같은 류의 게임을 보면 어깨 뒤쪽 쯤에서 바라보는 카메라를 배치하게 되는데 이것 "3인칭 Shoulder View"입니다.

숄더뷰의 특징이 여러가지 있습니다. 게임을 해보신 분들은 무슨 느낌인지 바로 압니다. ㅎㅎ 왜냐면 숄더뷰 카메라로 인해 생동감도 넘치는 효과가 있고, 좁은 공간에 있으면 숄더뷰가 캐릭터에 가까이 가게 되어 긴장감도 높여주고 하니까 말이죠..
캐릭터와 카메라 사이에 벽이 있으면 카메라가 캐릭터에 거의 붙도록 다가간다는 특징이 있습니다.

캐릭터와 카메라의 충동 체크는 한쪽에서만 진행을 하게되는 경우 체크가 실패할 수가 있기 때문에 양쪽방향으로 체크를하게 됩니다.

 



"Double Viewing Check"라고 부릅니다.

New Scene을 하나 추가하고, Plane을 추가하여 바닥면을 하나 생성해줍니다.
숄더뷰 카메라는 별도로 생성해도 되지만 이미 존재하는 Main Camera를 숄더뷰로 사용합니다.




ThirdPersonOrbitCam 스크립트를 생성하고 코드를 작성합니다.

// 카메라 속성중 중요 속성 하나는 카메라로부터 위치 오프셋 벡터, 피봇 오프셋 벡터
// 위치 오프셋 벡터는 충돌 처리용으로 사용하고 피봇 오프셋 벡터는 시선이동에 사용하도록
// 충돌체크 : 이중 충돌 체크 기능 (캐릭터->카메라, 카메라->캐릭터)
// 사격 반동을 위한 기능
// FOV 변경 기능.
public class ThirdPersonOrbitCam : MonoBehaviour
{
    public Transform player;
    public Vector3 pivotOffset = new Vector3(0.0f, 1.0f, 0.0f);
    public Vector3 camOffset = new Vector3(0.4f, 0.5f, -2.0f);
    
    public float smooth = 10f; // 카메라 반응속도
    public float horizontalAimingSpeed = 6.0f; // 수평 회전속도
    public float verticalAimingSpeed = 6.0f;
    public float maxVerticalAngle = 30.0f;
    public float minVerticalAngle = -60.0f;
    public float recoilAngleBound = 5.0f; // 사격반동 바운스값
    private float angleH = 0.0f; // 마우스 이동에 따른 카메라 수평이동 수치.
    private float angleV = 0.0f;
    private Transform cameraTransform; // 카메라 트랜스폼 캐싱.
    private Camera myCamera;
    private Vector3 relCameraPos; // 플레이어로부터 카메라까지의 벡터.
    private float relCameraPosMag; // 플레이어로부터 카메라사이의 거리.
    private Vector3 smoothPivotOffset; // 카메라 피봇용 보간 벡터
    private Vector3 smoothCamOffset; // 카메라 위치용 보간 벡터
    private Vector3 targetPivotOffset; // 카메라 피봇용 보간 벡터.
    private Vector3 targetCamOffset; // 카메라 위치용 보간 벡터
    private float defaultFOV; // 기본 시야값
    private float targetFOV; // 타겟 시야값
    private float targetMaxVerticleAngle; // 카메라 수직 최대 각도
    private float recoilAngle = 0f; // 사격 반동 각도
    
    public float GetH { get => angleH; } // return angleH; 같은 코드.
}

위까지가 3인칭 숄더뷰를 위한 기본 변수들의 준비를 마쳤습니다.
다음 시간에는 카메라를 구동하는 함수들을 작성하게 됩니다.

FPS 게임이라는 특성으로 인한 카메라 구현 내용이 있고, FPS 특성으로인해 3D 멀미 등을 유발할 수 있기 때문에 이를 방지하기 위한 변수들과 함수들이 존재하게 되는 것 같습니다 ^^.





<위의 코드들은 제가 보면서 주요한 함수, 코드를 확인하기 위해 타이핑한 용도로, 전체 소스코드가 아님에 주의해 주세요. 전체 코드는 교육 수강을 하면 완벽하게 받으실 수가 있답니다 ^^>

패스트캠퍼스 - 올인원 패키지 : 유니티 포트폴리오 완성 bit.ly/2R561g0


 

유니티 게임 포트폴리오 완성 올인원 패키지 Online. | 패스트캠퍼스

게임 콘텐츠 프로그래머로 취업하고 싶다면, 포트폴리오 완성은 필수! '디아블로'와 '배틀그라운드' 게임을 따라 만들어 보며, 프로그래머 면접에 나오는 핵심 개념까지 모두 잡아 보세요!

www.fastcampus.co.kr

 

[패스트캠퍼스 수강 후기] 올인원 패키지 : 유니티 포트폴리오 완성 100% 환급 챌린지 38회차 미션 시작합니다.

04. 배틀로얄 - 21, 22 번을 진행합니다.




저번 시간에 이어 SoundManager 스크립트를 지속 작업합니다.

public class SoundManager : SingletonMonobehaviour<SoundManager>
{
    // 저번시간 작성했던 변수들..
    
    void Start() {
        if (mixer == null) {
            mixer = Resources.Load(MixerName) as AudioMixer;
        }
        if (audioRoot == null) {
            audioRoot = new GameObject(ContainerName).transform;
            audioRoot.SetParent(transform);
            audioRoot.localPosition = Vector3.zero;
        }
        if (fadeA_audio == null) {
            GameObject fadeA = new GameObject(FadeA, typeof(AudioSource));
            fadeA.transform.SetParent(audioRoot);
            fadeA_audio = fadeA.GetComponent<AudioSource>();
            fadeA_audio.playOnAwake = false;
        }
        if (fadeB_audio == null) {
            GameObject fadeB = new GameObject(FadeB, typeof(AudioSource));
            fadeB.transform.SetParent(audioRoot);
            fadeB_audio = fadeB.GetComponent<AudioSource>();
            fadeB_audio.playOnAwake = false;
        }
        if (UI_audio == null) {
            GameObject ui = new GameObject(UI, typeof(AudioSource));
            ui.transform.SetParent(audioRoot);
            UI_audio = ui.GetComponent<AudioSource>();
            UI_audio.playOnAwake = false;
        }
        if (effect_audios == null || effect_audios.Length == 0) {
            effect_PlayStartTime = new float[EffectChannelCount];
            effect_audios = new AudioSource[EffectChannelCount];
            for (int i = 0; i < EffectChannelCount; i++) {
                effect_PlayStartTime[i] = 0.0f;
                GameObject effect = new GameObject("Effect" + i.ToString(), typeof(AudioSource));
                effect.transform.SetParent(audioRoot);
                effect_audios[i] = effect.GetComponent<AudioSource>();
                effect_audios[i].playOnAwake = false;
            }
        }
        
        if (mixer != null) {
            fadeA_audio.outputAudioMixerGroup = mixer.FindMatchingGroups(BGMGroupName)[0];
            fadeA_audio.outputAudioMixerGroup = mixer.FindMatchingGroups(BGMGroupName)[0];
            UI_audio.outputAudioMixerGroup = mixer.FindMatchingGroups(UIGroupName)[0];
            for (int i = 0; i < effect_audios.Length; i++) {
                effect_audios[i].outputAudioMixerGroup = mixer.FindMatchingGroups(EffectGroupName)[0];
            }
        }
        
        VolumeInit();
    }
    
    public void SetBGMVolume(float currentRatio) {
        currentRatio = Mathf.Clamp01(currentRatio);
        float volume = Mathf.Lerp(minVolume, maxVolume, currentRatio);
        mixer.SetFloat(BGMVolumeParam, volume);
        PlayerPrefs.SetFloat(BGMVolumeParam, volume);
    }
    
    public float GetBGMVolume() {
        if (PlayerPrefs.HasKey(BGMVolumeParam))
            return Mathf.Lerp(minVolume, maxVolume, PlayerPrefs.GetFloat(BGMVolumeParam));
        else
            return maxVolume;
    }
    
    public void SetEffectVolume(float currentRatio) {
        currentRatio = Mathf.Clamp01(currentRatio);
        float volume = Mathf.Lerp(minVolume, maxVolume, currentRatio);
        mixer.SetFloat(EffectVolumeParam, volume);
        PlayerPrefs.SetFloat(EffectVolumeParam, volume);
    }
    
    public float GetEffectVolume() {
        if (PlayerPrefs.HasKey(EffectVolumeParam))
            return Mathf.Lerp(minVolume, maxVolume, PlayerPrefs.GetFloat(EffectVolumeParam));
        else
            return maxVolume;
    }
    
    public void SetUIVolume(float currentRatio) {
        currentRatio = Mathf.Clamp01(currentRatio);
        float volume = Mathf.Lerp(minVolume, maxVolume, currentRatio);
        mixer.SetFloat(UIVolumeParam, volume);
        PlayerPrefs.SetFloat(UIVolumeParam, volume);
    }
    
    public float GetUIVolume() {
        if (PlayerPrefs.HasKey(UIVolumeParam))
            return Mathf.Lerp(minVolume, maxVolume, PlayerPrefs.GetFloat(UIVolumeParam));
        else
            return maxVolume;
    }
    

 



여기까지가 기본적인 사운드 초기화 및 초기 설정을 하는 코드입니다. 이어서 소리 켜고 끄기 및 Fade In/Out 등을 작성합니다.



    void PlayAudioSource(AudioSource source, SoundClip clip, float volume) {  // 소리 재생
        if (source == null || clip == null) return;
        source.Stop();
        source.clip = clip.GetClip();
        source.volume = volume;
        source.loop = clip.isLoop;
        source.pitch = clip.pitch;
        source.dopplerLevel = clip.dopplerLevel;
        source.rolloffMode = clip.rolloffMode;
        source.minDistance = clip.minDistance;
        source.maxDistance = clip.maxDistance;
        source.spartialBlend = clip.spartialBlend;
        source.Play();
    }
    
    void PlayAudioSourceAtPoint(SoundClip clip, Vector3 position, float volume) { // 특정 위치에서 재생
        AudioSource.PlayClipAtPoint(clip.GetClip(), position, volume);
    }
    
    public bool IsPlaying() {
        return (int)currentPlayingType > 0;
    }
    
    public bool IsDifferentSound(SoundClip clip) {
        if (clip == null) return false;
        if (currentSound != null && currentSound.realId == clip.realId && IsPlaying() && currentSound.isFadeOut == false) return false;
        else return true;
    }
   
    private IEnumerator CheckProcess() {
        while (isTicking == true && IsPlaying() == true) {
            yield return new WaitForSeconds(0.05f);
            if (currentSound.HasLoop()) {
                if (currentPlayingType == MusicPlayingType.SourceA) {
                    currentSound.CheckLoop(fadeA_audio);
                }
                else if (currentPlayingType == MusicPlayingType.SourceB) {
                    currentSound.CheckLoop(fadeB_audio);
                }
                else if (currentPlayingType == MusicPlayingType.AtoB) {
                    lastSound.CheckLoop(fadeA_audio);
                    currentSound.CheckLoop(fadeB_audio);
                }
                else if (currentPlayingType == MusicPlayingType.BtoA) {
                    lastSound.CheckLoop(fadeB_audio);
                    currentSound.CheckLoop(fadeA_audio);
                }
            }
        }
    }

 


DoCheck, FadeIn 함수도 위와 같이 구현해 줍니다.

    public void FadeIn(int index, float time, Interpolate.EaseType ease) {
        FadeIn(DataManager.SoundData().GetCopy(index), time, ease);
    }
    
    public void FadeOut(float time, Interpolate.EaseType ease) {
        if (currentSound != null)
            currentSound.FadeOut(time, ease);
    }
   
    void Update() {
        if (currentSound == null) return;
        if (currentPlayingType == MusicPlayingType.SourceA) {
            currentSound.DoFade(Time.deltaTime, fadeA_audio);
        }
        else if (currentPlayingType == MusicPlayingType.SourceB) {
            currentSound.DoFade(Time.deltaTime, fadeB_audio);
        }
        else if (currentPlayingType == MusicPlayingType.AtoB) {
            lastSound.DoFade(Time.deltaTime, fadeA_audio);
            currentSound.DoFade(Time.deltaTime, fadeB_audio);
        }
        else if (currentPlayingType == MusicPlayingType.BtoA) {
            lastSound.DoFade(Time.deltaTime, fadeB_audio);
            currentSound.DoFade(Time.deltaTime, fadeA_audio);
        }
        
        if (fadeA_audio.isPlaying && fadeB_audio.isPlaying == false) {
            currentPlayingType = MusicPlayingType.SourceA;
        }
        else if (fadeB_audio.isPlaying && fadeA_audio.isPlaying == false) {
            currentPlayingType = MusicPlayingType.SourceB;
        }
        else if (fadeA_audio.isPlaying == false && fadeB_audio.isPlaying == false) {
            currentPlayingType = MusicPlayingType.None;
        }
    }
}


사실 이런 구현은 말이 많을 것 같다는 느낌도 들긴 하네요. 분명 위와 같은 기능을 하는 툴이 있어야 함은 분명한데..
매번 툴을 만들때마다 많은 시간이 들어가야 하며 코드 관리도 힘들다면 오히려 짐이 될 것도 같기 때문입니다.

다음 시간에는 사운드 매니저를 마무리하고, 3인칭 카메라 제작에 들어갑니다 ^^~




<위의 코드들은 제가 보면서 주요한 함수, 코드를 확인하기 위해 타이핑한 용도로, 전체 소스코드가 아님에 주의해 주세요. 전체 코드는 교육 수강을 하면 완벽하게 받으실 수가 있답니다 ^^>

패스트캠퍼스 - 올인원 패키지 : 유니티 포트폴리오 완성 bit.ly/2R561g0

 

유니티 게임 포트폴리오 완성 올인원 패키지 Online. | 패스트캠퍼스

게임 콘텐츠 프로그래머로 취업하고 싶다면, 포트폴리오 완성은 필수! '디아블로'와 '배틀그라운드' 게임을 따라 만들어 보며, 프로그래머 면접에 나오는 핵심 개념까지 모두 잡아 보세요!

www.fastcampus.co.kr

 

+ Recent posts