와콤 원(WACOM ONE) - 온라인 강의에 액정태블릿은 필수품

와콤 원은 와콤사에서 출시한 다양한 모델 중 가장 밑바닥에 있는 모델로서 정확한 색감이나 표현력은 포기한 대신 저렴한 가격과 튼튼한 하드웨어, 캐쥬얼한 사용성을 내세운 제품이다. 저렴한 가격이라고? 그렇다. 전문가용 액정 태블릿은 수백만원 하는 대신 고작 40만원대에서 구입할 수 있으니까.

글을 쓰는 본인은 태블릿 전문가가 아니기 때문에 다른 제품과 비교한 장단점을 서술하기는 어렵고, 다만 태블릿을 처음 써보려고 하는 초보자들 입장에서 태블릿의 특징 + 와콤 원의 특징을 나열해보고, 특히 강사 입장에서 사용한 경험을 서술하려 한다.

1. 액정태블릿은 추가 모니터다.

모니터를 한대 더 추가한다고 생각하면 된다. 메인 모니터와 동기화해도 되고 제 2의 작업 영역으로 확장해도 된다.

만약 메인 모니터가 16:9가 아닌데 동기화를 한다면 태블릿에서는 여백이 보이게 된다. 이 상태에서 펜 위치와 포인터 위치가 안 맞는다면 드라이버에서 정렬 프로그램을 실행한다.

2. 전용 프로그램이 필요하다.

드라이버를 설치해야 제대로 작동이 된다. 즉 들고 다니면서 다른 컴퓨터 아무데나 꽂아서 쓰기에는 불편하다.

2. 연결 단자가 많다.

일단 컴퓨터에는 USB와 HDMI를 같이 꽂아야 한다.
전원도 USB로 공급받기 때문에 별도의 전원 설치가 귀챃으면 그것도 컴퓨터에 꽂아도 된다. 하지만 밝기를 강하게 유지하려면 전기가 많이 들기 때문에 콘덴서에 꽂는 것을 추천. 220v 콘덴서 단자도 같이 제공해준다.

3. 화질은 그저 그렇다.

일단 RGB24bit를 다 표현하지 못한다. 평소에는 모르겠지만 그라데이션을 뿌려보면 미세하게 계단이 보인다. 그러나 기초적인 밸런스는 잡혀있고, 채도나 명암에 큰 하자가 있는 것은 아니므로 너무 걱정할 건 없다. FHD의 해상도라서 선명도를 걱정할 것도 없다. 다만 표면 재질때문에 약간 뿌옇게 보이기는 한다. 하여튼 그저 그렇다. 아주 나쁘다는 건 아니고.

내가 가지고 있는 LG 울트라북이랑 비교해보면 색감에서 큰 차이가 없다. 원래 울트라북에 탑재된 패널도 전문가용은 아니지만, 하여튼 화질 좀 좋다는 노트북이랑 비교해도 큰 갭은 못 느낀다는 것이다.




가장 오른쪽 밤 부분에서 그나마 와콤원이 좀 흐릿하게 보이는데 눈으로 보면 거의 구분 못한다.






그라데이션을 펼쳐놓으면 계단현상이 조금 보인다.


4. 악세사리가 부실하다.

일단 와콤에서 공식적으로 제공하는 거치대가 없다. 강의하려면 펜으로 필기도 해야 하고 키보드 타이핑하면서 모니터처럼 쓰기도 해야 하고 여러 가지 역할을 해주면 좋을 텐데, 그러기에는 거치대가 마땅히 없는 것이 불만이다.

그래서 본인은 알루미늄 노트북 거치대를 대신 쓰고 있다. 필기에도 편하고 모니터용도로도 나쁘지 않은 45도 각도! 펜도 거치할 수 있다.






펜에는 뒷꼭지 지우개가 없다. 대신 검지 위치에 버튼이 달려 있는데 이걸 지우개로 설정하면 엄청 불편하지는 않다. 펜이 삼성 S펜이랑 호환이라 다양한 호환가능한 펜을 고를 수 있다.



5. 필기에 불편함은 없다.

펜이 닿는 표면과 디스플레이되는 표면 사이에 갭이 존재하기 때문에 필기가 어색하지 않을까 걱정했지만 전혀 불편한 점이 없고 자연스럽다. 적응할 시간 조차 필요 없다. 최소 필기에 있어서는 말이다. 표면의 마찰력도 적절해서 펜촉을 갈아버릴 정도는 아니면서도 너무 미끌거리지도 않는다.

6. 밝기, 명암 조절이 가능은 한데

가능은 한데 외부 버튼이 없고 소프트웨어로 조정할 수 있다. 다행히 한 번 조정된 값은 유지된다.




7. 튼튼하다.

액정이 왠만큼 세게 두드려가지고는 손상될 염려가 없다. 태블릿 초보가 다루기 좋다.

8. 두꺼운 바젤

바젤리스가 대세가 되어 가는 중에 아직도 옛날 아이패드가 생각난다. 다른 비슷한 가격대의 제품들은 바젤에 이런 저런 버튼이라도 달려 있는데 와콤원은 그런 거 없다.

9. 작은 화면

FHD임에도 불구하고 13인치이기 때문에 화면이 작다, 그 대신 dpi가 높아서 선명하다. 강의용도로는 어차피 큰 폰트를 사용하기 때문에 오히려 더 좋다.

10. HDMI를 연결하지 않으면 일반적인 판타블렛처럼 쓸 수 있다.

화면은 안 나오는데 그 위에서 터치는 된다. 물론 이렇게 쓸 이유가 없지만..


덤으로 판서 프로그램은 '판서펜'을 추천.

그리고 에픽펜도 추천

그리고 내가 만든 더펜도 추천

Read More

우분투에서 C++ 개발하기(3) - CMake

앞선 시리즈 :
우분투에서 C++ 개발하기(1) - https://ladofa.blogspot.com/2018/07/c-1.html
우분투에서 C++ 개발하기(2) - https://ladofa.blogspot.com/2020/08/c-2.html
여기서 사용하는 예제는 두 번째 시리즈에서 사용한 예제를 그대로 사용한다. 예제를 몰라도 읽는데 문제는 없다.

-------------------------

1편과 2편을 잘 정독했던 분들이라도 여기서부터는 예제가 복잡해서 이해하기 쉽지 않다. 쉬운 예제로 설명하고 싶은데.. 불가능하다. cmake가 원래 복잡한 컴파일 과정을 간단하게 하는 거라서... 여기서부터는 구경만 해도 좋고, 어쩌다 CMakeLists.txt 를 분석할 일이 있으면 그 때 한 번 더 봐주시길...

-------------------------


리눅스에서 C++ 코드를 컴파일하려면 최종적으로는 gcc나 다른 컴파일러를 이용해서 컴파일 명령을 내려줘야 한다. 그러나 파일 개수가 많고 의존성이 방대한 큰 프로젝트에서 일일이 gcc 명령을 내릴 수는 없다. 이를 보완하기 위해 Makefile을 작성해서 컴파일 명령어를 미리 입력해두면 나중에는 별 다른 수고 없이 간단한 명령으로 컴파일이 가능하다. 그런데 Makefile을 작성할 때도 결국은 gcc를 잘 알고 있어야 하고, 각종 옵션과 명령어를 직접 입력하는 것도 힘든 일이다.

CMake 기본


CMake는 이런 작업들조차 단순화하여 간단한 명령어를 통해 입력 가능하도록 돕는다. CMake는 사용자가 작성한 스크립트를 해석해서 Makefile을 만든다. 결국 cmake 를 실행한 뒤 make를 다시 실행해야 한다.

CMake도 프로그램이기 때문에 안 깔려 있으면 직접 깔아야 하는데 우분투에서는 다음과 같이 패키지를 통한 설치를 지원한다.

$sudo apt install cmake


여기서 CMake의  apt 패키지 이름이 cmake이고, 실행 프로그램의 이름도 cmake이다. 터미널에 그냥 cmake라고 입력해보자.

Usage

  cmake [options] <path-to-source>
  cmake [options] <path-to-existing-build>
  cmake [options] -S <path-to-source> -B <path-to-build>

Specify a source directory to (re-)generate a build system for it in the
current working directory.  Specify an existing build directory to
re-generate its build system.

Run 'cmake --help' for more information.

위와 같이 뜨면 성공이다. 컴퓨터에 깔려 있는 cmake 프로그램을 실행한 것이다. 버전을 확인하고 싶으면 다음과 같이 입력한다.

$cmake --version

cmake가 인식하는 스크립트 파일의 이름은 CMakeLists.txt 로 정해져있다. make가 기존에 존재하고 있는 Makefile 을 자동으로 인식하는 것처럼 cmake 역시 CMakeLists.txt 라는 이름의 파일을 찾는다.

이전 시리즈에서 작업했던 것과 같이 my.cpp, my.h, main.cpp 파일이 있다고 가정할 때, 이를 빌드하기 위한 CMakeLists.txt 스크립트는 다음과 같다.


cmake_minimum_required (VERSION 3.10)
project (mytest)
add_executable (mytest my.cpp main.cpp)

맨 첫째 줄은 cmake의 최소 버전을 밝히는 것이다. 해당 버전보다 아래인 cmake로 실행할 수  없게끔 막는다.
project()는 해당 스크립트의 프로젝트 이름을 밝힌다. mytest는 이 프로젝트의 이름이며 실행파일을 생성할 경우 실행파일의 이름이 될 것이다.
add_executable은 이 스크립트를 통해 최종적으로 실행파일을 만들고자 한다는 뜻이다. 실행파일 말고 정적 라이브러리를 만들고 싶을 때는 add_library라는 명령을 이용한다.

이 스크립트를 실행하려면 다음과 같이 입력하면 되는데...

$cmake .

make 는 무조건 실행한 경로에서 Makefile의 존재유무를 찾지만 cmake는 반드시 CMakeLists.txt의 경로를 지정해줘야 한다. cmake 다음에 나오는 점(.)이 바로 경로를 나타내는 것이다. 점 하나 찍으면 현재 경로를 말한다.

cmake는 Makefile을 생성하면서 기타 다양한 파일들도 생성하므로 그냥 현재 폴더에서 실행하면 이런저런 파일이 생겨 지저분해진다. 그래서 보통은 build 디렉토리를 만들어서 거기서 실행한다.

$mkdir build
$cd build
build$cmake ..

위와 같이 build 디렉토리를 만든 뒤, 해당 디렉토리 내에서 cmake를 실행한다. 이 때 cmake 뒤에는 점 두개 (..) 가 붙어 있다. 이는 상위 디렉토리를 나타낸다. CMakeLists.txt 파일이 build디렉토리에 있지 않고 그 상위 디렉토리에 있기 때문이다.

빌드에 성공하면 이런 저런 메타파일이 생성되고, 가장 중요한 Makefile이 만들어진다. 이 Makefile의 타겟은 기본적으로 all 과 clean을 가지고 있다. 타깃을 입력하지 않으면 all을 기본으로 한다. 아래와 같이 입력해보자.

build$make

그냥 make라고 하면 자동 생성된 Makefile을 실행시킨다. 여기까지는 거의 공식처럼 사용한다.



빌드에 성공하면 mytest 파일이 만들어져 있다. mytest를 실행해보자.

build$./mytest
3^2 == 9

이제 main.cpp파일을 수정할 것이다. 다음 프린트 구문을 추가한다.

printf("This code is modified.\n" );

다시 mytest를 빌드해서 실행해보자.

build$make
build$./mytest
3^2 == 9
This code is modified.

위와 같이 수정되서 나타난다. 뭔가 신기한 일이 이뤄진 것 같지만 사실 별 것도 아니다. 여기서 일단 CMake는 하는 일이 없다. make를 실행하면 수정된 파일을 감지해서 다시 빌드를 해준다. 그리고 그 결과가 나타난 것 뿐이다.

이제 your.h, your.cpp 파일을 추가할 것이다.

<your.h>
int your_func(int x);

<your.cpp>
#include "your.h"

int your_func(int x)
{
    return x + 10;
}


main.cpp에서도 your_func 을 사용하도록 수정한다.

<main.cpp>
#include <iostream>
#include "my.h"
#include "your.h"

int main(void)
{
    printf("%d^2 == %d\n", 3, my_func(3));
    printf("This code is modified.\n" );
    printf("%d + 10 == %d\n", 3, your_func(3));
}


마지막으로 CMakeLists.txt파일을 다음과 같이 수정한다.

cmake_minimum_required (VERSION 3.10)
project (mytest)
add_executable (mytest my.cpp main.cpp your.cpp)


add_executable에 your.cpp 를 추가한 것이다. 이제 아까와 마찬가지로 새로 빌드를 해본다.

build$make
build$./mytest
3^2 == 9
This code is modified.
3 + 10 == 13

수정된 결과가 반영되어 있다. cmake는 수정된 CMakeLists.txt 파일을 자동으로 반영하여 Makefile을 미리 바꿔놓았다. 그리고 나는 make명령어를 통해  바뀐 Makefile을 실행해서 결과를 확인했다. 

만약 CMakeLists.txt에 오류가 있으면 어떻게 될까?

cmake_minimum_required (VERSION 3.10)
project (mytest)
add_executable (mytest my.cpp main.cpp your.cpp nobody.cpp)

build$make

나는 make를 실행했는데, 실행해보면 CMakeLists.txt파일이 잘못되었다는 에러 메시지가 나온다. cmake는 건들지도 않았는데!

make는 어떻게 cmake를 인식하고 일반적인 빌드 오류가 아닌 cmake 오류를 출력하는 것일까? make가 cmake와 뭔가 연동되어 있는 것일까? Makefile 내부를 보면 cmake 에러가 없는지 확인하고 메시지를 출력하도록 되어 있다. cmake가 Makefile을 생성하면서 그 속에 cmake관련 내용을 스파이처럼 넣어놨다. 그래서 make만 실행해도 CMakeLists.txt의 오류를 검사하게 된다.


라이브러리 구조화

이제 my 라이브러리를 분리해서 컴파일해보자. 보통 프로그램 개발에서 핵심적인 기능을 담당하는 모듈은 기본 프로그램과 분리해서 따로 라이브러리 형식으로 개발하고, 본 프로그램은 해당 라이브러리를 사용하도록 만든다. 지금 예제에서는 mylib 라는 이름의 라이브러리를 개발하는 것으로 가정할 것이다.

일반적으로 라이브러리를 포함한 구조는 다음과 같이 되어 있다. 이 구조를 무조건 지킬 필요는 없지만 보통 이렇다..

  - 라이브러리 이름
    - src
      - files.cpp
    - include
      - files.h
    CMakeLists.txt
  - 또 다른 라이브러리
    ......
main.cpp
CMakeLists.txt

이렇게 글씨로 쓰면 구조가 안 보일까봐 VSCode 캡쳐 화면도 준비했다.



라이브러리마다 CMakeLists.txt 파일이 따로 있고 여기에는 src 디렉토리와 include 디렉토리가 있다. 빌드를 마치고 나서 src 폴더에 있는 cpp파일은 당연히 소스코드니까 공개하지 않지만 include 폴더에 있는 h, hpp 파일은 라이브러리를 사용하는 측에게 공개해야 한다. C의 라이브러리들은 헤더파일이 있어야 쓸 수 있다. 그런 이유를 포함해서 관리상의 편리함 등 여러 가지 이유로 src와 include는 분리해놓는 것이다.

혹시나 다른 사람이 만든 C언어 소스를 보게 되면 항상 include 디렉토리와 src 디렉토리가 따로 나뉜 걸 보게 된다. 또한 src를 컴파일한 결과는 bin 혹은 build 디렉토리에 모셔놓게 된다. 만약 소스코드가 아닌 빌드된 라이브러리를 다운받게 되면 include 속에 있는 헤더파일과 bin디렉토리 내부의 컴파일된 바이너라 파일만 보게 된다. 왜 그런지를 이해하려면 1편을 참고한다...


하여튼 mylilb 속에 있는 CMakeLists.txt의 내용은 다음고 같다.


cmake_minimum_required (VERSION 2.8)
project (mylib)
add_library (mylib src/my.cpp)
target_include_directories(mylib PUBLIC include)


아까의 CMakeLists.txt와 비교해서 다른 점은 add_executable 대신 add_library로 바뀌어 있다는 것이다. 실행파일을 만들지 않고 라이브러리를 생성한다는 뜻이다. 여기에는 사용되는 모든 cpp파일을 적어주어야 한다. 그리고 target_include_directories가 추가되었는데, 여기에 include 디렉토리를 알려줘야 한다.

다음과 같이 빌드해볼 수 있다.

mylib$mkdir build
mylib$cd build
mylib/build$cmake ..
mylib/build$make

빌드하고 나면 libmylib.a 파일이 생성되었다. 이것을 메인에서 이용하면 된다. 바깥쪽에 있는 CMakeLists.txt의 내용은 다음과 같다.

cmake_minimum_required (VERSION 2.8)
project (mytest)
add_executable (mytest main.cpp)
target_link_libraries(mytest PUBLIC mylib)
target_link_directories(mytest PUBLIC mylib/build)
target_include_directories(mytest PUBLIC mylib/include)

target_link_libraries에 라이브러리 이름을 추가한다. 라이브러리 이름이란 *.a에서 맨 앞에 lib를 제외한 것이다. gcc빌드할 때와 마찬기자로 라이브러리 파일은 맨 앞에 lib가 prefix로 붙는다. 파일 확장자가 앞쪽에 붙었다고 생각하면 된다.

target_link_directories 에는 라이브러리 파일의 경로를 추가한다. target_include_directorie 에는 헤더 파일의 경로를 추가하면 된다.

사실 이런 식으로 하는 것은 아예 동떨어진 다른 라이브러리를 가져오는 것과 동일하다. 그런데 현재 디렉토리/프로젝트 구조는 mylib 를 포함하고 있는데, 이 특징을 전혀 살리지 않은 것이다. 하위 디렉토리에 라이브러리가 들어있는 상황에서는 조금 더 간결하게 cmake명령을 만들 수 있다.

이제 add_subdirectory 를 이용해서 디렉토리를 구조화한 보람을 찾아보자.  mylib 디렉토리 내에 있는 CMakeLists.txt는 그대로 두고 메인 프로그램의 CMakeLists.txt를 다음과 같이 수정한다.

cmake_minimum_required (VERSION 2.8)
project (mytest)
add_subdirectory(mylib)
add_executable (mytest main.cpp)
target_link_libraries(mytest PUBLIC mylib)

add_subdirectory에 mylib를 추가했다. 이렇게 하면 mylib 디렉토리 속에 있는 CMakeLists.txt를 인식하고 가져온다. 라이브파일의 경로나 헤더 파일의 경로는 따로 추가할 필요가 없다. 다만 target_link libraries에 mylib를 추가하면 끝이다.

이렇게 하고 build 디렉토리를 만들어서 cmake를 해보면 mylib와 mytest가 같이 만들어지게 된다. 즉 여러 개의 CMakeLists.txt에 각각 명령어를 실행할 필요 없이 한 번에 연쇄적으로 실행된다. 실제로 build 내부에 mylib 디렉토리가 따로 생성되며 여기에 빌드된 라이브러리가 들어 있다.



외부 패키지 추가


마지막으로 외부 패키지를 찾아보도록 하자. 다른 사람이 빌드한 라이브러리를 추가할 때 위에서 소개한 바와 같이 include 디렉토리와 라이브러리를 일일이 추가하는 것은 상당히 번거롭다. 때문에 누군가 고수님께서 우리를 위해 라이브러리를 만드실 때는 CMake를 활용해서 자기 라이브러리를 잘 추가할 수 있도록 메타 정보를 같이 만들어둔다. 우리는 해당 메타 정보만 읽어들이면 라이브러리 추가에 필요한 각종 파라미터(include디렉토리, lib 디렉토리 등)를 자동으로 얻을 수 있다.

대표적인 라이브러리로 OpenCV가 있다. OpenCV를 본 프로젝트에 추가하려면 CMakeLists.txt에 다음과 같이 입력한다.


cmake_minimum_required (VERSION 2.8)
project (mytest)
find_package(OpenCV REQUIRED)
add_subdirectory(mylib)
add_executable (mytest main.cpp)
target_link_libraries(mytest PUBLIC mylib ${OpenCV_LIBS})
target_include_directories(mylib PUBLIC ${OpenCV_INCLUDE_DIRS})


find_package는 주어진 이름의 패키지(메타정보)를 찾아서 라이브러리의 목록과 헤더 파일의 디렉토리 목록을 변수에 저장한다. OpenCV 패키지는 어떻게 찾는가? 그 방법에 대한 링크가 있다.


대략 9가지 정도의 방법으로 패키지를 찾는다(...) 보통은 라이브러리 설치할 때 sudo make install 과 같은 명령어를 입력하면 그 속에 CMake 패키지 등록 과정이 포함되어 있다.

라이브러리를 찾는데 성공하면 OpenCV_LIBS와 OpenCV_INCLUDE_DIRS 가 변수로 제공된다. 이것을 타겟 빌드하는데 추가해주면 된다. 다른 라이브러리인 경우 OpenCV 자리에 다른 이름을 넣으면 된다.

만약 cmake가 없었다면? 우리는 OpenCV를 활용하기 위해 OpenCV 헤더 정보가 있는  include디렉토리를 직접 찾아서 입력해야 하고, 라이브러리 파일도 직접 찾아서 (아마 Makefile에) 추가해줘야 했을 것이다. 라이브러리 버전이 바뀌거나 업데이트되면? 또 달라진 경로와 파일을 일일이 수정해줘야 한다. 이 과정을 cmake가 알아서 해준다.

여기까지 와서 왜 라이브러리와 인클루드 디렉토리를 추가해야 하는가? 이런 의문이 들면 C컴파일 방법을 처음부터 다시 배워야 한다. 이글 맨 위의 링크에서 1탄으로 가시기 바란다.

참고로 CMake 스크립트에서는 순서가 중요하다. target_xxx 인 명령어는 add_executable이나 add_library 뒤에 와야 한다. 그 밖의 명령어는 add_executable/add_library 앞에 오면 된다. 제일 중요한 부분인데.... 마지막에 밝힌다.



  이상으로 우분투에서 C+ 개발하기 시리즈를 마친다.

--------

VSCode로 빌드하기... 는 그냥 연재 안 하는 것으로...  검색해보면 다른 글이 많으니 굳이 내가 수고할 필요가 없다. Remote SSH로 연결해서 컴파일하고, 디버그하고.. 그런 내용일 것이다.
여러분들이 라즈베이파이, 어디 서버 등 리눅스에서 돌릴 프로그램을 개발한다면 파이썬이든 C++ 이든 무조건 VSCode의 Remote SSH 기능을 활용하는 것을 추천한다.

--------

제 블로그에서 가장 인기있는 글이 바로 여기 시리즈라서 따로 인사를 남깁니다. 방문하신 모든 분들, 댓글 달아주신 분들 감사합니다.


Read More

롤 설치 에러 (004 혹은 업데이트의 파일 일부가 손상)



간만에 롤을 깔아보려니 이상한 에러가 자꾸 뜬다.

이 업데이트의 파일 일부가 손상되거나 사라졌습니다. 재시작해 다시 시도하거나 재설치해주세요. 문제가 계속 발생할 경우 고객지원에 문의해 주세요.

라는 메시지인데, 고객지원을 눌러봐야 영 엉뚱한 얘기만 써 있고..


근데.. 어쩌다 해결이 됐다..??
참 이상한데

1. 바탕화면에 깔린 아이콘에 오른쪽을 눌러서 관리자 권한으로 실행

2. 업데이트

반복..?

한 30번 정도 반복하니까 어쩌다 됐다. ?

그런데 클라이언트 실행하면 또 004 에러.. 여기서부터는 포기다.


이 당시 결제 문제로 서버 점검중이었는데 풀리고 나니까 설치 잘 된다. 아무래도 뭔가 문제가 있는 상황에서는 업데이트나 신규 설치를 막는 듯 하다. 물론 왜 막았는지 왜 안 되는지 바로바로 안 알려줘서 그렇지. 게임 서버 점검은 항상 급박하게 이뤄지고 그런 상황에서 유저에게 일일이 친절하게 대응하기가 쉽지 않다.

인터넷에 찾아보면 관리자 권한으로 실행하라는 둥 별 얘기 많은데, 혹시 문제가 있어서 점검중이면 끝날 때까지 기다려보자.
Read More

나이먹기 - 전래놀이 주제에 깊은 게임성

나이먹기는 내 평생 겪은 전래놀이 아니 그냥 게임 중에서도 가장 재미있던 놀이이다. 아주 어렸을 때부터 시작해서 중3때까지 했던 것 같다. 고등학교 올라가고 나서는 점심시간에 자느라 바빴지, 놀 생각을 못했으니까.

찾아보니 역시나 전래놀이답게 룰이 조금씩 다른데, 아무리 찾아봐도 내가 했던 룰을 찾을 수 없다. 다른 룰을 읽어보니 내가 했던 그 게임이 아니고 완전히 다른 게임을 얘기하고 있다. 그래서 내가 겪었던 로컬 룰을 소개한다.



필수요소


인원수는 최소 6명은 되야 재미있다. 많으면 12명정도 까지 좋고 그 이상은 번잡하다.

팀 게임으로서 두 편으로 나눠야 한다. 인원수가 달라도 상관은 없다.

두 팀은 각각 본진을 가지고 있다. 본진은 전봇대나 나무 기둥과 같은 봉 형태여야 한다. 너무 얇으면 안 되고 역시 전봇대가 적당하다. 두 본진과의 거리도 전봇대 거리 정도가 적당하다.

게임 시간은 보통 30분에서 1시간. 보통 200살 넘기 시작하면 그만 둔다.


기본 룰

(빨간색으로 표시된 것이 이 로컬룰의 특이한 점이다.)

모든 사람은 자신의 나이를 가진다. 나이는 절대 서로 같을 수 없다.

사람끼리 접촉(태그)이 일어나면 그 즉시 서로 나이를 따져본다. 비교해서 나이가 많은 쪽 팀이 30살을 먹는다. 나이를 먹은 팀은 팀내 가장 연소자에게 그 나이를 준다.

만약 나이를 먹어서 두 사람 이상이 같은 나이가 되면 반드시 서로 가위바위보를 해서 이긴 사람이 10살 더 먹는다. 여러 명이 같은 나이면 다 같이 가위바위보를 해서 진 사람 한 명은 자기 나이 그대로이고 나머지는 10살씩 먹고 또 가위바위보를 한다.

벌어들인 나이는 한꺼번에 먹을 수 없다. 내가 0살인데 상대가 10살이 있다면 반드시 10살 먹고 상대랑 가위바위보를 해야 한다. 만약 30살을 벌었으면 나(혹은 우리팀 꼴찌)에게는 3번의 기회가 있는 것이고 상대는 한 번만 지면 나보다 나이가 낮아지게 된다.

이렇게 나이가 새로 정해지면 반드시 본진을 한 번 터치하고 나가야 한다. 그렇지 않으면 무조건 0살이다. 즉 가위바위보가 끝날 때마다 본진을 찍고 시작한다. 기습적으로 엉뚱한 곳에서 숨어있을 수 없다.

같은 팀끼리 손을 잡고 있으면(아무 접촉이나 상관없다) 나이를 합칠 수 있다. 예를 들어 20살과 30실이 손을 붙잡고 있으면 40살을 이길 수 있다. 3명이 합쳐도 되고 팀 전체가 합쳐도 상관없다.

본진은 무한대의 나이를 제공한다. 즉 본진과 연결된 사람(들)은 무적이다. 그러나 본진을 직접 태그하면 태그한 팀이 50살을 먹는다. 이런 점은 야구와 비슷하다 홈 베이스를 밟은 상태에서 상대를 태그하면 아웃이지만 상대가 나를 피해서 홈 베이스를 밟으면 1점인 것이다.

게임이 끝날 때 나이를 많이 먹은 팀이 이긴다. 게임을 끝내는 시점은 자유다.


튜토리얼


처음에는 전부 다 0살이다. 다같이 모여서 가위바위보를 해서 0살이 누구인지 정한다. 그 다음 10살, 20살 등 모든 나이를 정한다. 

0살은 아무 데도 못 가고 무조건 본진 수비를 해야 한다. 0살의 비애 ㅜㅜ

 최고령자는 자기 마음대로 돌아다닐 수 있는데 달리기에 자신 없으면 2인 1조 공격을 조심해야 한다. 주로 상대 본진 뒤쪽을 노리는 공격을 한다. 달리기가 빠르면 0살이라도 도망다니면서 어그로를 끌 수도 있다. 꼭 달리기 자신있는 형들이 자기 나이랑 상관없이 시작하자마자 뛰쳐나가고 본다 ㅋㅋ

여러 명이 본진으로부터 손을 연결하면 리치가 매우 긴 무적 공격을 할 수 있다. 대신 본진 수비가 허술해진다. 기습적으로 둘 셋이 손을 잡고 본진을 노리는 상대에게 달려들면 효과적이다.

가끔 경찰과 도둑 게임으로 착각하고 한참 멀리 나가서 안 돌아오는 경우도 있다. 나이를 먹었는데도 안 보이면 일단 빼고 나이를 먹다가 돌아오면 겹치는 나이만 가위바위보를 한다. 멀리 나갔던 우리 편이 승전보를 들고 올 때 엄청 반갑다.

수비할 때는 360도를 다 봐야 하므로 정신이 하나도 없는데, 그게 또 재미지다.

서로 나이 계산이 안 되거나 서로 상대방이 몇 살인지 모른다거나 할 수도 있다. 나이를 반드시 알려줄 의무는 없고, 태그가 일어났을 때만 어느 쪽이 이겼는지 따져보면 된다. 이기는 나이인 데도 지는 척하고 도망가서 상대를 잡기도 한다. 상대를 쫒아가는데 상대가 갑자기 뒤를 돌게 되면 내가 설마 나이가 적던가 싶어서 되려 도망가기도 한다ㅋㅋ


왜 이 게임이 재미있는가


이 게임의 핵심 중의 핵심은 나이의 우세와 열세에 주어지는 보상이 확실하다는 것이다. 아무리 나이 어린 꼬맹이라도 가위바위보만 잘 하면 연장자가 되어 마음대로 돌아다닐 수 있는 힘을 만끽할 수 있다. 반대로 열세에 몰리면 본진만 붙잡고 살아야 한다. 나이가 많을 때 상대를 압도할 수 있는 이 느낌과 만족감이 중독의 핵심이다.

그러면서도 역전이 잘 나온다. 본진을 붙잡으면 무적이기 때문에 기습적으로 상대를 태그할 수도 있고, 합체나 다른 방법으로 불리한 상황을 뒤집을 수 있다. 가위바위보 실력(?)으로 역전도 가능하다. 완전히 불리해져서 본진 수비만 하더라도 상대를 이길 가능성이 없는 것은 아니기 때문에 얼마든지 재미있게 즐길 수 있다.

절대적인 팀 게임이다. 팀에서 벌어도 벌어들인 나이는 무조건 연소자에게 돌아간다. 캐리하는 기분 / 버스타는 기분을 느낄 수 있다. 집만 지키고 있는다고 해서 나중에 나이를 먹을 희망이 없는 게 아니다. 보상은 팀원 전체가 누린다.

0살에서부터 키워가는 육성의 재미가 있다.

처음에 0살에서 시작했어도 나이 10살만 딱 먹고 가위바위보만 다 이기면 가능성은 희박하지만 최고령자가 될 수 있다. 반대로 아무리 나이를 벌어도 가위바위보에서 지면 말짱 꽝이다. 실력 요소와 운 요소가 적절히 잘 결합되어 있다.

전략 요소가 충분하다. 상대 본진 방향의 얼굴쪽, 반대방향의 등쪽 모두 공간적으로 중요하다. 순간적인 합체를 통해 열세를 극복할 수 있고, 어그로를 끌고 돌아다니는 상대방을 구석으로 몰아서 잡을 수도 있다. 나이가 많다고 죄다 공격하러 나왔다면 본진의 빈틈을 노릴 수도 있다.

피지컬로 승부를 걸 수도 있다. 달리기가 빠른 사람은 나이와 상관없이 유리하니 나이의 상성을 뒤집는 재미가 있다. 불리한 상황을 실력으로 극복할 수 있는 것이다.

운동량이 많다. 뛰는 것은 그 자체로도 재미있다.


결론


정리하면서 생각해보니까 재미있을 수 밖에 없는 게임 요소를 모두 가지고 있다. 워낙 게임 요소가 탄탄해서 중독성이 있을 정도이다. 어릴 때 하던 변변찮은 놀이라고 생각하기에는 상당한 게임성을 가지고 있다. 가만 보니 롤이랑 많이 비슷한 것 같다.

이번 나이먹기를 시작으로 전래 놀이를 하나씩 기록해보고 싶다.

Read More

영빈혜선 결혼 축가






2020년 9월 5일 결혼식 축가

어쩌다 보니 결혼식이 계속 미뤄져서 너무 정성스럽게 만들게 됐다..
양가 모두 기독교 집안에 주례를 목사님이 하게 되므로 거기에 맞춰 가사를 썼음.
모티브가 된 곡은 CCM은 예수안에서, 누구나 삶의 시작은 작구나(한웅재)
그리고 김동률의 출발, 데파페페 Start.

왠지 자꾸 가사가 어둡게 나와서 곡이라도 최대한 밝은 분위기로 가려고 노력했다. 가사도 사실 더 어둡고 끈적끈적했었는데 아무래도 결혼식 분위기를 생각해서 힘찬 내용, 그리고 교회 다니는 어르신들이 좋아할 수 있는 바람직하고 성경적인 가사들로 채웠다.

가장 먼저 만들어진 가사는 '우린 보이지 않는 길을 믿음으로 가네', 그리고 '사랑 하나로 우리 그 먼 길을 갈 수 있을까' 이다. 결론적으로 사랑과 믿음만 있으면 얼마든지 갈 수 있다, 이런 내용. 그리고 후렴구는 어떤 믿음과 사랑인지를 구체화하는 내용들이다.

가장 마지막에 쓴 가사는 '주님의 사랑 뜻하신 계획 우리안에 이뤄지리라.' 이거는 그냥 뭐 공간은 남는데 가사는 더 없고 해서 상투적으로 쓰는 말들을 갖다 붙인 것.


음악 작업은 먼저 기타로 시작했다. 데파페페 Start와 같은 리듬으로 노래를 불러보면서 작곡을 끝내고, 편곡은 피아노부터 시작했다. 사실 이렇게 곡 전체를 피아노로 채울 생각은 없었는데 이러나 저러나 교회 음악은 역시 피아노가 가장 잘 어울린다. 피아노에서 베이스를 빼고 어택감을 살려서 소리가 뭉치지 않게  신경을 많이 썼다.

피아노 위에 퍼커션을 깐다. 그 다음 공간을 채우기 위해 아르페지에이터로 탱탱거리는 소리들을 넣었다. 메탈느낌의 짦은 벨이랑 마림바랑 신스콤프가 섞인 건데 이런 도움 없으면 인제 노래도 못 만든다. 어택을 짧게 해서 퍼커션을 보조하는 느낌으로 채우니 리듬도 살고 공간도 채우고 일석이조.

베이스도 마찬가지로 경쾌한 느낌으로  채웠는데 특이하게 베이스에 딜레이가 걸려 있다. 베이스도 아르페지에이터의 일부인 것처럼 넣고 싶었다.

가장 마지막에 들어간 것은 벨이다. 별로 복잡한 노트도 아닌데 곡과 어울리게 적절히 넣는 게 쉽지 않더라.

건반 좀 미스가 많은데 어떤 부분은 불협화음이 마음에 들기도 해서 그냥 놔둠. 불협화음이나 삑사리나는 소리들은 그 악기로 집중하게 만드는 효과가 있다. 어떤 악기가 작아서 잘 안 들리는데 무작정 음량을 키우기도 뭐할 때는 일부러 불협화음을 내는 것도 좋다. 플룻이 가끔 삑삑거리는 것도 다 그런 이유로 넣은 것.

마스터링을 잘 했어야 하는데 불륨이 작다. 하지만 원본 음질은 더 잘 보존한 셈... 으로 치자~ 퍼커션이 크게 들어가서 사실 컴프레싱이 쉽지 않은데, 그래도 퍼커션은 줄이기가 싫었다. 현장은 분명 모니터링이 잘 안 될 테니 노래를 잘 부르려면 박자라도 맞추기 쉽게 해야 한다.



최종적으로는 어쿠스틱 기타를 붙잡고 반주 위에 연주까지 곁들여서 노래하는 것이 원래 계획이었는데 그냥 번거롭고 해서 보컬만으로 공연.











 

Read More

파이썬에서 부울이 아닌 값에 대한 논리연산자

C먼저 확인해보면

C언어에서는 bool 타입이 따로 존재하지 않는다. 0이면 false, 그렇지 않으면 true이다. 심지어는 float도 피연산자로 참여할 수 있다. 그래도 어쨌든 논리연산자의 결과값은 0 아니면 1이 되는 1byte 정수형을 리턴한다.

예를 들어

int a = 10;

float b = 3.14;

printf("%d, %d\n", a && b, sizeof(a && b));

위의 코드에서 출력은 1, 1 이다.


파이썬의 and, or

그런데 파이썬은 조금 더 변태같다.

a = 10

b = 20

print(a and b, a or b)

결과는 20, 10이다. 어째써? and와 or는 다음과 같이 구현되어 있다.

a and b => if a is true, return b, else return a
a or b => if a is true, return a, else return b

and의 경우 a가 참이면 b를 리턴한다. 결과적으로 a and b가 참인지 거짓인지는 b에 달린 상황이다. 만약 a가 거짓이면 그냥 a를 리턴한다. a가 거짓인 줄 알고 리턴하니까 a and b도 거짓이 된다. 이 때 b는 체크하지 않는다.

or의 경우 a 가 참이면 그냥 a를 리턴한다. a가 참이니까 a or b 도 참이다. 이 때 b는 체크하지 않는다. 만약 a가 거짓이면 b를 리턴한다. a or b가 참인지 거짓인지는 b에 달렸다.

한 번 더 정리하자면 a and b 에서 a 가 거짓이면 b를 체크하지 않고 a를 리턴한다. a or b에서 a 가 참이면 b를 체크하지 않고 a를 리턴한다. a and b에서 a가 참이면 b를 리턴하고, a or b에서는 a가 거짓이면 b를 리턴한다.


C언어의 논리연산자는 정수형 입력을 받아서 정수형 출력을 한다. 파이썬의 논리연산자는 입력 타입이 정해져 있지 않다. 그래서 입력 타입이 부울이 아닌 경우 엉뚱한 결과가 발생한다.


bool이 아닌 값들의 참, 거짓

뭐 당연하겠지만 또 웃기는 것은 True의 타입은 <class 'bool'>인데 산술연산에 참여할 때는 정수 1처럼 여겨진다는 것이다.

print(True + True)

결과는 2이다.


또 한 가지 팁이라면 파이썬에서는 None을 거짓으로 취급한다. 반대로 리스트나 기타 오브젝트는 참으로 취급한다. 아래 예제에서

a = [1, 2, 3]

print(a or None)

print(None and True)

결과는 [1, 2, 3], 그리고 None이다.


그런데 비어있는 리스트, 문자열, 딕셔너리, 셋, 튜플 따위는 거짓으로 취급한다.

print( [] or dict() or set() or tuple() or '' or 10 )

결과는 10이다. 10 앞에 나열한 모든 것들은 전부 거짓으로 취급된다.



bool로 변환해야 True가 된다

여기 또 다른 함정이 있다. 예를 들어 10은 bool로 형변환하면 True가 되긴 하지만 그렇다고 1이 True인 것은 아니다.

a = 10

print(a is True)

print(a == True)

결과는 둘 다 False이다. a는 정수 10일 뿐, bool도 아니고 True도 아니다. 


if문을 쓰지 않고 a가 참인지 체크하려면 간단히 bool로 형변환해보면 된다.

print(bool(a))

결과는 당연히 True이다.


마지막으로 아래 식을 확인해보자.

print(type(a and True))

print(type(True and a))

결과는 <class 'bool'>, <class 'int'> 이다. and 연산의 리턴 타입을 보면서 파이썬의 함수는 리턴 타입이 정해져있지 않다는 사실이 새삼 현실로 다가온다.


and, or 응용하기

파이썬의 이러한 특성을 이용하면 변태같은 코딩이 가능하다.


if a < b : func() #이 문장은

a < b and func() #요렇게 바꿀 수 있다.


if not (a < b) : func()

a < b or func()


조건문 대신 and와 or를 쓸 수 있다. 영 and와 or가 어색하다면 and 대신 then, or 대신 otherwise로 읽어보면 조금 더 자연스럽다. 어셈블리어를 해봤으면 매우 자연스러울 수 있다, 점프처럼 생각하면 되니까.

여기에 보태서 None이 거짓으로 인식되는 점을 이용해 None 체크를 할 수 있다.


if a is not None: b = a

else: b = somethingDefault #이 두 문장은

b = a or somethingDefault #요 한 문장으로 바꿀 수 있다.


a를 b에 대입하는데 만약 None이면 미리 정해준 기본값을 대입하도록 한 것이다. 같은 원리로 비어있는 리스트를 체크할 수도 있다.


myList = []

x = min(myList or [-1])

x = min(myList) #에러 발생


만약 myList == [] 즉 비어있는 리스트라면 에러가 발생한다. 이걸 try 로 잡아서 어쩌구 해도 되지만 어차피 비어있을 경우 x에 기본값 -1을 넣을 작정이라면 위와 같이 or를 이용할 수 있다.


결론

당연히 논리연산자의 피연산자는 bool로 묵시적 형변환이 일어나는 줄 알았고, 당연히 출력은 무조건 bool인줄 알았는데 입력 타입을 그대로 살려서 출력한다니 좀 어이없긴 하다. 파이썬의 철학이 단 하나의 목적을 위한 단 하나의 아름다운 코드 아닌가? 이런 변태같은 부분은 파이썬의 기본 철학을 정면으로 부정하는 것이다. 통일성과 간편함을 동시에 추구하는 것이 그렇게 쉬운 일은 아닌 셈이다.

파이썬의 이런 점이 마음에 들지 않는다, 혹은 헷갈려서 공부 못하겠다 싶으면 정수나 기타 이상한 타입은 일절 논리 연산에 참여시키지 말아야 한다. 반드시 bool(a) 또는 a != 0 과 같은 코드를 써서 명시적으로 bool로 변환해주는 것이 좋다. C를 제외한 대부분의 언어, 그러니까 Java와 C#에서는 당연히 이렇게 한다. 논리연산에는 bool만 참여할 수 있기 때문에 반드시 명시적 형변환이 필요하다. 차라리 이게 나은 것 같은데.

Read More

프레젠테이션 샘플 : 전자쓰레기





예전에 누구 자료 만들어준다고 작업한 게 있다. 전자쓰레기를 주제로 한 발표인데, 내 프레젠테이션 스타일이 고스란이 녹아있어서 한 번 소개하고자 올려본다.

업무용, 혹은 제안서 발표용 프레젠테이션은 절대 이렇게 할 수 없다. 그런 데서는 ppt가 문서의 역할을 대신하기 때문이고, 그 쪽 세계에서 통용되는 양식이란 따로 있기 때문이다. 그러나 단순히 프레젠테이션 하나만을 생각한다면 아래 소개된 점들을 활용하면 좋다.

1. 획일적인 레이아웃 타파
 - 매 페이지 넘길 때마다 똑같은 장면이 나와서는 안 된다. 절대 지루하지 않도록 다양한 레이아웃을 활용한다.
 - 제목이 상단에 위치할 필요가 없다. 중간이나 하단에 있어도 된다. 제목이 없어도 된다.
- 화면을 꽉 채우는 그림
- 분위기에 따라 배경 색을 변화

2. 목차나 중간 제목이 없음
 - 목차는 앞으로 어떤 내용이 있을 것인지 전체를 보여주는 역할을 한다. 그런데 미리 알려주고 시작하는 건 재미를 반감시킨다. 흥미를 끌어올리려면 목차나 중간 제목을 없애는 선택도 좋다.

3. 제목보다 더 큰 메시지
 - 슬라이드 한 장의 내용을 요약하는 메시지를 마지막에 넣어서 강조시키면 뭔가 이해가 잘 되는 기분을 느끼게 해줄 수 있고 집중을 얻어내기 쉽다.
 - 이것도 너무 계속 쓰면 뻔한 느낌이 나니까 적당히 사용한다.

4. 시작하는 방법
 - 질문으로 시작한다.
 - 가장 쉽고 재미있는 것으로 시작한다.
 - 주제와 가장 근접한 질문일 수록 좋다.
 - 슬라이드를 다 마치고 사람들에게 던질 질문이 무엇인지 생각해본다, 그 중에서 시작할 때도 던질 수 있는 질문을 찾아서 처음과 끝 두 번 똑같은 화두를 던진다.
 - 밸런스 질문을 활용한다. (군대 두번 가고 10억 혹은 한 번도 안 가고 1000만원 납부 같은)

5. 서술 트릭
 - 숲에서부터 나무로 향하는 전형적인 탑다운 방식 외에도 다양한 서술의 방법이 있다.
 - 여기서는 전자쓰레기를 먼저 말하지 않고 익히 알고 있는 사실들을 나열하면서 본래 주제(전자 쓰레기)로 접근하는 방법을 썼다.
 - 슬라이드에서 제목이 나중에 올라온다.
 - 트릭이 너무 심하면 불편하고 이해하기 어려우니 적당히 쓴다.

6. 애니메이션
 - 모든 요소에는 사소한 애니메이션이라도 있어야 한다.
 - 애니메이션을 쓴다고 화면의 중앙을 너무 오래 비워놓으면 안 된다.

7. 위치 활용
 - 화면의 중앙이 제일 중요하다.
 - 극적인 효과를 위해 아래쪽이나 구석을 활용한다.

8. 동영상 편집을 한다면
 - Youtube 에 올릴 동영상이라고 생각하면 기존 관습적인 ppt 스타일에서 벗어나 현재 유행하고 있는 기법을 받아들이기 쉬운 마음가짐이 된다.

9. 사람이 먼저다
 - 프레젠테이션은 자료가 아니라 사람이 하는 것이다.
 - 스피치를 먼저 구상하고 자료가 뒷받침해야 한다.
 - 전체 내용을 몇 개의 문장으로 요악하면 그것이 전체 발표의 구성/흐름이 된다.
 (우리는 살면서 스마트폰 등 많은 전자 제품을 사고 버립니다. 그 버려진 전자제품들을 전자 쓰레기라고 하는데 지구 환경에 큰 문제입니다. 그러나 전자쓰레기를 재활용하면 좋은 자원이 될 수도 있습니다.)

10. 내용이 더 먼저다.
 - 내용이 충실하고 그 내용을 발표자가 잘 이해하고 있으면 자신감이 생겨서 자료고 뭐고 상관없이 알아서 잘 풀린다.
 - 사람들은 결국 내용이 좋아야 만족한다.

11. 안 듣는 척 다 듣는다.
 - 딴 짓 하는 사람들이 강의평가는 가장 냉정하다.
 - 좋은 푸줏간 주인은 좋은 쇠고기를 팔 뿐이다. 보든 안 보든 그저 열심히 해야 한다.
 - 어째 ppt 자료랑 상관 없는 내용인데 ㅋㅋㅋ


Read More

Gladiabots - 싸움밖에 모르는 AI 배틀로봇



Gladiabots 는 로봇 배틀 + AI 프로그래밍을 소재로 한 게임이다. 우리가 알던 배틀로봇이 하드웨어 + 조종술의 대결이라면 Gladiabots는 로봇을 직접 조종하는 것이 아니라 로봇이 어떻게 움직일지를 미리 프로그래밍해야 한다. 같은 로봇을 쓰더라도 얼마나 똑똑하게 움직이느냐가 승패의 관건이다.

로봇은 4종류가 주어지며 각각 속도와 사거리, 파워, 내구성 측면에서 특징이 있다. 이들 로봇을 잘 조합하여 상대와의 대결에 승리해야 한다. 단순한 전멸전도 있지만 특정 영역을 사수한다든지, 깃발 뺏기라든지 다양한 게임 룰이 있다.

싸움은 어떻게 일어날까? 기본은 바로 어그로와 포커스이다. 체력이 떨어진 로봇은 후퇴해서 쉴드를 채우고 상대방을 공격할 때는 하나씩 집중 공격하는 것이 유리하다. 또한 가령 깃발 뺏기의 경우 자연스럽게 수송 병력과 호위 병력으로 나뉘어지며 어느 쪽을 먼저 공격할 것인지, 전략을 잘 세워야 한다.



AI 프로그래밍은 모두 그래픽 기반으로 이루어지며 약간의 연습이 필요하다. 그래서 상당한 양의 튜토리얼을 제공하고 있다.

문제는 너무 순수하게 로봇, 배틀, 프로그래밍에 치중했다는 것이다. 네러티브와 스토리가 없고, 차가운 바닥에 로봇밖에 없다.  포탈을 보라. 자칫 평범한 퍼즐게임이 될 수 있는 것에 환상적인 스토리와 연출이 더해지자 역사에 길이 남을 대작이 되지 않았는가. 자칫 지루하고 까다로울 수 있는 프로그래밍이 어떻게 하면 유저들에게 쉽게 다가갈 수 있는지에 대한 고민이 전혀 없다는 것은 좀 문제가 있다.


AI가 하는 일이란 것도 미로 찾기도 아니고 그저 사거리 계산해서 왔다갔다 하면서 쉴드 채우고 점사하고 이 정도 뿐이라 체감상 불륨이 작다. 파고들기로 얼마나 파고들 수 있는지 모르겠지만 그것만이 게임 컨텐츠의 전부인 것이다.

좋은 그래픽과 스크립트 편집기를 가지고 다양한 컨텐츠를 보여주지 못하는 것이 참 아쉬운 게임이다. 섬멸전, 깃발뺏기, 점령전 외 다른 룰이 있다든지, 로봇의 하드웨어를 고치고 그에 맞는 AI를 설계한다든지 더 다양한 요소가 추가된다면 좋겠다.
 


Read More

프로스트 펑크 - 최상의 연출과 시나리오


 11bit studio는 This War Of Mine 으로 화제가 되어 그 동안 다양한 게임들을 내놓았다. 대형 게임은 아닐지라도 특유의 레트로 감성과 충실한 시나리오로 매나이를 형성하고 있다.

프로스트 펑크는 그 동안의 게임 중 This War Of Mine과 가장 닮은 게임이라고 할 수 있다. 똑같이 혹한의 설정, 그리고 서바이벌 상황에서 무너지는 인간의 존엄성을 주제로 하고 있다.



게임의 주된 컨텐츠는 경영과 심시티이다. 주변의 자원을 채취하고, 건물을 건설하고, 테크트리를 개발하는 등 게임 구조는 매우 평범하다. 다만 혹한에 싸우는 작은 인간 사회라는 설정 속에서 생존을 위해 인간의 존엄성과 양심을 버리도록 선택을 강요한다. 여기에 충분한 연출로 몰입감을 더해서 단순한 매니악한 스크립트 위주의 게임성을 벗어나 대중적인 입맛도 만족시키고 있다.

중요한 건 난이도이다. 난이도가 너무 쉬우면 특유의 긴장감을 느끼기 어렵지만 난이도가 너무 높으면 게임의 분위기를 느끼기보다 시스템을 분석하고 파고들기에 열중하여 그 역시 몰입을 방해한다. 또한 게임에서 다 이기려고 하면 안 된다. 사상자 한 명도 없이 게임을 끝내려고 하는 노력은 안 하는 것이 좋다. 좀 고생도 하고 이래저래 난관이 와도 어떻게든 게임을 붙잡고 진행을 해보는 것이 게임을 제대로 즐기는 방법이다. 공포영화를 보는데 아무도 안 죽는 건 말이 안 된다. 사람이 죽는 긴장감과 스트레스가 싫으면 애초에 공포영화를 선택해서는 안 된다. 이 게임은 사람들이 죽어나가는 상황에서 어떻게든 발버둥쳐야 하는 스트레스와 긴장을 동반하고 있다. 그리고 그 긴장을 즐기는 것이 이 게임의 목적이다.

또 재미난 건 일반적인 심시티와는 달리 직교좌표가 아닌 극좌표계를 채용하여 가운데를 중심으로 동그랗게 건물을 쌓아나가야 한다. 극좌표계 그 자체로도 나름의 재미가 있다.

경영 시뮬레이션 + 심시티 + 생존게임에 적절한 연출이 합쳐진 수작임에 틀림없다.


Read More

강철비2 정상회담 - 좌파출신 국뽕 영화

스포 없음. 아마도. 이 정도면?

코로나 국면에 간만에 영화가 나와서 상당한 기대를 하고 보았으나 초반 5분만에 그냥 안 보고 버릴까 하는 갈등이 생길 만큼 초반 앞 부분은 드럽게 재미가 없다. 대통령과 영부인의 티격태격, 각종 장관들과의 장황한 상황 설명, 그리고 전혀 왜 나오는지 모르겠는 한미일 훈련... 하.. 앞 부분은 정말 볼 게 없다. 전혀 극 전개에 상관없기에 왜 보고 있어야 되는지 모르겠는 이상한 컷들 잔뜩 들어 있다. 할 이야기가 너무 많아서 고르고 고른 장면들이 아니라 시간을 때우려고 작정한 듯한 내용들로 느껴진다.

무엇보다 시작장면. 한반도 위성 사진이 나오면서 자막이 깔리는데, 와 시작부터 진짜 재미없는 영화겠다 그런 느낌.

정상회담 들어가고 나면 그 때부터 시작이다. 트럼프랑 김정은이랑 말싸움 하는 데부터 흥미진진해지기 시작하고, 문재인까지 합세해서 세 사람의 캐릭터극이 시작된다.

그리고 전개되는 것은 일본과의 해전. 핵을 쏘냐 마냐 다투는 중에 잠수함 내부의 권력 다툼과 정치가 펼쳐진다.

그리고 클래식이라고 해야 하냐, 유치한 유머들 덕지덕지 발라져있다. 트럼프가 방귀 뀌고 김정은이 통역하고 막 말도 안 되는 상활들이 펼쳐진다. 트럼프를 완전 개그맨으로 그려놨다.

작중에 계속 나오는 북한 사투리는 북한 사람이 들으면 어떨지 몰라도 내가 듣기에는 충분히 자연스럽고 맛깔나서 나중에는 즐기게 된다. 그 동안 이북 억양은 개그 소재로나 쓰이고 말았지 이렇게 진지한 장면에 그대로 쓰이게 된 것은 근래의 일이다. 이제는 전혀 위화감이 없고 마치 외국어 중 하나를 듣는 기분이다. 잠수함 운전하는 군인들 얼굴도 나중에는 정 들더라.

곽도원은 아주 또라이로 되어 있다. 그 모든 불합리한 부분들을 다 무시하고 그냥 일본에 핵 날리고 말거라고, 생각 없는 자살 공격을 하고 있다. 전혀 공감이 되지 않는 비이성이다. 글쎄, 곽도원의 악역은 이제 좀 질린다. 변호인에서 실컷 했으면 됐지 뭘 자꾸 이런 걸 또 해, 좀 넣어두지.

반면에 김일성은 연기가 아주 좋다. 트럼프한테 북한 사투리로 따질 때 아주 사람 속을 통쾌하게 만드는 그의 분노 연기에 칭찬 1점.



반면 일본군 비행기 조종사의 오바연기는 이게 무슨 건담인가 싶었다. 이쿠죠! 긴박한 상황을 그런 오바연기로밖에 전달할 수 없는 영화의 부실함.

그리고 최악 중의 최악은 음악. 그저 시끄럽다. 시작도 시끄럽고 마지막 잠수함에서 나오면서 깔리는 스트링도 매우 시끄럽다.

그런데도 맨 마지막 평화협정 장면을 보면서 눈물이 왈칵 났다. 현실에서 이뤄진다면 얼마나 좋을까 싶어서. 영화적 완성도는 떨어지는데 순전히 애국심으로 사서 끝까지 봤다. 이게 국뽕 영화랑 다를 게 뭐냐.


---

구글 플레이 무비.. 이거 캡쳐가 안 된다. 그냥 공유 사이트에서 똑같은 돈 주고 다운받으면 마음대로 물고 뜯고 즐기고 맛보는 건데. 플레이어도 매우 불편해서 넘겨보기도 안 되고. 화질도 못 바꾸고. 곰플레이어로 틀면 밝기랑 채도랑 다 조절할 수 있는데. 이래가지고 다음 번에는 절대 안 쓴다. 화질도 최대 720p까지 지원. 아니 720p 까지 밖에 안 지원.

그래도 굳이 보려면 구글 플레이 사이트 들어가지 말고 구글에서 보면 좀 낫다.


Read More

Unity VideoPlayer로 한 프레임씩 동영상 불러오기

Unity에서 동영상을 불러오려면 보통 VideoPlayer를 쓰거나 OpenCV의 VideoCapture를 많이 쓰게 된다. 여기서는 https://forum.unity.com/threads/how-to-extract-frames-from-a-video.853687/ 여기 링크를 참고하여 VideoPlayer를 사용하는 방법을 설명한다.


VideoPlayer는 unity 컴포넌트라서 new VideoPlayer() 식으로 할당하면 안 되고 씬에서 생성한 다음에 넣어줘야 하는데 스크립트에서만 동작시키고 싶으면 Start()와 같은 곳에서 다음과 같이 쓰면 된다.


VideoPlayer videoPlayer = gameObject.AddComponent(typeof(VideoPlayer)) as VideoPlayer;
videoPlayer.Stop();
videoPlayer.renderMode = VideoRenderMode.APIOnly;
videoPlayer.prepareCompleted += Prepared;
videoPlayer.sendFrameReadyEvents = true;
videoPlayer.frameReady += FrameReady;


gameObject가 필요하니까 MonoBehavior 클래스를 상속받아야 한다. 어차피 유니티 모듈이니까 아예 유니티와 상관없이 동작은 안 되는 것이다. 위의 코드는 그냥 예제라서 로컬로 선언했지만 멤버로 선언하는게 맞으르 것이다.

받아오자마자 Stop()부터 하고 APIOnly 모드로 설정한다. 이는 화면에 직접 플레이하는 일은 안 하고 내부적으로만 동작하겠다는 것이다.

preparedCompleted 는 동영상의 헤더를 다 읽어와서 준비가 되면 호출된다. frameReady는 프레임 한 장을 grab 하는 일이 완료되면 불러와진다. 매 프레임마다 불러와지는 것이다.


이제 아래와 같이 주소값을 넣어주고 Prepare를 호출한다.


videoPlayer.url = path;
videoPlayer.Prepare();


여기서 path를 잘 넣어줘야 한다. 아래와 같은 구문을 참고해보자.


string outputPath = System.IO.Path.Combine(Application.streamingAssetsPath, "result.avi");


준비가 완료되었을 때 호출될 함수는 다음과 같다.


void Prepared(VideoPlayer vp)
{        
    vp.Pause();
}


이렇게 포즈를 걸면 0번째 프레임을 불러온다.


void FrameReady(VideoPlayer vp, long frameIndex)
{
    var textureToCopy = vp.texture;

    //initialize
    if (frameIndex == 0)
    {
        images = new List<Mat>();
        texture = new Texture2D((int)vp.width, (int)vp.height, TextureFormat.RGB24, false);
        Debug.Log(vp.width + "" + vp.height);
        Debug.Log(textureToCopy.width + "" + textureToCopy.height);
    }

    if (saveImage)
    {
        Mat mat = new Mat((int)vp.height, (int)vp.width, OpenCVForUnity.CoreModule.CvType.CV_8UC3);
        OpenCVForUnity.UnityUtils.Utils.textureToTexture2D(textureToCopy, texture);
        OpenCVForUnity.UnityUtils.Utils.texture2DToMat(texture, mat);
        images.Add(mat);
    }        

    processRate = frameIndex / (double)videoPlayer.frameCount;
    ProcessRateChanged.Invoke();
    if (frameIndex + 1 == (long)vp.frameCount)
    {
        Debug.Log("INVOKE!!");
        ReadCompleted.Invoke();
    }

    if (frameIndex < frameLimit || (ulong)frameIndex < vp.frameCount - 1 )
    {
        vp.frame = frameIndex + 1;
    }
    else
    {
        ReadCompleted.Invoke();
    }
}


중간에 frameIndex == 0 블럭이랑 saveImage 블럭은 내가 OpenCVForUnity를 활용하기 위해 작성한 것이니 신경쓰지 말자. 하여튼 중요한 것은 textureToCopy가 들어왔다는 것이고, 이것을 이용하여 본인 원하는 작업을 하면 된다.

맨 마지막에 frameLimit는 내가 직접 선언한 것이니 신경쓰지 말고, 중요한 것은 vp.frame에 그 다음으로 읽고 싶은 프레임 번호를 넣는 것이다. vp.frame은 단순한 멤버 변수가 아니고 property이기 때문에 값을 집어넣는 순간 다음 프레임을 읽어오는 동작을 수행한다.

ReadComplete도 내가 직접 만든 것이다. 하여튼 여기에서 다 읽어왔을 때의 동작을 수행하면 된다.


이 방법의 문제점은 Prepare에 실패했을 때 아무런 피드백이 없다는 것이다. Prepare()를 호출하고 얼마간 지났는데도 Prepared 이벤트 함수로 들어오지 않는다면 뭔가 조치를 취할 수 있도록 해야 한다. 우선 아래와 같은 무식한 방법이 있긴 하다.


int count = 0;
while (!videoPlayer.isPrepared && count++ < 100)
{
    Debug.Log("Preparing Video");
    yield return null;
}
Debug.Log("Done Preparing Video");


100 frame이니까 약 3초 정도 기다려보는 것이다. while을 빠져나오고 나면 isPrepared를 다시 검사해서 준비가 되서 빠져나온 건지 아니면 count가 다 되서 빠져나온 건지 확인해보면 된다.

또한 일부 Unity 플러그인에서 레코딩한 파일은 몇 프레임 읽다가 실패한다. 상당수의 비디오 레코더들이 표준 포맷을 지키지 않고 파일을 쓴다. 여타 다른 비디오 플레이어들은 어떻게든 잘못된 포맷 형태를 무시하고 동영상을 플레이해주는데, VideoPlayer는 그들만큼 정성스럽지가 못하다.

유니티에서 공식적으로 지원한다고 밝힌 확장자는 아래와 같다.

https://docs.unity3d.com/Manual/VideoSources-FileCompatibility.html

그런데 여기에 함정이 있다. mp4의 경우, h.264는 잘 불러와지는데 h.265는 따로 코덱을 깔아야 한다. 나는 대충 깔아서 해봤는데 잘 안 되고 신통치 않다;; 같은 avi, mp4 확장자라도 코덱은 천차만별이라 신경 쓰이는 게 한두가지가 아니다. 게다가 윈도우가 아닌 안드로이드로 넘어가면 골치아픔은 두 배가 된다.


Read More

음정

 중3 때 처음 음정을 배울 때 음정에 대해서 이렇게 배웠다.

  *숫자를 세릴 때는 자기 자신부터 세린다.

  *계이름 사이에 반음(미파, 시도)이 한 없으면 장, 있으면 단, 2개면 감

  *감 - 단 - 장 - 증 순이며 조표가 붙어서 간격이 넓어지면 오른쪽으로, 좁아지면 왼쪽으로


뭐든지 이해를 못 할 때는 외우는 게 좋고 외우나 이해하나 결과적으로는 같게 되는 경우가 많다지만 그냥 이해하면 쉬운 걸 굳이 어렵게 외울 때가 있는데, 바로 이런 경우라 하겠다.

음정이란 음 사이의 간격을 나타내는 말이다. 우리가 거리를 잴 때, 25cm, 3m 등으로 말하듯이 음악에서 음과 음 사이의 거리를 말할 때 쓰는 용어가 음정이다.

음악에서 모든 음은 반음 간격으로 이루어져 있으며 1옥타브 내에 12개의 음이 존재한다. 그러므로 그냥 음과 음 사이의 거리를 반음의 개수로 3반음 5반음 이런 식으로 나타내면 그냥 편하지 않느냐고, 공학적인 입장에서는 설명할 수 있지만, 실제로 음악은 그렇지 않다. 음악의 음은 음계 위에서 이루어지며 음 과의 거리도 음계 위에서 설명해야 한다. 예를 들어 자연 장음계에서 미와 솔 사이에는 파, 파# 이렇게 두 개의 음이 있으므로 미부터 솔까지 가려면 3칸 움직어야 하니까 미 솔은 3칸 이라고 하고 솔과 시 사이에는 솔#, 라, 라# 이렇게 3개의 음이 있으므로 솔부터 시까지 가려면 4칸 움직여야 하니까 4칸! 이래버리면 편할 것 같지만... 이렇게 해봐야 원래 음정을 얘기하는 취지가 무색해지고 음악적이지가 않다. 장음계 위해서는 자기 자신과의 거리가 1도이고 미와 솔은 미 파 솔 순으로 진행되므로 3도, 솔과 시 는 솔 라 시 순으로 진행되므로 역시 3도이다. 그런데 같은 3도라고 해도 완전히 똑같은 3도는 아니기 때문에 별명을 붙여서 미솔은 단3도, 솔시는 장3도라고 부르게 된 것이다.

어쨌든 처음 음계의 개념을 이해할 때는 음악적으로 접근하기보다 그냥 공학적으로 접근해버리는 것이 더 이해가 빠를 수도 있다.

다음과 같이 외워보자.

자기 자신과의 거리 = 완전1도

반음 1칸 거리 = 단2도 = 증1도 (미파, 시도)

반음 2칸 거리 = 장2도 = 감3도 (도레, 레미, 파솔, 솔라, 라시)

반음 3칸 거리 = 단3도 = 증2도 (레파, 미솔, 라도, 시레)

반음 4칸 거리 = 장3도 = 감4도 (도미, 파라, 솔시)

반음 5칸 거리 = 완전4도 = 증3도  (도파, 레솔, 미라, 솔도, 라레, 시미)

반음 6칸 거리 = 증4도 = 감5도 (파시)

반음 7칸 거리 = 완전 5도 = 감6도 (도솔, 레라, 미시, 파도, 솔레, 라미)


이런 식이다. 음 사이의 거리에 대해 각각의 별칭이 붙었다고 생각하면 편하다.


그럼 왜 단, 장, 완전 이런 용어들을 붙였을까? 그건 그냥 그 음 간격이 주는 음악적 느낌으로부터 왔다고 해야 될 것이다.

같은 3도 화음이라도 도미, 솔시와 같은 장3도는 밝은 느낌을 주는데 반해 미솔, 라도 등 단3도는 어두운 느낌을 준다. 한 가지 힌트로서 장음정이나 완전음정은 도부터 시작하는 음이 존재한다. 예를 들어 도레 : 장2도, 도미 : 장3도, 도파 : 완전4도, 도솔 : 완전5도, 도라 : 장6도, 도시 : 장7도 이다. 만약에 도부터 출발해서 단3도를 만들려면 도레#이 되어야 하는데 반음이 섞여 있으므로 어두운 느낌이 난다. 음정을 최초에 어떤 놈이 만들었는지 알 수는 없지만 분명 내가 생각한대로 도를 기준으로 나열하여 장음과 완전음정을 정하고, 나머지를 단음정이라고 했을 것으로 강력히 추측된다. 완전 내 뇌피셜 ㅋㅋㅋ 가끔 보면 뇌피셜을 진짜 어디서 확인한 사실인 양 우선 얘기하고 보는 사람들 있는데 나도 그 축에 낀다 헤헤헤 내가 맞다고 생각한 거니까 맞는 거다, 그게 나 같은 인간의 사고 체계.

완전4도, 완전 5도 완전 8도는 배음과 관련이 있다. 주파수를 2배로 올렸을 때 한 옥타브 높은 음이 나며 1.5배 올렸을 때 완전 5도 높은 음이 생긴다. 1.5배음과 2배음 사이의 음정은 완전 4도이다. 예로부터 이들 사이의 화음이 가장 아름답다 하였고, 심지어는 complete하다고 여겼다. 겨우 음악의 음정 따위에 완전이라는 거룩한 명칭을 붙인 서양인들의 세계관이 간접적으로 느껴지는 부분이다.

다른 자료가 없으면 내가 엄청 열심히 설명할테지만 널리고 널린 게 음정 자료니까 요까지만.

Read More

C언어 증감연산자 파고들기

우연한 계기로 구르미 코딩 테스트를 해보다가 이런 문제를 만났다.




난 당연히 정답이 8, 3, 5일 줄 알았는데 9, 3, 5라고?

왜일까?
이것을 풀기 위해 연산자 우선순위를 생각해봐야 한다.


증감 연산자는 전위연산과 후위연산으로 나뉜다. 전위연산(++a)은 값을 증가시킨 후 증가된 값을 리턴하고, 후위연산(a++)은 현재 값을 리턴한 뒤 나중에 값을 증가시킨다.

그런데 이렇게까지만 생각하고 있으면 문제가 안 풀린다. 뒤에 있는 ++b가 앞에 있는 ++a + b--에 영향을 주는 기이한 현산이 발생하기 때문이다. 또한 앞에 있는 b--도 뒤에 있는 ++b에 영향을 줘서 5가 나온다. 도대체 순서가 어떻게 되는 걸까?

전위 연산자인 ++a는 연산은 그 어떤 연산보다 가장 먼저 실행하되, 그 expression(리턴값)은 확인하는 시점의 a값으로 결정된다. 반대로 후위 연산자는 리턴값 확인 시점 그 당시의 a 값을 expression으로 보낸 뒤 즉시 증감을 수행한다.

위의 문제에서 연산자 우선 순위는 ++a, ++b, +, b--, printf 순이다. 우선 ++a와 ++b가 먼저 진행되면서 a == 3, b == 6이 된다. 이 상태에서 + 연산이 진행되면 그 피연산자인 ++a와 --b의 값을 확인한다. --b는 이 확인 시점에서 6을 리턴하면서 실제값은 다시 5가 된다. +연산의 결과는 9가 되고 이제 printf를 진행한다. printf에서 맨 마지막 ++b 값을 확인할 때는 그 시점의 b값을 리턴하게 되는데 이것은 5이다.


다음 예제를 보자.

int a = 2, b = 5;
int c = --a + b * a++;
printf("%d, %d, %d\n", a, b, c);

정답은 2, 5, 7이다.

우선 전위 연산자인 --a가 수행되어 a == 1 이 된다. 그 다음 곱셈 연산이 수행되는데, 그 순간 곱셈의 피연산자가 되는 b, a++의 값을 확인한다. a++의 값을 확인하면 a는 현재 값인 1을 리턴하고, 동시에 a를 2로 만든다. 곱셈연산의 결과는 5 * 1 => 5가 되고 이제 덧셈 연산을 수행한다. 덧셈 연산의 왼쪽 피연산자 --a의 값을 확인해보면 확인하는 시점의 a 값 2를 리턴한다. 그래서 c는 7이다.


int a = 2, b = 5;
printf("%d, %d, %d, %d\n", b--, b--, b, ++b);


정답은 5, 6, 4, 4 이다. 연산자 순서는 ++, --, --, printf이다. 먼저 ++b가 수행되면서 우선 b == 6이 된다. b-- 가 수행되면 수행당시 값인 6을 리턴하고 5로 만든다. 또 한 번 실행되면 5를 리턴하고 4로 만든다. 마지막으로 printf가 수행될 때 b, ++b의 값을 확인해보면 4이다.

int a = 2, b = 5;
printf("%d, %d, %d, %d\n", b--, b--, b, a + ++b);

여기에서 정답은 5, 6, 4, 8 이다. ++b가 수행되면서 6이 되고 그 다음 우선순위인 덧셈 연산이 수행된다. 이 때 ++b의 값을 확인해보면 6이므로 덧셈 결과는 8이다. 나머지는 위와 같다.


이렇듯 증감연산자는 그 자체로 핵지랄이기 때문에 왠만하면 한 줄에 중복해서 안 쓰는 것이 권장되고, 아니 그냥 안 쓰는 것이 강력히 권장되고, C에 긴밀이 오리엔트된 파이썬에서조차 사라진 이유이기도 하다.



C는 배워도 배워도 끝이 없네 ㅋㅋㅋ
Read More

핸즈온 비지도 학습 - 이것은 책이 아니다

 



비지도학습과 관련해서 좀 공부하고 싶은 마음에 책을 검색하다가 그냥 가장 최근에 나온 아무 거나 골라서 보게 된 책?이다.

텐서플로우, 케라스 막 이런 걸 제목에 달고 있지만 저것은 말 그대로 제목 장사이다. 대부분의 내용은 PCA와 군집화를 다루고 있다.

석사 수준의 다양한 방법들을 나열하고 있기는 한데, 제목만 나열하고 설명은 한 페이지 정도인데, 그 설명조차 매우 빈약하다. 처음엔 번역을 못 해서 그런가 하고 생각했는데 가만히 다시 보니까 그냥 애초에 내용이 부실하다.

다양한 코드 예제가 있지만 코드에 대한 설명은 전혀 없다. 그냥 독학해야 된다.

다양하고 쓸데없는 실험 결과를 나열하고 있는데 전혀 해설이 없다. 자고로 가장 좋은 실험이란 결과를 이미 예측한 상태에서 검증을 해보는 것이다. 그 다음으로 좋은 실험은 결과는 모르지만 실험으로 밝히고자 하는 바가 분명한 것이다. 최악의 실험은 왜 하는지도 모르고 당연히 결과도 모르는 실험이다. 더 최악은 결과에 대해 아무 해설도 할 수 없는 실험이다. 이 책의 실험은 어디에 해당할까 하니 가장 최악이거나 그 다음 악이거나 그렇다.

특히 내가 아는 내용일수록 설명과 실험과 테스트가 너무 엉터리라는 것이 드러난다. 그러고 나니 모르는 내용은 감히 쳐다볼 엄두가 나지 않는다.

가장 백미라고 할 수 있는 부분은 28x28 MNIST 이미지를 플랫한 다음에 앞에서부터 n개를 꺼내서 그 특징으로 군집화를 돌려보는 부분이다. PCA는 10개로 추려도 잘 되는데 그냥 n개 꺼내면 결과가 좋지 않으니 PCA가 얼마나 우수한가! 이러고 앉았다.


야.. 진짜 사기당했다 이거는 ㅋㅋㅋㅋ 이것은 책이 아니다. 진짜 책도 아니다.

Read More

파닥파닥 - 스며드는 것 미만 잡

 




2013년인가 나왔던 국산 애니메이션인데, 스팀에서 3300원에 구매할 수 있다.

https://store.steampowered.com/app/468060/PADAK/


횟집에 잡혀들어온 고등어가 어항을 탈출해서 바다로 간다는 이야기인데, 매우 현실적인 묘사가 특징이다. 벌써 이렇게 한 줄만 봐도 내용을 다 설명하고 남은 느낌이다.

회라는 요리, 생으로 살을 썰어 먹는다는 그로테스크함, 생선이란 동물이 가지고 있는 기괴함이랄까, 그리고 약육강식의 현실이 주는 잔혹함, 그런 것들을 적극적으로 차용해서 단순한 탈출 동화를 매우 극적으로 느껴지게 만든다. 





주인공인 우리 파닥이는 매우 단순한 캐릭터에 멍청함까지 가지고 있다. 어항에 들어오자마자 나갈꺼야! 만 외치며 하루 종일 유리벽에 머리를 들이받는다. 실제 고등어야 그럴 수 있지만 영화 속 주인공이 저래도 되나 싶다. 게다가 바다라는 야생에서 컸음에도 불구하고 양식장에서 자란 물고기들보다 야성이 없고 순한 것도 공감할 수 없게 만드는 부분이다.

이야기의 핵심이 되는 것은 오히려 고등어가 아니라 넙치. 유일하게 입체적인 캐릭터를 가졌고, 나름 스토리가 있는 인생을 살았다. 그리고 그게 이 영화의 유일한 스토리라고 할 수 있을 것이다.


더빙은 모두 전문 성우들이 맡았다. 인간의 경우는 자연스러운 일상톤으로 연기했고 물고기들은 약간의 극화톤이 느껴진다. 전체적으로 훌륭한 편이다. 성우의 연기를 항상 애니메이션이나 게임으로만 접하다보니 뭔가 말투가 과장되어 있고 억지로 목을 눌러 목소리를 변형시킨 티가 나서 영 거북했는데, 그나마 여기서는 자연스럽다.





본격적인 뮤지컬 형식은 아니지만 몇 곡의 노래가 들어있고 이 때는 2D 애니메이션이 나온다. 나름 볼만한 요소, 들을만한 요소이다. 성우들이 직접 노래를 불렀다.



"밥 먹는 데 울고 지랄이야, 밥맛 떨어지게" - 같은 수족관 물고기의 꼬리를 뜯어먹으면서 하는 말

선도 악도 없는 잔인한 약육강식의 세계, 그 속에서 최상위포식자인 우리는 인간이다. 그래서 평소에 물고기의 입장으로 생각하지 않았는데, 과연 물고기들은 어떨까? 잔인한 묘사를 통해 그 모습을 있는 그대로 보여주면서 약간의 위트를 섞어서 너무 거부감이 들지 않도록 배려했다. 그 잔인하고 (물고기 입장에서)현실적인 묘사라는 것은 나름 충격적으로 다가오는 면이 있으나, 그것은 그저 작품의 분위기만 전달할 뿐, 전체적인 영화구조나 스토리에 큰 영향이 없으며 충격, 그걸로 그냥 끝이라는 게 문제다. 먹고 먹히는 현실에 충분히 몰입하는 경험은 좋지만 어항과 바다를 대비시켜 그 의미를 부여하는 것에는 미흡하다. 대사는 전체적으로 임팩트가 부족하고, 특히 고등어가 바다로 가는 희망을 얘기할 때는 좀 루즈하다. 무엇보다 역시 내용이 좀 없다.

횟감이 되는 물고기의 입장에서 횟집에서 벌어지는 일을 물고기 입장에서 잔인한 톤으로 그려본다는 것, 벌써부터 뻔하지 않나.


영화를 보면서 떠오른 건 안도현의 '스며드는 것'. 영화보다 한 편의 시가 더 나은 것 같다.


'저녁이야, 불 끄고 잘 시간이야'


Read More
Powered by Blogger.