ゲームのロゴを作った

開発中のゲームのロゴを作った話をしようと思う。ロゴを作るのは初めてだ。
今年の1月から試行錯誤していたが、こんな感じでに仕上がった。

f:id:masatoko:20170317012111p:plain

今回は、これの製作過程を書いてみる。

ロゴに必要な要素は、

1.ロゴの質からゲームの質の高さが推し量れること
2.ゲームの雰囲気・ジャンルがおおよそ分かること

であると思う。素人考えだが。

Steamでゲームを眺めていると、ロゴの出来とゲームの出来は比例しているように感じる。誰もが無意識に感じ取っていることだと思う。みんな、ロゴを見た瞬間に中身の出来を推測し、ストアのページに進むかをどうかを判断しているのだろう。ロゴは最初に見られる看板であり、ロゴ製作には情熱を注ぐべきだ。また、自分の好きな雰囲気やジャンルとマッチするかも判断するだろうから、これが分かるように作らなきゃならない。

結論から言うと、コンピュータに入っているフォントや、WEBからダウンロードしてきたフォントを使って作ったロゴはしっくりこなかった。
下のロゴは、Nexaというフォントで、画像をかすれさせたもの。かすれているから、恐らくホラーなんだろうということは推し量れるが、ちょっと安っぽい。フォント自体には罪はない。
f:id:masatoko:20170317020303p:plain

開発中のゲームは、雰囲気がホラーライクなので、不安定な感じを表現するため、手書きの文字を取り込むことにした。

まず、油性サインペンを使って文字を構成する線をたくさん描いた。ただし、'G'は曲線なので個別に描いた。
f:id:masatoko:20170316180728j:plain

これをGIMP2で取り込み、2値化(白と黒の2色に)してから、白い背景部分を削除し、直線を組み合わせて文字を組んだ。それをpng画像として書き出した。
f:id:masatoko:20170318173644j:plain
この時点の画像は、境界がドットでギザギザ。
f:id:masatoko:20170318173410p:plain

次に、InkscapeというAdobe Illustratorの代わりとなるソフトで読み込み、”ビットマップのトレース”で境界からパスを作成した。
f:id:masatoko:20170317021451p:plain

あとは細かいパスを手直しした。
f:id:masatoko:20170317021539p:plain

これで、ベクタ形式のロゴが出来上がった。色も変えられるし、様々なサイズで出力できる。というか、ホラーというより、少しスタイリッシュ寄りになっちゃったか?
f:id:masatoko:20170318173948p:plain

ゲームの進捗

ところで、ゲームの開発状況だが、もう少しでSteamのストアページが公開できそうだ。
あと、最終PVももう少しで完成する。

Haskellで色の配列から画像を生成

JuicyPixelライブラリを利用して、png画像を生成する。
座標ごとに色をRGBで指定する。

JuicyPixelの使い方が良く分からなかったので、
一度bmp形式のByteStringを作ってから、それをpngで保存するっていう、回りくどいやり方になってしまった。
bmp形式ならばByteStringをそのまま出力すればいいが、pngは構造が複雑なので、何らかのライブラリを利用せざるを得ない。

サンプルでは、下のような画像が出力される。

きっと、もっと簡単な方法があると思う。

レベルのサムネイル自動生成(1)

ユーザーが自作レベルをSTEAM上で公開する場合、
一目でどんなレベルかを把握できるようなサムネ画像があると便利だ。
ということで、レベルを1枚の画像として表示するプログラムを作っている。
ひとまず、1つのセルを1ドットで表してみた。

f:id:masatoko:20170123143347p:plain

ブログのために拡大しているが、もとは128x128の小さい画像だ。
ちょっと問題なのは、遊ぶ前からレベルの構造が見えてしまい、ネタバレになってしまう点。
もちろん、ユーザー側で任意の画像を用意したりできるようにできるつもりだけど、
労力無しでサムネが用意されたほうが良いだろう。

一度、サムネの役割をまとめてみる。

  • サムネを見て、そのレベルを見て面白そうと思える。(STEAMからレベルを落とす場面)
  • レベルの選択画面で、サムネを見て、レベルを識別できる。(ゲーム内でレベルを選択する場面)
  • ネタバレにならないこと。(レベルを初めて遊ぶ場面・探索しきっていない場合)

こう考えると、ゲーム画面のスクショっていう選択肢があってもいいかも。
簡単にスクショをサムネにできる仕組みがあったらいいな。


画像生成に戻って、この画像の問題点は2つ。

  1. レベル構造が鮮明すぎて、ネタバレになってしまう。
  2. 画像を縦に並べるので、マップが広いと下が切れてしまう。

1については、画像をゆがませたり、上に汚れみたいなエフェクトをかけたりして、不鮮明にするとか?
結構手間かかりそうでやだなあ。

2については、複数の長方形(1つのマップ)をどううまく配置するかっていう課題だ。
検索すると、”長方形詰込み問題”として解法が出てくるけど、
まあ、今回はそんな大仰なもんでもないので、適当に詰め込んでみよう。

http://repo.lib.hosei.ac.jp/bitstream/10114/8970/1/13_s_m_nozawa.pdf
http://www.orsj.or.jp/~archive/pdf/bul/Vol.50_05_335.pdf

次回は、いい感じに配置できた画像を公開する予定。

EIN(米国納税者番号)の取得

海外でゲームを販売することになり、
EIN(米国納税者番号)が必要になった。
これを取得しないと二重課税になる。
つまり、アメリカで30%の源泉徴収をされ、さらに日本で税金を引かれてしまう。
アメリカの源泉徴収を回避するために必要。
すごくとまどったので、今後迷う人のためにまとめておく。

方法について

EINはIRS(内国歳入庁)で発行してもらう。
方法は以下のとおり。

# 方法 メリット デメリット
1 電話 即時発行! 英語でやりとり
2 SS-4を書いてFAX送信 英語での会話不要・手軽 届いたか確認できない・記入ミスの場合やり直し
3 SS-4を書いて郵送 英語での会話不要 届いたか確認できない・記入ミスの場合やり直し・面倒

3はメリットないので、1か2で迷うと思うが、1と2の合わせ技がよい。
SS-4を書いてから電話し、オペレーターからFAX番号を教えてもらい、そこに送る。
それでも多少の英語での会話が必要だけども。
僕は事前にFAXを送ってから電話したが、オペレーターが送信した文書を探せないので、これはNGだった。

SS-4の書き方

省略します。検索すると色々でてきます。
下記サイトからダウンロードできます。
Form SS-4, Application for Employer Identification Number (EIN)

国際電話について

アメリカへの国際電話なので料金に注意。
Skypeだと安い。
Skypeは、相手の国によって料金が決まるんだけど、
このときは、2.26円/分だった。
Skypeクレジット500円で十分。

国際FAXについて

僕の家はFAXが無かったので、ローソンのFAXを利用して送った。
電話中に外出して、その間待ってもらった。
これ、ちょっと迷惑だったかも。ごめんよ。。
家にFAXがあれば、その場で送るのがよい。
しかし、家庭用の電話は、国際FAXに対応していないものがあるらしいので注意。
また、インターネットFAXというのもあるようだけど、
月額とかだし、色々と調べた結果、やめておくことにした。(適当なこと書けないので、詳しい理由は書かない。)

まあ2の方法でもよいのかな。
返信が来ないとかのトラブルもあるようだけど、
期間的に余裕があるならば。

LeapMotionをHaskellで動かすための準備 その2

前回の続き。

今回はHaskellでLeapMotionを動かすところまでやる。
具体的には、HaskellFFIを通してc++用のLeapMotoinSDKを使う。

まずは普通にc++でLeapMotionSDKを使ってみる。

step4.cc

#include <iostream>
#include "Leap.h"
using namespace Leap;

Controller *new_controller(void){
    return new Controller();
}
void delete_controller(Controller *controller){
    delete controller;
}
int num_hands(const Controller *controller){
    return controller->frame().hands().count();
}

int main() {
    Controller *controller = new_controller();
    while(true){
        std::cout << "num hands: " << num_hands(controller) << std::endl;
        sleep(1);
    }
    delete_controller(controller);
    return 0;
}

Haskellから呼べるように、手の数を得るための関数を書いている。

LeapMotionのヘッダファイルを"include/Leap.h"に用意し、コンパイルする。

g++ step4.cc -I./include -o step4 libLeap.dylib

実行してみる。

num hands: 0
num hands: 0
num hands: 1
num hands: 1
num hands: 2
num hands: 0

手を検出して手の数が表示された。


では、これをHaskellで実行するように改造する。

先ほどのstep4.ccのメイン関数以外を抜き出して、extern "C"で囲って、wrapper.ccとして保存する。

wrapper.cc

#include "Leap.h"
using namespace Leap;

extern "C" {
    Controller *new_controller(void){
        return new Controller();
    }
    void delete_controller(Controller *controller){
        delete controller;
    }
    int num_hands(const Controller *controller){
        return controller->frame().hands().count();
    }
}

これをHaskellFFIで呼ぶコードを書く。

LeapMod.hs

{-# LANGUAGE ForeignFunctionInterface #-}
module LeapMod where

import Foreign.Ptr
import Foreign.C

data LeapController = LeapController
data LeapFrame = LeapFrame

foreign import ccall "wrapper.h new_controller" cNewController :: IO (Ptr LeapController)
foreign import ccall "wrapper.h delete_controller" cDeleteController :: Ptr LeapController -> IO ()
foreign import ccall "wrapper.h num_hands" cNumHands :: Ptr LeapController -> IO CInt

numHands :: Ptr LeapController -> IO Int
numHands controller = do
    num <- cNumHands controller
    return $ fromIntegral num

そしてそれをmain関数からループ内で呼ぶコードを書く。

Main.hs

import Control.Monad
import Control.Concurrent

import LeapMod

main = do
    ctrl <- cNewController
    forever $ do
        threadDelay $ 1 * 1000 * 1000
        num <- numHands ctrl
        putStrLn $ "num hands: " ++ (show num)

controllerをdeleteする場所が無いのが気になるものの、とりあえずこれで準備はできた。
コンパイルしてみる。

g++ -c -I./include wrapper.cc -o wrapper.o
ghc --make -main-is Main Main.hs -o ex_step4 libLeap.dylib -lstdc++ wrapper.o

実行する。

num hands: 0
num hands: 0
num hands: 1
num hands: 1
num hands: 2
num hands: 0

同じ結果を得ることができました。

これでHaskellからLeapMotionを触れることがわかりました。
あとは、適当にラッパーを充実させてやれば、色々できそうです。

LeapMotionをHaskellで動かすための準備 その1

HaskellOpenGLを動かせてテンションがあがってしまったので、そのままLeapMotionも購入してしまった。この勢いで、Haskellで動かそうと思う。

でも大きな問題があって、LeapMotionのSDKの対応言語が、JavaScriptC#Python、ObjectiveC、C++JAVA(、その他)などで、Haskellがかすりもしていない。

色々調べたところ、下のような方法でできるかもということが分かった。

f:id:masatoko:20140416231624p:plain

LeapMotionのライブラリを利用するラッパーをc++で作成し、それをHaskellからFFIで利用し、LeapMotionの機能を使う。

。。。本当にできるのか?

未知の世界すぎる。段階を踏んで成功に近づこう。


具体的には以下のステップとした。

  • ステップ1

FFIを使ってHaskellからC言語で書かれたプログラムを利用してみる。

  • ステップ2

FFIを使ってHaskellからc++で書かれたプログラムを利用してみる。

  • ステップ3

図中の構造をシンプルなケースを作って試す。

  • ステップ4

実際にLeapMotionのラッパーをc++で作成してHaskellから呼ぶ。


ステップ1

FFIを使ってHaskellからC言語で書かれたプログラムを利用

まず、単純に二乗するコードをC言語で書く。

hoge.h
int square(int x);
hoge.c
#include "hoge.h"

int my_square(int x) {
    return x * x;
}

FFIで読み込み、関数sqrとして利用できるようにする。

HogeMod.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module HogeMod where
import Foreign.C

foreign import ccall "hoge.h my_square" c_square :: CInt -> CInt
sqr :: Int -> Int
sqr x = fromIntegral $ c_square (fromIntegral x)

そして、メイン関数で呼ぶ処理を書く。

Main.hs
module Main where

import HogeMod

main = print $ sqr 9

コードが書けたので、gccでCソースのオブジェクトファイルを作成し、
GHChaskellソースから実行ファイルを作成する。

gcc -c hoge.c -o hoge.o
ghc --make -main-is Main -o ffi_ex Main.hs hoge.o

実行してみる。

./ffi_ex
81

よし。


ステップ2

FFIを使ってHaskellからc++で書かれたプログラムを利用

今度はC言語ではなくc++のプログラムをFFIで呼んでみる。

まず、クラスを使ったc++のプログラムを書く。

BigEaterは整数を食いまくる。

big_eater.h
class BigEater {
public:
    BigEater(void);
    void eat(int x);
    int energy(void) const;

private:
    int energy_;
};
big_eater.cc
#include "big_eater.h"

BigEater::BigEater(void) : energy_(0)
{}

void BigEater::eat(int x) {
    energy_ += x;
}

int BigEater::energy(void) const {
    return energy_;
}

こいつを利用するためのラッパー関数を書く。
Haskellから直接クラスは生成できないから。(たぶん)

wrapper.h
#include "big_eater.h"

extern "C" {
    BigEater* new_big_eater(void);
    void delete_big_eater(BigEater* big_eater);
    void eat(BigEater* big_eater, int x);
    int energy_of(const BigEater* big_eater);
}
wrapper.cc
#include "wrapper.h"

BigEater* new_big_eater(void) {
    return new BigEater();
}

void delete_big_eater(BigEater* big_eater) {
    delete big_eater;
}

void eat(BigEater* big_eater, int x) {
    big_eater->eat(x);
}

int energy_of(const BigEater* big_eater) {
    return big_eater->energy();
}

Haskellでこれらを読み込めるようにする。

BigEaterMod.hs
{-# LANGUAGE ForeignFunctionInterface #-}
module BigEaterMod where

import Foreign.Ptr
import Foreign.C

data BigEater = BigEater

foreign import ccall "wrapper.h new_big_eater" cNewBigEater :: Ptr BigEater
foreign import ccall "wrapper.h delete_big_eater" cDeleteBigEater :: Ptr BigEater -> IO ()
foreign import ccall "wrapper.h eat" cEat :: Ptr BigEater -> CInt -> IO ()
foreign import ccall "wrapper.h energy_of" cEnergyOf :: Ptr BigEater -> CInt

メイン関数で使わせる。

Main.hs
module Main where

import BigEaterMod

main = do
    let ptrBigEater = cNewBigEater
    print . fromIntegral . cEnergyOf $ ptrBigEater
    ptrBigEater `cEat` 1
    print . fromIntegral . cEnergyOf $ ptrBigEater
    ptrBigEater `cEat` 5000
    print . fromIntegral . cEnergyOf $ ptrBigEater
    cDeleteBigEater ptrBigEater

コンパイルする。

g++ -c big_eater.cc wrapper.cc
ghc --make -main-is Main Main.hs -o ex_big_eater -lstdc++ big_eater.o wrapper.o

実行する。

./ex_big_eater

0
1
5001

よしよし。

というか、newしたらdeleteしなきゃってのをhaskell使ってて気にするのはやっぱり気持ち悪い。
しょうがないんだけど。


ステップ3

シンプルなケースを作って試す

ステップ2のコードを流用し、BigEaterをライブラリとして作成し、ラッパーをコンパイルしてオブジェクトファイルを作り、Haskellから呼ぶ。

まず、BigEaterのライブラリファイルを作る。

g++ -dynamiclib big_eater.cc -o big_eater.dylib

これで big_eater.dylib が作成された。

次にwrapperのオブジェクトファイルを作成する。

g++ -c -o wrapper.o wrapper.cc

wrapper.oができた。

あとはhaskellのソースをコンパイルする。

ghc --make -main-is Main Main.hs -o ex_big_eater big_eater.dylib -lstdc++ wrapper.o

実行ファイルができたので実行してみる。

./ex_big_eater

0
1
5001

よしよしよし。


これで、c++のライブラリをhaskellから利用できることが確認できた。
このライブラリをLeapMotionのものに変えて、ラッパーを書けばできそうな感触をつかんだ。

これ以降はまだ試していない。
長くなってしまったし、とりあえずここまでにしとこう。


今回は、以下のサイトを参考にさせていただきました。


FFI Introduction - HaskellWiki

備忘録 [Haskell]FFI使ってC++バインディングに入門

mac の gcc で dylib を作成する方法 - 雑記 - Yahoo!ブログ

HaskellとメタセコイアとOpenGL

Haskellメタセコイア形式のモデルを解析してOpenGLで表示してみた。

f:id:masatoko:20140413234938p:plain

なぜHaskell

まあ趣味ですよね。
3Dプログラミングなら普通はc++ですよね。速いですもんね。
Haskellにはまった経緯なんですが、仕事でバグの出ないプログラムを探求してたら、参照透過性っていうキーワードに出会って、そのままずるずると純粋関数型ワールドに突入してしまったわけです。今では信者です。周りからはあいつ暴走してるよやばいよって思われてます。きっと。ちなみにOCamlも触ってみたんだけど構文がちょっとと思ってしまいました。たぶん慣れなんでしょうけどね。

HaskellOpenGL

OpenGLは、c++で少し触っていたので、多少免疫があるんですが、そもそもHaskellで3Dってどんくらい表現できるかが未知なので、ちょっと不安です。

メタセコイア形式のモデル読み込み

メタセコイアは和製3Dモデリングソフトです。昔触ったことがあったのと、独自形式の出力ファイルがテキストファイルであり読み込みやすそうなので、ひとまずこれを表示してみることにした。
HaskellのパーサーライブラリParsecを使って読み込みました。強力です。素敵です。

結果

まず、Haskellの公式チュートリアル
OpenGLTutorial1 - HaskellWiki
)を写経して下のものができました。

f:id:masatoko:20140413230854p:plain

次に、立方体にライトを当てて、

f:id:masatoko:20140413231030p:plain

最後に、メタセコイアで適当なモデルを作ってレンダラ関数に食わせてひとまず完了。

f:id:masatoko:20140413231121p:plain

リーゼントの顔っぽい何かです。実は出っ張ってる部分はリーゼントって呼ばないことを今知りました。ショックです。
ちなみに寄り目で見ると飛び出して見えます。


モデルの回転も視点の移動も、c++の時とほぼ同じようにできました。
ライティング(陰影付け)に関してはちょっと違いました。こちらの方がぶーたれてますね。
OpenGL and Haskell | Two Guys Arguing
参考にさせてもらいました。感謝。

まとめ

HaskellOpenGLを扱うのは、c++とそんなに変わらない感覚でできることがわかりました。
ただ、大きいモデルを読み込んでみると、今は座標などをリストで扱っているため、当然のごとく重くなりました。配列で実装するなど工夫が必要そうです。

でも、重くならないような処理にとどめておけば、Haskellっぽい、というか関数型の特徴を生かしたプログラミングが許されるはずなので、高効率かつ柔軟な3Dプログラミングができて、プロジェクトががんがん進むんじゃないかと妄想中です。

まあとにかく、意外にあっさりいったので、このままLeapMotionとOculusRiftで仮想世界にまで突っ込んでみたいですね。