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

바빌론JS - NPC, 내 이름은 케이!

지난 시간 엄청난 기술들을 선보이며 1위 자리를 다시 탈환한 미니 자동차,

https://itadventure.tistory.com/697

 

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

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

itadventure.tistory.com

우리의 NPC군도 가만 있을순 없다고 하네요. 그러면서 본인의 이름을 밝히는데요..

본 게시글은 바빌론 공식 튜토리얼로 시작했다가 점점 안드로메다로 가는 크레이의 입맛에 맞는 게시글입니다 :)


관심받고 싶은 NPC

미니자동차의 활약에 NPC군, 카메라의 주도권을 본인도 갖고 싶다고 합니다.
하지만 미니 자동차도 그것만은 양보할 수 없다고 하네요. 이것 참 난감합니다.
옆에서 지켜보던 PD, 한가지 아이디어를 제안하는데요.
버튼을 2개 만들어 누를때마다 카메라를 전환하는건 어떠냐고 하네요.

사실 NPC에게 카메라를 붙이는건 간단합니다.

아래 자동차 모델을 불러오는 함수 안에서

 BABYLON.SceneLoader.ImportMeshAsync(
        "", 
        "./", 
        "car.glb").then((result) =>  {

카메라의 대상이 되는 코드를 삭제하고

camera.lockedTarget = mesh;

캐릭터 모델을 불러오는 쪽으로 옮기면 그만이거든요.

하지만 버튼 2개를 만드려면 UI를 준비해야 합니다.
UI를 먼저 붙이는 부분을 살펴보겠습니다:)


패널과 버튼 추가

제일 먼저 GUI 를 붙이겠습니다. ( 그래픽 유저 인터페이스의 준말입니다 )

아래 코드를 찾아,

var scene = new BABYLON.Scene(engine);

GUI 를 총괄하는 코드를 추가합니다.
이제 advencedTexture 가 모든 GUI의 제어도구가 되는 거지요.

// GUI
const advancedTexture = BABYLON.GUI.AdvancedDynamicTexture.CreateFullscreenUI("UI");

그리고 버튼 2개를  추가하면 되는데요.
미리 함수화 코드를 추가하도록 하겠습니다.

아래 코드를 찾아

// 씬 리턴
return scene;

그 위에 ui를 준비할 함수 코드를 추가해 주세요.

GUISystem(camera, advancedTexture);

그리고 UI준비 함수는 그 아랫 부분에 다음 코드를 찾아

    // 씬 리턴
    return scene;
};

그 아래 함수코드를 추가하면 됩니다.

function GUISystem(camera, advancedTexture)
{
    // 패널 UI 추가
    const panel = new BABYLON.GUI.StackPanel();    
    // 가로 중앙 정렬
    panel.horizontalAlignment = BABYLON.GUI.Control.HORIZONTAL_ALIGNMENT_CENTER;
    // 세로 하단 정렬    
    panel.verticalAlignment = BABYLON.GUI.Control.VERTICAL_ALIGNMENT_BOTTOM;    
    // 하단 여백
    panel.paddingBottom = 20;
    // 패널을 UI 시스템에 붙임
    advancedTexture.addControl(panel);   

    // 버튼1 추가
    const button = BABYLON.GUI.Button.CreateSimpleButton("btnpc", "Follow NPC");
    button.width = 0.1; // 가로폭 10%
    button.height = "40px"; // 세로높이 40픽셀
    button.color = "white"; // 글자섹
    button.background = "green";    // 배경색
    button.cornerRadius = 5;    // 버튼 모서리 둥근 정도
    panel.addControl(button);   // 버튼을 패널에 붙임
    
    // 버튼2 추가
    const button2 = BABYLON.GUI.Button.CreateSimpleButton("btnCar", "Follow Car");
    button2.width = 0.1; // 0.2 = 20%
    button2.height = "40px";
    button2.cornerRadius = 5;
    button2.color = "white";
    button2.background = "blue";
    panel.addControl(button2);
}

화면이 이렇게 보이실텐데요.
하단에 버튼 2개가 보이실 겁니다. 아직 눌러도 아무 작동은 안 합니다.


카메라 코드 함수화

이제 카메라 코드를 함수화해서 버튼 누를때마다 전천후로 쓸 수 있도록 하겠습니다.
이렇게 생긴 코드가 있을텐데요.

// 팔로우 카메라
const camera = new BABYLON.FollowCamera(
    "FollowCam", 
    new BABYLON.Vector3(-6, 0, 0), 
    scene
);

// 대상과의 거리
camera.radius = -1;

// 카메라의 높이
camera.heightOffset = 0.5;

// 카메라 가속도
camera.cameraAcceleration = 0.005

//최대 가속도
camera.maxCameraSpeed = 10

camera.wheelDeltaPercentage = 0.01; // 마우스휠 속도
camera.minZ = 0;    // 근거리 커팅 X

// 카메라 캔버스 연결
camera.attachControl(canvas, true);

이와 같이 코드를 변경해 주세요.

// 팔로우 카메라
const camera = new BABYLON.FollowCamera(
    "FollowCam", 
    new BABYLON.Vector3(-6, 0, 0), 
    scene
);

followCam(camera, null);

그리고 금방 GUISystem 함수를 정의한 아랫 부분에 카메라 함수를 추가합니다.

function followCam(camera, mesh){
    if(mesh!=null)camera.lockedTarget = mesh;
    // 대상과의 거리
    camera.radius = -1;    
    // 카메라의 높이
    camera.heightOffset = 0.5;    
    // 카메라 가속도
    camera.cameraAcceleration = 0.005    
    //최대 가속도
    camera.maxCameraSpeed = 10
    camera.wheelDeltaPercentage = 0.01; // 마우스휠 속도
    camera.minZ = 0;    // 근거리 커팅 X

    // 카메라 캔버스 연결
    camera.attachControl(canvas, true);
}

아직 기능상의 변화는 없지만 이로써 카메라를 자유롭게 전환할수 있는 기반이 마련되었습니다.


버튼 클릭하여 카메라 전환하기

카메라가 NPC, 차를 따라가게 하려면
NPC, 차 모델 glb 파일을 받아올 때 mesh를 함수 내부가 아닌 외부에 저장해야 합니다.

// 이 상태로를 쓸수 없어...
BABYLON.SceneLoader.ImportMeshAsync(
    "", 
    "./", "character01.glb", scene).then((result) => {
    var mesh = result.meshes[0];

아래 코드를 찾아

var createScene = function () {

그 위 변수를 선언합니다. 각각 미니자동차, 캐릭터 메쉬를 저장할 변수입니다.

let mesh_car = null;
let mesh_npc = null;

자동차 모델 불러오는 아래 코드를 찾아

// 자동차 부르기
BABYLON.SceneLoader.ImportMeshAsync(
    "", 
    "./", 
    "car.glb").then((result) =>  {
    // 로딩 후 실행할 코드        
    var mesh = result.meshes[0];

아래 코드를 추가합니다.

mesh_car = mesh;

역시 캐릭터 모델을 불러오는 코드를 찾아

BABYLON.SceneLoader.ImportMeshAsync(
    "", 
    "./", "character01.glb", scene).then((result) => {
    var mesh = result.meshes[0];

아래 코드를 추가합니다.

mesh_npc = mesh;

자, 거의 다 왔습니다. 마지막으로 버튼을 누르면 카메라를 바꾸는 코드입니다.
GUISystem() 함수 안에서 아래 코드를 찾아,

panel.addControl(button);   // 버튼을 패널에 붙임

버튼1 클릭시 작동할 코드를 추가합니다. mesh_npc 를 카메라가 따라가는 코드입니다.

// 버튼 클릭 이벤트
button.onPointerClickObservable.add(() => {
    followCam(camera, mesh_npc);
});

버튼2 도 마찬가지로 추가해주죠.
아래 코드를 찾아

panel.addControl(button2);

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

button2.onPointerClickObservable.add(() => {
    followCam(camera, mesh_car);
});

이것으로 끝입니다.
이제 Follow NPC 버튼을 누르면 카메라가 NPC 를 따라가고

Follow Car 버튼을 누르면 카메라가 미니자동차를 따라갑니다.


내 이름은 케이!

NPC 군이 이걸로 끝낼수 없다고 하네요.
뭔가 특별한 걸 보여줘야 한다며 자신의 이름을 공개한다고 합니다.

GUI 시스템에는 NPC 머리 위에 이름을 뛰우는 기능이 있는데요.
코드가 간단하더라구요.

금방 추가한 mesh_npc 코드를 찾아

 mesh_npc = mesh;

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

// NPC 이름
// 검정 배경
const rect1 = new BABYLON.GUI.Rectangle();
rect1.width = "100px";
rect1.height = "40px";
rect1.cornerRadius = 5;
rect1.color = "White";
rect1.thickness = 0;
rect1.background = "black";
rect1.alpha = 0.5;  // 투명도
advancedTexture.addControl(rect1);        
// 글자
var label = new BABYLON.GUI.TextBlock();
label.text = "NPC 케이";
rect1.addControl(label);
rect1.linkWithMesh(mesh_npc);   // 메시에 붙이기
rect1.linkOffsetY = -50;        // 메시 위로 띄우는 간격

그러면 이렇게 NPC 위에 이름 태그가 붙습니다. 한글도 되더라구요.

전체 소스가 궁금하거나 실습이 어려우신 분은 아래 크레이가 준비한 URL을 참조해 주세요.

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


마무~리

미니자동차와 NPC의 불꽃튀는 신경전, 다음에는 또 어떤 이야기가 기다리고 있을까요?
필요하신 분에게 도움이 되시길 바랍니다 :)

오늘도 방문해주신 모든 분들께 감사드립니다.


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

 

바빌론JS - 내 진짜 정체를 알려주지.

지난 시간 카메라 주도권 쟁탈전을 벌이던 NPC군은 자신의 이름을 밝혔는데요.https://itadventure.tistory.com/698 바빌론JS - NPC, 내 이름은 케이!지난 시간 엄청난 기술들을 선보이며 1위 자리를 다시 탈

itadventure.tistory.com