fc2ブログ
ヽ|∵|ゝ(Fantom) の 開発blog? ホーム »Unityリファレンス
このページの記事一覧

【Unity】【C#】double型の Clamp (拡張メソッド)  


 前回 double型の Repeat を作ったので、よく使うものとして、ついでに Clamp も定義しておく。といっても、めちゃくちゃ簡単なので、誰でも作れるものだけどね。

(※) Unity 2020.3.34f1 / Windows11(x64) で確認

●double 型の Clamp 拡張メソッド
using System;

public static partial class MathExtensions //※クラス名は任意
{
/// <summary>
/// double での Clamp.
/// 2024/02/18 Fantom
/// http://fantom1x.blog130.fc2.com/blog-entry-438.html
/// </summary>
/// <param name="value">元の値</param>
/// <param name="min">下限値 (inclusive)</param>
/// <param name="max">上限値 (inclusive)</param>
/// <returns></returns>
public static double Clamp(this double value, double min, double max)
{
if (value < min) return min;
if (max < value) return max;
return value;
}
}

●メインコードでの使用例
using UnityEngine;

Debug.Log(12.0.Clamp(0.0, 5.0)); //5
Debug.Log((-12.0).Clamp(0.0, 5.0)); //0

 Repeat と違い、上限値を"含む"(inclusive) なので注意。上限値を上回ったときや、下限値を下回ったときに、下限~上限値に収める関数だね。よく使うものなので関数として定義した方が楽だと思うが、一行で簡単に書きたいなら、Math クラスの Min, Max を使っても同じことができる。

●Math クラスの Min, Max を使って Clamp と同じことをする
using System;

var value = Math.Max(min, Math.Min(max, value));

 Unity のライブラリみたいに 0~1 に収める Mathf.Clamp01 みたいのを作っても良いね。これはオーバーロードでも良いだろう。Unity には無いが、0~100 なんてのもよく使うので、Clamp0100 みたいのも定義すると便利かもね。

●Clamp01, Clamp0100 を定義する(Clamp のオーバーロード)
using System;

public static partial class MathExtensions //※クラス名は任意
{
/// <summary>
/// double での Clamp01 (0~1).
/// 2024/02/18 Fantom
/// http://fantom1x.blog130.fc2.com/blog-entry-438.html
/// </summary>
/// <param name="value">元の値</param>
/// <returns></returns>
public static double Clamp01(this double value)
{
return Clamp(value, 0, 1);
}

/// <summary>
/// double での Clamp0100 (0~100).
/// 2024/02/18 Fantom
/// http://fantom1x.blog130.fc2.com/blog-entry-438.html
/// </summary>
/// <param name="value">元の値</param>
/// <returns></returns>
public static double Clamp0100(this double value)
{
return Clamp(value, 0, 100);
}
}

 とても地味な関数だけど、double に型変更したとき無いと不便なので、いつでも使えるようにライブラリ化しておくと便利。

(関連記事)
【Unity】【C#】double型の Repeat (拡張メソッド)
【Unity】【C#】範囲を指定できる Mathf.Repeat
【Unity】【C#】倍数での Floor, Ceil, Round(一定間隔での切り捨て、切り上げ、四捨五入) [float 版]
【C#】最大公約数を求める/分数の約分をする(ユークリッドの互除法)
【Java】最大公約数・最小公倍数を求める(ユークリッドの互除法)
【Java】3つ以上の最大公約数を求める(ユークリッドの互除法②)
【Java】拡張ユークリッドの互除法


関連記事
スポンサーサイト



category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityライブラリ  Unityリファレンス  算術関数 
tb: 0   cm: --

【Unity】【C#】double型の Repeat (拡張メソッド)  


 Unity には標準の算術関数:Math クラスを float 型にした Mathf クラスをよく用いるが、double 型だと使えないんだよね。なので、型変更したら関数も Math クラスにしないといけないのだが、全ての関数が一対一で用意されてるわけではない。Mathf.Repeat も Math クラスには無かった…。Repeat って Unity では結構使うこと多いし、ググっても実装例見つからなかったので、double 型でもあったら良いなと思って作った拡張メソッド。

(※) Unity 2020.3.34f1 / Windows11(x64) で確認

●double 型の Repeat 拡張メソッド
using System;

public static partial class MathExtensions //※クラス名は任意
{
/// <summary>
/// double での Repeat.
/// 2024/01/18 Fantom
/// http://fantom1x.blog130.fc2.com/blog-entry-437.html
/// </summary>
/// <param name="value">元の値</param>
/// <param name="length">上限値 (exclusive)[> 0]</param>
/// <returns></returns>
public static double Repeat(this double value, double length)
{
if (length <= 0)
{
throw new AggregateException($"length must be greater than 0 : length = {length}");
}

if (length <= value)
{
return value % length;
}
else if (value < 0)
{
return length - (-value) % length;
}
return value;
}
}

●メインコードでの使用例
using UnityEngine;

Debug.Log(12.0.Repeat(5.0)); //2
Debug.Log((-12.0).Repeat(5.0)); //3
Debug.Log((-12.0).Repeat(-5.0)); //AggregateException

 1つ注意点は、Mathf.Repeat のマニュアルにもあるが、length は 0 より大きい値でないといけない。なので、0 または負の長さはエラーをスローしている。
 これは単純に length が割り算の分母になるからもあるが、0 が分母に使えないのは無論のこと、負の値の剰余は言語によって違ってたりして信用できない値となるので、メソッドに使うのはオススメしない。これは全ての言語に関わることなので、覚えておいた方が良いだろう。以下に資料を載せておく。

(参考)
負数の剰余を計算してはならない

 あと、細かい事だが、例の中で Debug.Log で負の値をカッコで括ってるが("(-12.0).Repeat(5.0)")、付けないと("-12.0.Repeat(5.0)")関数の戻値にマイナスを掛けることになるので注意("-1 * (12.0.Repeat(5.0))"←みたいになる)。場合によっては、負の値にカッコを付けた方が見やすいこともあるね。


(関連記事)
【Unity】【C#】範囲を指定できる Mathf.Repeat
【Unity】【C#】double型の Clamp (拡張メソッド)
【Unity】【C#】倍数での Floor, Ceil, Round(一定間隔での切り捨て、切り上げ、四捨五入) [float 版]
【C#】最大公約数を求める/分数の約分をする(ユークリッドの互除法)
【Java】最大公約数・最小公倍数を求める(ユークリッドの互除法)
【Java】3つ以上の最大公約数を求める(ユークリッドの互除法②)
【Java】拡張ユークリッドの互除法


関連記事

category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityライブラリ  Unityリファレンス  算術関数 
tb: 0   cm: --

【Unity】【C#】CullingMask をレイヤー名でオン/オフする (拡張メソッド)  


 Light, Camera, ReflectionProbe 等にはレイヤー分けして効果の対象を選択できる CullingMask が設定できるけど、用例を見てると、地味にわかりずらいんだよね…(ビット演算で 1<<0 みたいな所)。

 なので、レイヤー名(文字列)で簡単に対象をオン/オフする拡張メソッドを作っておくと便利。ビット列ではないので、後でレイヤー番号を変更しても、文字列指定ならわかり易いしね。

(※) Unity 2020.3.34f1 / Windows11(x64) で確認

●Light コンポーネントの CullingMask のオン/オフをする拡張メソッド
using UnityEngine;

public static partial class Extensions //※クラス名は任意
{
/// <summary>
/// ライトの CullingMask のオン/オフ (LayerMask)
/// 2023/12/18 Fantom
/// http://fantom1x.blog130.fc2.com/blog-entry-436.html
/// </summary>
/// <param name="light">対象のライト</param>
/// <param name="mask">LayerMask.GetMask の値を入れる</param>
/// <param name="isOn">true = On / false = Off</param>
public static void SetCullingMask(this Light light, int mask, bool isOn)
{
if (light == null)
return;

if (isOn)
{
light.cullingMask |= mask; //ビットを OR でオンにする
}
else
{
light.cullingMask &= ~mask; //反転して、AND することで、ビットを 0 にする
}
}

/// <summary>
/// ライトの CullingMask のオン/オフ (レイヤー名)
/// 2023/12/18 Fantom
/// http://fantom1x.blog130.fc2.com/blog-entry-436.html
/// </summary>
/// <param name="light">対象のライト</param>
/// <param name="layerName">レイヤー名</param>
/// <param name="isOn">true = On / false = Off</param>
public static void SetCullingMask(this Light light, string layerName, bool isOn)
{
if (light == null || string.IsNullOrEmpty(layerName))
return;

SetCullingMask(light, LayerMask.GetMask(layerName), isOn);
}
}

●メインコードでの使用例
using UnityEngine;

public class SetCullingMaskTest : MonoBehaviour
{
public Light _light; //インスペクタでセットする

private void Start()
{
var layerName = "Character"; //Tag & Layers の名前(※任意)
_light.SetCullingMask(layerName, true);
}
}

 最初の「SetCullingMask(this Light, int, bool)」の int引数 はビット列(レイヤー番号)用のメソッドとなる。次の「SetCullingMask(this Light, string, bool)」の string引数 が本題のレイヤー名(※ここでは"Character")用のメソッドになる。内容的には「LayerMask.GetMask(layerName)」を挟んで、ビット列(レイヤー番号)用をオーバーロードしてる感じになる。文字列(レイヤー名)とオン/オフ(true/false)の引数なので、使い方も難しくはないだろう。Camera や ReflectionProbe も this~ の型を変えたメソッドを定義すれば、簡単に流用できる。

 ちなみにレイヤー名は「Tag & Layers」で自由に付けられる。インスペクタなどから [Layer>Add Layer...] で一覧を表示し、空いてる所に名前を入れれば良い(無効化されてるのはシステム予約のレイヤー)。

●[Layer>Add Layer...] で「Tag & Layers」を表示

●空いてる所に任意に名前を入れる

●メインコードでの使用例の結果(起動後のようになる)



(関連記事)
【Unity】【C#】Light の Halo はランタイム操作できない?
【Unity】Standard Assets の Flare (レンズフレア) は Gamma 用だった?
【Unity】【C#】指定ワールド位置がカメラに映っているか調べる
【Unity】【C#】固定背景画像(2D)を表示する


関連記事

category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityライブラリ  Unityリファレンス  C# 
tb: 0   cm: --

【Unity】【エディタ拡張】インスペクタのフィールドに属性で色を付ける  


 以前インスペクタのフィールドを入力不可にする PropertyAttribute を作ったが、Unity2019.4 以降は Personal(無料)アカウントでもダークテーマを使えるようになったので、無効の色(グレー:たぶんアルファが低くなる)が少し見ずらく感じるようになったんだよね…。

●ライトテーマ(Unity2018)時の入力不可(Disable)属性を付けたフィールド

●ダークテーマ(Unity2020)での入力不可(Disable)属性を付けたフィールド


 なのでいっそのこと自分の好きな色にできないかとググったが、なぜか込み入ったコードしか見つからなかったので、Disable 属性と同じ要領で色を付けられるかと試してみたら、意外と簡単にできたので、コードを載せておこう。無効化とは併用できなかったが(グレーになってしまう)、自分でフィールドを色で見分けるくらいの用途なら十分に役に立つと思う。

(※) Unity 2020.3.34f1 / Windows10(x64) で確認

●デバッグ用途のフィールドに色を付ける例(属性):DebugFieldAttribute.cs
using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace Example
{
public class DebugFieldAttribute : PropertyAttribute
{
//※中身は空で良い
}

#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(DebugFieldAttribute))]
public class DebugFieldDrawer : PropertyDrawer
{
static readonly Color _color = Color.green; //色を指定

public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property, label, true);
}

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var tmpColor = GUI.color; //一時退避
GUI.color = _color;
EditorGUI.PropertyField(position, property, label, true);
GUI.color = tmpColor;
}
}
#endif
}

●クラス内部値用途のフィールドに色を付ける例(属性):InternalAttribute.cs
using UnityEngine;

#if UNITY_EDITOR
using UnityEditor;
#endif

namespace Example
{
public class InternalFieldAttribute : PropertyAttribute
{
//※中身は空で良い
}

#if UNITY_EDITOR
[CustomPropertyDrawer(typeof(InternalFieldAttribute))]
public class InternalFieldDrawer : PropertyDrawer
{
static readonly Color _color = Color.cyan; //色を指定

public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
{
return EditorGUI.GetPropertyHeight(property, label, true);
}

public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
var tmpColor = GUI.color; //一時退避
GUI.color = _color;
EditorGUI.PropertyField(position, property, label, true);
GUI.color = tmpColor;
}
}
#endif
}

●実際にインスペクタで表示してみる例(メインコード等):FieldColorTest.cs
using UnityEngine;

public class FieldColorTest : MonoBehaviour
{
[SerializeField, DebugField] string debugValue = "hoge";
[SerializeField, InternalField] int internalValue = 123;
[SerializeField, Disable] float disableValue = 3.141592f; //Disable 属性は以前に作ったもの
[SerializeField] string normalValue = "piyo";
}

●ダークテーマ(Unity2020)での色を付けたフィールド

 今回はエディタスクリプト部分をプリプロセッサ(UNITY_EDITOR)で囲んでしまったが、Disable 属性のときのようにスクリプトを分けて「Editor」フォルダに PropertyDrawer を継承したスクリプトを置いても良い。"DebugField", "InternalField" の名前は任意なので、自分で好きに付けると良いだろう。とても簡単なスクリプトだが、名前と色だけ変えて使い回せば、インスペクタも結構見やすくなった。思いつきだったが、何個かあらかじめ定義しておけば、簡単に色分けで分類できて、意外と便利だったので、誰かの役に立つと嬉しい。


(PropertyAttribute, PropertyDrawer をもっと知りたいときは、以下を参照)
UnityのAttribute(属性)についてまとめてメモる。
自分だけのPropertyDrawerを作ろう!


(関連記事)
【Unity】【エディタ拡張】インスペクタで入力不可(Disable)な属性を作る
【Unity】インスペクタの値を保持したまま変数をリネームする
【Unity】【C#】インスペクタでの UnityEvent のコールバック登録の有無を調べる
【Unity】【C#】UnityEvent, Action, delegate, interface でのコールバック実装方法とインスペクタでの登録
【Unity】【エディタ拡張】インスペクタの表示項目を動的に変更する
【Unity】【エディタ拡張】独自のギズモ(Gizmo)を表示する


関連記事

category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityライブラリ  Unityリファレンス  インスペクタ  エディタ拡張 
tb: 0   cm: --

【Unity】【C#】Light の Halo はランタイム操作できない?  


 現在 VRMLiveViewer v3.8 に入れるカスタムなライトを実装中…。せっかくなので、Light コンポーネントの細かい機能も操作できるようにしたいと思って、色々調べていたが、どうやらインスペクタにある DrawHalo はスクリプトから操作できないようだ…(プロパティ自体が無い)。

 不思議に思ってググっていたら、なぜか Halo は public な機能ではないらしいね。予め設定したものをビルドして使うだけのものなのか…?

 また、Light 内の DrawHalo ではなく、別コンポーネントの Halo (インスペクタで個別にアタッチするやつ) でオン/オフするコードが出てきた。しかしそれもやはり少し変わっていて、Behaviour クラスを用いて enabled を true/false してるね。まぁ、一応成功したので、コードだけ載せておこう。

(※) Unity 2020.3.34f1 / Windows11(x64) で確認

●アタッチした Halo コンポーネントをオン/オフするコード
using System;
using UnityEngine;

public static partial class Extensions //※クラス名は任意
{
public static void SetEnableHalo(this Light light, bool isOn)
{
if (light == null)
return;

var halo = (Behaviour)light.gameObject.GetComponent("Halo"); //Behaviour 型
//var halo = light.gameObject.GetComponent("Halo"); //Component 型
if (halo != null)
{
halo.enabled = isOn; //Behaviour 型
//halo.GetType().GetProperty("enabled")?.SetValue(halo, isOn, null); //Component 型
}
}
}

●スクリプトからの使用例
using UnityEngine;

public class SetEnableHaloTest : MonoBehaviour
{
public Light _light; //インスペクタでアタッチしておく

//Button の OnClick 等からコールバックする
public void HaloOnClick()
{
_light.SetEnableHalo(true);
}

//Button の OnClick 等からコールバックする
public void HaloOffClick()
{
_light.SetEnableHalo(false);
}
}

 SetEnableHalo 内ではコメントアウトで Component 型のコードも書いてあるが、どちらでもいけるようだ。ただこれはインスペクタで予め Halo コンポーネントを追加しておくか、コードで AddComponent("Halo") しなければならない。型指定にはジェネリック型 <Halo> は使えないようだ。GetComponent も同じ。なぜか名前(文字列)でしか指定できないらしい。以下の参考資料(UnityCsReference)に「internal sealed partial class Halo : Behaviour」となっているので(public ではないので)、そのせいか?

(参考資料)
UnityCsReference/Runtime/Export/GraphicsComponents.bindings.cs
Getting the Halo property of a point light in Unity
How can I change the value of 'Draw Halo' inside Point Light - Unity3D
Enable Draw Halo in Light Component via Script



 結局、オン/オフはできても色や距離の変更はできないので(やはり public なプロパティが無いので)、実装自体をやめた。また、リフレクションでプライベートメンバーを取得するような方法もググってたら出てきたが、そもそも public でない時点でランタイム動作は保証されないので、使わない方が良い気がする。

 また同じ様な効果なら、Volumetric Light の方が綺麗だったしね。無理矢理やろうと思えば、予めビルドにオンとオフの2つの状態を別GameObjectにアタッチしておき、切り替える方法もあるが、それなら Light の DrawHalo でやった方が良いか気がする(Color と Range が自動的に連動するので)。ただそれほど有用でもないし、使い勝手も悪いので(コードが無駄に複雑になるので)、Halo 自体のランタイム操作は諦めた方が良いかな…。



(関連記事)
【Unity】Standard Assets の Flare (レンズフレア) は Gamma 用だった?
【Unity】【C#】指定ワールド位置がカメラに映っているか調べる
【Unity】【C#】ガンマ(Gamma, sRGB) - リニア(Linear) 値の相互変換


関連記事

category: Unity

thread: ゲーム開発

janre: コンピュータ

tag: Unityリファレンス  Unityライブラリ  グラフィックス 
tb: 0   cm: --


プロフィール

Social

検索フォーム

全記事一覧

カテゴリ

ユーザータグ

最新記事

リンク

PR

▲ Pagetop