새로운 팀프로젝트가 시작되는 날이다.

우리 팀은 Alt F4라는 게임을 모작한다.

 

일단 방해물이 주된 컨텐츠이기때문에 방해물들을 먼저 제작한 후 다른 구현을 하기로 했다.

나는 진자 운동을 하는 공튀어오르는 생선 구현을 맡았다.

진자 운동하는 공, 밑에 큐브는 임시생선이다.

 

 

진자 운동 공 구현

빈 오브젝트 자식으로 막대기, 막대기의 자식으로 구를 넣은 후

빈 오브젝트에 rotation.z를 변경하는 스크립트를 넣어줬다.

 

진자 운동 구현

첫 번째로 시도했던 방법

https://srdeveloper.tistory.com/41

이 블로그의 코드를 참고했다.

moveTime += Time.deltaTime * speed;

transform.rotation = Quaternion.Lerp(
   Quaternion.Euler(transform.forward * angle), 	// Vector3.forward
   Quaternion.Euler(-transform.forward * angle),	// Vector3.back
   (Mathf.Sin(moveTime) + 1) * 0.5f);

Quaternion.Lerp를 사용해  transform.rotation.z의 값을

(0,0,1) * angle부터 (0,0,-1) * angle까지 왔다갔다 하면서 부드럽게 증감소 시키는 코드이다.

 

Mathf.Sin(moveTime) + 1 * 0.5f는

Quaternion.Lerp()의 t(마지막인자)는 0 ~ 1 값을 넣어줘야 하는데 Mathf.Sin()의 값은 -1 ~ 1 이기때문에 보정을 위한 코드다.

단순히 Mathf.Sin(moveTime)을 사용하면 진자운동 시작 위치에 잠깐 멈춰있는다.

 

이렇게 했을 경우 잘 돌아가지만, 오브젝트의 방향을 바꿨을 때도 같은 방향으로 진자운동을 한다.

다시 말해서 오브젝트의 transform.rotation.x 값과 transform.rotation.y값은 항상 0으로 고정되어 다른 방향의 진자 공 오브젝트가 여러개 있을 때도 다 같은 방향으로 움직이는 상황이 벌어진다.

이를 해결하기 위해 아래 방법을 사용했다.

 

 

두 번째로 시도했던 방법

moveTime += Time.deltaTime * speed;

Quaternion currentRotation = transform.rotation;
float targetZRotation = Mathf.Sin(moveTime) * angle;
Quaternion targetRotation = Quaternion.Euler(currentRotation.eulerAngles.x, currentRotation.eulerAngles.y, targetZRotation);

transform.rotation = Quaternion.Lerp(currentRotation, targetRotation, 0.5f);

원래의 Rotation값을 저장해 놓고 z축의 값만 바뀌도록 구현했다.

 

Quaternion.Lerp의 마지막인자(t)의 값(0.5f)은 선형 보간의 가중치(weight)또는 보간 정도이고

0은 시작 값(currentRotation), 1은 목표 값(targetRotation)이고 0.5이면 그 중간의 값이다.

따라서 현재 회전값과 목표 회전값의 중간 지점으로 게임 오브젝트의 회전을 어느 한 쪽에 치우치지 않고 부드럽게 변경한다.

 

 

+

float t = Mathf.PingPong(Time.deltaTime * speed, 1.0f);

구현하다가 발견한 PingPong 함수. 정말 핑퐁하는 것 처럼 움직인다.

 

 

튀어오르는 생선 구현

튀어올라서 플레이어를 공격하는 생선을 구현할 것이다.

생선은 ObjectPool를 이용할 예정이다.

ObjectPool을 이용하게 되면 SetActive(true)가 되었을 때 튀어오르게 하기 위해

OnEnable()을 이용했다.

 private void OnEnable()
 {
     _rigidbody = GetComponent<Rigidbody>();

     float randomX = Random.Range(-1.0f, 1.0f);
     float randomZ = Random.Range(-1.0f, 1.0f);
     _rigidbody.AddForce(randomX * _jumpForce, 1.0f * _jumpForce, randomZ * _jumpForce);

     StartCoroutine(Flap());
 }

 

또 팔닥거리는 움직임을 주기 위해 Coroutine을 이용했다.

0.6초에 한 번 AddForce와 AddTorque를 이용해 팔닥거리는 움직임을 주려했다.

IEnumerator Flap()
{
    yield return new WaitForSeconds(3f);
    while (true)
    {
        _rigidbody.AddForce(Vector3.up * _flapForce);
        _rigidbody.AddTorque(Vector3.forward * Random.Range(-1.0f, 1.0f) * 100f);

        yield return new WaitForSeconds(_flapTime);
    }
}

 

Coroutine은 SetActive(false)를 해도 계속 돈다고 한다.

따라서 OnDisable()이 되었을 때 Coroutine을 종료해 주었다.

 private void OnDisable()
 {
     StopCoroutine(Flap());
 }

아직 큐브지만 잘 팔닥거린다..

 

'내일배움캠프(Unity)' 카테고리의 다른 글

숙련 주차 팀프로젝트 3 - 방해물 넉백, ragdoll  (0) 2024.01.04
숙련 주차 팀프로젝트 2 - Object Pool, 플레이어 튕겨내기, lagdoll  (1) 2024.01.03
TIL  (0) 2023.12.28
TIL  (0) 2023.12.27
클린 코드 4  (0) 2023.12.26