Live2D Cubismでパーツのフェード方法

結論:『Live2Dパーツ表示項目内のパーツのアルファ値をフェードアウトしたい場合は100から0に、フェードインしたい場合は0から100にし、グラフエディタを開き、リニアでフェードの線形補間をかける』


フェードイン・アウトで左腕パーツの切り替え




東北イタコのLive2Dモデルを弄っていたが、複数の腕の種類があり、アニメーションの途中でうまく切り替えたいと思った。
が、なかなかフェードイン・アウトを利用した切り替え方法がわからなかったので、ここに備忘録的に記載する。


最初はフェードイン・アウトなど考えずに普通に切り替えようと思い、アルファ値を普通に表示したいパーツを0から100に、非表示にしたいパーツを100から0に変更するという手をとった。
その結果が下図。見ての通り、ぶつ切りになり、違和感がある。


フェードイン・アウトなしで左腕パーツの切り替え


この状況を改善するためにフェードイン・アウトを導入していく。
先ず、パーツをフェード開始のタイミングで、

  • 既存で表示しているパーツにアルファ値100を振る
  • これから表示するパーツにアルファ値0を振る。

そして、フェード終了のタイミングで、

  • 既存で表示しているパーツにアルファ値0を振る。
  • これから表示するパーツにアルファ値100を振る。


パーツそれぞれにフェード開始と終了のタイミングでアルファ値を振る。
そのあとにグラフエディタを開く


上図のように各アルファ値を振り終えたら、フェードアウトするパーツを選択した状態でグラフエディタを押下する。
グラフ上に0と添字についたポイントを押下し、リニアボタンを押下する。
すると、グラフが下図のように変更される。この斜めになったグラフが徐々にアルファ値が変更されることを示している。


グラフがこのような形になればフェードアウトはOK


フェードインするパーツにも同様の操作を行う。
下図のようになる。


フェードインはこのようになる


以上の設定が全て完了すれば、フェードを利用したパーツの切り替えが完了となる。

DOTweenの導入方法と使用例

DOTweenはUnityのAssetのひとつで、Objectの動きを制御するAsset。
無料版と有料版があるが、今回は無料版を利用した。


assetstore.unity.com


先ず、上記のAssetをDownloadし、Importする。
その次に下記のようなウィンドウが表示されるので、「Setup DOTween」を押下。


「Setup DOTween」押下


そうするとAdd/Remove Modulesに遷移するので、「Apply」を押下。


「Apply」押下


これで準備完了。
あとは、Objectにアタッチされているスクリプトに動きをコーディングすると完了となる。


動きのコーディングの前にやることは、スクリプト冒頭に、

using DG.Tweening;

を記載。これでDOTweemingをこのスクリプト内で使用可能となる。


では、実際に動きのコーディングをしていく。
 今回は2種類の動きを作ろうと思う。
どのような動きか、画像をあげるので灰色の円盤状の機体に注目してほしい。


まず1つ目。
下記のような簡単な直線的な動き。



この動きを実現させるためには、下記のコーディングをする。

void Start()
{
    transform.DOMove(new Vector3(0, -750, 0), 4.0f)
                    .SetEase(Ease.Linear);
}

簡単に説明すると、

  • 第1引数は到着点
  • 第2引数は到着点に行くまでにかかる時間
  • チェーンメソッドSetEase()は加速減速の方法

今回のケースだと、
(0, -750, 0)4秒かけて加速減速なしで向かう
となる。
これだけで完成となる。
ちなみにObject出現位置が動きの開始位置となるのでそこは記述の必要はない。


2つ目。
Pathを指定してその経路を通る動き。下記のような動き。



この動きを実現させるためには、下記のコーディングをする。

void Start()
{
            Vector3[] paths = new[] {
                                    new Vector3(0, 0, 0),
                                    new Vector3(-450, 300, 0)
                                 };
            transform.DOPath(paths, 2.0f, PathType.CatmullRom)
                            .SetEase(Ease.Linear);
}

簡単に説明すると、
先ず、Vector3でPathの配列を作る。
そのあとに動きの制御のDOPathを利用する。

  • 第1引数はPathの配列
  • 第2引数は到着点に行くまでにかかる時間
  • チェーンメソッドSetEase()は加速減速の方法

今回のケースだと、
(0, -750, 0)、(-450, 300, 0)を経由して2秒かけて加速減速なしで向かう
となる。
これだけで完成となる。

OnTrigger系関数の利用に関わるCollider Component内のIsTrigger

結論:『OnTrigger系関数を利用するときは、少なくとも片方の衝突ObjectのColliderのIsTriggerがTureであれば良い』


Unityでシューティングゲームを作っているときに、

  • 操作機の弾と敵機が衝突したら爆発
  • 敵機の弾と操作機が衝突したら爆発
  • 操作機と敵機が衝突したら爆発
  • 弾同士が接触しても物理的挙動が起こらない

という制御をしたいと思った。


で、今回は上記制御するにあたり、物理的挙動は全て不要だったので、結論的には、

  • 操作機のIsTriggerをTrue
  • 敵機のIsTriggerをTrue
  • 弾のIsTriggerをTrue

でOKであった。


Collider ComponentにあるIs Triggerは何かと言うと、 そのObjectがOnTrigger系関数を稼働させるトリガーになるかどうかというもの。
True: トリガーになる
False: トリガーにならない


IsTriggerをTrueにするとトリガーになる


そして、OnTriggerを発生させるための必要条件は他にも2つあり、 Rigidbody(2d) Componentを少なくとも片方の衝突Objectが有している必要がある。 RigidBodyというのは、物理的挙動を制御するComponent。


Rigidbody(2d) Componentを片方のObjectだけでもいいので有している必要がある


もう一つの必要条件は、 Collider Componentを両方の衝突Objectが有している必要があるということである。


Collider Componentは両方のObjectに必要


OnTrigger系関数の利用条件をまとめると、

  • 少なくとも片方のObjectのIsTriggerをTrueにする
  • 少なくとも片方のObjectにRigidbody(2d) Componentをアタッチ
  • 両方のObjectにCollider Componentをアタッチ

となる。

Float型数値の等価比較

Unityでシューティングゲームを作成している時、敵機の位置を読み取り、その位置がある値と等しいかを確認する必要が出てきた。
何をしたかったかというと、敵機の位置により、その動きのパターンを決めたかったということ。


そこで先ず、どのように敵機の位置を把握しようとしたかというと以下の通り。 (x座標が0という条件が当てまるかの確認)

if (transform.position.x == 0.0f)

しかしこの方法だと以下のような警告が出てしまった。


こんな警告や
こんな警告がでてしまった


「Fix floating point number comparing. compare a difference with epsilon.」 「Comparison of floating point numbers can be unequal due to the differing precision of the two values.」

警告分は異なるが、記載してある内容としては、

「Floating型数値を等価比較する際はその精度の違いを考慮して、EPSILONを利用した比較をすべき」

というようなことを言っていると思う。


どうも一見同じに見える数値でも、Float型であると丸め誤差などで微妙に差が生じてしまい、全く同じにならないケースがあるようだ。

なので、Epsilonというとても小さい数値の定数を使用し、2つのFloat型数値が「おおよそ」同じが確認するということをするようだ。


そして、ググった結果、以下のようにコードを書き換えた。

if (Mathf.Approximately(transform.position.x, 0.0f))


このMathf.Approximatelyの詳しい内容は後述のリンクを参照して欲しいが、 簡単に内容を説明すると 「第一引数と第二引数の差がEPSILON(というすごい小さな値)いないかどうか」 を調べるというもの。 これを使えば同じだと想定されるFloat型数値の等価比較が誤差を気にせずできるようになる (と思う) docs.unity3d.com


ブログの記事がGoogleで検索されるようにすべきこと

先ほど自分の書き上げたブログの記事がGoogleで検索されない。

 

f:id:exwks:20200516204731p:plain

記事のURLでGoogle検索しても、その記事が引っかからない

 

このような場合は、まだその記事がGoogleに登録されていないということが原因のようだ。

 

これを解決するためにはまず、Googleにこの記事を見つけてもらう必要がある。

 そこで利用するものが「Google Search Console」である。

 

まずはブログをそのもの「Google Search Console」にて登録。

このブログそのものの登録自体は最初の一回きりなので、ここでは方法の記載は割愛。

 

次に問題の検索されないブログの記事をGoogleに登録依頼をする。

まず、下図のように「Google Search Console」の「URL検査」を押下し、上の検索バーでその記事のURLを検索する。

 

f:id:exwks:20200516211237p:plain

左側のサイドバーの「URL検査」押下、そのあと検索バーに記事のURL入力

 

そうすると、GoogleがまだそのURLの記事を登録していない場合には、下図のような画面が表示される。

 

 

f:id:exwks:20200516223511p:plain

記事がGoogleに登録されていない場合、このような画面がでる

 

このようにGoogleがその記事を登録していないと、記事のURLやその記事の文章でGoogle検索しても表示されない状態ということになる。

なので、Googleにその記事を見つけて登録してください、というリクエストを送り、Google検索で引っかかるようにする必要がある。

そのリクエスト方法が、「インデックス登録をリクエスト」を押下。これだけである。

すると下図のようなポップアップが出現する

 

f:id:exwks:20200516212155p:plain

「インデックス登録をリクエスト」を押下後、このようなポップアップが出現

 

しばらくしてから、記事のURLや記事中の文章でGoogle検索をしてみると、下図のようにちゃんと引っかかることが確認できる。

ちなみに今回の場合は「インデックス登録をリクエスト」してからだいたい30分後には登録が完了していたようだ。

 

f:id:exwks:20200516215530p:plain

記事のURLでGoole検索するとちゃんとその記事が引っかかった

 

Screen Space-Camera時のJoystick Packの設定

Unityにてシューティンゲームを作成している際、Joystick PackのFloating Joystickを利用した。

 

assetstore.unity.com

 

今回、自分が作っているこのゲームではCanvasのRender ModeをScreen Space-Cameraと設定していた。

このScreen Space-Cameraだと、Floating Joystickの挙動が少し変だった。

 

具体的には下記のようになってしまった。

 

f:id:exwks:20200510225058p:plain

赤星マーク部分をタッチしているのにFloating Joystickは全然違うところに出現している

 

画面タッチした位置とFlaoting Joystickの出現位置がずれてしまっている。

しかもこれは一番最初のタッチだけで発生し、それ以降はタッチとlaoting Joystickの出現位置は同位置となり、正常となる。

 

この現象を解消するために、スクリプトを書き換えた。

具体的には、Joystick.jsのStart()部分とOnDrag(PointerEventData eventData)部分である。

 

おそらく、原因はFloatingJoystickのbackground.anchoredPositionが決まる前にcam = canvas.worldCameraの設定が効いていない事かと思う。

なので、background.anchoredPositionが決定される前にcanvas.worldCameraの設定を下記のように行った。

 

f:id:exwks:20200510230845p:plain

上図のようにStart()に「cam = canvas.worldCamera」を追加

 

加えて、

 

f:id:exwks:20200510230740p:plain

上図のようにOnDrag(PointerEventData eventData)の「cam = null」とif文をコメントアウト

 

こうする事で、タッチイベントが発生する前にcanvas.worldCameraの設定ができ、そのあとの余計な処理(OnDrag(PointerEventData eventData)内のコメントアウトしたところ)を省くことができる。

 

以上の書き換えを行ったところ、

 

f:id:exwks:20200510233708p:plain

タッチ位置とFloating Joystickの位置が同位置にある

 

最初のタッチ位置とFloating Joysickの位置が同位置にあるようになった。

 

UIがカメラ範囲外にレンダリングされてしまう場合の対処法


カメラの範囲外の領域にUI(今回はフロート型のジョイスティック)がレンダリングされてしまい、それが残り続けてしまう現象に遭遇した。

 

f:id:exwks:20200423023004p:plain

左下の残り続けるUIのレンダリング

 

このような感じ。左下にジョイスティックの残骸があるのがわかると思う。
これがずっと残ってしまう為下記のように対応した。

 

CanvasのRender ModeをScreen Space - Cameraに変更」

 

f:id:exwks:20200423023008p:plain

Render ModeをScreen Space - Cameraに変更

 

UIがレンダリングされ、残骸が残ってしまう場合の設定は、
Screen Space - Over layで設定されていた。

 

Render Cameraには画角設定しているCameraを設定。
このようにすると、下図のようにカメラ範囲外にUIがレンダリングされず残らない。

 

f:id:exwks:20200423023018p:plain

カメラ範囲外にUIが入ったとしてもその残骸が残らなくなった