-
Notifications
You must be signed in to change notification settings - Fork 0
튜토리얼 1. 함선 움직여 보기 (2)
자 그럼 빠르게 두번째 목표인 특정 위치로 함선을 움직여 보려합니다.
특정 위치로 움직이기전에, 극좌표를 알고 넘어가야 합니다.
극좌표(polar coordinate)란
STARPOO의 좌표계는 극좌표(polar coordinate) 입니다. 기준점을 중심으로 한 점을 x,y가 아닌, 거리(r)와 각도(θ)로 표현하는 좌표계입니다. STARPOO에서는 각도로 degree 단위를 사용하고 있습니다. 위 그림과 같이, 원점을 중심으로 오른쪽 정방향이 0도이며 각도가 증가하면 반시계방향으로 회전하게 됩니다.
자 그럼 가장 쉽게 (0, 0)인 지점인 원점으로 함선을 이동시켜 보도록 하죠.
먼저 현재 함선의 위치를 가져와야겠죠?
STARPOO API 에서 제공하는 polarFrom({x, y, rot}, {x, y})
함수를 사용하면 쉽게 함선과 target 사이의 거리와 각도를 구할 수 있습니다.
polarFrom({x, y, rot}, {x, y})
함수의 반환값인 rot과 r은
-
r
: 첫번째 인자와 두번째 인자간의 거리를 의미하며, -
rot
: 첫번째 인자가 바라보고 있는 방향을 기준으로 두번째 인자와의 각도를 의미합니다.
지금 우리는 원점과 함선사이의 거리와 각도를 구할 것이기 때문에 첫번째 인자에 myShips[0]을, 두번째 인자에 {x: 0, y: 0}
를 넣어주면 됩니다. 따라서 현재 함선의 위치에서 원점까지 거리와 각도를 구하기 위해 아래와 같이 코드를 작성한 뒤 log를 살펴 봅시다.
function update(){
var pos = polarFrom(myShips[0], {x: 0, y: 0});
// 로그 찍어보기
log("rot : " + pos.rot);
log("r : " + pos.r);
}
자, 이제 우리는 현재 함선과 원점 사이의 거리와 각도를 알았습니다. 이 정보를 토대로 함선을 원하는 위치인 원점으로 이동시키려합니다. 이를 위해서 함선이 수행해야하는 일은 두가지로 볼 수 있습니다.
- 함선의 뱃머리를 목표지점으로 돌리기
- 함선을 목표지점에 도착하지 않았다면 전진
위의 두가지 수행을 토대로 코드를 작성하여 봅시다.
var b_once = true;
function update() {
var ship = myShips[0];
var destination = {x: 0, y: 0};
var pos = polarFrom(ship, destination);
// 함선을 목표지점에 도착하지 않았다면
if (pos.r > 0) {
myShips[0].setRotSpeed(pos.rot); // 1. 함선의 뱃머리를 목표지점으로 돌리기
myShips[0].setSpeed(shipMaxSpeed); // 2. 전진
}
// 목표 지점 도착
else
{
// 정지
myShips[0].setRotSpeed(0);
myShips[0].setSpeed(0);
if (b_once) {
b_once = false;
log("x : " + ship.x);
log("y : " + ship.y);
}
}
}
원점으로 가 멈추는 모습을 볼 수 있습니다.
그렇다면 위에서 작성한 script에 목적지만 (200, 700)으로 변경한 뒤 스크립트를 돌려 봅시다.
var b_once = true;
function update() {
var ship = myShips[0];
var destination = {x: 200, y: 700};
var pos = polarFrom(ship, destination);
...
}
정확한 점에 멈추지 않고 빙글빙글도는 모습을 보게됩니다.. 왜 이런걸까요?
이러한 현상의 원인을 아래와 같이 3가지 정도로 추려볼 수 있습니다.
- 목표 지점에 거의 도착할때 감속하지 않아서 지나쳐가게됨
- 마찬가지로 목표 각도에 거의 도착할때 각도 회전을 감속하지 않아서 지나쳐가게됨
- 거리(r)의 오차 범위 고려 안함
무슨말인지 모르겠다고요? 위의 원인을 하나씩 뜯어보며 이해해 봅시다.
위에서 우리는 함선의 속도를 shipMaxSpeed
로 설정하였습니다. 즉, 함선은 1초당 shipMaxSpeed 만큼의 거리를 이동하게 되며, 이는 1 Frame 에 (shipMaxSpeed / 초당 프레임 수) 만큼의 거리를 이동하게 됩니다.
여기서, STARPOO 는 초당 30 Frame의 고정된 수치로 게임을 출력하므로, shipMaxSpeed
값이 300이므로 1 Frame 에 최대 10만큼 움직이게 됩니다. 그렇다면, 만약 함선이 이동하고자 하는 목표의 거리가 701이라면 어떻게 될까요. 함선은 70 Frame이 지나고 목표 지점과 거리가 1이되지만, 우리가 원하던 r 이 0이 되지 않았으므로 71번째 Frame에는 목표지점을 지나쳐 가게 됩니다. 즉, 이러한 고질적인 문제를 가지고 있어서 1 Frame 당 이동거리인 10의 배수만큼의 거리가 아니라면 정확히 멈추긴 힘듬을 알 수 있습니다.
현재 함선이 최대 속도로 이동하고 있다는 가정하고, 그렇다면 우리는 1 Frame 동안 움직일 수 있는 최대 이동거리를 목표 지점과의 거리의 오차범위로 설정하여 이 문제를 해결할 수 있습니다.
즉, if (pos.r > 10)
함선과 목표 지점사이의 거리가 10 이내라면 이동을 멈추는 방법이죠. 아래는 적용한 모습입니다.
function update() {
var ship = myShips[0];
var destination = {x: 0, y: 0};
var pos = polarFrom(ship, destination);
// 함선을 목표지점에 도착하지 않았다면
if (pos.r > 10) {
myShips[0].setRotSpeed(pos.rot); // 1. 함선의 뱃머리를 목표지점으로 돌리기
myShips[0].setSpeed(shipMaxSpeed); // 2. 전진
}
...
}
하지만, 뭔가 찝찝하지 않나요?
함선은 우리가 이동하길 원했던 지점과 거리가 최대 10까지 차이가 날 수 있습니다. (물론 기적적으로 딱 원하는 지점에 떨어질수도 있죠)
이러한 오차는 상대 함선을 조준하여 맞춰야하는 전략가 입장에서 달가운 소식은 아닙니다.
그렇기에 우리는 한가지 테크닉을 덧붙여 오차범위를 거의 0에 가깝게 최소화 하고자 합니다.
바로 **감속
**입니다.
위와 마찬가지 이유로 회전 속도 또한 감속이 필요합니다.
자, 위에서 설명한 감속에 대한 보정을 적용해 보도록 하겠습니다.
var bonce = true;
function update() {
var ship = myShips[0];
var dest = {x: 200, y: 700};
var pos = polarFrom(ship, dest);
if (pos.r > 1) {
myShips[0].setRotSpeed(pos.rot / dt);
myShips[0].setSpeed(pos.r / dt);
}
else
{
myShips[0].setRotSpeed(0);
myShips[0].setSpeed(0);
if (bonce) {
bonce = false;
log("x : " + ship.x);
log("y : " + ship.y);
}
}
}