動画 You Tubeチャンネル移動
こんばんは。ネノワヲンです。 この度、新ゲームを作成することにしました。
進捗をYou Tubeに上げていこうかと思ったのですが、 アカウントの情報を忘れてしまったのでチャンネル移動することにしました。
↓新チャンネル
新ゲームの最初の動画を近々公開予定です。 それではまた。
Unity マルチシーン シーンを動的に読み込む
こんにちは。ネノワヲンです。今回は
の続きになります。
初めに
実行形式では、初めから複数のシーンを読み込んでおくことができません。
そのため、ゲームが起動してから必要なシーンを読み込む必要があります。
動的にシーンを追加する
SceneManagerのLoadSceneは、シーンの読み込み方法を選択することができます。
// そのシーンだけ読み込む(いつもの) SceneManager.LoadScene(sceneIndex); // ↑と同じ SceneManager.LoadScene(sceneName, LoadSceneMode.Single); // LoadSceneModeをAdditiveにするとシーン追加になる SceneManager.LoadScene(sceneName, LoadSceneMode.Additive);
活用例
実際に私が使った手法です。
メインとなるシーンに、↑のようにシーン名を登録しておきます。
Startで、登録しておいたシーンを追加で読み込みます。
private async void Start() { // サブシーンを読み込む foreach (var sceneName in subSceneNames) { await SceneController.AddSceneAsync(sceneName); } // ステージを読み込む await SceneController.AddSceneAsync(GameParameterManager.Instance.StageSceneName); // ステージのマップを読み込む await SceneController.AddSceneAsync(StageSceneManager.Instance.StageMapSceneName); // シーン読み込み完了イベントを発行 OnLoadSceneCompleted.OnNext(Unit.Default); OnLoadSceneCompleted.Dispose(); }
SceneControllerは自作クラスです。詳しくは
をご覧ください。やっていることは動的にシーンを追加しているだけです。
今回は、ゲームに必要なUI、ステージマップ、ステージの敵を組み合わせています。
このようにすることで、違うステージを使いたいときには読み込むシーンを変えることで対応できます。
Unity 自作シーン遷移クラス
こんにちは。ネノワヲンです。 今回は、私が使っている自作シーン管理クラスを晒していこうと思います。
コード
using UnityEngine; using UnityEngine.SceneManagement; public class SceneController { /// <summary> /// 指定したシーンに飛ぶ /// </summary> /// <param name="sceneName"></param> public static void JumpScene(string sceneName) { SceneManager.LoadScene(sceneName); } /// <summary> /// 指定したシーンに飛ぶ /// </summary> /// <param name="sceneIndex"></param> public static void JumpScene(int sceneIndex) { SceneManager.LoadScene(sceneIndex); } /// <summary> /// 指定したシーンを追加で生成 /// </summary> /// <param name="sceneName"></param> public static void AddScene(string sceneName) { if (IsSceneLoaded(sceneName)) { return; } SceneManager.LoadScene(sceneName, LoadSceneMode.Additive); } /// <summary> /// 指定したシーンに飛ぶ(非同期) /// </summary> /// <param name="sceneName"></param> public static AsyncOperation JumpSceneAsync(string sceneName) { return SceneManager.LoadSceneAsync(sceneName); } /// <summary> /// 指定したシーンを追加で生成(非同期) /// </summary> /// <param name="sceneName"></param> public static AsyncOperation AddSceneAsync(string sceneName) { if (IsSceneLoaded(sceneName)) { return null; } return SceneManager.LoadSceneAsync(sceneName, LoadSceneMode.Additive); } /// <summary> /// 現在のシーンを読み直す(リトライ) /// </summary> public static void ReloadSceneAsync() { JumpScene(SceneManager.GetActiveScene().buildIndex); } /// <summary> /// そのシーンが読み込み済みかどうか調べる /// </summary> /// <param name="sceneName"></param> /// <returns></returns> public static bool IsSceneLoaded(string sceneName) { // 現在読み込まれているシーン数だけループ for (int i = 0; i < SceneManager.sceneCount; i++) { // 読み込み済みかどうか調べる if (SceneManager.GetSceneAt(i).name.Equals(sceneName)) { Debug.LogWarning($"シーン名:{sceneName}は既に読み込まれています"); return true; } } return false; } }
機能
通常のシーン遷移、シーン追加があります。
また、非同期版ではこのように↓
// サブシーンを読み込む foreach (var sceneName in subSceneNames) { await SceneController.AddSceneAsync(sceneName); } // ステージを読み込む await SceneController.AddSceneAsync(StageSceneName); // ステージのマップを読み込む await SceneController.AddSceneAsync(StageMapSceneName);
awaitでシーン読み込みを待機できます。
Unity Zenjectを用いたマルチシーン設計について
こんにちは。ネノワヲンです。
今回は、Zenjectを用いたマルチシーン設計についての話をしたいと思います。
Unityバージョン : 2018.4.2f1
目次
マルチシーン設計とは
Unityでは複数シーンを同時に読み込み、使用することができます。
今回は、シーンを1つの機能として使おう、というお話です。
何が嬉しいか
色々な場面で使いまわし、かつ他の機能と組み合わせて使うものと相性がいいです。
例えば、ゲーム中のUI。シーンを見ながらレイアウトを変更することができるうえ、そのUIを変更する場合はシーンを1つ変更すればよくなり、変更漏れなどが少なくなります。
Zenjectとは
簡単に言うと、あるクラスが持つ変数にインスタンスを入れてくれるライブラリです。
本来であればインスタンスを登録するのは自分でやる必要がありますが、Zenjectを使用することで自動化ができたりします。
やってみた
まず、1つのシーンのみで作ってみます。
今回は、プレイヤーの座標を画面に表示するシンプルなシーンを作りました。
このように、必要なクラスをインスペクターから設定しています。
このシーンをマルチシーンに分割していきます。
マルチシーンにする
シーンを複数作成します。 今回はメインシーン以外のカメラやライトは必要ないので消します。
UI用のオブジェクトをUIシーンに移します。 unityでは、実行時にしか他のシーンのオブジェクトを参照できません。
Zenjectを使用することで、この問題を解決できるようになります。
Zenjectをインストール
assetstore.unity.com Zenjectをアセットストアからダウンロードします。
SceneContextを作る
Zenjectでは、インジェクトをしてくれるコンテナとして、いくつかのContextが用意されています。 今回は、シーン単位でインジェクトを行うSceneContextを作成します。
ZenjectBinding
シーン内のコンポーネントを登録しておくことで、自動的にインジェクトを行ってくれるZenjectBindingという機能を使います。
登録したコンポーネントをインジェクトしてもらうために、変数に[Inject]属性を付けます。
/// <summary> /// プレイヤークラス /// </summary> [Inject] private PlayerProvider playerProvider;
[Inject]が付いたすべてのオブジェクトにインスタンスをインジェクトしてくれます。
また、コンポーネントは複数登録できます。
シーンを超えたBinding
SceneContextは親子関係を持つことができます。
子シーンは、親シーンのオブジェクトもインジェクトできます。
親シーンのcontextのContractNamesを設定します。
子シーンのcontextのParentContractNamesに親シーンのコンテキスト名を入れます。 後の手順は同じです。
活用例
マルチシーン。 pic.twitter.com/XfE7gGilbi
— ネノワヲン@ねのぷろ! (@nenowawon) 2019年6月16日
デバッグシーンを追加。 pic.twitter.com/fsxd8qC6sG
— ネノワヲン@ねのぷろ! (@nenowawon) 2019年6月16日
追記: 続き書きました。
Unity Layerの管理について
こんにちは。ネノワヲンです。 今回は、Layer管理についてのお話です。
値の持ち方
レイヤーを、enumで管理しています。
/// <summary> /// レイヤー名と番号 /// </summary> public enum Layer { Ground = 8, Player = 9, HangObject = 10, AttackPoint = 11, Hook = 12, Enemy = 13, MiniMap = 14, PlayerFace = 15, Guide = 16, EnemyBase = 17, Goal = 18 }
unityではレイヤーはintで使うので、直接intにできるenumだと管理がしやすいです。
LayerMaskの管理
/// <summary> /// フックの衝突レイヤー /// </summary> public const int hookCol = (1 << (int)Layer.Ground | 1 << (int)Layer.HangObject | 1 << (int)Layer.AttackPoint | 1 << (int)Layer.Enemy); /// <summary> /// カメラとの障害物判定のマスク /// </summary> public const int cameraBlockCheck = ~(1 << (int)Layer.Player | 1 << (int)Layer.Hook | 1 << (int)Layer.Enemy); /// <summary> /// 敵の本体の衝突レイヤー /// </summary> public const int enemyBaseCol = (1 << (int)Layer.Ground | 1 << (int)Layer.EnemyBase);
Raycastの際に使用するMaskの値もあらかじめ格納しておくことで、管理が楽になります。
C++ 衝突応答(めり込み防止)
こんばんは。ネノワヲンです。
やったこと
めり込み直ったーーーーーーーーーー!!!!!!!!!! pic.twitter.com/ZDfKKLIu29
— ネノワヲン@ネノぶろ! (@nenowawon) 2018年11月21日
ソースコード
void Player::LateUpdate(float deltaTime) { vector<RectangleCollider*> colliderList; // コライダーのリストを取得 for (auto collider : DirectXRenderer::instance->m_ColliderList) { //テスト用オブジェクトにぶつかった場合 if (collider->m_pGameObject->m_tag != Tag::TEST) { continue; } // 衝突判定をする if (!m_pCollider->CheckCollider(collider)) { continue; } // 判定するコライダーを格納する colliderList.emplace_back(collider); } XMFLOAT3 movePos = XMFLOAT3(0.0f, 0.0f, 0.0f); for (auto collider : colliderList) { // 衝突物の座標 XMFLOAT3 checkColliderPos = collider->m_pGameObject->m_pTransform->m_pos; // 自分の頂点ごとのワールド座標 RectangleVertex myRect = m_pCollider->GetRect(*m_pTransform); RectangleVertex collisionRect = collider->GetRect(*collider->m_pGameObject->m_pTransform); Transform transformTemp = *m_pTransform; bool isPositisionBackY = false; bool isPositisionBackX = false; // Y軸座標の移動があった場合 if (m_CurrentMoveTemp.y > 0.0f || m_CurrentMoveTemp.y < 0.0f) { // Y軸座標を戻す transformTemp.m_pos.y -= m_CurrentMoveTemp.y; // 衝突判定をする if (!m_pCollider->CheckColliderTransform(collider, transformTemp)) { float moveYTemp = 0.0f; isPositisionBackY = true; OutputDebugString(_T("縦に戻す\n")); } } transformTemp = *m_pTransform; // X軸座標の移動があった場合 if (m_CurrentMoveTemp.x > 0.0f || m_CurrentMoveTemp.x < 0.0f) { // X軸座標を戻す transformTemp.m_pos.x -= m_CurrentMoveTemp.x; // 衝突判定をする if (!m_pCollider->CheckColliderTransform(collider, transformTemp)) { float moveXTemp = 0.0f; isPositisionBackX = true; OutputDebugString(_T("横に戻す\n")); } // if } // if if (isPositisionBackX&&isPositisionBackY) { // 衝突したコライダーが他にある場合 if (colliderList.size() > 0) { continue; } } // x座標を元に戻す if (isPositisionBackX) { movePos.x = -m_CurrentMoveTemp.x; } // y座標を元に戻す if (isPositisionBackY) { movePos.y = -m_CurrentMoveTemp.y; } } // for // 移動する Move(movePos); }
今日はもう遅いので、概要に関しては改めて明日書こうと思います。
あとがき
情報を調べていたら自分のブログが出てくるという嬉しいのか悲しいのか分からない現象(嬉しい)