인간의 마음
카테고리
작성일
2021. 9. 12. 04:52
작성자
cooker

이전 글에서, quartett이라는 룰의 시스템을 소개하며 캐릭터시트의 능력치 9가지에 대해 설명하고 html 코드를 작성해보았습니다. 이번에는 거기서 조금 더 복잡한 계산을 수행할 수 있도록, javascript를 써 봅시다.

구글 스프레드시트나 엑셀을 사용해 보셨다면, 함수가 어떤 방식으로 작동하는지 이해하실 거라고 생각합니다. js도 마찬가지인데, 컴퓨터의 연산능력은 매우 빠르기 때문에 모든 것을 동시에 처리하는 것처럼 보이지만 실제로는 무언가를 순서대로 수행하고 있습니다. 그래서 roll20의 캐릭터시트 내에 js를 사용하려면 html의 모든 코드를 작성한 뒤, 가장 끝부분에 <script type="text/worker"></script>로 쓰게 됩니다. 맨 위에 쓰거나 중간에 그것을 쓰면, js에서 처리해야 할 값이 이전까지의 html 중에 존재하지 않았기 때문에 없다고 생각하고 처리를 하지 않을 수 있어요.  그러면 html의 맨 끝에 Sheet Worker Scripts를 쓰겠습니다.

<script type="text/worker">
	on("change:math change:language change:social change:nature change:body change:machine change:living change:birth", function() {
        getAttrs(["math", "language", "social", "nature", "body", "machine", "living", "birth"], function(values) {
            setAttrs({total: Number(values.math)+Number(values.language)+Number(values.social)+Number(values.nature)+Number(values.body)+Number(values.machine)+Number(values.living)+Number(values.birth)}
            );
        });
    });
</script>

먼저 1번째 줄과 8번째 줄은 그 안에 javascript를 적겠다고 말하고 있습니다. 그러면 roll20에서는 이것을 인식하고 처리해주기로 합니다.

그 다음 2번째 줄에서는 언제! 이 처리를 할 지에 대한 이벤트 타이밍을 지정해줍니다. 가령 change:math라는 것은 math라는 항목의 값이 변경될 때를 말합니다. 여러 타이밍을 띄어쓰기(space)로 구분하여 나열하였는데, 이 중 하나라도 해당되면 그 안에 속한 명령을 처리합니다. 이벤트는 값이 변경되는 change 뿐만 아니라 시트를 열었을 때마다의 sheet:opened, 어떤 버튼을 클릭했을 때의 clicked:도 있으니까 roll20위키(https://wiki.roll20.net/Sheet_Worker_Scripts)를 참고하세요. 그리고 7번째 줄에서 닫아주었다는 것을 확인할 수 있습니다.

3번째 줄부터 6번째 줄까지는 무엇을 할 것인지에 대한 내용이 그 안에 들어있는데, 먼저 getAttrs는 각각의 항목들의 값이 얼마인지를 받아오는 함수입니다. 이 끝에서 function(values)라고 하였기 때문에 이제부터 values.math라고 하면 우리가 실제로 캐릭터시트에서 입력한 값이 이것이 됩니다. 그리고 중괄호{를 열고 6번째 줄에서 }닫아서 이 안에서 처리하고 있습니다.

4번째 줄의 setAttrs는, getAttrs와 반대로 그 항목을 특정 값으로 저장하자고 선언하는 함수입니다. 마치 불러오기와 내보내기처럼 작동하는데, 다른 기능들도 위에서 안내한 roll20위키에 더 있으니 한번 살펴보시면 좋습니다. 여기서는 중괄호를 열고 total:로 시작해서 내용을 적은 뒤 중괄호를 닫았습니다. 그 다음 5번째 줄에서는 setAttrs에서 열었던 소괄호를 다시 닫고 세미콜론으로 종료를 알린 뒤 엔터를 쳤습니다.

 

이어서 javascript를 처음 접하시는 분들을 위해서 주의점을 설명하겠습니다. 위에서 해설한 예제를 보면서, 어디서 소괄호를 닫고 중괄호를 닫고 대괄호를 닫는지 혼란스러울 수도 있습니다. 하지만 의외로 간단히, 침착하게 열었던 순서대로 닫아주면 됩니다. 엑셀 함수도 여러 개를 중첩해서 쓰면 조금 눈이 빙글빙글 돌아가며 헷갈리는 것처럼요. 아니면 사용하고 계시는 코드 편집기에서 새 파일을 만들어 확장자를 .js로 저장하시고, 저 <script type="text/worker"> 의 다음부터 </script>가 나오기 전까지의 부분만을 작성하는 식으로 문법검사의 도움을 받아도 좋습니다. 첫번째 포스팅에서는 이미 sublime text에서 html내에 등장하는 roll20용 하이라이터를 소개했기 때문에, 그것을 사용하고 계시다면 가장 편하다고 생각합니다. 소괄호를 닫은 다음에는 세미콜론을 잊지 마세요. js가 동작하지 않는 대부분의 원인은 여기에 있습니다.

그리고 on에서 나열되는 이벤트들은 스페이스만으로 구분되지만, getAttrs에서 나열되는 항목들은 각각에 대해 쌍따옴표로 묶어줘야 하며 쉼표로 구분된다는 것에 주의하세요. javascript는 대소문자를 엄격하게 구분합니다.

 

위에서는 roll20에서 지원하는 함수들만을 소개했는데, 이제부터는 js에서 통용되는 함수에 대해서도 설명하겠습니다. 이미 javascript에 대해 익숙하신 분이라면 읽지 않아도 무방합니다. 예제에는 Number만이 등장했는데, 파이썬의 print("Hello, World!")처럼 콘솔 로그에 무언가를 출력하는 console.log, 경고창을 띄워 메세지를 출력하는 alert, 조건에 해당하면 내용을 수행하는 if... else 등 여러가지가 있습니다. 자세한 내용은 다음에 다시 소개하겠습니다.

이전 글을 확인해보면, html에서 각 항목들을 <input type="text">에 입력받았습니다. 즉, 우리가 거기에 능력치를 넣으면 일반적으로는 숫자를 입력하겠지만 사실은 글자도 입력 가능한 칸이 되는 겁니다. 처음부터 <input type="number">를 넣으면 예제에 등장한 Number를 사용하지 않고, 그냥 values.math+values.language+values.social+values.nature+values.body+values.machine+values.living+values.birth 으로도 해결할 수 있습니다. 하지만 roll20의 캐릭터 시트에는 type이 number인 input에 대해 가로 크기를 강제하고 있는 css가 존재하고 있기 때문에, 임의로 서식을 지정하기 위해서 저는 type을 text로 사용했습니다. 그런 경우, 받아온 values.math가 3이고 values.language가 5라고 가정한다면 +라는 연산자를 사용했을 때 결과가 이상해집니다. 처리할 변수의 타입이 text인 경우, +는 8이 아니라 35라는 값을 내놓습니다. 두 개의 텍스트를 연결하는 것이죠. 그래서 Number를 사용해 각각의 변수를 숫자로 전환한 뒤 +로 연산하면 제대로 그 값을 수학적인 합계로 처리하게 됩니다.

 

여기까지 잘 이해했다면, 이제 다시 음악의 값을 구해봅시다. 아까의 8번째 줄에서 엔터를 쳐서 새 줄을 만들고, 또 on으로 시작하는 js를 작성합니다. 반올림을 하기 위해 Math.round를 사용했습니다.

on("change:total", function() {
      getAttrs(["total"], function(values) {
          setAttrs({music: Math.round((100-Number(values.total))/5)}
          );
      });
  });

이렇게 하고 나서 마지막 줄에서 </script>로 닫습니다. 그러면 음악을 제외한 8개의 능력치가 바뀔 때마다 total을 계산해주고, 그것이 다시 music을 계산해주는 형태가 됩니다. 여기서 지난번에 작성한 html을 약간 고치도록 합시다. auto calc를 보여주기 위해 총합에 해당하는 input의 value는 [[@{math}+@{language}+@{social}+@{nature}+@{body}+@{machine}+@{living}+@{birth}]]로 하고 disabled를 걸어 주었는데, <input type="number" name="attr_total" value="" readonly>라고 하는 것으로 충분할 것 같습니다. readonly는 이것을 편집할 수 없게 해도 실제로 존재하는 값이긴 하므로 attributes에도 그 항목이 나타납니다. 임의로 수정해야 할 때는 그쪽을 이용하면 되겠지요.

 

roll20 캐릭터시트를 만들기 위해서 처음 코딩을 시작하는 분이라면, javascript는 아주 어렵습니다. 저도 python쪽을 주로 했었지만 쉽지만은 않습니다. 어째서인지 오류가 나고 원인을 알 수 없어도, 다른 사람과 함께 고민하다 보면 방법이 떠오르기도 합니다. 눈 앞의 결과가 당장 멋지게 펼쳐지지 않아서 의욕도 떨어지곤 하는 부분이에요. 이번에는 아주 어려운 것을 해냈기 때문에, 다음 글은 쉽고 멋진 것을 해 보겠습니다. 생명력이라던지 능력치를 게이지 바 형태로 만들어서 클릭하고 색칠하는 css로 또 만나요.