Galaxy Card/1-2. 시스템 개발 #스테이지

(3) 게임 스테이지 구현 #3 (행성 공전 구현, 달의 움직임 구현, 카메라 기본 연출)

DOlpa_GB 2025. 7. 15. 00:18

지난글에 이어서 이번엔 태양을 공전하는 공전주기를 구현해보도록 하겠다

 

using UnityEngine;

public class Moving : MonoBehaviour
{
    [Header("공전 설정")]
    [SerializeField] private float orbitRadius = 5f;     // 공전 반경
    [SerializeField] private float orbitSpeed = 30f;     // 공전 속도 (도/초)
    
    private Vector3 orbitCenter = new Vector3(0, 0, 0); // 고정된 중심점
    private float currentAngle = 0f;

    private void Start()
    {
        // 게임 시작 시 랜덤한 각도(0~360도)에서 시작
        currentAngle = Random.Range(0f, 360f);
        
        // 초기 위치 설정
        UpdatePosition();
    }

    private void Update()
    {
        // 각도 업데이트 (시계 방향으로 회전)
        currentAngle -= orbitSpeed * Time.deltaTime;
        
        UpdatePosition();
    }

    private void UpdatePosition()
    {
        // 라디안으로 변환
        float radian = currentAngle * Mathf.Deg2Rad;
        
        // 원형 궤도 계산 (XY 평면에서의 원운동)
        float x = Mathf.Cos(radian) * orbitRadius;
        float y = Mathf.Sin(radian) * orbitRadius;
        
        // 위치 업데이트 (Z축은 유지)
        transform.position = new Vector3(
            orbitCenter.x + x,
            orbitCenter.y + y,
            orbitCenter.z
        );
    }
}

 

가장 먼저 행성을 공전 시킬 Moving 스크립트를 하나 작성한다

공전 반경과 속도는 언제든지 Inspector 창에서 조작할 수 있도록 해주었다

 

 

원래는 태양의 지름을 참고하여 각각 행성들도 그에 맞는 현실 태양과의 거리를 둘려고 했었다

위에 보이는 사진에서 태양이 대충 네모칸 6.5칸 정도 잡아먹고 있다. 

 

그래서 태양의 지름이 65 정도라고 한다면 수금지화목토천해는 각각 태양에서 어느정도 거리인지 수치화해서 알려달라고 부탁했더니...

 

더보기
행성태양으로부터 평균 거리 (백만 km)태양 지름 배수65 기준으로 환산 시 거리
수성 57.9 약 41.6 2,704
금성 108.2 약 77.8 5,057
지구 149.6 약 107.6 6,994
화성 227.9 약 163.9 10,653
목성 778.5 약 559.8 36,387
토성 1,433.5 약 1,030.6 66,989
천왕성 2,872.5 약 2,065.4 134,251
해왕성 4,495.1 약 3,231.2 210,027

너무 바보같은 질문이었다. 아무리 현실고증이 중요하다지만 해왕성을 21만칸이나 떨어뜨려 구현할 순 없기에

유일하게 이 부분만 합의를 보기로 했다. 그냥 적당히 한눈에 들어오기 적당한 크기로 배치하겠다

 

....하지만? 이것도 최대한 고증을 지키는 방법이 있다

 

 

이런식으로 보기편하게 일렬로 행성들을 나열한뒤

 

수성의 위치가 x축으로 35, 맨끝 해왕성의 위치가 x축으로 90이라면

그 사이에 행성들을 그 비율에 맞춰 위치를 넣어주면 된다. 물론 어려운건 챗지피티가 계산할 예정

 

더보기

🧮 변환 공식

우리는 수성의 위치를 x = 35, 해왕성의 위치를 x = 90으로 고정했기 때문에
거리 비율을 수성 - 해왕성 구간 (177.6)을 x=35~90 사이에 선형 매핑하면 된다.

x=35+(행성거리비율−1)(77.6−1)×(90−35)x = 35 + \frac{(행성 거리 비율 - 1)}{(77.6 - 1)} \times (90 - 35)

 

...대충 이런 계산식을 쓴다고 한다


📌 계산 결과

행성거리 비율x 위치 (근사값)
수성 1 35.00
금성 1.868 35.80
지구 2.583 36.42
화성 3.937 37.59
목성 13.439 45.14
토성 24.752 53.88
천왕성 49.595 72.20
해왕성 77.6 90.00

아무튼 이 수치만 있으면 되는것

 

 

이걸 각 행성의 Orbit Radius에 넣어주면 된다

 

 

자 이제 제대로 된 현실고증을 거친 실제 행성들 사이의 거리들이다

 

 

그리고 공전 속도 역시 현실고증을 할 생각이다

 

더보기
행성실제 공전 주기지구년 기준 비율계산식 (10초 × 비율)결과
수성 약 88일 0.24 10 × 0.24 2.4초
금성 약 225일 0.615 10 × 0.615 6.15초
지구 365.25일 1 10 × 1 10초
화성 약 687일 1.88 10 × 1.88 18.8초
목성 약 11.86년 11.86 10 × 11.86 118.6초
토성 약 29.46년 29.46 10 × 29.46 294.6초
천왕성 약 84년 84 10 × 84 840초
해왕성 약 164.8년 164.8 10 × 164.8 1,648초

 

지구가 태양 한바퀴를 도는데 10초라면 다른 행성들의 공전 속도에 대한 계산표이다

 

게임속에서 한바퀴를 10초에 돌게 하는게 필요한 스피드는 36

그럼 다른 행성들도 지구를 기준으로 계산했을때

 

더보기
행성속도 (지구 기준)
수성 58.1
금성 42.3
지구 36
화성 29.2
목성 15.8
토성 11.6
천왕성 8.2
해왕성 6.6

 

이것도 그대로 스피드에 넣어주자

 

...근데 생각보다 행성들이 너무 휙휙 빨리 돌아버려서 값을 반으로 낮춰주었다

그래도 빠른것 같아 또 반으로 낮춰주었다

 

결국 지구는 태양 한바퀴 도는데 10초에서 40초로 늘어났다

 

자 그럼 마지막으로 한가지 더

 

 

각 행성에는 공전할때마다 태양에 비춰지는 애니메이션이 있다.

공전속도를 참고하여 이 애니메이션 프레임이 한바퀴 도는데 걸리는 시간도 정해주어야 한다

 

사실 별건없다. 각 행성이 한바퀴 공전하는데 걸리는 현실시간을 계산한다음

애니메이션 주기를 그만큼으로 조절해주면 된다. 

 

더보기
속도시간 = 360 ÷ 속도결과 (초)
15 360 ÷ 15 24.00
10.5 360 ÷ 10.5 34.29
9 360 ÷ 9 40.00
7.5 360 ÷ 7.5 48.00
4 360 ÷ 4 90.00
2.9 360 ÷ 2.9 124.14
2.05 360 ÷ 2.05 175.61
1.65 360 ÷ 1.65 218.18

 

 

이렇게 맞춰주었다

 

 

 

 

이제 한번 확인해보자 잘 공전하는것을 확인할 수 있다

사실 갤럭시볼에서 한번 해본거라 큰 어려움은 없었다. 그나마 차이점이라면

그땐 각 행성, 태양의 기준점같은것도 잡지 않고 무작위로 막 집어넣었다면

 

이번엔 철저하게 태양과 카메라를 (0,0,0) 좌표로 잡아 기준점으로 둔뒤 그걸 기점으로 공전하게 만든것. 

당연히 이렇게 해야하는것이 맞다

 

 

-----------------------------

 

하지만 한가지 더 남아있다. 수금지화목토전해, 태양 말고도 달이라는 스테이지가 하나 남아있다

기존 행성들은 그냥 고정되어 있는 태양을 기준으로 공전을 시켜주면 되지만,

달의 경우는 실시간으로 움직이는 지구를 기준으로 같이 이동하며 돌아줘야 하는것. 

사실 갤럭시볼에서도 이걸 구현해보려고 했었는데 실력이 되질 않아 구현에 실패했었다..ㅎㅎ

 

using UnityEngine;

public class MoonMoving : MonoBehaviour
{
    [Header("공전 설정")]
    [SerializeField] private Transform target;           // 공전할 기준 오브젝트
    [SerializeField] private float orbitRadius = 5f;     // 공전 반경
    [SerializeField] private float orbitSpeed = 30f;     // 공전 속도 (도/초)
    
    private float currentAngle = 0f;
    private Vector3 offset;

    private void Start()
    {
        // 초기 각도 랜덤 설정
        currentAngle = Random.Range(0f, 360f);
        
        // 초기 위치 설정
        UpdatePosition();
    }

    private void Update()
    {
        if (target == null) return;
        
        // 각도 업데이트 (시계 방향으로 회전)
        currentAngle -= orbitSpeed * Time.deltaTime;
        
        // 위치 업데이트
        UpdatePosition();
    }

    private void UpdatePosition()
    {
        // 라디안으로 변환
        float radian = currentAngle * Mathf.Deg2Rad;
        
        // 원형 궤도 계산 (XY 평면에서의 원운동)
        float x = Mathf.Cos(radian) * orbitRadius;
        float y = Mathf.Sin(radian) * orbitRadius;
        
        // 타겟의 위치를 기준으로 공전
        transform.position = new Vector3(
            target.position.x + x,
            target.position.y + y,
            target.position.z  // Z축은 타겟과 동일하게 유지
        );
    }
}

 

하지만 그때처럼 행성 하나하나마다 물리계산이나 충돌처리가 필요하지 않고 정말 단순한

움직임만 있으면 되기에 RigidBody를 쓰지않고 콜라이더도 사용하지 않기에 더욱 쉽게 구현할 수 있었다

여담으로 갤볼 시절 최적화의 주 원인이었던 interpolate를 사용하지 않고도 부드러운 움직임을 구현할 수 있다 

 

 

정말 간단하다. 위처럼 Moon Moving이라는 스크립트를 따로 하나 만들어준뒤 타겟에 지구를 할당해주면 된다

 

 

 

우왕! 이제 달의 움직임도 보기좋게 구현하는데 성공했다

 

------------------------------------------

 

이렇게 태양계 행성 시스템을 얼추 만들었으니 그 다음은 카메라 연출을 구현해보도록 하겠다

 

처음엔 우주의 전체 면적을 보여준뒤, 천천히 확대해 현재 진행중인 스테이지에 속하는 행성에 카메라를 고정시키는 연출이 필요하다

 

 

카메라를 조절해본 결과 태양계 모든 행성이 한 화면에 담기려면 대략 사이즈 110...이지만 극적인 연출을 위해 70

태양이 우주의 하나의 점처럼 보이려면 5000정도

 

 

public class CameraMoving : MonoBehaviour
{
    [Header("맨 처음 카메라와 확대할 사이즈")]
    [SerializeField] private float initialSize = 5000f;      // 초기 카메라 크기
    [SerializeField] private float targetSize = 70f;        // 목표 카메라 크기
    [Header("첫 카메라 확대와 확대 대기 시간")]
    [SerializeField] private float zoomDuration = 5f;        // 줌 인/아웃 지속 시간 (초)
    [SerializeField] private float startDelay = 10f;         // 시작 전 대기 시간 (초)
    
    private Camera mainCamera;
    private Tween zoomTween;

    private void Awake()
    {
        mainCamera = Camera.main;
    }

    private void Start()
    {
        InitializeCamera();
        StartZoomSequence();
    }

 

그래서 이번엔 카메라 연출을 담당할 CameraMoving 스크립트를 만들어주었다

그리고 이번엔 mainCamera 자체를 그냥 Camera.main으로 알아서 할당하도록 만들어

굳이 Inspector에서 카메라를 찾아와 드래그할 필요없이 스크립트를 메인 카메라에 붙여주기만 하면된다

 

그리고 위에 보이는 연출에 필요한 변수들을 헤더를 사용해 상세 설명을 적어주었다

좀 유치할수도 있는데 나중엔 변수들이 더 많아질거라 미리 헷갈리지 않게 적어주는게 좋을것 같다

 

우선은 사이즈 5000으로 시작해 10초 대기후 70까지 5초간 줌인 하는 연출을 만들어주었다

 

 

 

확실히 DOTween을 사용해서 그런지 움직임도 갤볼에 비해 더 부드러워진 느낌이다

 

이게 기본 연출의 시작이지만 앞으로 튜토리얼과 스테이지 시스템이 더 확정된다면 그때 연출을 더 수정해보는걸로 하겠다

 

반응형