BLOG

閲覧数: 9,693

【Unity】まばたきを適当な間隔で行うスクリプト【C#】

アイコン

お久しぶりでございます!

生駒万憲(いこまかずのり)です。

さて今回は開発中の自作ゲームの話などしたいと思います!

いえちゃんと漫画も描いてますよ!

なかなか完成しないだけで…。

ふふふ…。

では、以前紹介した当ブログのかわいい看板息子まほば君、

今回は動画で紹介します!

とりあえず、まずはこちらの動画をご覧くださいませ。

音が出るので、ご注意ください!

よし!かわいい!

長年夢見ていた、うちの子の動いている姿を

ようやく見ることが出来ました!

嬉しい!!

現在シンプルな3Dの脱出ゲームを2年位一人で制作中ですが、

基本的なシステム周りは大体完成しました。

出来るだけ早く公開出来ればいいなと思っていますが、

ボリュームが全く無いので、

ステージをもう少し広げて、仕掛けを増やしたいと思っています。

せめて15分位はプレイ出来る様にしたい。

それが完成するまで間は、

モデリングとかスクリプトの紹介も出来たらいいなと思っています。

というわけで、

早速、動画にも映っている、まほば君のまばたきの解説をしてみましょう!

画面に映っているキャラクターがまばたきすると、

途端に生きてるって感じがしますよね!

アニメやゲームでは必須の演出ですね!

実はちょっとこだわって作りました。

基本となるスクリプトはこちらです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AutoBlink : MonoBehaviour
{
    //とじ目のBlendShapesが登録されているSkinnedMeshRendererを取得
    //まほば君の場合は顔のオブジェクトが持っている
    public SkinnedMeshRenderer face_SkinnedMeshRenderer;

    //とじ目の要素数
    public int eyeClose_KeyNumber;

    //SetBlendShapeWeightに使用する数値
    //0でまぶたが完全に開く、100でまぶたが完全に閉じる
    private float weight = 0.0f;
    
    //時間を計測するための変数
    public float countTime = 0.0f;
    //まばたきの発動タイミングの変数
    public float blinkTriggerTime = 5.0f;

    void FixedUpdate()
    {
        //FixedUpdateは初期設定のままなら
        //0.02秒間隔でくり返し呼ばれる
        CheckCountTime();
    }

    void CheckCountTime()
    {
        //時間を計測
        countTime += Time.deltaTime;
        //時間がまばたきの発動タイミングを超えたら
        if (countTime > blinkTriggerTime)
        {
            //計測時間をリセット
            countTime = 0.0f;
            //まばたきの発動タイミングの変数に
            //5.0fから10.5fの間でランダムな数値を取得
            blinkTriggerTime = Random.Range(5.0f, 10.5f);

            //目を閉じる処理開始
            StartCoroutine("CloseEye");
        }
    }

    IEnumerator CloseEye()
    {
        //閉じる際の絶妙な中目加減
        weight = 80.0f;
        //中目にしてちょっとだけ次の処理を待つ
        face_SkinnedMeshRenderer.SetBlendShapeWeight(eyeClose_KeyNumber, weight);
        yield return new WaitForSeconds(0.008f);
        //まぶたを完全に閉じてちょっとだけ次の処理を待つ
        face_SkinnedMeshRenderer.SetBlendShapeWeight(eyeClose_KeyNumber, 100.0f);
        yield return new WaitForSeconds(0.040f);

        //目を開く処理開始
        StartCoroutine("OpenEye");
    }

    IEnumerator OpenEye()
    {
        //開く際の絶妙な中目加減
        weight = 60.0f;
        //中目にしてちょっとだけ次の処理を待つ
        face_SkinnedMeshRenderer.SetBlendShapeWeight(eyeClose_KeyNumber, weight);
        yield return new WaitForSeconds(0.015f);
        //まぶたを完全に開く
        face_SkinnedMeshRenderer.SetBlendShapeWeight(eyeClose_KeyNumber, 0.0f);
    }
    
}

実際の実装ではさらに他の要素との兼ね合いもあるので、

処理を止めたりする機能も必要ですが、基本はこんな感じにしました。

多くの日本のアニメーションで採用されている、

中一枚のまばたきを再現しました。

CGらしい滑らかな動きではないですが、

まほば君の様な、セルルックなキャラクターの場合、

こういう方法も有りかなと。

このスクリプトを実際にUnityのエディターで動かした動画がこちらです。

ちゃんと動いていますね。

詳しく見ていきます。

経過時間を格納するcountTimeの値が、

発動時間を保持するblinkTriggerTimeの

値を超えたタイミングで、

まほば君がまばたきしているのがお分かり頂けると思います。

まばたきと同時にcountTimeの値は0にリセットされ、

blinkTriggerTimeには5.0秒から10.5秒の範囲内で、ランダムな値が新しく入ります。

これを繰り返しているわけですね。

上記のスクリプトは、別にどこにアタッチしてもかまわないのですが、

今回は、空のオブジェクトを作って、そこにアタッチしました。

では、その他の変数も見てみましょう。

まずはこちらの画像をご覧下さい。

MHB_unityImage1_1

face_SkinnedMeshRendererとeyeClose_KeyNumberという、

2つの変数がありますね。

この2つは、

まほば君のモデルデータの構造と深い関係があります。

まほば君のモデルデータを見てみましょう。

画像

まほば君の場合ですが、

いろんな表情のデータをface_Baseという顔のパーツが全て保持しています。

上から5番目にあるeye_closeという名前のデータが、

まぶたを閉じるモーフデータです。

パラメータに0から100の値を与える事で、

まぶたの閉じ具合をコントロール出来ます。

0でまぶたが完全に開き、100でまぶたが完全に閉じます。

こんな感じ。

この値をスクリプトから弄りたいので、先ほどの2つの変数が必要なわけです。

ではもう一度、先ほどの画像を見てみましょう。

MHB_unityImage1_1

まほば君のSkinnedMeshRendererにアクセスするため、

face_SkinnedMeshRendererには、

まほば君のSkinnedMeshRendererが入っています。

そして、まほば君のまぶたの動きをコントロールしたいので、

eyeClose_KeyNumberには、

モーフデータの上から5番目という意味の、

4という数値が入っています。

配列の要素数は0から数えるというルールがあるので

5番目は4になるわけですね。

では、いよいよ実際に、

まほば君にまばたきをして貰う処理の開始です。

もう一度スクリプトを見てみましょう。

スクリプトの48行目から始まります。

IEnumerator CloseEye()
{
  //閉じる際の絶妙な中目加減
  weight = 80.0f;
  //中目にしてちょっとだけ次の処理を待つ
  face_SkinnedMeshRenderer.SetBlendShapeWeight(eyeClose_KeyNumber, weight);
  yield return new WaitForSeconds(0.008f);
  //まぶたを完全に閉じてちょっとだけ次の処理を待つ
  face_SkinnedMeshRenderer.SetBlendShapeWeight(eyeClose_KeyNumber, 100.0f);
  yield return new WaitForSeconds(0.040f);

    //目を開く処理開始
    StartCoroutine("OpenEye");
}

IEnumerator OpenEye()
{
    //開く際の絶妙な中目加減
    weight = 60.0f;
    //中目にしてちょっとだけ次の処理を待つ
    face_SkinnedMeshRenderer.SetBlendShapeWeight(eyeClose_KeyNumber,weight);
    yield return new WaitForSeconds(0.015f);
    //まぶたを完全に開く
    face_SkinnedMeshRenderer.SetBlendShapeWeight(eyeClose_KeyNumber, 0.0f);
}

weightという変数に私のこだわりの値を入れています。

この値を、まほば君のSkinnedMeshRendererが持つ

モーフデータであるBlendShapesのパラメータに、数値をセットします。

0から数えて4番目のパラメータでしたね。

入れた値の分だけまぶたが動きます。

次の行でyield return new WaitForSeconds(♡♡)というクラスを使い、

処理を一時中断、

指定した♡♡秒後に続きの処理を再開します。

これにより、途中のまぶたの状態を一定時間維持出来ます。

この処理を順番に3回繰り返して行い、少しずつまぶたを動かしていきます。

そして最後に

パラメータの値を0に戻したらまばたき完了です。

つまり、こいうこと。

画像

まさにパラパラまんがです。

途中の計算は一切せず、一コマ毎に数値を直接セットしています。

いかがでしょうか?

たったこれだけの短いプログラムで、

適度な間隔で、まばたきを繰り返し行う機能が実装出来ました。

Unityの経験がない方でも、

意外に簡単かも!

と思われた方もいるかも知れません。

そうなんです!

Unityの沼はとても深いですが、入り口はすごく簡単!!

いい時代になりました。

本当にありがたいツールです!!

もし興味がわいたら是非挑戦してみて下さい!

さて、ちゃんと解説出来たか不安ですが、

頑張って解説してみました。

今回のお話は以上になります。

今後もUnityの話題にはふれていきたいと思います!

最後まで読んで頂きありがとうございます!

ではまた。

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

カテゴリー

アーカイブ

ページ上部へ戻る