저번에 네이버 겜메커 카페에서 쓴걸 그대로 가져왔어요.
오늘은 부드러운 애니메이션을 위한 Easing 알고리즘을 알아볼게요.
보통 오브젝트를 움직일 때 게임 메이커에 내장되어있는 여러 움직임에 관련된 함수들을 쓰곤 합니다.
x = 300 //x 좌표를 300으로 정의
y = 200 //y 좌표를 200으로 정의
이런 아무 생각 없는 코드로는 캐릭터가 순간이동을 해버리고 맙니다. 우리는 그런 걸 원하는게 아니에요.
그럼 다른 코드의 예를 하나 들어볼게요.
move_towards_point(x,y,speed)
이 함수는 x,y 지점으로 speed의 속도로 무언가를 이동시키는 함수입니다.
매우 간단하게 쓸 수 있지만 시작 지점부터 끝까지 지정한 speed 의 속도로 밖에 움직이지 못합니다.
그럼 speed 부분에 특정 수를 넣지 않고 계산 식을 넣으면 더 부드럽게 나오지 않을까요?
맞습니다. 스텝마다 속도를 계산해서 넣으면 부드러운 움직임이 가능해지겠지요. 빨리 넣어봅시다.
create event
step event
movespeed = 0 //초기속도 0으로 지정
left button
movespeed += 1 //매 스탭마다 속도를 1씩 높임
자 이제 어떻게 될까요. 움직이는 자동차를 생각해보죠.
move_towards_point(movetox,movetoy,movespeed)
//movetox,movetoy 지점을 향해서 movespeed 의 속도로 움직임
자동차의 속도는 0 km/h에서부터 점점 늘어나게 될거에요.
하지만 이대로라면 자동차는 도착지점까지 계속 스피드가 무한대로 늘어나며 도착지점에서 갑자기 스피드가 0이 됩니다.
좀 어색하죠. 왜냐면 현실이라면 자동차는 최고속도도 있고, 또한 감속도 해야 할테니까요.
자동차는 최대속도로 달리다 도착하려는 지점이 보이면 브레이크를 밟아서 속도를 줄여나가고 점차 0이 된 후 멈추게 됩니다.
step event
if point_distance(x, y, movetox, movetoy) > 50
{ //목표(movetox, movetoy)와의 거리가 50 초과 일 때
if movespeed < 10
{ //만약 스피드가 10 보다 작으면
movespeed += 1 //매 스탭마다 속도를 1씩 높임
}
}
else
{ //거리가 50 미만 일 때
if movespeed > 0
{ //스피드가 0보다 크면
movespeed -= 1 //매 스탭마다 속도를 1씩 높임
}
}
적당히 현실과 비슷해졌죠? 이렇듯 좀 더 현실과 비슷하게 넣으려면 수식을 열심히 생각해봐야합니다.
내 자동차가 목표지점까지 1분 만에 도착하고 싶은데 출발 때는 부드럽게 가속하고 천천히 멈췄으면 좋겠어.
뭐가 필요할까요. 현재 위치와, 목표와의 거리, 시간이 주요 변수라는 것은 생각해보면 금방 알 수 있지요.
그럼 걸리는 시간과...현재...위치...이렇게 저렇게...으아ㅏㅏ
어느 세월에 그런걸 궁리하고 있겠습니까. 누군가 벌써 이런 수식을 정리해 두지 않았을까요?
맞습니다.
http://easings.net/
Robert Penner가 고안한 자연스러운 움직임을 위한 30여개의 알고리즘 그래프가 보이실겁니다. 오 멋져.
easeInSine, easeInBack 등등...각각 이름이 붙어있습니다.
우리가 이 수식들을 이용하면 알고리즘을 통해 훨씬 자연스러운 이동을 해낼 수 있겠지요.
이번에는 어떻게 적용할지 알아보도록 할게요.
자연스러운 이동에 필요한 함수가 하나 더 있습니다. Lerp 함수입니다.
lerp(start, end, change)로 구성이 되어있는데
그림으로 보면 lerp(start,end,0) 의 값은 시작점이고, lerp(start,end,0.5) 는 중간지점이며, lerp(start,end,1) 은 끝점입니다.
보시다싶이 시작지점과 끝점을 설정하고 중간값(0~1)을 입력하면 중간위치를 계산해서 리턴해 주는 함수입니다.
당장 시험해보고 싶네요!
create event
step event
_start = x //시작 x 위치
_end = 500 //목표 x 좌표 지점
present = 0 // 현재 위치 초기화
time = 0 //현재 시간 변수
duration = 60 // 목표까지 걸리는 시간 변수 여기서는 60스텝
확인해봅시다. 60스텝에 맞춰서 원하는 목표에까지 위치 이동이 될 것입니다.
time += 1 // 1스텝 진행 중
present = lerp(_start,_end,time/duration) //(현재 시간/완료시간)에 따른 위치를 present 에 기록
x = present //x현재 위치 갱신
if time >duration time =0 // 완료시간이 넘어가면 초기화
이번에는 다시 저번 게시물에 첨부했던 파일을 살펴보도록 합시다.
easing 알고리즘의 30여가지의 함수를 새로 추가하는 파일을 첨부해드렸는데요.
알고리즘 이름(time,start,change,duration) 으로 구성되어있는데.
차례대로 현재 시간, 시작위치, 변화량, 목표까지 걸리는 시간을 넣으면 알고리즘에 따라서 위치값을 리턴해주죠.
앞서 쓴 lerp함수의 마지막 값에 이 알고리즘의 값을 넣는다면 어떻게 될까요.
물론 시간에 따라서 자연스러운 움직임을 얻게 되겠지요.
오브젝트를 하나 만들어봅시다. 이번에는 y값도 지정해보죠.
create event
step event
start_x = x //시작 x 위치
start_y = y //시작 y 위치
end_x = 500 //목표 x 좌표 지점
end_y = 300 //목표 y 좌표 지점
presentx = 0 //현재 x좌표
presenty = 0 // 현재 y좌표
time = 0 //현재 시간 변수
duration = 60 // 목표까지 걸리는 시간 변수 여기서는 60스텝
time += 1 //스텝마다 1을 더해줌
easings = easeInOutCubic(time, 0, time/duration,duration)
//easeInOutCubic 알고리즘의 값을 리턴해서 easings에 기록 easeInOutCubic자리에 다른 알고리즘을 넣어도 됨.
presentx = lerp(start_x,end_x,easings)
presenty = lerp(start_y,end_y,easings)
x = presentx //현재 x 위치 갱신
y = presenty // 현재 y위치 갱신
if time >duration time =0 // 완료시간이 넘어가면 초기화
각 캐릭터에 EaseInBounce,EaseInOutQuint,EaseInSine를 적용해보았습니다.
잘 되는지 확인해보세요. 그리고 다른 30여개의 알고리즘도 넣어보고 기본적인 코드를 수정해서 자신에게 알맞고 쓸만하게 응용도 해봅시다.
물론 캐릭터 뿐만이 아니라 메뉴UI의 움직임같은 부분에서도 쓸 수 있겠지요.
게임메이커에서 쓸 수 있는 알고리즘 파일이에요 easing.gml
네이버까페에서 가져오는 이미지는 네이버에서 타사이트에서 링크로 오는걸 막는지 안보일 경우가 많더라구요.