본문 바로가기
자바스크립트와 캔버스

바빌론JS - 경로 우대? 경로 따라 걷는 NPC

지난 시간에는 한자리를 빙글 빙글 돌며 걷는 NPC를 만들었는데요.
움직임이 좀 단순하지요?

https://itadventure.tistory.com/695

 

바빌론JS - 이동하는 NPC

지난 시간에는 마을을 달리는 미니 자동차에 대해 다뤄보았습니다.https://itadventure.tistory.com/693 미니자동차 마을을 달리다이번 시간에는 지난 시간에 이어 https://itadventure.tistory.com/692 바빌론JS -

itadventure.tistory.com

이번 시간에는 경로를 따라 걷는 NPC를 다뤄보겠습니다.

튜토리얼을 참고하긴 했지만 세컨드라이프에서 익혔던 크레이 나름의 기술을 활용하였습니다.


레이저를 쏴라! ( 좌표 조사 )

경로란 캐릭터가 이동하는 길을 의미하는데요. ( 아래 파란선 )

이 경로를 독자 여러분께서 조사해서 정의할 수 있습니다.
숫자 계산 일체 없이 말이지요.
참고로 튜토리얼에는 없는 크레이의 전용 기술이기도 하지만 이번에 공개합니다~

3차원 그래픽에는 레이캐스트라는 멋진 기술이 있는데요.
카메라화면에서 마우스 클릭하는 지점을 기준으로 화면 앞으로 보이지 않는 레이저를 발사하는 기술입니다.
그러다 어떤 물체에 레이저가 부딪히면 그 부분의 3차원 좌표를 알아 낼 수 있는 것이지요.

먼저 이 기능을 구현해야 경로를 만들 좌표를 조사할 수 있습니다.
바빌론에서는 레이캐스트라는 이름을 쓰지는 않고 pick()이라는 이름을 사용합니다.

코드 가장 위쪽의 아래 코드를 찾아

const engine = new BABYLON.Engine(canvas,true);

다음 코드를 추가하고

// 입력 시스템
const deviceInputSystem = new BABYLON.DeviceSourceManager(engine);
// 마우스
const mouseDeviceSource = deviceInputSystem.getDeviceSource(BABYLON.DeviceType.Mouse);

아래 코드를 찾아

const scene = createScene();

그 아래 함수를 하나 추가해 주세요.

// 마우스 클릭 추적 3차원 벡터 추출 ( cray )
// 필요할 떄 scene.onBeforeRenderObservable.add 에 넣고
// 메쉬를 클릭, alert 창에서 좌표를 복사할 수 있습니다.
function mousepick_traceVector3d()
{
    if (mouseDeviceSource.getInput(BABYLON.PointerInput.MiddleClick)) {
        const picking = scene.pick(scene.pointerX, scene.pointerY);
        if (picking.hit) {
            const Point = picking.pickedPoint;
            prompt("복사하세요.", "new BABYLON.Vector3( "
                + Point.x.toFixed(2) + ", " 
                + Point.y.toFixed(2) + ", " 
                + Point.z.toFixed(2) + " )");
        }
    }
}

그리고 아래 코드를 찾아 

scene.onBeforeRenderObservable.add(() => {

함수 안쪽에 아래 코드를 추가해 주시면 됩니다.

 // 마우스 클릭 3차원 벡터 추적
mousepick_traceVector3d();

이제 어떤 일이 일어 났을까요?
NPC는 여전히 한자리를 뺑뺑이 돌고 있고 화면에는 아무 변화가 없는데요.
자, 이제 땅바닥 아무곳이나 마우스 가운데 버튼을 클릭해 보세요. ( 집 건물 말구요 :) )

좌표가 보이네요. 이 좌표가 바로 금방 클릭한 3차원 좌표입니다.
확인이나 취소 버튼을 눌러 닫아 주세요.


작은 경로 만들어 보기

캐릭터가 이동할 경로를 만들어 보겠습니다.
처음부터 크게 작업하면 확인하기 힘드니 캐릭터에 가까운 위치를 시범 삼아 해볼텐데요.

먼저 경로를 배열로 저장할거니,
아래 코드를 찾아

mesh.position.y = 0.55;

그 아래 코드를 추가해 주세요.

// 경로 정의
const track = [];

이제 첫번째 이동할 위치를 지정해보죠.
1) 번 표시된 위치를(정확하지 않아도 됩니다) 마우스 가운데 버튼 클릭하면 팝업창이 나옵니다.
2) Ctrl + C 버튼으로 코드를 복사해 주세요
3) 그리고 확인 버튼을 눌러 창을 닫습니다.

이제 금방 복사한 코드를 추가한 다음,

new BABYLON.Vector3( -0.50, 0.00, 0.39 )

앞 뒤를 track.push() 함수로 감싸 주세요.
이렇게 말이지요.

track.push(new BABYLON.Vector3( -9.24, -0.00, -0.42 ));

이어서 또 다른 위치를 마우스 우클릭한 다음 똑같은 동작을 반복해 줍니다.

track.push(new BABYLON.Vector3( 0.71, 0.00, 0.80 ));

이렇게 좌표를 하나 더 조사해 3군데 좌표를 만들어 줍니다.

track.push(new BABYLON.Vector3( 0.13, 0.00, 0.12 ));

그리고 처음 조사한 좌표를 복사하여 마지막 줄에 추가해 줍니다.

이제 작은 삼각형의 경로가 완성되었습니다.
아래 코드를 추가하여 삼각형의 경로를 확인할 수 있습니다.

 // 경로를 선으로 그림
const pathLine = BABYLON.MeshBuilder.CreateLines("triangle", {points: track});
pathLine.color = new BABYLON.Color3(1, 0, 0);

빨간 가느다란 선 보이시지유 ? :)


캐릭터, 첫번째 위치로!

이제 NPC가 첫번째 목표 지점을 바라보고 앞으로 나아가게 할텐데요.
이동하는 코드를 새로 만들 겁니다.
지난번 작업했던 걸 삭제하고 다시 처음부터 할 겁니다.

아래 코드를 삭제하고,

// 왼쪽을 바라보게 회전
mesh.rotate(
    BABYLON.Axis.Y, 
    -Math.PI / 2, 
    BABYLON.Space.LOCAL
);

let distance = 0;

아래 코드도 삭제해 주세요.

distance += step;
if (distance > p + 1) {                    
    mesh.rotate(
        BABYLON.Axis.Y, 
        BABYLON.Tools.ToRadians(-90), 
        BABYLON.Space.LOCAL
    );
    p++;
    if (p === 4) {
        p = 0;
        distance = 0;
    }
}

그리고 아래 코드를 찾아

let p = 0;

그 아랫 부분에 코드를 추가합니다.

mesh.lookAt(track[p]);

lookAt() 함수는 대상 좌표를 바라보게 하는 함수입니다.
그러니까 첫번째 목표 지점 ( -0.50, 0.00, 0.39 ) 을 바라보게 하고,
앞으로 직진하면 해당 좌표로 이동하는 것이지요.

그런데 실행해보면 한가지 문제가 있습니다.

캐릭터가 첫번째 좌표로 가긴 가는데 땅속으로 들어갑니다.
왜 그럴까요?

그것은 이 캐릭터의 경우 머리 위치의 Y축 중심점이기 때문인데요.
이 경우 경로의 Y 높이를 캐릭터 높이와 똑같이 맞춰 주어야 합니다.

track.push 마지막 행을 찾아

track.push(new BABYLON.Vector3( -0.50, 0.00, 0.39 ));

그 아래에 다음 코드를 추가해 주세요.

// 캐릭터와 높이값을 맞춤
track.forEach((number, index)=>{
    track[index].y=mesh.position.y;
});

이제 똑바로 이동하는데요.
첫번째 목표 지점을 지나 무한 직진하는 건 아직 다음 목표 지점 회전 기능을 안 만들었기 때문이지요.


코스 뺑뺑이

본격적으로 코스를 따라 도는 코딩을 하겠습니다.
원리는 "목표 지점의 다다르면 다음코스로"라는게 원칙인데요.
이동하는 속도가 있다보니 정확히 목표 좌표에 도달하지는 않고 근접 지점에 도달하면 다음 지점으로 이동하게 해야 합니다.

아래 코드를 찾아

mesh.movePOV(0, 0, -step);

아래 코드를 추가해 주세요.

let distance = 
    Math.sqrt( Math.abs( mesh.position.x - track[p].x ) ) +
    Math.sqrt( Math.abs( mesh.position.z - track[p].z ) );

if(distance < 0.2)
{
    p++;
    if(p>=track.length)p = 0;
    mesh.lookAt(track[p]);
}

그러면 NPC 가 코스를 따라 빙글 빙글 돕니다.

주의하실 점은 이동 속도를 높이면 근접 지점을 그냥 지나칠수 있습니다.
그럴 때는 아래 코드의 숫자값(0.2)을 더 높여주어야 합니다.
여러번 실험해 값을 찾아내시면 됩니다 :)

if(distance < 0.2)

이제 캐릭터를 코스 처음 위치부터 출발하게 합시다.
아래 코드를 찾아

let p = 0;

아래 코드를 추가해 주세요.

// 캐릭터를 시작 위치로
mesh.position = track[p];

그러면 첫번째 위치에서 출발하는 NPC를 보실 수 있습니다.


거대한 코스도 문제 없어

이제 핵심 코드는 완성되었습니다.
코스가 작든 크든 NPC는 코스대로 따라갈텐데요.
마을 전체를 순회하는 코스를 만들어 봅시다.
마을 전체를 순회하는 좌표를 마우스 가운데 클릭으로 모두 조사해 줍니다.
그림과 똑같지 않아도 됩니다.

원래 trace.push(...) 을 모두 지우고 해당 좌표 목록을 넣어 주세요.

track.push(new BABYLON.Vector3( -9.24, -0.00, -0.42 ));
track.push(new BABYLON.Vector3( 0.18, -0.00, 2.19 ));
track.push(new BABYLON.Vector3( -0.14, 0.00, 4.02 ));
track.push(new BABYLON.Vector3( 3.75, 0.00, 4.12 ));
track.push(new BABYLON.Vector3( 3.75, -0.00, -4.45 ));
track.push(new BABYLON.Vector3( 1.83, -0.00, -5.58 ));
track.push(new BABYLON.Vector3( 0.98, 0.00, 0.95 ));
track.push(new BABYLON.Vector3( -4.11, 0.00, 0.68 ));

그리고 첫번째 track.push(...); 코드는 복사해서
맨 아래에 한번 더 넣어주시면 됩니다.

이제 코스를 따라 순회하는 NPC를 보실 수 있습니다.

실습이 어려우신 분은 크레이가 준비한 결과물 페이지를 참조해 주세요.

http://dreamplan7.cafe24.com/babylon/ex13/

이제 빨간 경로선은 보이지 않게 숨겨주셔도 됩니다.

경로선이 있든 없든 NPC는 경로를 잘 따라 가거든요 :)
아래 코드를 찾아

const pathLine = BABYLON.MeshBuilder.CreateLines("triangle", {points: track});
pathLine.color = new BABYLON.Color3(1, 0, 0);

주석처리해주시면 경로선이 사라집니다.

// const pathLine = BABYLON.MeshBuilder.CreateLines("triangle", {points: track});
// pathLine.color = new BABYLON.Color3(1, 0, 0);

좌표를 조사하는 코드도 마찬가지입니다.
아래 코드를 찾아

mousepick_traceVector3d();

주석처리해주시면 좌표 조사 기능이 중지됩니다.

//mousepick_traceVector3d();

마무~리

코스를 따라 걷는 NPC, 흥미로우셨나 모르겠네요 :)
다음에는 또 어떤 이야기가 기다리고 있을까요?
오늘도 방문해주신 분들께 감사드립니다.


다음 게시글 : https://itadventure.tistory.com/697

 

바빌론JS - 미니자동차의 마을 탐방

지난 시간에는 마을을 돌아다니는 NPC가 주인공이었지만,https://itadventure.tistory.com/696 바빌론JS - 경로 우대? 경로 따라 걷는 NPC지난 시간에는 한자리를 빙글 빙글 돌며 걷는 NPC를 만들었는데요.움

itadventure.tistory.com