Dice (Creator) Pack (ストアへの外部リンク)
サイコロの3Dモデルと、出目の判定システムが含まれた、アセット[Inner Drive Studios] Dice (Creator) Packの使い方。
2018年に20%OFFセールがあったらしいが、ここ最近は無し。
やや粗いが無料のアセットをまとめた記事は↓。
以下、デモ動画。
サイコロの種類
- D2
- D4:一面に複数の値があるように見えるが、角に出目が振られているだけ。
- D6
- D6Pips:ドット(ドットの数で出目を表現するタイプ)。
- D6R:ラウンド(角が丸められているタイプ)。
- D6RPips:ラウンド&ドット。
- D8
- D10-00:10の位。
- D10-0:1の位。
- D10-X:1の位だが0がX。
- D12
- D20
以下の2種類は、別フォルダに取り分けられている、「1つの面に複数の目(記号)がある特殊なサイコロ」。
- D6_A
- D6_B
【使用準備】サイコロプレハブの設置と設定
- Projectウィンドウ -> Assets -> InnerDriveStudios -> DiceCreator -> Prefabs -> PhysicsDice_SingleValueを開く。
- 各種サイコロのプレハブをヒエラルキーに設置。
「サイコロをタッチした時にロールする機能」を消すには、サイコロ本体にアタッチされたMouseClickDieRollerコンポーネントをデタッチ。
複数のサイコロを扱う
複数のサイコロの値や、ロールを纏めて管理する場合は、DieCollectionを使用する。
- Assets -> InnerDriveStudios -> DiceCreator -> Prefabs
のDieCollectionをヒエラルキーに設置。 - DieCollectionコンポーネントのRollablesリストに、インスペクターからサイコロを紐付け。
「キーを押した時にロールする機能」を消すには、DieCollectionにアタッチされたKeyPressCollectionRollerコンポーネントをデタッチ。
1つの面に複数の目がある特殊なサイコロ
メインの数値 + 雷やハートのマークが刻まれた、独特なサイコロのプレハブ。
- 6面ダイスのみ。
- マーク違いで2種類ある。
Assets -> InnerDriveStudios -> DiceCreator -> Prefabs -> PhysicsDice_SampleMultiValue
の各種サイコロのプレハブをヒエラルキーに設置。
複数のサイコロを扱う場合にDieCollectionを使用するのは共通。
「サイコロをタッチした時にロールする機能」を消すには、サイコロ本体にアタッチされたMouseClickDieRollerコンポーネントをデタッチ。
サイコロ台
サイコロを振る為の台のプレハブもある。
- Projectウィンドウ -> Assets -> InnerDriveStudios -> DiceCreator -> Prefabsを開く。
- RollingAreaをヒエラルキーに設置。
既にColliderは設定されているので、そのまま使える。
ダイスロールの実行
プレハブには既にColliderや、Rigidbodyがアタッチされている為、特段弄る事なくダイスロールが出来る。
【コード】単数
- 各種サイコロのプレハブにアタッチされた、「PhysicsDieコンポーネント」をインスペクター等から紐付けし、保持しておく。
- PhysicsDie.Rollを呼ぶ。
//名前空間が設定されているのでusing宣言。
using InnerDriveStudios.DiceCreator;
public class Test : MonoBehaviour
{
//インスペクターから紐付けしておく。
[SerializeField]
PhysicsDie physicsDie;
void Roll()
{
physicsDie.Roll();
}
}
【コード】複数
- DieCollectionプレハブにアタッチされた、「DieCollectionコンポーネント」をインスペクター等から紐付けし、保持しておく。
- DieCollection.Rollを呼ぶ。
//名前空間が設定されているのでusing宣言。
using InnerDriveStudios.DiceCreator;
public class Test : MonoBehaviour
{
//インスペクターから紐付けしておく。
[SerializeField]
DieCollection dieCollection;
void Roll()
{
dieCollection.Roll();
//結果が出ていない(Sleep状態でない)物を全てロール。
dieCollection.RollNonExact();
}
}
ダイスロールの設定
各種サイコロのプレハブにアタッチされた、「PhysicsDieコンポーネント」の各種値をインスペクターから変更する事で、ダイスロール時の挙動を設定出来る。
- ThrowVector:投げるベクトル。
- MaxAngleDeviation:投げるベクトルにランダムに加えられる角度。
- MinVelocity:最低速度
- MaxVelocity:最高速度
- MinAngularVelocity:最低回転速度
- MaxAngularVelocity:最高回転速度
- NudgeAlongForce:角が下の状態で安定してしまった時に加える力
備考
- 【ロールの仕様】最低加速度~最高加速度間の力が、ランダムにThrowVectorに掛けられる。
- ThrowVectorは、ノーマライズされるので、大きい値を設定してもOK(内部的には1に収まる)。
- MaxAngleDeviationを、0に設定した場合、ほぼThrowVector通りの挙動になる。
- Rigidbody.MaxAngularVelocityを変更していないので、一定以上の回転速度にはならない(高い回転速度が必要なら、初期化時にRigidbody.MaxAngularVelocityの値を高く設定する)。
結果、状態の取得
DieSidesの状態
DieSides.GetDieSideMatchInfo()で取得したDieSideMatchInfoからの結果の取得。
- DieSides.dieSideCount
:intでダイスタイプが返される(10面ダイスなら10)。 - DieSideMatchInfo.closestMatch.values[0]
:出目の値をintで返す(1つの面に複数の出目がある場合、引数でindexを渡す(通常は0))。 - DieSideMatchInfo.closestMatch.ValuesAsString()
:出目の値をstringで返す(1つの面に複数の出目がある場合、コンマで区切った全てを返す)。
PhysicsDieの状態
PhysicsDie.GetRollResult()で取得したIRollResult。
- PhysicsDie.isRolling
:現在ロール中か否かをboolで返す。 - IRollResult.Value()
:出目の値をintで返す(valueCountが1以上の場合、引数でindexを渡す)。 - IRollResult.valuesAsString
:出目の値をstringで返す(1つの面に複数の出目がある場合、コンマで区切った全てを返す) - IRollResult.valueCount
:1つの面に幾つの出目があるかをintで返す(通常は1) - IRollResult.isExact
:結果が正確か否かをboolで返す?
DieCollectionの状態
DieCollection.GetRollResult()で取得したIRollResult。
前項と同じ型だが、やや違う挙動。
- DieCollection.isRolling
:全サイコロが、現在ロール中か否かをboolで返す。 - IRollResult.Value()
:出目の合計の値をintで返す(valueCountが1以上の場合、引数でindexを渡す。
0はメインの出目の合計値、1~2は記号の出目の合計値)。 - IRollResult.valuesAsString
:出目の合計の値をstringで返す(1つの面に複数の出目がある場合、コンマで区切った全てを返す)。 - IRollResult.valueCount
:1つの面に幾つの出目があるか(DieCollectionに登録したサイコロの最大値)をintで返す(通常は1)。 - IRollResult.isExact
:結果が正確か否かをboolで返す?
【コード】単数
以下のテストコードで、各種変数をコンソールに表示する。
//名前空間が設定されているのでusing宣言。
using InnerDriveStudios.DiceCreator;
public class Test : MonoBehaviour
{
//サイコロのプレハブをインスペクターから紐付け。
[SerializeField]
PhysicsDie physicsDie;
//サイコロのプレハブをインスペクターから紐付け。
[SerializeField]
DieSides dieSides;
IRollResult result;
DieSideMatchInfo dieSideMatchInfo;
void Awake()
{
//Awakeのタイミングで実行したらエラーが出るので、適当に遅延処理。
Invoke("Roll", 0.1f);
Invoke("PrintResult", 5);
}
//適当にロール。
void Roll()
{
physicsDie.Roll();
}
void PrintResult()
{
dieSideMatchInfo = dieSides.GetDieSideMatchInfo();
print("ダイスタイプ:" + dieSides.dieSideCount + "面ダイス");
print("出目の値をintで返す:" + dieSideMatchInfo.closestMatch.values[0]);
print("出目の値をstringで返す:" + dieSideMatchInfo.closestMatch.ValuesAsString());
print("結果が正確か否かをboolで返す? " + dieSideMatchInfo.isExactMatch);
result = physicsDie.GetRollResult();
print("現在ロール中か否かをboolで返す:" + physicsDie.isRolling);
print("出目の値をintで返す:" + result.Value());
print("出目の値をstringで返す:" + result.valuesAsString);
print("1つの面に幾つの出目があるかをintで返す:" + result.valueCount);
print("結果が正確か否かをboolで返す?:" + result.isExact);
}
}
【コード】複数
以下のテストコードで、各種変数をコンソールに表示する。
//名前空間が設定されているのでusing宣言。
using InnerDriveStudios.DiceCreator;
public class Test : MonoBehaviour
{
//DieCollectionのプレハブをインスペクターから紐付け。
[SerializeField]
DieCollection dieCollection;
IRollResult collectionResult;
void Awake()
{
//Awakeのタイミングで実行したらエラーが出るので、適当に遅延処理。
Invoke("Roll", 0.1f);
Invoke("PrintResult", 5);
}
//適当にロール。
void Roll()
{
dieCollection.Roll();
}
void PrintResult()
{
//1つのみの場合と同一のIRollResultインターフェイスが返される。
//ほぼ同じだが、ValueやvaluesAsStringが出目の合計になっている。
collectionResult = dieCollection.GetRollResult();
print("現在ロール中か否かをboolで返す:" + dieCollection.isRolling);
print("出目の合計の値をintで返す:" + collectionResult.Value());
print("出目の合計の値をstringで返す:" + collectionResult.valuesAsString);
print("1つの面に幾つの出目があるかをintで返す:" + collectionResult.valueCount);
print("結果が正確か否かをboolで返す?:" + collectionResult.isExact);
//出目の結果が蓄積されてしまうので、「結果が出た後、次のロールをする前」にリセットする。
dieCollection.ClearEndResult();
}
}
イベントリスナー (ロール開始、終了タイミング)
イベントリスナーに登録する事で、
- ロール開始
- ロール終了
- ロール結果のクリア
のタイミングに、任意のメソッドを呼ぶ事が出来る。
【コード】単数
//名前空間が設定されているのでusing宣言。
using InnerDriveStudios.DiceCreator;
public class Test : MonoBehaviour
{
//インスペクターから紐付けしておく。
[SerializeField]
PhysicsDie physicsDie;
void Awake()
{
//ダイスロール開始時のイベントリスナーにメソッドを登録。
physicsDie.OnRollBegin += onRollBegin;
//ダイスロール終了時のイベントリスナーにメソッドを登録。
physicsDie.OnRollEnd += onRollEnd;
//ダイスロール結果クリア時のイベントリスナーにメソッドを登録。
//一応あるが、単数の場合は使わないっぽい。
physicsDie.OnEndResultCleared += onEndResultCleared;
}
//引数は一致させる。
private void onRollBegin(ARollable die)
{
}
private void onRollEnd(ARollable die)
{
}
private void onEndResultCleared(ARollable die)
{
}
}
【コード】複数
//名前空間が設定されているのでusing宣言。
using InnerDriveStudios.DiceCreator;
public class Test : MonoBehaviour
{
//インスペクターから紐付けしておく。
[SerializeField]
DieCollection dieCollection;
void Awake()
{
//全体のダイスロール開始時のイベントリスナーにメソッドを登録。
dieCollection.OnRollBegin += onRollBegin;
//全体のダイスロール終了時のイベントリスナーにメソッドを登録(全ての結果が出た時に呼ばれる)。
dieCollection.OnRollEnd += onRollEnd;
//全体のダイスロール結果クリア時のイベントリスナーにメソッドを登録。
dieCollection.OnEndResultCleared += onEndResultCleared;
//各ダイスロール開始時のイベントリスナーにメソッドを登録。
dieCollection.OnChildRollBegin += onRollBegin;
//各ダイスロール終了時のイベントリスナーにメソッドを登録。
dieCollection.OnChildRollEnd += onRollEnd;
//各ダイスロール結果クリア時のイベントリスナーにメソッドを登録。
dieCollection.OnChildEndResultCleared += onEndResultCleared;
}
//引数は一致させる。
//オーバーロードによって、OnRoll~とOnChildRoll~で同名メソッドの使い回しも可能。
private void onRollBegin(ARollable die)
{
}
private void onRollEnd(ARollable die)
{
}
private void onEndResultCleared(ARollable die)
{
}
//OnChildRoll~用。
private void onRollBegin(DieCollection dieCollection, ARollable die)
{
}
private void onRollEnd(DieCollection dieCollection, ARollable die)
{
}
private void onEndResultCleared(DieCollection dieCollection, ARollable die)
{
}
}
まとめ
名前空間の設定や、参照の保持もキッチリ行われており、最適化も十分。
また、非アクティブなサイコロは、ロールや結果の表示から除外してくれる(エラーも出ない)。
文句の付け所はないです。