最終更新: kenken2020 2024年03月20日(水) 16:08:53履歴
目次
◎リパックしたUnityデータ「***_thumbnail_list.json」を正規表現でYAML形式に変換していく
サムネイルは以下の4項目が一塊として必要(名前、ID、アセットバンドルへのパス、アセットの名前)
・Name": "*****",
・ID": ****,
・"Bundle": "map/thumbnail/*****.unity3d",
・ "Asset": "**_***_****_**"
◎正規表現で不要な行を消していく
・以下のコマンドで指定したキーワードを含む行を削除する
・単純な置換で「 - Name」に置き換える
◎要らないマップの情報を削除する
・マップのサムネイルは「 Name、 ID、Bundle、Asset」の4つのパラメータ×「朝・昼・夕方・夜」の4種類で一つのかたまりとなっている
・最後にエディタ等で行数をチェックし、4の倍数になっているか確認する
Free HやStudioで使用できるマップMODの作成例です。
マップMODは非常に複雑で、初心者に優しいものではありません。
まず、PurpleRoomファイルを開いてください。他のタイプのMODとは異なり、マップはアセットバンドル内のアセットではなく、アセットバンドル内のシーン(シーンアセットバンドル)です。
→AssetBundleにScene自体を含める? 参考:【Unity】SceneをAssetBundleに格納して実行時にロードする方法について:https://tsubakit1.hateblo.jp/entry/2016/08/23/2336...
一度開くと、壁、床、オブジェクト、照明、Hポイントなどを含むマップのプレビューがシーンビューに表示されるはずです。
このマップはUnityの基本的なシェイプから作られていますが、通常はBlenderやお好みの3Dエディタでマップを作成し、.
obj, .fbx, .blend などのファイルをプロジェクトフォルダに保存しておきます。
Unityはそのモデルをインポートし、シーン階層にドラッグ&ドロップすることでシーンに追加することができます。
Blenderで再度モデルを保存すると、Unityはそれを再インポートし、変更内容で自動的にシーンを更新します。
したがって、マップを作成するワークフローは、3Dモデリングプログラムでモデルを構築し、
Unityにインポートし、MonoBehaviorsやライティングなどを追加することになります。
ルートノード(Map)を選択すると、2つのMonoBehaviorsがアタッチされているのが見えます。
SunLightInfo。1日のさまざまな時間帯の太陽光に関するデータです。3つの要素(昼、夕方、夜)があり、それぞれに光の色と角度、霧の色、LUTテクスチャなどが含まれている必要があります。
VisualizeGizmos。エディタでHポイントを視覚化するためのカスタムスクリプトです。マップの最終版をビルドしてリリースする前に削除する必要があります。
これを独自のマップに設定するには、HPointContainer を HP ポイントを含むトランスフォームに設定します。
次に「太陽光」を選択します。これは、ゲーム側が制御するシーンに追加される指向性光です。
インスペクタに「Sun」というタグがあるので、正しくタグ付けされないと正しく機能しないことに注意してください。
ここで設定したものは、SunLightInfoの設定によって上書きされますが、Unityのライティングをプレビューするのに便利です。
Sunlightの下には、SunShaftSourceトランスフォームがあります。
これ自体は何もしませんが(単なる空のトランスフォーム)、SunLightInfo はこのトランスフォームを、
サンシャフトが発生する位置として使用するように設定されています。
h_free は空のトランスフォームで、フリー H モードが開始される位置と回転をゲームに指示します。
background は、シーン全体を囲む大きなメッシュで、色は黒です。フォグが正しく機能するために必要です。
shadowcaster は、シーンを囲むメッシュで、影を落とす役割をします。
シーンの壁は影を落とすモードがオフに設定されており、
このメッシュは影を落とすモードが影のみ、つまり見えないが影を落とすモードに設定されていることに注意してください。
roomは、シーン全体を構成するメッシュの束です。すべてのメッシュはレイヤー「マップ」を使用していることに注意してください。
マップMODは非常に複雑で、初心者に優しいものではありません。
まず、PurpleRoomファイルを開いてください。他のタイプのMODとは異なり、マップはアセットバンドル内のアセットではなく、アセットバンドル内のシーン(シーンアセットバンドル)です。
→AssetBundleにScene自体を含める? 参考:【Unity】SceneをAssetBundleに格納して実行時にロードする方法について:https://tsubakit1.hateblo.jp/entry/2016/08/23/2336...
一度開くと、壁、床、オブジェクト、照明、Hポイントなどを含むマップのプレビューがシーンビューに表示されるはずです。
このマップはUnityの基本的なシェイプから作られていますが、通常はBlenderやお好みの3Dエディタでマップを作成し、.
obj, .fbx, .blend などのファイルをプロジェクトフォルダに保存しておきます。
Unityはそのモデルをインポートし、シーン階層にドラッグ&ドロップすることでシーンに追加することができます。
Blenderで再度モデルを保存すると、Unityはそれを再インポートし、変更内容で自動的にシーンを更新します。
したがって、マップを作成するワークフローは、3Dモデリングプログラムでモデルを構築し、
Unityにインポートし、MonoBehaviorsやライティングなどを追加することになります。
ルートノード(Map)を選択すると、2つのMonoBehaviorsがアタッチされているのが見えます。
SunLightInfo。1日のさまざまな時間帯の太陽光に関するデータです。3つの要素(昼、夕方、夜)があり、それぞれに光の色と角度、霧の色、LUTテクスチャなどが含まれている必要があります。
VisualizeGizmos。エディタでHポイントを視覚化するためのカスタムスクリプトです。マップの最終版をビルドしてリリースする前に削除する必要があります。
これを独自のマップに設定するには、HPointContainer を HP ポイントを含むトランスフォームに設定します。
次に「太陽光」を選択します。これは、ゲーム側が制御するシーンに追加される指向性光です。
インスペクタに「Sun」というタグがあるので、正しくタグ付けされないと正しく機能しないことに注意してください。
ここで設定したものは、SunLightInfoの設定によって上書きされますが、Unityのライティングをプレビューするのに便利です。
Sunlightの下には、SunShaftSourceトランスフォームがあります。
これ自体は何もしませんが(単なる空のトランスフォーム)、SunLightInfo はこのトランスフォームを、
サンシャフトが発生する位置として使用するように設定されています。
h_free は空のトランスフォームで、フリー H モードが開始される位置と回転をゲームに指示します。
background は、シーン全体を囲む大きなメッシュで、色は黒です。フォグが正しく機能するために必要です。
shadowcaster は、シーンを囲むメッシュで、影を落とす役割をします。
シーンの壁は影を落とすモードがオフに設定されており、
このメッシュは影を落とすモードが影のみ、つまり見えないが影を落とすモードに設定されていることに注意してください。
roomは、シーン全体を構成するメッシュの束です。すべてのメッシュはレイヤー「マップ」を使用していることに注意してください。
Map階層の外側にHPoint_Disabledが表示されているはずです。
これはHPointデータのプレハブを含むGameObjectを無効にしたものです。
Hポイントとは、ゲーム内で位置の遷移に使われるポイントです。
HPointsで使用されるIDの一覧は、このReadmeの最後を参照してください。
HPoint 通常のHポジションのHポイントに関するデータが格納されています。
HPoint_Add。レズビアン、オナニーに関するデータが含まれています。
HPoint_3P:3Pのデータが含まれています。
各種Hモードの開始位置は、このように計算されます。
Free H:シーン内の h_free トランスフォーム
レズとオナニー シーンの中心に最も近い、正しいカテゴリーのHポイント
3P: 3P_00 Hポイント
これらが存在しない場合、マップの中心(0,0,0)が開始点となります。
Hポイントは、マップMODを構築してリリースする前に、シーンから削除する必要があります。
開発中に視覚化する目的で、このシーンにのみ残されています。
HPointプレハブは、シーンとは別のアセットバンドルにコンパイルされています。
これはHPointデータのプレハブを含むGameObjectを無効にしたものです。
Hポイントとは、ゲーム内で位置の遷移に使われるポイントです。
HPointsで使用されるIDの一覧は、このReadmeの最後を参照してください。
HPoint 通常のHポジションのHポイントに関するデータが格納されています。
HPoint_Add。レズビアン、オナニーに関するデータが含まれています。
HPoint_3P:3Pのデータが含まれています。
各種Hモードの開始位置は、このように計算されます。
Free H:シーン内の h_free トランスフォーム
レズとオナニー シーンの中心に最も近い、正しいカテゴリーのHポイント
3P: 3P_00 Hポイント
これらが存在しない場合、マップの中心(0,0,0)が開始点となります。
Hポイントは、マップMODを構築してリリースする前に、シーンから削除する必要があります。
開発中に視覚化する目的で、このシーンにのみ残されています。
HPointプレハブは、シーンとは別のアセットバンドルにコンパイルされています。
マップマスキングは、カメラがマップの後ろに行ったときに、マップの一部を隠します。
つまり、邪魔にならないように、壁の一部全体が消えます。
マスキングは、map_col_(MapID)という形式の .txt ファイルであるリストファイルによって制御されます。
これは、h/list/フォルダー内のアセットバンドルにコンパイルされている必要があります。
リストファイルはタブ区切りのリストで、最初のエントリはコライダと、それによって隠されるすべてのトランスフォームです。
この例では、2つのカプセルがマスクされるように設定されています。
マップマスキングは、コライダーがカメラターゲットとカメラの間に来ると、ゲーム内でトリガーされます。
トリガーされると、指定されたトランスフォームが非表示になります。
つまり、邪魔にならないように、壁の一部全体が消えます。
マスキングは、map_col_(MapID)という形式の .txt ファイルであるリストファイルによって制御されます。
これは、h/list/フォルダー内のアセットバンドルにコンパイルされている必要があります。
リストファイルはタブ区切りのリストで、最初のエントリはコライダと、それによって隠されるすべてのトランスフォームです。
この例では、2つのカプセルがマスクされるように設定されています。
マップマスキングは、コライダーがカメラターゲットとカメラの間に来ると、ゲーム内でトリガーされます。
トリガーされると、指定されたトランスフォームが非表示になります。
太陽光の挙動は、Map にアタッチされた SunLightInfo MonoBehavior で設定されます。
影は通常、マップオブジェクトではなくシャドウキャスターメッシュによって制御されます。
なぜなら、多くのマップオブジェクトは単一の面しか持たず、一方向から影を落とさない傾向があるからです。
屋内マップの大部分は影になるので、これを補正するために、マテリアルはある程度の発光を持つように設定する必要があります。
時間帯によって照明の方向や色が変わるだけでなく、ゲームオブジェクトも時間帯によって変化させることができます。
RoomのWallsフォルダ内に、Window_d、Window_e、Window_nがあります。
これらのうち2つは無効になっており、1つはUnityでプレビューするために有効なままになっています。
SunLightInfo MBにはVisibleList要素があり、その中にこの3つのオブジェクトがあり、1日の3つの時間帯にそれぞれ1つずつあります。
指向性ライトの角度を変更することは、ライティングのプレビューに便利ですが、ゲーム内で一度設定した角度は保持されないことに注意してください。
SunLightInfo MonoBehaviorで設定された角度が、指向性光の制御に使用されます。
影は通常、マップオブジェクトではなくシャドウキャスターメッシュによって制御されます。
なぜなら、多くのマップオブジェクトは単一の面しか持たず、一方向から影を落とさない傾向があるからです。
屋内マップの大部分は影になるので、これを補正するために、マテリアルはある程度の発光を持つように設定する必要があります。
時間帯によって照明の方向や色が変わるだけでなく、ゲームオブジェクトも時間帯によって変化させることができます。
RoomのWallsフォルダ内に、Window_d、Window_e、Window_nがあります。
これらのうち2つは無効になっており、1つはUnityでプレビューするために有効なままになっています。
SunLightInfo MBにはVisibleList要素があり、その中にこの3つのオブジェクトがあり、1日の3つの時間帯にそれぞれ1つずつあります。
指向性ライトの角度を変更することは、ライティングのプレビューに便利ですが、ゲーム内で一度設定した角度は保持されないことに注意してください。
SunLightInfo MonoBehaviorで設定された角度が、指向性光の制御に使用されます。
マップとそのデータは、6つの別々のアセットバンドルにまとめられています。
purpleroom.unity3dを自分の好きなアセットバンドル名に置き換えて、自分のMODを作成します。
また、マップはList/Studioフォルダに.csvを追加することで、簡単にStudioに追加することができます。
マップをStudioで機能させるために追加で変更する必要はなく、Free Hで動作するものはStudioでも問題なく動作します。
- map/list/mapinfo/purpleroom.unity3d
- PurpleRoom MapInfo アセットはここにあります。
- マップをFree Hの選択リストに追加するために必要な、マップに関する情報が含まれています。
- map/scene/purpleroom.unity3d
- PurpleRoomのシーンは、このアセットバンドルにコンパイルされています。
- このシーンは、リストファイルに反映される限り、自分のマップ用に好きな名前に変更することができることに注意してください。
- map/thumbnail/purpleroom.unity3d
- 3つのサムネイルはここにあります。
- サムネイルは、昼、夕方、夜のサムネイルのために、_00, _01, _02という接尾辞で名前を付ける必要があります。
- h/list/purpleroom.unity3d
- マップマスキングリストがここにあります。
- map_col_(MapID)という名前の.txtファイルであるべきです。
- h/common/purpleroom.unity3d
- Hポイントのプレハブはここにコンパイルされます。
- vr/common/purpleroom.unity3d
- VR用のH Pointはここにコンパイルされています。
- Hポントのコピーを2つ別々に管理するのは時間がかかるので、これを半自動化するスクリプトが存在します。
- 3つのHPointプレハブをVRPointフォルダにコピーし、右クリックから「Configure VR HPoints」を選択します。
- (.metaファイルはコピーしないでください)HPointsのテストと設定がすべて完了した後、リリース前に一度だけこの作業を行ってください。
purpleroom.unity3dを自分の好きなアセットバンドル名に置き換えて、自分のMODを作成します。
また、マップはList/Studioフォルダに.csvを追加することで、簡単にStudioに追加することができます。
マップをStudioで機能させるために追加で変更する必要はなく、Free Hで動作するものはStudioでも問題なく動作します。
- 目標:Unityのスクリプタブルオブジェクト(ScriptableObject)をYAML形式でやや強引に編集する
- マップの情報はUnityのスクリプタブルオブジェクト(ScriptableObject)で定義されている
- 上記のデータを直接開いてYAML形式で書き換える
◎リパックしたUnityデータ「***_thumbnail_list.json」を正規表現でYAML形式に変換していく
サムネイルは以下の4項目が一塊として必要(名前、ID、アセットバンドルへのパス、アセットの名前)
・Name": "*****",
・ID": ****,
・"Bundle": "map/thumbnail/*****.unity3d",
・ "Asset": "**_***_****_**"
◎正規表現で不要な行を消していく
・以下のコマンドで指定したキーワードを含む行を削除する
^.*キーワード.*$(\r\n|\r|\n)?・正規表現の「^(キャレット)」で行頭にコピペで空白を挿入する
・単純な置換で「 - Name」に置き換える
◎要らないマップの情報を削除する
・マップのサムネイルは「 Name、 ID、Bundle、Asset」の4つのパラメータ×「朝・昼・夕方・夜」の4種類で一つのかたまりとなっている
・最後にエディタ等で行数をチェックし、4の倍数になっているか確認する
・KKS版と同じUnityバージョン(2019.4.9f1)で新しくプロジェクトを作成する
・KoikatsuSunshineModdingToolsのKKS版のUnityプロジェクトから、
マップのスクリプタブルオブジェクトの作成に必要な、以下のスクリプトをコピーして持ってくる
・KoikatsuSunshineModdingToolsのKKS版のUnityプロジェクトから、
マップのスクリプタブルオブジェクトの作成に必要な、以下のスクリプトをコピーして持ってくる
- MapInfo
- MapThumbnailInfo
参考:【Unity】今更ScriptableObject入門:https://qiita.com/4_mio_11/items/a7d8967b853cef438...
ScriptableObjectとは、ゲームやアプリの中で変化せず、あちこちで共用するデータを格納する時に便利なクラス
→例えば、敵のパラメータなど
個別のゲームオブジェクト等にアタッチはせず、都度アセットをロードして使用する
別の手法の例
例えば敵の最大体力が共通のものならば、各Prefabのコンポーネントにパラメータを持ってしまうと、
敵の数分そのパラメータの容量が必要になるがScriptableObjectのテーブルから参照すれば、データは一つですむ
ScriptableObjectのテーブルを使えば、パラメータのみが別アセットに分離しているのでコンフリクトしにくい
ゲームが終了した後にデータは全て初期値に戻るため、セーブデータ的な使い方はできない
逆にエディタ上で値を変更すると、そのままアセットに直保存される。
「エディタ上で実行中にパラメータ等の値を変更してゲームバランスを調整する」という工程がこの仕様によって非常に楽に進めることができる
アセットファイルへの書き込みは AssetDatabaseクラスから行われ、
スクリプト側からパラメータ等の値を変更した際には明示的に AssetDatabase の SaveAsset() を呼び出す必要がある
ただ、このSaveAsset()は実機での起動中は呼び出すことができない
ScriptableObjectの使用方法の流れ
ScriptableObjectとは、ゲームやアプリの中で変化せず、あちこちで共用するデータを格納する時に便利なクラス
→例えば、敵のパラメータなど
個別のゲームオブジェクト等にアタッチはせず、都度アセットをロードして使用する
別の手法の例
- ハードコーディング(クラス内に直接書く)
- CSVやJsonで定義して読み込む
例えば敵の最大体力が共通のものならば、各Prefabのコンポーネントにパラメータを持ってしまうと、
敵の数分そのパラメータの容量が必要になるがScriptableObjectのテーブルから参照すれば、データは一つですむ
ScriptableObjectのテーブルを使えば、パラメータのみが別アセットに分離しているのでコンフリクトしにくい
ゲームが終了した後にデータは全て初期値に戻るため、セーブデータ的な使い方はできない
逆にエディタ上で値を変更すると、そのままアセットに直保存される。
「エディタ上で実行中にパラメータ等の値を変更してゲームバランスを調整する」という工程がこの仕様によって非常に楽に進めることができる
アセットファイルへの書き込みは AssetDatabaseクラスから行われ、
スクリプト側からパラメータ等の値を変更した際には明示的に AssetDatabase の SaveAsset() を呼び出す必要がある
ただ、このSaveAsset()は実機での起動中は呼び出すことができない
ScriptableObjectの使用方法の流れ
- ScriptableObject派生クラスの作成
- ScriptableObject派生のクラスをアセット化
- パラメータを設定
- ScriptableObject派生のクラスを使用
参考:作成したScriptableObjectを呼び出す:https://tsubakit1.hateblo.jp/entry/20140322/139547...
1.ScriptableObjectの作成
2.ScriptableObjectのパラメーターを設定する
3.ScriptableObjectの派生クラスの作成
1.ScriptableObjectの作成
using UnityEngine; [CreateAssetMenu(fileName = "TestData", menuName = "ScriptableObjects/CreateAsset")] public class TestData : ScriptableObject { [SerializeField] public int count; [SerializeField] public string msg; }
2.ScriptableObjectのパラメーターを設定する
3.ScriptableObjectの派生クラスの作成
using UnityEngine; public class CallTestData : MonoBehaviour { public TestData m_testData; void Update() { Debug.Log(m_testData.count); Debug.Log(m_testData.msg); } }後はドラッグ&ドロップでScriptableObjectを登録すれば呼び出すことが出来る
下のコードではStartのタイミングでResourcesフォルダに配置したtestdata.assetファイルをを呼び出している。
Resourcesフォルダ以外から呼ぶ場合
Resourcesフォルダ以外から呼ぶ場合
m_testData = AssetDatabase.LoadAssetAtPath<TestData>("Assets/TEST_001/testdata.asset");
using UnityEngine; public class CallTestData : MonoBehaviour { private TestData m_testData; void Start () { m_testData = Resources.Load<TestData> ("testdata"); } void Update () { Debug.Log (m_testData.count); Debug.Log (m_testData.msg); } }
Unityプロジェクトを作成する(KKSと同じUnityVer2019.4.9が無難?)
「パッケージマネージャー」ウィンドウ→「UnityRegistry」タブ→「Asset Bundle Browser」をインストールする
KoikatsuSunshineModdingToolsにある以下のスクリプトを自分のプロジェクトにドロップ
上記で自分のアセットにインポートしたスクリプトに対応した、ScriptableObjectを作成する
→プロジェクトウィンドウ→アセットタブ→何も無いところで右クリック→「Map Thumbnai lInfo」など
→新しく作ったScriptableObjectには接頭にMODのイニシャルみたいなのをつける?
Resourcesフォルダを作成し、そこに上記のScriptableObjectを入れる
→unityでの動作テスト用
「パッケージマネージャー」ウィンドウ→「UnityRegistry」タブ→「Asset Bundle Browser」をインストールする
KoikatsuSunshineModdingToolsにある以下のスクリプトを自分のプロジェクトにドロップ
- 「MapThumbnailInfo」→マップのサムネイルに関するScriptableObject
- 「mapinfo」→マップ情報
- 「」
上記で自分のアセットにインポートしたスクリプトに対応した、ScriptableObjectを作成する
→プロジェクトウィンドウ→アセットタブ→何も無いところで右クリック→「Map Thumbnai lInfo」など
→新しく作ったScriptableObjectには接頭にMODのイニシャルみたいなのをつける?
Resourcesフォルダを作成し、そこに上記のScriptableObjectを入れる
→unityでの動作テスト用
リソースフォルダのあるアセットバンドルを読み込む例
設定が正しければ、Unityのコンソールに出力される
設定が正しければ、Unityのコンソールに出力される
public class CallTestData : MonoBehaviour { //マップサムネイル用のScriptableObjectの型 private MapThumbnailInfo m_testData; void Start() { m_testData = Resources.Load<MapThumbnailInfo>("MHM_thumbnail_list"); //マップの名前 UnityEngine.Debug.Log("name::" + m_testData.param[0].Name); //マップのID UnityEngine.Debug.Log("ID::" + m_testData.param[0].ID); //マップのバンドル UnityEngine.Debug.Log("Bundle::" + m_testData.param[0].Bundle); //マップのアセット UnityEngine.Debug.Log("Asset::" + m_testData.param[0].Asset); } }
参考:【Unity】AssetBundleの簡単なつくり方【コード不要】:https://your-3d.com/unity-assetbundle-simple/
◎ScriptableObjectをアセットバンドルとしてビルドする
◎ビルドしたアセットをゲーム側の「StreamingAssets」フォルダからロードする
「C:\illusion\KoikatsuSunshine\KoikatsuSunshine_Data」にある「StreamingAssets」フォルダへ先程ビルドしたアセットバンドルを入れる
→ビルドしたのはUnityプロジェクトの\AssetBundles\StandaloneWindowsにある?
◎サイドローダー形式に対応して読み込む
◎ScriptableObjectをアセットバンドルとしてビルドする
◎ビルドしたアセットをゲーム側の「StreamingAssets」フォルダからロードする
「C:\illusion\KoikatsuSunshine\KoikatsuSunshine_Data」にある「StreamingAssets」フォルダへ先程ビルドしたアセットバンドルを入れる
→ビルドしたのはUnityプロジェクトの\AssetBundles\StandaloneWindowsにある?
◎サイドローダー形式に対応して読み込む
private MapThumbnailInfo m_testData2; void Start() { // サイドローダー経由の「abdata」からAssetBundleをロードする var assetBundle2 = AssetBundle.LoadFromFile("C:/illusion/KoikatsuSunshine/abdata/map/list/mapthumbnailinfo/MHM000.unity3d"); UnityEngine.Debug.Log("assetBundle2::" + assetBundle2); // AssetBundle内のアセットにはビルド時のアセットのパス、またはファイル名、ファイル名+拡張子でアクセスできる m_testData2 = assetBundle2.LoadAsset<MapThumbnailInfo>("MHM_thumbnail_list"); UnityEngine.Debug.Log("m_testData2::" + m_testData2); //マップの名前 UnityEngine.Debug.Log("name::" + m_testData2.param[0].Name); //マップのID UnityEngine.Debug.Log("ID::" + m_testData2.param[0].ID); //マップのバンドル UnityEngine.Debug.Log("Bundle::" + m_testData2.param[0].Bundle); //マップのアセット UnityEngine.Debug.Log("Asset::" + m_testData2.param[0].Asset); }
コメントをかく