【ゲームアプリとベジェ曲線：その③(完結)】パーツによる絵のバリエーション

## はじめに

このシリーズでは **iOS**/**Android** ゲームアプリの描画手法として、ベジェ曲線の可能性を模索します。
第三回目は、素材をパーツ単位で作成することで、手軽に絵のバリエーションを増やす手法について探っていきます。

サンプルアプリのプロジェクトは **GitHub** にあります。
[**https://github.com/hakumai-iida/BezierSample**](https://github.com/hakumai-iida/BezierSample)
[![title_3rd](https://user-images.githubusercontent.com/13220051/99179158-25d42000-275e-11eb-8372-94f13bdd8681.png)](https://github.com/hakumai-iida/BezierSample)
前回：【[**その②：ストローク(線)による表現の付け足し**](https://qiita.com/hakumai-iida/items/fb688ed3df5cb2cf23c9)】

## パーツ分けのメリット
↓の画像は、【[**その①：環境準備とアンカーポイント(点)による形の変化**](https://qiita.com/hakumai-iida/items/57d27776176eb4f1e9f1)】で作成したミクさんの顔です。
![ss00](https://user-images.githubusercontent.com/13220051/99161971-72f2ca80-273b-11eb-8889-0da7da692b5c.png)
白目や目玉、口や鼻、顔や頭など、構成要素をパーツごとに作成しておき、アプリ上で組み合わせて描画することで、顔の絵を構成しています。

でも、なぜこんな面倒なことをするのでしょう？

アプリで処理する際、顔なら顔として１回の描画で済むように、データ上で１つにまとめておいたほうが無駄がないはずです。
絵をバラバラにしておくメリットとはなんでしょうか？

### メリット１：パーツの差し替えによるバリエーション
例えば、下記のような素材があるとします。
![ss01](https://user-images.githubusercontent.com/13220051/99161973-7423f780-273b-11eb-9bd8-6dbc334e593e.png)
これらの画像は全てアプリ上で描画されたものですが、先に説明したミクさんと同様、顔や体の要素がバラバラに作成されています。
（*※ミクさんの顔に追加されている陰影やタッチについては【[**その②：ストローク(線)による表現の付け足し**](https://qiita.com/hakumai-iida/items/fb688ed3df5cb2cf23c9)】をご覧ください*）

そして、各パーツが共通のルールで作成されているため、目なら目、前髪なら前髪、手足なら手足として、パーツ間で互換性があります。
言い換えると、パーツどうしを差し替えられるということです。
![ss02](https://user-images.githubusercontent.com/13220051/99161974-7423f780-273b-11eb-89ed-464af3a615a2.png)
一見するとこれらの絵は、一枚一枚が個別の素材に見えますが、基本素材のパーツをアプリ上でランダムに組み合わせて描画したものになります。

素材を部位毎に作成することで入れ替えが可能となり、『**手軽に絵のバリエーションを生み出せる**』のがパーツ分けの１つめのメリットです。

### メリット２：パーツの変化によるアニメーション
ベジェ曲線として作成したデータは実行時に線を計算して描画するため、拡大／縮小＆回転しても絵的に劣化しないという特性があります。
この強みのおかげで、パーツ単位で拡大／縮小＆回転をフルに活用できます。

例えば、体、腕、脚などのパーツを横方向に大きくすることで、キャラクタの見た目を太らせることができます。
同様に、パーツを縦方向に大きくすることで背を高く、小さくすることで背を低く見せることもできます。

さらに腕や脚などのパーツを、関節を中心に回転させることでちょっとした動きをつけることもできます。
![ss03](https://user-images.githubusercontent.com/13220051/99161975-74bc8e00-273b-11eb-812e-fbd6e5fbb618.gif)
上記は、キャラクタの体型を変えつつ、手足の関節を曲げることで、素材的には１枚の絵をアニメーションさせています。
（*※体型や関節の動きについては【[**その①：環境準備とアンカーポイント(点)による形の変化**](https://qiita.com/hakumai-iida/items/57d27776176eb4f1e9f1)】をご覧ください*）

各部位を個別に変化させることで、『**手軽に絵を動かせる**』のがパーツ分けの２つ目のメリットです。

## パーツ分けにおける課題
素材をパーツ単位で分けて作る際、パーツ同士をどう馴染ませるかが課題になります。

### いかにパーツをつなげるか？
例えば、腕のパーツを「上腕」と「前腕」に分けて作るとします。
![ss04](https://user-images.githubusercontent.com/13220051/99161976-75552480-273b-11eb-9f6f-30cf75eac80d.png)
仮に上記のようなパーツがあったとして、肘を曲げる動きをつけようとしましょう。
絵的になんの調整もせずに前腕だけを回転させてしまうと、肘の部分で線が綺麗につながらず、見た目に違和感がでてしまいます。
![ss05](https://user-images.githubusercontent.com/13220051/99161977-75edbb00-273b-11eb-9805-fa39f4b55ea0.png)
形状が一致しないパーツ同士をくっつける場合、いかに線をつなげて違和感のない形状にするかが課題となります。

### いかにパーツの向きを判定するか？
パーツに対して体型的な操作をしようとした場合、拡大／縮小を適用する方向の判断が必要になってきます。
![ss06](https://user-images.githubusercontent.com/13220051/99161978-75edbb00-273b-11eb-817e-c66208b5e28d.png)
例えば上記画像において、①の下げた腕であればＸ方向に拡大することで腕を太く見せられますが、②の上げた腕をX方向に拡大すると腕が伸びて見えてしまいます。
![ss07](https://user-images.githubusercontent.com/13220051/99161980-76865180-273b-11eb-9498-5358796bc0ca.png)
パーツの大きさを変える際、どの向きに拡大／縮小するかの判定も課題となります。

## パーツ分けに対するベジェ曲線的アプローチ

さて、ベジェ曲線における描画では、点（アンカーポイント）を計算しつつ形状を構成していきます。
この時、アンカーポイントに色々な情報を紐付けておくことで、状況に応じて形を変化させることが可能です。
（*※アンカーポイントについては【[**その①：環境準備とアンカーポイント(点)による形の変化**](https://qiita.com/hakumai-iida/items/57d27776176eb4f1e9f1)】をご覧ください*）

上述の課題の解決には、このアンカーポイントが活躍します。
では、ベジェ曲線的なアプローチを見ていきましょう。

### フックによるストロークの接続

サンプルデータでは、顔の輪郭は「顔の上部＝生え際からこめかみ」と「顔の下部＝こめかみからアゴ」の２つのパーツで構成されます。
ですが、データ上でストローク間の座標が微妙にずれていて、パーツを縦に並べてただけでは、こめかみのラインがきれいに繋がってくれません。
![ss08](https://user-images.githubusercontent.com/13220051/99161981-76865180-273b-11eb-9164-dca06a193ee5.png)
そこで、この２つのパーツのストロークの両端（アンカーポイント）に座標を共有するためのIDを設定し、パーツが描画される際にこめかみの所で線がフック（接続）されるようにします。
![ss09](https://user-images.githubusercontent.com/13220051/99161982-771ee800-273b-11eb-8ce4-53e44e2b8555.png)
上記画像において、緑の四角がフック指定されたアンカーポイントとなります。
これらがIDによりフックされることで、きれいにこめかみが繋がりました。

パーツ間のストロークを接続するためのアプローチ、それがフックとなります。

### ジョイントによる太さの維持

ここで、上腕と前腕のパーツに話しを戻しましょう。
![ss04](https://user-images.githubusercontent.com/13220051/99161976-75552480-273b-11eb-9f6f-30cf75eac80d.png)
これらのパーツもフックにより接続されるのですが、単純にアンカーポイントの座標が共有されただけでは、前腕のパーツが回転した場合に肘の太さが潰れてしまいます。
![ss11](https://user-images.githubusercontent.com/13220051/99161994-93bb2000-273b-11eb-959d-09df9b1df13c.png)
そこで、パーツ間で角度に差がでることが想定される場合（*言い換えるとパーツのどちらかが独自に回転する可能性がある場合*）、パーツの接続部分を円にみたててジョイント（関節）情報を設定します。

この時ジョイントはその直径により、二本のストローク間で保たれるべき「**太さ**」の役割を担います。
具体的には、パーツ間の角度の差分をジョイントが把握し、ストローク端を円上で回転させてからフックします。
![ss12](https://user-images.githubusercontent.com/13220051/99161996-9453b680-273b-11eb-9771-dedeb7a04684.png)
パーツ間の太さを維持するためのアプローチ、それがジョイントとなります。

### 呼び出し位置によるパーツの伸縮

サンプルデータでは、「腹」パーツが描画の起点となり、「上半身」と「下半身」を呼び出します。
その後、上半身は「上腕」と「首」を呼び出し、上腕は「前腕」を、首は「頭」を呼び出します。
さらに、前腕が「手」を呼び出し、さらに、さらに、と言うように、体の中心に近いパーツが末端へ向けてパーツを呼び出すことで、キャラクタの絵が構成されます。
![ss14](https://user-images.githubusercontent.com/13220051/99161997-9453b680-273b-11eb-8d90-108871063d78.gif)
さて、パーツの呼び出しはとても簡単です。
適当な位置にアンカーポイントを置いて、呼び出すパーツの種別を設定するだけです。

そして、先に説明した通り、パーツ間のストロークはフック指定によって自動で繋がってくれるため、パーツの呼び出し位置を遠ざけることでパーツ間の見た目を伸ばしたり、近づけることで縮ませることが可能となります。

パーツの伸縮にはこの特性を利用します。

体型による変化のパラメータをアンカーポイントに設定することで、パーツの呼び出し位置を補正し、キャラクタの体を伸ばしたり縮めたりすることが可能となります。
（*※実際には、体型パラメータは呼び出し位置だけではなくストロークの座標＝あらゆる形状に影響します.　詳しくは【[**その①：環境準備とアンカーポイント(点)による形の変化**](https://qiita.com/hakumai-iida/items/57d27776176eb4f1e9f1)】をご覧ください*）

試しに、パーツの呼び出し位置を極端にしてみた画像が下記となります。
![ss15](https://user-images.githubusercontent.com/13220051/99161998-94ec4d00-273b-11eb-89f9-385b93df12ac.png)
この例では、「頭」、「前腕」、「下腿」、「つま先」パーツが、親パーツからかなり離れた位置に呼び出された結果、キリンのような見た目になりました。

### 最終手段のカバー

さて、今までは、パーツ同士をいかに結合させるかを考えてきました。
ですが、「**見た目の親和性＝絵としてのなじみ具合**」の観点から結合が厳しい場合もでてきます。

例えば、ミクさんは「絵的にノースリーブ」です。
一方で、他のキャラクタ達は「絵的に袖のあるシャツ」を着ています。

処理上は、ミクさんの上半身に他のキャラの上腕を接続しても何の問題もありませんが、肌の露出した肩口に袖を接続さてしまうと「**見た目的に変な絵**」になってしまいます。

段ボールやネギの着ぐるみの場合はさらに深刻で、そのままパーツを呼び出すと、首や上腕の付け根が絵的になじまず、違和感が顕著になります。
![ss16](https://user-images.githubusercontent.com/13220051/99161999-9584e380-273b-11eb-853f-0a95e57b1e95.png)
そこで、パーツ間の絵的な親和性が低そうな場合、見苦しい部分を誤魔化すためにカバー（粗隠し）を適用します。

例えば、段ボールを上半身として利用する時のカバーとして、「首や上腕を通す穴」のようなパーツを追加で作成します。
![ss17](https://user-images.githubusercontent.com/13220051/99162000-9584e380-273b-11eb-81cc-9b859a24ae21.png)
そして、段ボールが上腕を呼び出した際、カバーを対象パーツのジョイントに紐づけることで、違和感のある付け根部分を、文字通り覆い隠してしまいます。

この時、カバーは紐づけられたジョイントから情報を受け取り、対象パーツの太さと向きにあわせて拡大／縮小＆回転して表示されます。
![ss18](https://user-images.githubusercontent.com/13220051/99162001-961d7a00-273b-11eb-8a78-765dbf57253a.png)
絵的にどうしようもない時の最終手段、それがカバーとなります。

### ごまかしとの戦い

以上がパーツ分け描画に対する、ベジェ曲線的なアプローチとなります。

とはいえまだまだ完璧というわけではありません。
サンプルアプリで「ランダム」生成を試してみると、粗の目立つ画像がコレでもかという具合に出てきてしまいます。

データ的には問題ないけど、見た目的に厳しい部分。
これをどう回避していくのかは今後の課題でもあります。
![ss19_1](https://user-images.githubusercontent.com/13220051/99162002-961d7a00-273b-11eb-9c32-099be90cd98b.png)
例えば基本ストロークで描画された上記の絵は、細かな粗がいくつも目につきます。
*・右耳のおさげの付け根が頭のラインをハミ出している*
*・右耳のおさげが前腕の前にきてしまっている*
*・両肩の接続が変（前述したミクさんのノースリーブに袖を接続した状態）*
*・右脇と上腕の接続が変（おそらくフックの設定漏れ）*

こういった粗は、データで丁寧に修正していくのが本来なのですが、一括で抑え込むことができたら楽ですし保険にもなります。
例えばストロークの種類をブレ線にしてみたり鉛筆線にしてみると細かな描写が潰れるため、いくつかの粗が目立たなくなったりします。
![ss19_2](https://user-images.githubusercontent.com/13220051/99162003-96b61080-273b-11eb-887d-6c8060a80624.png)
絵のニュアンスが大きく変わるので功罪ではありますが、これもある意味、ベジェ曲線的なアプローチと言えるかもしれません。

データの作り方、パーツの構成、それを支えるシステム。
まだまだ試行錯誤の余地がありそうです。

## ベジェ曲線の可能性

さて、ゲームアプリの描画におけるベジェ曲線の可能性について、３回にわたって探ってきました。

当初想定していた機能の実装＆検証が終わった今、ベジェ曲線の可能性として１番に感じていることは、色々な素材をゴチャ混ぜにして、１つのニュアンス（解像度＋ストローク＋塗り）の絵として表示できる点です。

とくにベジェ曲線は、素材を再利用するアプローチが豊富なため、少ない素材でバリエーションを容易に生み出せます。
さらにこの強みは、素材の数に対して加速度的に増していきます。
（*※基本素材を１００種類ぐらい用意できたら、そこから生成されるランダム画像のバリエーションは物凄いことになりそうです*）

キャラクタの見た目の変化を前面に押し出すようなジャンル等、ベジェ曲線は十分にゲーム描画で活用できると思います。

例えば「**女の子を合成するゲーム**」とか。
あるいは「**女の子が着ぐるみに身を包んで闘って、負けたら爆ぜて素体に戻るゲーム**」とか。

やばい、ドキドキしてきた！

では、このシリーズはこれにて完結となります。
お読みいただきありがとうございました。

【[**その①：環境準備とアンカーポイント(点)による形の変化**](https://qiita.com/hakumai-iida/items/57d27776176eb4f1e9f1)】
【[**その②：ストローク(線)による表現の付け足し**](https://qiita.com/hakumai-iida/items/fb688ed3df5cb2cf23c9)】