일단 물리 연산은 Update()가 아니라 FixedUpdate()에 구현한다
FixedUpdate()
: 물리 연산 프레임마다 호출되는 생명주기 함수
오브젝트를 이동시키는 방법 세가지
public class Player : MonoBehaviour
{
public Vector2 inputVec;
public Rigidbody2D rigid;
private void Awake()
{
rigid = GetComponent<Rigidbody2D>();
}
private void Update()
{
inputVec.x = Input.GetAxis("Horizontal");
inputVec.y = Input.GetAxis("Vertical");
}
private void FixedUpdate()
{
//1. 힘을준다
rigid.AddForce(inputVec);
//2. 속도 제어
rigid.velocity= inputVec;
//3. 위치 이동 -체스말 이동하듯
rigid.MovePosition(rigid.positioninputVec);
}
}
1. 힘을 준다
rigid.AddForce(inputVec)
2. 속도 제어
rigid.velocity= inputVec;
3. 위치 이동 (체스말 이동하듯 position자체를 다룸)
rigid.MovePosition(rigid.positioninputVec);
- MovePosition은 그냥 rigid.MovePosition(rigid.positioninputVec)만 해주면 안됨.
- inputVec은 우리가 방향키를 누른 "방향"을 의미하기 때문에 rigid.position 과 더해주어야 한다
- 현재 rigid.position은(0, 0, 0);이고 inputVec은 누른키에따라 (0,1) (-1, 0) (1,0) 등등.. 이 둘을 더해주는 것
- transform.position 과 다르게 rigid.position은 물리의 위치이다
1,2번은 참고하고 3번의 방식 사용할건데
rigid.MovePosition(rigid.positioninputVec);
라고만 쳐서 실행시키면 움직여지긴 하는데 너무 빠르다. 그리고 컴퓨터 프레임에 따라 속도가 달라질 수 있다
결론부터 얘기하면
대각선의 속도가 좌우보다 더 빠른것 : normalized() (벡터의 정규화) 사용하여 해결
컴퓨터 프레임에 따라 속도가 다른것 : Time.fixedDeltaTime 사용하여 해결
normalized()
벡터를 정규화 시킨다.
x,y축으로 이동할땐 (1,0) (0,1) 로 벡터의 크기가 1이겠지만
대각선으로 이동할땐 피타고라스 정리에 의해 루트 2이다. 실제로 1.414...의 값이 나옴
그래서 정규화를 하지 않으면 대각선에서 더 빠르게 이동된다. 정규화 이후로 대각선 벡터는 (0,707.. , 0.707..)로 이동됨
따라서 코드 변경
private void FixedUpdate()
{
Vector2 nextVec = inputVec.normalized * speed * Time.fixedDeltaTime; //다음 나아갈 방향의 크기
rigid.MovePosition(rigid.position + nextVec); //+ inputVec 대신 정규화 등의 연산을 거친 nextVec사용
}
Time.DeltaTime
Time.fixedDeltaTime
FixedUpdate한번 만큼 (= 물리 프레임 하나가) 소비된 시간
이 코드가 실질적으로 "성능에 무관하게 Time.fixedDeltaTime"으로 두 사용자가 동일한 FPS결과값을 보장하게 하는 코드이다. 거의 필수적이네
Time.DeltaTime 은 Update()에서,
(의미는 Time.fixedDeltaTime 과 마찬가지로 이전프레임에서 현재 프레임까지 걸린 시간이다)
Time.fixedDeltaTime은 FixedUpdate()에서 사용한다
만약,
int speed=1;
void Update(){
shotBullet += speed;
}
정리하면,
슈퍼 컴퓨터는 1초에 1000프레임이라고 가정하자.
그러면 Time.deltaTime는 1/1000(1000분의 1)이다.
이것을 곱하면 1000 * speed * 1/1000 이므로 = speed만 남는다.
게임용 일반 컴퓨터는 1초에 80프레임이라고 가정하자.
그러면 Time.deltaTime는 1/80(80분의 1)이다.
이것을 곱하면 80 * speed * 1/80 이므로 = speed만 남는다. (프레임이 달라도 동일한 결과값)
참고: https://codingmania.tistory.com/172
Input.GetAxis vs Input.GetAxisRaw
이제 다시 실행시켜서 Inspector 창의 speed값을 할당해주면 플레이어가 정상적으로 움직인다.
하지만 키보드를 놓았을 때 미끄러지는 감이 심한데, 이것은
Input.GetAxis가 입력값을 부드럽게 만드는 보정이 들어가서 그렇다 이게 싫다면
Input.GetAxisRaw로 더 명확한 컨트롤 구현이 가능하다