【Unity】スクリプトのpublic・privateって何?使い分けは?

最近初心者の頃に疑問に思ったことが常識になり始めてブログの本来の目的を見失いかけている気がします。

ですので今回は記事のボリュームはありませんが、私が最初に結構疑問に思ったスクリプトの最初にあるprivateとかpublicについて最低限Unityで使う上で必要な情報を説明したいと思います。

 

はじめたばかりのときにスクリプトの最初の変数定義は全部publicで私は行っていました。これは非常に危うさを含んだことということに時が進むにつれて知ることになって行きました。

でははじめにpublic以外に何が使えるのかということを説明します。

だいたいUnityでは以下の3つを覚えておけばよいです。

    // パブリック変数.
    public int _publicInt;

    // プライベート変数.
    private int _privateInt;

    // シリアライズフィールドのプライベート変数.
    [SerializeField]
    private int _serializedfieldPrivateInt;

 

では1つずつ説明したいと思います。

  • Public

UnityでInspectorで欄が出てきて設定できる。

他のスクリプトからアクセス可能となる、参照できる。

  • Private

UnityでInspectorで欄が出てきて設定できない。

他のスクリプトからアクセス不可となる、参照できない。

  • [SerializedField] Private(変数のみ)

UnityでInspectorで欄が出てきて設定できる。

他のスクリプトからアクセス不可となる、参照できない。

 

では

UnityでのInspectorの欄で設定とはなんでしょうか?

それはこういうことです

f:id:graphicalpoxy:20190624195129p:plain

ここに欄が出来て数値やオブジェクトを設定できるようになるということです。

そう、あると便利な奴です。 [SerializedField]を知らなかった頃の私は、インスペクタに表示して設定したいがためにPublicを乱用していました。

ただPublicは便利なのですが他のスクリプトからもアクセス可能なので非常に危うさを含みます!

 

他のスクリプトからもアクセス可能となる、参照できるってなに?

これの何が怖いって他のスクリプトから書き換えることが出来ちゃうということです。

 

Unityに慣れてくるとスクリプトの数が多くなります。それは機能ごとにスクリプトを別々に作り始めることが理由に挙げられます。たとえばRPGならば、現在のプレイヤーのステータスだけを管理するスクリプト、レベルアップ処理だけを管理するスクリプト、所持金だけを管理するスクリプトなどと分けていきます。これはわかりやすさや、修正のしやすさが増すなど様々なメリットがあるためです。

しかしこうなってくると無考慮のPublicは危うさが増してきます。

 

 

例えばRPGとかのレベルっていろんな要素で使われますよね。ステータス管理したり、進行可能場所の制限をしたり、購入可能アイテムを制限したり・・・

なのでレベルというのは様々なスクリプトで参照したくなるわけです。ただこれをPublicにしておくと、どこかで書き換えられてしまう危険性が出てくるわけです。

レベルが予期せぬところで書き換わるってとんでもないバグですよね・・・

ということでPulicは使い分けをしっかりしないといけないということです。

複数人で開発なんてしている場合とかだともっと危険度は増しますからね。

 

どう使い分けるのか?

いろいろ書いてきましたが変数においての使い分けは簡単です。

 

public

  • 他で参照しないなら絶対に使わない。
  • 理由がない場合極力避ける

private

  • とりあえずこれ

[SerializedField] Private

  • Inspectorで直接オブジェクトや数値などを入れ込みたい

 

 

 

(おまけ)他のスクリプトで参照しないとだめな重要な変数があるんですけど・・・

たとえば先ほどの例にあったレベルに応じて進行可能場所の制限したいからレベルは重要な変数だけどpublicしないとだめなんだよ!とかなる可能性ってありますよね。

こんなときはpublicにしてもいいか?私の答えはpublicはつかっちゃダメです!レベルは重要すぎます!どうにかして回避する方法を考えましょう。関数が増えたとしても!

 

じゃあどうすれば良いのか、そういうときはレベル管理しているスクリプトのレベルはprivateにしたままで、進行可能か判断するスクリプトから、レベルのスクリプトに対して現在のレベルが進行可能なレベルに達しているかどうか聞く関数をレベル管理側に作ってOKかNGかbool型で進行スクリプトに返してあげることで回避することができますよね!

 

こんな感じで重要な変数は絶対にpublic使うのを避けることを心がけましょう!

 

 

 

【Unity】アニメーションクリップ(人型)をスクリプトで作成する

今回は人型キャラのアニメーションクリップをスクリプトで作成する方法を紹介したいと思います。

使い方としてはゲーム上で動くキャラを録画するのではなくモーションとしてアニメーションクリップにしたいだったり、モーションキャプチャーをゲーム上で行いそのデータでアニメーションクリップを作成したいなどを想定しています。

 

まず作成するにあたりクリップに必要な情報はなにか知る必要があります。

その情報とは

どのオブジェクトどの時間にどんななのか

ということです。

たとえば1秒の手の動かすアニメーションでは

(オブジェクト)のlocalPosition.x(何)が0秒(時間)に(値)

(オブジェクト)のlocalPosition.x(何)が1秒(時間)に(値)

という情報があればlocalPosition.xをうごかすアニメーションに必要な情報は取得完了ということになります。ここではlocalPosition.xだけで例を出しましたが、他の値も動かしたいのであれば他の値もそれぞれ取得します。

 

上記の情報を格納するものを

AnimationCurve(アニメーションカーブ)といいます。

そしてこのアニメーションカーブのなかのどの時間にどんなの部分を

keyframe(キーフレーム)といいます。

 

これをUnity上で見ると

f:id:graphicalpoxy:20190615152525p:plain

こんなかんじで

赤枠AnimationCurve(アニメーションカーブ)

青枠keyframe(キーフレーム)になります。

アニメーションカーブにキーフレームをどんどん足していくと一つの要素のアニメーションが完成します。

公式では

AnimationCurve 時間の経過をとおして評価される Keyframes の集合を保存します。 

keyframe アニメーションカーブでの単一のキーフレームです。

図があるとなるほどとなりますよね。

ということで知識が充実してきたところでスクリプトの例を出して終わりたいと思います。

詳しい情報はスクリプトに書きますね。

 

 

 

スクリプト作成

 

今回のスクリプトでは適当な値で1秒のアニメーションを作っています。

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

public class animetest : MonoBehaviour
{
    private AnimationClip _clip;
    private Animator _animator;

    [SerializeField]
    private Transform _unitychan;
    private Transform _leftHand;

    private string _path;
    private AnimationCurve handPosXCurve;
    private AnimationCurve handPosYCurve;
    private List<Keyframe> keyframesPosX;
    private List<Keyframe> keyframesPosY;

    void Start()
    {
        _animator = _unitychan.GetComponent<Animator>();
        _leftHand = _animator.GetBoneTransform(HumanBodyBones.LeftHand);
        _path = FindPath();
        handPosXCurve = new AnimationCurve();
        handPosYCurve = new AnimationCurve();

        SetKeyframes();
        AddKeyframe();
        FindPath();
        SetAnimationCurve();
        ClipSave();
    }

    // keyframeの作成.
    // keyframe(float time, float value)
    // 値は適当です
    private void SetKeyframes()
    {
        keyframesPosX.Add(new Keyframe(0, 0));
        keyframesPosX.Add(new Keyframe(1, 1));
        keyframesPosY.Add(new Keyframe(0, 2));
        keyframesPosY.Add(new Keyframe(1, 3));
    }

    // CurveにKeyframeを追加.
    private void AddKeyframe()
    {
        for (var i = 0; i < keyframesPosX.Count; i++)
        {
            handPosXCurve.AddKey(keyframesPosX[i]);
        }
        for (var i = 0; i < keyframesPosY.Count; i++)
        {
            handPosYCurve.AddKey(keyframesPosY[i]);
        }
    }

    // 適応するオブジェクトのパス検索.
    private string FindPath()
    {
        string objectPath = _leftHand.name;

        Transform parent = _leftHand.parent;

        while (parent != null)
        {
            objectPath = parent.name + "/" + objectPath;
            parent = parent.parent;
        }

        return objectPath;
    }

    // アニメーションクリップの作成.
    // SetCurve(動かしたいオブジェクトパス,タイプ,プロパティ,AnimationCurve)
    private void SetAnimationCurve()
    {
        _clip.SetCurve(_path, typeof(Transform), "localPosition.x", handPosXCurve);
        _clip.SetCurve(_path, typeof(Transform), "localPosition.y", handPosYCurve);
    }

    // 保存(UnityEditorのみの動作).
    private void ClipSave()
    {
        AssetDatabase.CreateAsset(_clip, "Assets/CreateAnime");
        AssetDatabase.Refresh();
    }
}

 

間違っていたらすいません。たぶんなんかわすれたけど最後にないかつけないと滑らかに動かないような気が・・・

一応確認のためにクリップをほぞんできるようにしています。エディター上でだけですけどね。

 

今回は左手を動かすというパターンを作りましたが、これを基盤につくれば全身でできます。またキーフレームも最低限しか用意していませんがたくさんつくるといい感じになります。

モーションキャプチャー中にキーフレームを作成しまくって、これでくりっぷを作成するとすばらしいアニメーションが出来ることでしょう。

【Unity】人型キャラクターの構成要素について(キャラクターのパーツのTransformを取得する)

Unityにおいて変数を知ることは熟練度を上げることや、思ったことを再現することに非常に重要な要素だと最近思っています。

 

今回はUnityの公式アセット、Unity-chanを使いながら人型キャラクターについて軽めに説明します。

別にこれがわからないとキャラクターをうごかせない訳ではないのですが、知っておくとキャラクターの情報を取得するときに使えるかもしれません。またキャラクターのアニメーションクリップを作成するときや、一部分のパーツだけ動かしたいときなどは知っていることが必須の項目になります。

 

ユニティちゃんは一つのオブジェクトとして存在していますが中身は腕や脚・頭、詳しくみると手や足などこんな感じに細かく要素に分かれています。

f:id:graphicalpoxy:20190615130413p:plain

たとえばもしユニティちゃんの脚だけ動かしたいとなった場合は

f:id:graphicalpoxy:20190615131414p:plain

このようにCharacter1_LeftUpLegのローテーションをいじると脚だけを動かすことができます。

アニメーションはこのように各要素の数値を時間ごとに記録させ、それを再生させることで決まったモーションで動かしています。

したがってこの要素を理解し、数値を取得できるようになるとアニメーションクリップも作成できます。

 

ちなみにポジションを動かすと・・・

f:id:graphicalpoxy:20190615131652p:plain

あー!僕達のアイドルユニティちゃんの脚がああああ!

となります。

 

 

ではこの要素ってどうすれば取得できるのでしょうか?

毎回getfindしたりpublicで設定するのって非常にめんどくさいですよね。


Unity上ではこの要素についてHumanBodyBonesとして定義されています。

要素の詳細は公式のマニュアルにありますので参考にしてみてください。

docs.unity3d.com

 

どうやって使うかなのですが、実際にユニティちゃんの左脚の情報を取得するスクリプトで説明します。

using UnityEngine;

public class test : MonoBehaviour
{
    // キャラクターのオブジェクト.
    [SerializeField]
    private Transform _unitychan;
    //左脚
    private Transform _leftUpperLeg;
    // アニメーターから抜き出すため.
    private Animator animator;

    // Start is called before the first frame update
    void Start()
    {
        // キャラクターからアニメーションを取り出す.
        animator = _unitychan.GetComponent<Animator>();
        // GetBoneTransform(HumanBodyBones.”要素名”)transformを取得可能.
        _leftUpperLeg = animator.GetBoneTransform(HumanBodyBones.LeftUpperLeg);
    }

    // Update is called once per frame
    void Update()
    {
        // ポジション.
        Debug.Log(_leftUpperLeg.localPosition.x.ToString());
        Debug.Log(_leftUpperLeg.localPosition.y.ToString());
        Debug.Log(_leftUpperLeg.localPosition.z.ToString());
        // 回転(オイラー角に変換して見やすくしています).
        Debug.Log(_leftUpperLeg.localRotation.eulerAngles);
        // スケール.
        Debug.Log(_leftUpperLeg.localScale);
    }
}

 

このような手法で取得できます。

実際に実行すると

f:id:graphicalpoxy:20190615140258p:plain

このようにきちんとTransformの情報を取得できていることがわかると思います。

 

次回はこれを基礎としてアニメーションクリップを作成する方法を紹介できたらなと思います。

【Unity】C#のインターフェース機能について

インターフェース機能について勉強したので備忘録的な感じでまとめたいと思います。

特にスクリプトを作ったわけではないので他の誰かが記事にされているもので詳しくは説明ということで概念的なことで行きたいと思います。

今後自分でスクリプトを作成したら差し替えますね。

 

まずインターフェース機能があるとどんな良いことがあるかを例を使って説明したいと思います。

メリットはずばり汎用性です!

あなたがSHARP製のテレビの4チャンネルにリモコン変えたいという場合で説明したいと思います。

登場人物は

・あなた

SHARP製リモコン

だとします。それぞれの動き関数として記述すると通常だと

 

あなた

SHARP製リモコンの4を押す

SHARP製リモコン

・4が押されたらSHARP製テレビに4にしろと命令する

 

 

まぁ別にこれはこれでいいのですが仮にあなたがSONY製に買い換えたとします。

するとあなたには4chにしたいときにはSHARP製のリモコンの4を押すことしか知らないのでSONY製のチャンネルを変えることはできません。

したがってSHARP製リモコンの4を押すという関数をSONY製リモコンの4を押すという関数に変えなければならないですよね。

 

また長期旅行とかにいってホテルを転々としていたとしたらいろんなメーカーテレビがあるので各メーカのリモコンの4を押すという関数をたくさん作らないといけませんよね。それってめんどくさいですよね。

 

そこでインターフェースという機能が役に立ちます。

インターフェースを使うとあなたの関数はリモコンの4を押すということだけをします。どこ製でもいいのでリモコンの4を押すそれだけをします。

するとどうでしょう?どこ製であっても関数を変えずに4chに変えることができます。

つまり汎用性が増すということにつながります。

わかりにくかったらすいません、でもこういうことだと思ってます。

詳しいことや、実装の仕方に関しては説明しませんが、どういうメリットがあるかがわかってもらえたらうれしいです。

 

 

 

記事で言うとここらへんが見るとわかりやすいです。

下の記事のほうはUnityでのスクリプト付きで解説しててわかりやすいですよ。

 

ufcpp.net

 

qiita.com

 

 

 

エンジニアの常識(個人開発だけじゃわからなかった!)

2019年に突入してunityを触り始め、これはいけると思いいわゆる大企業を辞めて転職をしました。

6月から新たな職場にいるのですが、やはり個人で開発するのとは全然違っているなと一週間働いただけで実感させられます。

 

今現在で思ったことを箇条書きしてみます。

私と同じようなことを考えている人の参考になればいいなと思います。

 

  • わかりやすくコード書く!

たぶんエンジニアの方にとっては常識でしょうが、個人でやっていて歴も浅いとこういうところに意識の違いを感じます。

とにかく誰が見てもわかりやすいような命名や書き方をする、ということですね。

個人では自分がわかればいいわけで、好き勝手に名前をつけて好き勝手に思いついたものを書いていたのですが、現場のコードは見やすかったです。

当たり前ですが、大人数で機能ごとに開発するわけですから全員が把握するのは難しいです。なのでこういう命名や書き方は判りやすくする必要があるわけですよね。

まぁ自分で作ったコードも数ヶ月した後見直すとよくわからないときがあるのでわかりやすくしておくに越したことはないですよね。

自作したゲームでいうと、マシンガンで攻撃するスクリプトがあったとき、MG()という関数を私は作りました。

しかしながら他の人がみるとMG()って何ってなりますよね、、、改良するならばAttackWithMachineGun()とかMachineGunFire()とかですかね。ながくなってもわかりやすくが味噌らしいです。

ちなみに私はリーダブルコードという本でそういうことを学んでいます。

 

 

  • 拡張性を意識する

これは純粋に関心したのですが、機能の拡張を意識してコードを書いているという点です。

言葉で説明するのが非常に難しいのですが、そういうことです笑

簡単に言うと攻撃力5の攻撃1と攻撃力10の攻撃2の方法があった場合それぞれで

hp-=5とhp-=10ってそれぞれ書くよりも

HPdecrease(int AttackPower){

hp -= AttackPower

って関数をつくるとこれから先攻撃力が変わったとしてもこのHPdecreaseという関数を使うといつでも対応できますよね?それが簡単に言うと拡張性です。

こういったことをいたるところで感じます。UI関連などはボタンが今後追加されるかもしれないとかを意識して作りこまれているなと感じました。

 

まぁいまはこんな感じですが、今後初心者目線で思うことがあったらどんどん記事にしていきたいと思います。

記事もたくさん書いてはいるんですがなんか重力の奴しかみられてない・・・

 

株式投資年間成績(2018.5~2019.5)

6月から新たな職場でプログラマー人生をスタートさせるのですが転職までの間、2週間ほどデイトレを行っていました。デイトレの結果はよくなかったです。。。。

 

去年5月から国内株式投資を行い1年経過したため結果を一応まとめておこうと思います。

 

400,000(現時点入金総額)→474,439(+74439)

 

年間で振り返ると、前半の6ヶ月と後半の6ヶ月で立ち振る舞いがちがっています。

 

前半6ヶ月

最初の投入資金は20万で、株に関する知識はゼロでした。

高齢化だから介護系は伸びるでしょみたいな感覚でニプロを購入し、まんまと高値掴み・・・

また資金も時々引き出していたので徐々に減っていくかんじでした。

 

後半6ヶ月

ボーナスが入ったので資金を追加し種を50万として運用開始。

レンジ相場にうすうす気づいてロゼッタで遊んでいたら好決算が出てきたため一気に利益に転じる。

ここからはいろいろバリュー系の知識を覚えていき新興系でちょくちょく利益を出すことができました。

GW後に大きく損失を出しついに損切りを覚えました。

これかもがんばっていきます。

 

 

 

これからはUnityもですが、週間ごとぐらいで投資結果をアウトプットして自分を戒めていきたいと思います。

【Unity】Unityで発光の制御(PostProcess・bloomをスクリプトで制御)

EDMのライブのような演出がしたいなぁと思って今いろいろと作成しています。

ライブといったら曲に合わせた光の演出は欠かせないですよね。

今回は曲に合わせたという部分は一旦置いといて(次回書いていこうと思います)光の演出について書こうと思います。

 

光の演出といってもいろいろあるのですが、私が実現したかったのは音の大きさによってオブジェクトの発光の強さを動的に制御していきたいというものです。

イメージで言うとネオン看板の光の強さをゲームプレイ中に変えていくみたいなものです。

今回もさまざまな方が詳しい記事を書かれているのでわかりやすかった記事をかいつまんでいきます。

 

(下準備)

 

まず今回やることをわかりやすくするために環境をつくって置いたほうがいいと思います。

メインカメラのBackgroundを黒に変更

DirectionalLightを非アクティブに変更

しておくと良いと思います。

他作業中だったのでいろいろあるアセットとかオブジェクトは無視してください

f:id:graphicalpoxy:20190429133140p:plain

 

オブジェクトを光らせる

 

オブジェクトを光らせるといったらこれを読めばだいたいわかる!

特に光のにじみとHDRの部分以下は読んでおくと良いです。

tsubakit1.hateblo.jp

 

余計なことは呪文だと思って簡単にどうすれば光らせることができるかというと

  • オブジェクト付けるのマテリアルにEmissionをチェック

f:id:graphicalpoxy:20190429134529p:plain

 

とりあえずこれで発光はするのですが・・・思ってたのと違いますよね

 

そこでカメラの効果であるBloom効果というのをつけて(後述します)

Intensityという値をいじるといい感じでもやができて発光感が一気に増します。

Bloom効果のありなしの比較画像を作ったので載せておきます。

とりあえずここでは光らせたいオブジェクトのマテリアルにEmissionのチェックをして置いてください。

f:id:graphicalpoxy:20190429135013p:plain

 

 

Bloom効果をPostProcessingでつける

おそらくBloom効果をカメラに付ける場合はほとんどの場合StandardAssetのEffectから行っていることが多いと思います。

しかしここではちょっと新しいものを使ってみたいと思います。

PostProcessingです。これを選んだ心としましては、新しくて他にもいろいろと効果をつけることができるのでこっちのほうがこれから役に立つかなと思いましたのでこれを使ってみました。

 

PostProcessingを使うには新たにインストールしないといけません。

はい、ここに記載されていることをすべてやってください笑

qiita.com

私もいろいろ調べて実装させていっているのですがこの記事が一番だと思います。

 

おそらくインストールして

  • カメラにPostProcessLayer
  • 空のオブジェクトにPostProcessVolume

がアタッチされた状態になったと思います。

次に

PostProcessVolumeのAdd effectからBloomを選択

Intensityにチェック、数値をいじる

 

f:id:graphicalpoxy:20190429140558p:plain

すると発光の強さを変更できることを確認できたと思います。

つまりこのIntensityの値をスクリプトから動かすことが出来ればゲーム内で動的に発光の強さを変更できるということです。

 

 

 

スクリプトでPostProcess・BloomのIntensityを変更する

 

正直ここからが本題です。

なぜかというとGetComponent<PostProcessVolume>でいじれないからです。

これが出来ればどんなに時間をつぶさずに済んだか・・・

ただすごく簡単だったのでみなさんは私の3時間ぐらいを3分で越えていってください。

今回もスクリプトを例として載せるのですがとにもかくにもおまじないが多いので気をつけてください。

今回は左クリックで明るく、右クリックで暗くするスクリプトです。

こちらをPostProcessVolumeのついたオブジェクトに付けてください。

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
//ここ必須
using UnityEngine.Rendering.PostProcessing;

public class EmissionTest : MonoBehaviour
{
    Bloom bloom;

    // Start is called before the first frame update
    void Start()
    {
        //おまじない1:Bloomのところを変えると他の効果でも応用化
        bloom = ScriptableObject.CreateInstance<Bloom>();
    }

    // Update is called once per frame
    void Update()
    {

        //左クリック
       if (Input.GetMouseButton(0))
        {
            set();
        }
       //右クリック
        if (Input.GetMouseButton(1))
        {
            setback();
        }
    }
    //発光(強)関数
    private void set()
    {
        //おまじない2:書き換えOKにしている?これがないと何度も変更できない
        bloom.enabled.Override(true);
        //変更したい項目に任意の数値を渡す
        bloom.intensity.Override(10f);
        //おまじない3:QuickVolume(PostProcessのレイヤー番号,Priority,効果)
        PostProcessManager.instance.QuickVolume(gameObject.layer, 1, bloom);
    }
    //発光(弱)関数(略)
    private void setback()
    {
        bloom.enabled.Override(true);
        bloom.intensity.Override(1f);
        PostProcessManager.instance.QuickVolume(gameObject.layer, 1, bloom);
    }
}

 

まず要点だけ説明すると

  • using UnityEngine.Rendering.PostProcessingは必須

そういうものだと覚えてください、おまじないとは別ですね。

  • おまじない1

bloom = ScriptableObject.CreateInstance<Bloom>();

GetCompornentとしたいところですが、上記のようにするらしいです。

  • おまじない2

bloom.enabled.Override(true);

これを入れないと何度も変更することが出来ませんでした。

個人的には書き換えOKにしているのかなと思っています。

書き換えるごとに書き換えNGになるからこの文言をいれないといけないのかなと

  • おまじない3

一番よくわからない、ないと動かなかった

QuickVolume(PostProcessのレイヤー番号,Priority,効果)

Priorityは1にしとけばうごく

 

  • (書き換えは関数にする?)

ここは私だけの問題だと思うのですが、Update内で今回の関数部分を書いておりまして、動的に動く変数をOverrideに入れたのですが全然動いてくれいなかったという問題がありました。

そこで今回のように関数にさせてUpdateでその関数を実行させるとなんかうまくいきました。

 

次回は音楽データについて記事にしたいと思います。そして今回の発光と音楽データを紐付けてライブっぽい演出を実現させたいと思います。