Skip to content

Instantly share code, notes, and snippets.

@chigirits
Last active September 17, 2022 17:05
Show Gist options
  • Save chigirits/32a1259f788a5c4d1892335be245823b to your computer and use it in GitHub Desktop.
Save chigirits/32a1259f788a5c4d1892335be245823b to your computer and use it in GitHub Desktop.
Udon用 C++のstd::vectorみたいな自動拡張配列
using UdonSharp;
using UnityEngine;
/// Objectクラスの値を格納可能な可変長配列
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class FlexArray_Object : UdonSharpBehaviour
{
/// <summary>初期サイズ</summary>
int initialSize = 4;
/// <summary>
/// 線形に拡張する単位
/// (このサイズに達するまでは倍々で、これ以降はこの値ごとに線形に拡張)
/// </summary>
int linearStepSize = 1024;
/// <summary>
/// 格納されている値の配列
/// (実際の長さよりも長い場合があり、Lengthはキャパシティを表します)
/// </summary>
Object[] values = new Object[4];
/// <summary>実際の配列長(values の有効部分の長さ)</summary>
int actualSize = 0;
/// <summary>実際の配列長を返します。</summary>
/// <returns>配列長</returns>
public int Size()
{
return actualSize;
}
/// <summary>
/// 配列のキャパシティを返します。
/// この長さを超えるまではメモリの再確保や複製処理が起こらず、高速にアクセスできます。
/// </summary>
/// <returns>配列のキャパシティ</returns>
public int Capacity()
{
return values.Length;
}
/// <summary>i番目の配列要素を返します。</summary>
/// <param name="i">配列内の位置</param>
/// <returns>i番目の配列要素</returns>
public Object Get(int i)
{
return values[i];
}
/// <summary>i番目の配列要素を設定します。</summary>
/// <param name="i">配列内の位置</param>
/// <param name="o">設定する値</param>
public void Set(int i, Object o)
{
values[i] = o;
}
/// <summary>配列の最後に要素を追加します。</summary>
/// <param name="o">追加する値</param>
public void Push(Object o)
{
Allocate(++actualSize);
values[actualSize - 1] = o;
}
/// <summary>配列の最後の要素を取り除き、その値を返します。</summary>
/// <returns>取り除かれた値</returns>
public Object Pop()
{
return values[--actualSize];
}
/// <summary>指定した値に等しい最初の配列要素の位置を返します。</summary>
/// <param name="o">検索する値</param>
/// <returns>配列要素の位置(見つからなかったときは -1)</returns>
public int IndexOf(Object o)
{
if (o == null) return -1;
for (var i=0; i<actualSize; i++) if (values[i] == o) return i;
return -1;
}
/// <summary>指定した値が配列に含まれないときに限り、配列の最後に要素を追加します。</summary>
/// <param name="o">追加する値</param>
/// <returns>配列要素が追加された位置</returns>
public int PushExclusive(Object o)
{
int i = IndexOf(o);
if (0 <= i) return i;
Push(o);
return actualSize - 1;
}
/// <summary>指定した位置の配列要素を取り除き、そこから末尾までの全要素を先頭方向に詰めます。</summary>
/// <param name="i">配列内の位置</param>
/// <returns>取り除かれた値</returns>
public Object RemoveAt(int i)
{
if (i < 0) return null;
var o = values[i];
actualSize--;
for (; i<actualSize; i++) values[i] = values[i+1];
return o;
}
/// <summary>指定した値に等しい最初の配列要素を取り除き、そこから末尾までの全要素を先頭方向に詰めます。</summary>
/// <param name="o">取り除く値</param>
/// <returns>取り除いた要素の位置(見つからなかったときは -1)</returns>
public int Remove(Object o)
{
var i = IndexOf(o);
RemoveAt(i);
return i;
}
/// <summary>他の配列の全要素を末尾に連結します。</summary>
/// <param name="another">連結する配列</param>
public void Concat(FlexArray_Object another)
{
var n = another.Size();
Allocate(actualSize + n);
for (var i=0; i<n; i++) values[actualSize+i] = another.Get(i);
actualSize += n;
}
/// <summary>空配列にリセットします。</summary>
public void Clear()
{
values = new Object[initialSize];
actualSize = 0;
}
/// <summary>キャパシティに関する設定を変更し、空配列にリセットします。</summary>
/// <param name="initialSize">初期サイズ</param>
/// <param name="linearStepSize">線形に拡張する単位</param>
public void Initialize(int initialSize, int linearStepSize)
{
this.initialSize = initialSize;
this.linearStepSize = linearStepSize;
Clear();
}
/// <summary>指定した長さまでキャパシティを拡張し、即座にメモリを確保します。</summary>
/// <param name="n">キャパシティ</param>
/// <returns>現在のキャパシティの方が大きい場合は何もしません。
public void Allocate(int n)
{
var l = values.Length;
if (n <= l) return;
while (l < n)
{
if (linearStepSize <= l)
l += linearStepSize;
else
l *= 2;
}
var newList = new Object[l];
for (var i=0; i<values.Length; i++) newList[i] = values[i];
values = newList;
}
/// <summary>
/// 現在の配列長に必要な最小限のキャパシティまで縮小し、不要なメモリを解放します。
/// 現在のキャパシティの方が小さい場合は何もしません。
/// </summary>
public void Minimize()
{
var l = initialSize;
while (l < actualSize)
{
if (linearStepSize <= l)
l += linearStepSize;
else
l *= 2;
}
if (values.Length <= l) return;
var newList = new Object[l];
for (var i=0; i<l; i++) newList[i] = values[i];
values = newList;
}
/// <summary>
/// UdonSharpBehaviour にキャスト可能な全要素に対し、指定したメッセージを送信します。
/// 指定した名前のメソッドが呼ばれます。
/// </summary>
/// <param name="message">メッセージ(メソッド名)</param>
public void SendCustomEventToAll(string message)
{
for (var i=0; i<actualSize; i++)
{
var o = (UdonSharpBehaviour)values[i];
if (o != null) o.SendCustomEvent(message);
}
}
}
@chigirits
Copy link
Author

使う側で [SerializeField] public FlexArray_Object listeners; みたくpublicメンバを定義
FlexArray_Object をつけた空オブジェクトを使う側の子に作成して、そのメンバにDnDして参照設定
みたくして使えます(VRCInstantiateしてもいいと思いますたぶん)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment