oniyarai’s tech memo

oniyarai’s tech memo

すぐ忘れる自分に捧げるメモ

Coroutineの使用方法と動作について

Coroutine使用法

コルーチンはコルーチンとして開始した関数内で処理を一旦停止、フレーム単位で停止後(または指定時間後)処理を再開できる機能。
別スレッドので処理を走らせられる(かのような)感。(実際にはマルチスレッドな訳ではない)
関数内で

  • 処理A
  • 指定時間待機
  • 処理B
  • 指定時間待機
  • 処理C

と言った一連の処理を記述できる。
処理間で待機が入っても、同一関数の処理なので、別途メンバ変数等によるState管理をしなくても、スタック変数で状態を保持できる。
また、時間のかかる処理を行う場合に「関数A->関数B->関数C->関数A」といった形で疑似的に並列処理を行える(懐かしのTSS)。

            private IEnumerator _honyaHonyaCoroutine = default;
            void Start()
            {
                _honyaHonyaCoroutine = CoHonyaHonya();
                StartCoroutine(_honyaHonyaCoroutine);
            }
            
            private IEnumerator CoHonyaHonya()
            {
                    // 処理A
                    yield return null;
                    // 処理B
                    yield return new WaitForSconds(3.0f);
                    // 処理C
                    yield return null;
                    // 処理D

            }

上記のようにIEnumerator型の関数を定義し、StartCoroutineの引数として渡してやることでコルーチンがスタートする。
コルーチンでは、
処理A->1frame待機->処理B->3秒待機->処理C->1frame待機->処理D->終了
という動作を行う。

StopCoroutine等についてはまた別途追記予定。

TextMeshProでのフォントインストール方法

TextMesh Proでttfファイルのフォントをインストールする方法


まず、使用するフォントファイル(ここではttfファイル)をダウンロードしててから、
Assets -> Import New Assetsで該当のファイルをUnityに取り込みます。 f:id:oniyarai:20191202215323j:plain


Window -> TextMeshPro -> Font Assets Creatorを開きます。
f:id:oniyarai:20191202215624j:plain


開いたFont Assets Creatorのウィンドウで、Source Font Fileにインポートしたttfを指定して、Generate Font Atlasをクリック!
f:id:oniyarai:20191202215934j:plain

出来たアセットファイルを適当なフォルダにセーブして(TextMesh Pro/Resources/Font & Materials辺りが妥当か)、インポートしたttfファイルを削除して完成。


以上で、Text Mesh Pro UGUIのコンポーネントでFont Assetとして使用できるようになります。
f:id:oniyarai:20191202220331j:plain


こんな感じ(HAMMER OF GODの部分)
f:id:oniyarai:20191202220807j:plain

Unityの処理停止について

Time.timeScale について止まるもの止まらないもの

Unityで停止処理を行う際に使えるのが、Time.timeScaleですが、止まる処理と止まらない処理がある。
Time.timeScaleは基本的に1で通常時間、0に近づくにつれて時間の経過をスローにしていくことができる。
0にすると、時間関連を停止することができ、FixedUpdateが呼ばれなくなる。また、Time.deltaTimeによる時間経過も進まなくなる。
ただし、Updateは変わらず呼ばれるため、Update内の処理でTime.deltaTimeを加味していない場合止まらない。


止まる処理

    void Update() {
        transform.Translate(2.0f * Time.deltaTime, 0, 0);
    }
}

止まらない処理

    void Update() {
        transform.Translate(2.0f , 0, 0);
    }
}

Rigidbodyへの操作は内部的に経過時間が加味されているため、重ねてTime.deltaTimeを加味していなくても止まる。最も、本来Rigidbody操作はFixedUpdateでやるべきなのでどちらにせよFixedUpdateは呼ばれないけれども。


追記
パーティクルシステムも止まってしまうので使いづらい……メニュー開いたときとかに止める用かな。

Mathf.Round 備忘録

Mathf.Roundすぐ忘れるんで。

Mathf.Round(float f)
偶数丸め。
一番近い整数に数値を丸めるが、小数点以下が ~.5で終わる場合は最も近い上下の整数のうち偶数側に丸める。
よって

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

public class test1 : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        Debug.Log(Mathf.Round(10.49f));
        Debug.Log(Mathf.Round(10.5f));
        Debug.Log(Mathf.Round(10.51f));
        Debug.Log(Mathf.Round(11.49f));
        Debug.Log(Mathf.Round(11.5f));
        Debug.Log(Mathf.Round(11.51f));
    }
}

f:id:oniyarai:20191124221406j:plain

10.5は10.5の上下の整数が10と11なので偶数である10に丸める。
11.5は11.5の上下の整数が11と12なので偶数である12に丸める。
それ以外は普通に四捨五入な感じに丸める。
~.5の場合のみ単純な四捨五入にはならないので注意。

お・ま・け
Mathf.Floor(float f) 小数点以下切り捨て。
Mathf.Ceil(float f) 小数点以下切り上げ。

オブジェクトの動的生成 Scriptから

Resources.Load

前準備

  1. 動的生成を行いたいオブジェクトのプレハブを作成。
  2. Assets直下にResourcesフォルダを作成
  3. 1で作成したプレハブを2に配置

ここからScriptでの動的なオブジェクト生成処理。

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

namespace PlayerControl {
    public class BulletController : MonoBehaviour {

        private void DeactivateSelf()
        {
            // 爆発エフェクトオブジェクトを表示
            GameObject explosiveCircleObj = (GameObject)Resources.Load("ExplosiveCircle");
            Instantiate(explosiveCircleObj, 
                        transform.position, 
                        Quaternion.identity);

        }

上記のScriptでResouces配下においたプレハブ"ExplosiveCircle"のオブジェクトを取得し、そのオブジェクトをtransform.positionで指定した位置に生成できます。 上記は、オブジェクトの取得からScriptで行っているが、Unityの方でプレハブのオブジェクトを設定しておきそれをInstantinateするという方法でも実行可能。(この辺どっちが良いのか場合によるのだろう) 以下のような感じ。

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

namespace PlayerControl {
    public class BulletController : MonoBehaviour {

        // 爆発エフェクトのオブジェクト
        [SerializeField] private GameObject ExplosiveObj;

        private void DeactivateSelf()
        {
            Instantiate(explosiveCircleObj, 
                        transform.position, 
                        Quaternion.identity);

取りうる値の制限(オブジェクトの移動範囲の制限など)

Mathf.Clamp intまたはfloatの値の範囲を制限する

使用法はIntもFloatも同様。第一引数で与えられるValueを第二引数(最小値)、第三引数(最大値)の間に制限する。 この場合表示される値は3となる(最大値より大きい10であるため)。

using UnityEngine;
using System.Collections;

public class ExampleClass : MonoBehaviour
{
    // Use this for initialization
    void Start()
    {
        // Clamps the value 10 to be between 1 and 3.
        // prints 3 to the console

        Debug.Log(Mathf.Clamp(10, 1, 3));
    }
}

これを利用してオブジェクトの移動などに制限を加える。 Mathf.Clampでオブジェクトが取りうるtransform.positionの値を-8~8に制限し、その範囲を超えてオブジェクトが移動することを防ぐ。

    void Update()
    {
        // X方向に入力*速度*時間分移動させる
        this.transform.Translate(Input.GetAxisRaw("Horizontal") * MoveSpeed * Time.deltaTime, 0, 0);
        // X方向の移動範囲を制限する
        this.transform.position = new Vector2(Mathf.Clamp(this.transform.position.x, -8.0f, 8.0f), transform.position.y);
    }

衝突時のTrigger処理

OnTriggerEnter系とCompareTag

ColliderのコンポーネントでIs Triggerのチェックを入れていた場合、以下は2Dの場合。 引数のcollisionに衝突したオブジェクトの情報がある。CompareTagでオブジェクトにTagが設定されているかどうかチェックできる。

        private void OnTriggerEnter2D(Collider2D collision)
        {
            // 隕石またはターゲットマーカのオブジェクトと接触した場合、爆発処理
            if (collision.gameObject.CompareTag("Meteor") || 
                collision.gameObject.CompareTag("TargetMarker")) {
                DeactivateSelf();
            }
        }
        }

同系列でOnTriggerExitとOnTriggerStayがあり、Exitはオブジェクトの衝突が終わった(離れた)時、Stayはオブジェクトが重なっている間中コールされる。 また、それぞれ2Dの場合は末尾に2Dが付く。 これはまた後日。