반응형
SMALL
코루틴을 사용하여 카메라 쉐이킹 이펙트를 구현하였다.
우선 두가지 코루틴이 함께 동작한다.
하나는 doShake 코루틴으로 유저의 위치를 기반으로 카메라가 followup 을 하며 플레이어의 위치를 기준으로 흔들리는 이펙트를 낸다.
두번째는 Flash 코루틴으로 현재게임을 함께 제작중인 TeamVizeon 로고 모양의 flash 이미지를 lerp 하며 히트 이펙트를 낸다.
이미지가 30 프레임 gif 인 관계로 조금 뻣뻣하게 흔들리는 걸로 보일수 있는데 실제 작동시 굉장히 부드럽게 흔들리는 타격 이펙트를 볼수 있다.
코드는 아래와 같다.
using System.Collections;
using System.Collections.Generic;
using Unity.VisualScripting;
using UnityEngine;
using UnityEngine.UI;
public class MainCameraController : MonoBehaviour
{
[SerializeField]
private float shakeDuration = 0.2f;
[SerializeField]
private float shakeMagnitude = 0.7f;
[SerializeField]
private float fadeDuration = 0.2f;
[SerializeField]
private GameObject FlashPoint;
[SerializeField]
private Sprite WhiteBox;
private bool isShaking;
private GameObject player;
private Color flashColor = Color.red;
private Vector3 initialPosition;
private Vector3 cameraOffset = new Vector3(0, 0, -11);
public void Init()
{
this.player = GameObject.FindGameObjectWithTag("Player");
EventDispatcher.Instance.AddListener(EventDispatcher.EventName.CoCameraShaking,this.Shake);
EventDispatcher.Instance.AddListener(EventDispatcher.EventName.CoCameraFlash,this.Flash);
EventDispatcher.Instance.AddListener(EventDispatcher.EventName.CoCameraShakingAndFlash,this.ShakeAndFlash);
}
private void ShakeAndFlash()
{
this.Shake();
this.Flash();
}
private void Shake()
{
this.StartCoroutine(this.DoShake());
}
private IEnumerator DoShake()
{
this.isShaking = true; // 카메라의 플레이어 추적을 막기 위한 bool
float elapsed = 0.0f; // 경과시간 초기화
while (elapsed < this.shakeDuration)
{
// 타겟 포지션 = 초기위치 + 반지름 1인 구 안에서 의 랜덤 위치 벡터 * 흔드는 세기
Vector3 position = this.initialPosition + Random.insideUnitSphere * this.shakeMagnitude;
// 플레이어 월드 좌표 + 카메라 기본 위치값 + 타겟 포지션
this.transform.localPosition = this.player.transform.position + this.cameraOffset + position;
elapsed += Time.deltaTime;
yield return null;
}
// 흔들기가 끝나면 플레이어 포지션 + 카메라 기본 위치값
this.transform.localPosition = this.player.transform.position + this.cameraOffset;
this.isShaking = false;
}
private Coroutine flash;
private void Flash()
{
// 코루틴이 중복 실행 방지 (혹시라도 다단계 히트시 날수 있는 오류 대처)
if(this.flash == null)
this.flash = this.StartCoroutine(this.DoFlash())
}
private IEnumerator DoFlash()
{
//카메라 오브젝트 앞에 추가된 flash 이미지가 나타날 지점 오브젝트에 스프라이트 렌더러 부착
SpriteRenderer spriteRenderer = this.FlashPoint.AddComponent<SpriteRenderer>();
// 스프라이트 할당
spriteRenderer.sprite = this.WhiteBox;
// 반짝일 색상 할당
spriteRenderer.color = this.flashColor;
// 레이 캐스트 타겟 모드 OFF
spriteRenderer.rayTracingMode = UnityEngine.Experimental.Rendering.RayTracingMode.Off;
spriteRenderer.sortingLayerName = "FlyingObject";
spriteRenderer.sortingOrder = 1000;
float elapsed = 0.0f;
float alpha = 1.0f;
while (elapsed < this.fadeDuration)
{
//mathf. lerp 메서드로 타겟 실수까지 선형 보정
alpha = Mathf.Lerp(1.0f, 0.0f, elapsed / this.fadeDuration);
// 알파값 할당
spriteRenderer.color = new Color(this.flashColor.r, this.flashColor.g, this.flashColor.b, alpha);
elapsed += Time.deltaTime;
yield return null;
}
//종료시 컴포넌트 파괴
GameObject.Destroy(spriteRenderer);
this.flash = null;
}
private void LateUpdate()
{
if (!this.isShaking)
{
Vector3 playerPos = new Vector3(this.player.transform.position.x, this.player.transform.position.y, -11);
this.transform.position = playerPos + this.cameraOffset;
}
if (Input.GetKeyDown(KeyCode.Space))
{
EventDispatcher.Instance.Dispatch(EventDispatcher.EventName.CoCameraShakingAndFlash);
}
}
}
카메라 제어 부분은 의외로 어렵지 않게 구현할수 있었데 오히려 타격 이펙트가 발생할때 flash 효과를 주는 것이 타겟지점을 잡아줘야 하고 너무 오래 남아있으면 안돼 까다로운 편이었던듯 하다.
현재 우리의 프로젝트는 무적타임이 있고 해당 무적타임이 0.2 초동안 반복될일이 없어 메모리 점유를 낮추기위해 (이정도라면 큰 차이는 없겠지만 ㅎㅎ) 컴포넌트를 붙였다 떼는 식으로 만들었고 오버헤드가 되지 않도록 중복 방지를 했지만 만약 다단계 히트가 가능한 게임이라면 코루틴에서 스프라이트 랜더러를 flashPoint object에 부착시켜주는 것이 아닌 상시 부착후 실행 -> 초기화 시키는 것이 좋을 듯하다.
반응형
LIST
'프로젝트 > 건즈앤 레이첼스' 카테고리의 다른 글
[유니티 프로젝트] 허브 (성소) -> 던전 -> 허브 루프 (윤회) (1) | 2023.04.23 |
---|---|
[유니티 프로젝트] 본 프로젝트용 맵 씬 제작 (0) | 2023.04.20 |
[유니티 프로젝트] 로그라이크 허브 마을 (기억의 성소) 제작 .3 구조잡기 - 완료 (0) | 2023.04.18 |
[유니티 프로젝트] 간단한이벤트 디스패쳐 EventDispatcher 제작 및 사용 (0) | 2023.04.17 |
[유니티 프로젝트] 로그라이크 허브 마을 (기억의 성소) 제작 .2 (레이어 정리 및 월드 팝업 UI) (0) | 2023.04.16 |