Unite 2016 Tokyoで登壇した『Unityを使った個人ゲーム開発における「収益化」の現状と未来』の続編です。登壇者のゲーム作品『Back in 1995』の振り返りと現在の取り組みから、Unityの力によってどのように活動を拡大していったのか紹介します。また、この5年で大きく変化した、日本のインディーを取り巻く環境についてご紹介します。
・『狂気講演』から5年、あのゲームは結局売れたのか?
・日本のインディーを取り巻く環境の変化
・開発を効率化する:Unity Services事例
・インディー創作活動を持続するために必要なこと
13. 2.Nativeコンテナってなんだ
var a = new NativeArray<MyStruct>(32, Allocator.Persistent);
生成
解放
Allocator.Persistent
Allocator.Temp
Allocator.TempJob
永続的に使用可能
同じフレームで解放しないとエラー
4フレーム以内に解放しないとエラー
a.Dispose();
例:NativeArray
フレームの概念が組み込まれている素晴らしさ
14. 2.Nativeコンテナってなんだ
var a = new NativeArray<MyStruct>(32, Allocator.Persistent);
var b = new MyStruct[32];
a.CopyTo(b);
生成
コピー (memcpyのloop)
今後NativeArray対応APIは増えていきます
a.CopyFrom(b);
とはいえ通常の配列を要求するUnityのAPIは多い・・・
21. 3.C# Job System のおさらい
struct AJob : IJobParallelFor {
public NativeArray<Vector3> positions;
public void Execute(int i) {
var pos = positions[i];
pos.y += 1f;
positions[i] = pos;
}
}
IJobParallelForを実装してExecuteを定義
indexは供給される
Jobが実行する
Uniform的なもの
Jobの書きかた
22. 3.C# Job System のおさらい
struct AJob : IJobParallelFor {
public NativeArray<Vector3> positions;
public void Execute(int id) {
var pos = positions[id];
pos.y += 1f;
positions[id] = pos;
}
}
毎フレームScheduleを呼ぶ
読んでしまったら ajob は破棄して良い
void Update() {
var ajob = new AJob() { positions = m_Positions, };
var handle = ajob.Schedule(positions.Length, 8, );
}
生成
実行指令
データ参照
Jobの呼びかた
23. 3.C# Job System のおさらい
struct AJob : IJobParallelFor {
public NativeArray<Vector3> positions;
public void Execute(int id) {
var pos = positions[id];
pos.y += 1f;
positions[id] = pos;
}
}
idは供給される
Jobが実行する
Uniform的なもの
Jobの書きかた
参照なので危険がつきまとう
[ReadOnly]や[WriteOnly]属性をつける
24. 3.C# Job System のおさらい
InvalidOperationException: The native container has been
declared as [WriteOnly] in the job, but you are reading from it.
Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle.Check
ReadAndThrowNoEarlyOut
(Unity.Collections.LowLevel.Unsafe.AtomicSafetyHandle
handle) <0x1472e5a80 + 0x00052> 本当にありがとうございます
出してくれるエラーの例
25. 3.C# Job System のおさらい
Scheduleの引数にJobHandleを渡す
void Update() {
var ajob = new AJob() { positions = m_Positions, };
var bjob = new BJob() { positions = m_Positions, };
var handle = ajob.Schedule(positions.Length, 8, );
handle = bjob.Schedule(handle);
JobHandle.ScheduleBatchedJobs();
handle.Complete();
}
ジョブ発行時に依存関係を定義
39. 6.Entity生成 step by step
public struct RigidbodyPosition : IComponentData {
public float3 velocity;
public float3 acceleration;
public float damper;
}
IComponentData は interface
手順1/3・Componentの定義
44. 6.Entity生成 step by step
var entity = entity_manager.CreateEntity(arche_type);
var entity = entity_manager.CreateEntity(arche_type);
var pos0 = new Unity.Transforms.Position { Value = new float3(0,0,0), };
entity_manager.SetComponentData<Unity.Transforms.Position>(entity, pos0);
SetComponentDataで初期化
SetComponentDataがEntityManager経由!
オブジェクト指向との思想の違い
手順3/3・CreateEntityでEntityを作成
76. 10.IComponentDataを見極める
IComponentDataに書けるもの/書けないもの
public unsafe struct MyComponent : IComponentData {
public int i; // OK
public string str; // NG (参照型)
public byte* ptr; // OK (要unsafe)
public bool flg; // NG (non blittable)
public NativeArray na; // NG
public fixed int fa[256]; // OK (要unsafe)
}
要するにblittableかどうか
132. 18.選ぶのは8個
Interlocked.CompareExchange
いわゆる CAS(Compare And Swap)
public bool TryIncrement(int inclusive_limit) {
int current = *m_Counter;
while (current < inclusive_limit) {
int next = current + 1;
int prev = Interlocked.CompareExchange(ref *m_Counter, next, current);
if (prev == current) {
return true;
} else {
current = prev;
}
}
return false;
}