

커밋 : 46abea94dc2a9d687badd7433e5bebed7c132341
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Item_Obj : MonoBehaviour
{
[SerializeField] float firingAngle = 45.0f; // 발사 각도 (기본값 45도)
[SerializeField] float gravity = 9.8f; // 중력 가속도
public void Init(Vector3 pos)
{
// 아이템을 초기 위치로 설정
transform.position = pos;
// 목표 위치를 랜덤하게 설정
Vector3 TargetPos = new Vector3(
pos.x + (Random.insideUnitSphere.x * 2.0f),
0.5f,
pos.z + (Random.insideUnitSphere.z * 2.0f)
);
// 포물선 이동 코루틴 시작
StartCoroutine(SimulateProjectile(TargetPos));
}
IEnumerator SimulateProjectile(Vector3 pos)
{
// 목표 위치까지의 거리 계산
float targetDistance = Vector3.Distance(transform.position, pos);
// 포물선 운동 속도 계산 (공식 적용)
float projectileVelocity = Mathf.Sqrt((targetDistance * gravity) / Mathf.Sin(2 * firingAngle * Mathf.Deg2Rad));
// 속도를 X, Y 방향으로 나누기
float vX = projectileVelocity * Mathf.Cos(firingAngle * Mathf.Deg2Rad);
float vY = projectileVelocity * Mathf.Sin(firingAngle * Mathf.Deg2Rad);
// 총 비행 시간 계산
float flightDuration = targetDistance / vX;
// 아이템을 목표 위치 방향으로 회전
transform.rotation = Quaternion.LookRotation(pos - transform.position);
float time = 0.0f;
while (time < flightDuration)
{
// 포물선 운동 적용
transform.Translate(0, (vY - (gravity * time)) * Time.deltaTime, vX * Time.deltaTime);
time += Time.deltaTime;
yield return null;
}
}
}
🔥 구현내용
이 코드의 역할은 `아이템이 포물선을 그리면서 목표 위치까지 날아가게 만드는 것`
즉, `중력의 영향을 받는 투사체 운동`(Projectile Motion)을 구현한 것!
어디로 날릴 것인지 타겟 지점 설정
public void Init(Vector3 pos)
{
transform.position = pos;
Vector3 TargetPos = new Vector3(
pos.x + (Random.insideUnitSphere.x * 2.0f),
0.5f,
pos.z + (Random.insideUnitSphere.z * 2.0f)
);
StartCoroutine(SimulateProjectile(TargetPos));
}
- 아이템을 pos 위치에 배치.
- 목표 위치(TargetPos)를 `랜덤하게 설정`.
- Random.insideUnitSphere를 사용해서 x, z 위치를 ±2 범위 내에서 랜덤하게 변경.
- y 값은 0.5로 고정해서 땅에서 살짝 뜬 상태에서 이동하도록 설정.
- StartCoroutine(SimulateProjectile(TargetPos))을 호출해서 포물선 이동을 시작.
목표 까지의 직선거리 R 구하기 (R은 포물선 운동 공식)
- 현재 위치에서 목표 위치까지 직선 거리를 구하는 코드이다.
float targetDistance = Vector3.Distance(transform.position, pos);
초기 발사 속도(projectileVelocity) V 구하기
포물선 운동에서 물체를 특정 위치까지 도달시키려면 `초기 발사 속도 (V)를 구해야 한다.
여기서 샤거리 공식 이라는 개념이 나오는데 아래 공식이 사거리 R 구하는 공식이다 하지만 우리는 R이 아니라 V를 구해야 하기 때문에 이 식을 변경시켜야 하는데 그 과정에 대해서는 스킵하자

어쩃든 위 사거리 공식이 아니라 결론적으로는 위 식을 응용해서 만든 `초기 발사 속도`구하는 아래 공식을 이용해서 V를 구행냐 한다


우리는 R, 세타, 중력 모두를 알고 있기 때문에 V도 구할 수 있다.

아래는 초기 발사 속도 (V)를 구하는 공식 이다
float projectileVelocity = Mathf.Sqrt((targetDistance * gravity) / Mathf.Sin(2 * firingAngle * Mathf.Deg2Rad));
그렇다면 초기 발사 속도(projectileVelocity)를 왜 구하는가?
- 목표까지 도달하기 위해 얼마나 빠르게 던져야 하는지를 계산하는 값!
- 목표 거리(R), 중력(g), 발사 각도(θ)를 알고 있으므로 V를 구할 수 있음
- 이 값이 없다면 움직이질 않으니까
실제 수식을 적용해서 V를 구하는 예시 1번.

실제 수식을 적용해서 V를 구하는 예시 2번

v의 단위가 m/s인 이유
보면 v의 단위가 m/s 로 되어있다
`속도는 일반적`으로 `시간당 이동한 거리`를 뜻한다고 하며 속도 = 거리 / 시간 이라고 한다
여기서 의문인 것은 내가 계산한 코드에서 거리 / 시간을 해서 나온 게 m/s 이 속도가 맞는지 궁금했었는데 맞다고 한다
어쩃든 V는 위 코드의 계산법을 이용해서 구하면 된다.
초기 발사 속도 v가 중요한 이유
✔ 이 값이 없으면 포물선 운동을 계산할 수 없음!
✔ 속도가 m/s 단위여야 프레임 단위(Time.deltaTime)와 곱해서 이동 거리를 계산할 수 있음!
✔ V를 vX(x축 속도)와 vY(y축 속도)로 나눠야 물체가 제대로 이동할 수 있음!
위에서 구한 초기 발사 속도 V(속도)를 x,y 방향으로 분리
갑자기 위에서 구한 초기 발사 속도를 x,y 방향으로 분리 해야한다고 한다 왜일까
float vX = projectileVelocity * Mathf.Cos(firingAngle * Mathf.Deg2Rad);
float vY = projectileVelocity * Mathf.Sin(firingAngle * Mathf.Deg2Rad);
알아본 바로는
x 방향(vX)은 속도가 변하지 않기 때문에 vX * Time.deltaTime을 이용해서 위치를 구할 수 있기 떄문이고
y 방향(vY)은 속도가 변하기 때문에 gravity를 반영해서 속도를 계속 업데이트 해야하기 때문이라고 한다.
결론은 속도를 x와 y로 따로 분리하지 않으면 중력의 영향을 올바르게 계산할 수 없는 것이 이유이고
그래서 Mathf함수를 이용하여 아래 처럼 Cos,Sin 해서 vX vY를 구했다
추가로 내 생각이긴 하지만 어쩃든 아이템을 움직일떄 translate 메서드를 통해 코루틴에서 움직이게 되는데 x랑 y값을 (실제는 y.랑 z만 쓰는듯 z는 앞뒤고 y는 위아래니까) 따로 설정하기 떄문이 아닐까 싪다.

결론 : 즉, 물리적으로 정확한 포물선 궤적을 만들 수 있음
이동 시간 계산 하기 (이동시간 = 목표거리 / 속도)
위 과정을 통해
x방향으로 가는 vX 방향 속도 값과
y방향으로 가는 vY 방향 속도 값을 구했다.
여기서 vX 이걸 가지고 이동 시간을 계산할 수 있다
단순하게 생각하면 내가 어느 지점까지 갈 건지에 대한 데이터 (목표거리)가 있고 속도(vX)가 있는데 소요시간을 모를 수가없는 것이다
이동시간에 대한 공식은
이동시간 = 목표거리 / 속도
이다.
float flightDuration = targetDistance / vX;
포물선 표현하기
- 이 코드는 아이템이 자연스럽게 포물선을 그리면서 이동하도록 계산하는 핵심 부분이다
- x 방향은 일정하게 이동하고, y 방향은 중력의 영향을 받아 점점 속도가 변하면서 포물선 궤적이 만들어진다!
float time = 0.0f;
while (time < flightDuration)
{
Debug.Log("중력 * 시간:" + gravity * time);
// 포물선 운동 적용
transform.Translate(0, (vY - (gravity * time)) * Time.deltaTime, vX * Time.deltaTime);
time += Time.deltaTime;
yield return null;
}
flightDuraion
아래 코드의 while 문 조건 부터 설명한다. flightDuration 은 위에서 구한 이동시간 이다 포물선이 도착지 까지 소요되는 시간 말이다. while문이 종료될 쯤엔 포물선 운동이 끝나있어야 한다.
transform.Translate
transform.Translate(x, y, z)를 이용해 프레임마다 위치를 갱신
ㄴx 방향(vX)은 일정한 속도로 움직임.
ㄴy 방향(vY)은 처음엔 상승했다가 중력(gravity * time) 영향으로 감소 → 포물선 궤적을 형성!
transform.Translate(0, (vY - (gravity * time)) * Time.deltaTime, vX * Time.deltaTime); 코드 설명
중력에 의해 vY 속도 줄이기
내가 위로 던진 야구공이 만약 중력을 안 받는다면 쭉 뻗어나겠지만 중력을 받으면 위로 올라가는 힘이 점점 감소되어 정점을 찍고 아래로 내려가게 된다.
위 과정을 코드로 풀어 보면 현재 vY가 y방향 ` ★ 속도 ★ `인데 중력처리를 한다고 치면 1초에 n값만큼 vY에서 빼면 된다. 그럼 올라가는 힘이 줄어들고 음수가 되면 아래로 떨어지게 되는 원리이다.
그럼 초당 9.8 중력 이라는 개념을 만들면 `gravity * time` 이라는 공식이 나오게 되고
그 초당 중력을 적용하는 것을 코드로 풀면 `vY - (gravity * time))`이 되는 것이다
[ 아래는 위에서 설명한 내용을 정리 및 예제 해놓은 글이다 ]

위 내용은 중력에 의해 vY 속도 가 줄어드는 것이다
이 속도 값 만으로는 이동거리를 계산할 수 없다
이동거리 = 속도 * 시간
이기 때문에 time delta를 따로 곱해줘야 한다 아래처럼
(vY - (gravity * time)) * Time.deltaTime)

vX 부분 설명 보기
vX * Time.deltaTime을 곱하는 이유
✔ vX는 초당 이동 속도(m/s)
✔ Time.deltaTime은 1프레임이 걸리는 시간(초)
✔ vX * Time.deltaTime은 "현재 프레임에서 이동해야 하는 거리"를 계산
vX * Time.deltaTime이 필요한 이유
✔ vX의 단위: m/s (초당 이동 거리)
✔ 게임은 초당 60프레임(60FPS)일 수도 있고, 120프레임(120FPS)일 수도 있음
✔ 만약 Time.deltaTime을 곱하지 않으면 FPS가 높을수록 너무 빠르게 움직임
💡 예제 (FPS 60일 때)
float vX = 4.0f; // x축 속도 (초당 4m)
float Time.deltaTime = 1/60f; // 60FPS 기준 1프레임 시간 (0.0167초)
float moveDistance = vX * Time.deltaTime;

✔ 즉, 1프레임에서 약 0.0667m 이동!
✔ 60프레임 동안 반복하면 정확히 4m 이동 → 초당 4m 이동 유지 ✅
Time.deltaTime을 안 곱하면 어떻게 될까?
transform.Translate(0, 0, vX);
✔ vX = 4라면,
✔ 매 프레임마다 4m씩 이동해버림 → 너무 빠름! ❌
✔ 60FPS이면 1초 동안 4m × 60 = 240m 이동 → 속도가 엉망이 됨 ❌
Time.deltaTime을 곱하면?
transform.Translate(0, 0, vX * Time.deltaTime);
✔ FPS가 높든 낮든, 1초 동안 총 이동 거리는 vX 값 그대로 유지 ✅
✔ Time.deltaTime을 곱하면 프레임 속도에 따라 적절한 이동 거리 계산 가능 ✅
📌 최종 버전
✔ vX * Time.deltaTime은 1프레임에서 이동해야 하는 거리를 계산하기 위해 필요함
✔ vX는 **초당 속도(m/s)**이므로, Time.deltaTime(초 단위)을 곱하면 **현재 프레임에서 이동할 거리(m)**가 됨
✔ 만약 Time.deltaTime을 곱하지 않으면, FPS가 높을수록 너무 빠르게 이동하는 문제가 발생
'유니티 > 구현내용정리' 카테고리의 다른 글
| 유니티 - 모바일에서 특정 해상도 UI 깨지는 문제 해결 (0) | 2025.03.19 |
|---|---|
| 유니티 방치형 프로젝트 - 아이템 획득 (이펙트) #2 (0) | 2025.03.19 |
| 유니티 방치형 프로젝트 - 코인 획득 (1) | 2025.03.16 |
| 유니티 방치형 프로젝트 - 타겟을 향해 날아가는 스킬 구현하기 #2 (0) | 2025.03.12 |
| 유니티 방치형 프로젝트 - 타겟을 향해 날아가는 스킬 구현하기 (0) | 2025.03.12 |
