O Unity, como motor, tem uma série de desvantagens que, graças às suas capacidades de customização e ferramentas de geração de código, podem ser resolvidas.
Agora contarei como escrevemos um plugin para Unity baseado no pós-processamento de projetos e no gerador de código CodeDom.
Problema
No Unity, o carregamento de cenas é feito por meio de um identificador de string. Não é estável, o que significa que pode ser facilmente alterado sem consequências óbvias. Por exemplo, ao renomear uma cena, tudo voará, mas será revelado apenas no final, no estágio de execução.
O problema aparece rapidamente em cenas usadas com frequência, mas pode ser difícil de detectar quando se trata de pequenas cenas aditivas ou cenas que raramente são usadas.
Decisão
Ao adicionar uma cena a um projeto, uma classe de mesmo nome é gerada com o método Load.
Se adicionarmos uma cena de Menu, a classe Menu será gerada no projeto e no futuro podemos iniciar a cena da seguinte maneira:
Menu.Load();Sim, o método estático não é o melhor layout. Mas me pareceu um desenho lacônico e conveniente. A geração ocorre automaticamente, o código-fonte desta classe:
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace IJunior.TypedScenes
{
public class Menu : TypedScene
{
private const string GUID = "a3ac3ba38209c7744b9e05301cbfa453";
public static void Load()
{
LoadScene(GUID);
}
}
}
De forma amigável, a classe deve ser estática, uma vez que não deve ser instanciada a partir dela. Este é um bug que iremos corrigir. Como você pode ver neste fragmento, o código não nos apegamos ao nome, mas ao GUID da cena, que é mais confiável. A própria classe base se parece com isto:
namespace IJunior.TypedScenes
{
public abstract class TypedScene
{
protected static void LoadScene(string guid)
{
var path = AssetDatabase.GUIDToAssetPath(guid);
SceneManager.LoadScene(path);
}
protected static void LoadScene<T>(string guid, T argument)
{
var path = AssetDatabase.GUIDToAssetPath(guid);
UnityAction<Scene, Scene> handler = null;
handler = (from, to) =>
{
if (to.name == Path.GetFileNameWithoutExtension(path))
{
SceneManager.activeSceneChanged -= handler;
HandleSceneLoaders(argument);
}
};
SceneManager.activeSceneChanged += handler;
SceneManager.LoadScene(path);
}
private static void HandleSceneLoaders<T>(T loadingModel)
{
foreach (var rootObjects in SceneManager.GetActiveScene().GetRootGameObjects())
{
foreach (var handler in rootObjects.GetComponentsInChildren<ISceneLoadHandler<T>>())
{
handler.OnSceneLoaded(loadingModel);
}
}
}
}
}- .
- ( , ), .
, .
, Game , .
.
using IJunior.TypedScenes;
using System.Collections.Generic;
using UnityEngine;
public class GameLoadHandler : MonoBehaviour, ISceneLoadHandler<IEnumerable<Player>>
{
public void OnSceneLoaded(IEnumerable<Player> players)
{
foreach (var player in players)
{
//make avatars
}
}
}, .
//------------------------------------------------------------------------------
// <auto-generated>
// This code was generated by a tool.
// Runtime Version:4.0.30319.42000
//
// Changes to this file may cause incorrect behavior and will be lost if
// the code is regenerated.
// </auto-generated>
//------------------------------------------------------------------------------
namespace IJunior.TypedScenes
{
public class Game : TypedScene
{
private const string GUID = "976661b7057d74e41abb6eb799024ada";
public static void Load(System.Collections.Generic.IEnumerable<Player> argument)
{
LoadScene(GUID, argument);
}
}
}. .. N , N . - .
, , , .
N?
YouTube .
. , , , .
, ?
. :
public class GameArguments
{
public IEnumerable<Player> Players { get; set; }
}, , , .
, : , . , .
ID .
PlayerPerfs
. , PlayerPrefs . , , .
ASPNet
- View ASPNet Core. ViewData ViewModel. Unity - .
Unity , - , View ASPNet. Additive ( , , ), .
, , , , .
Proof-of-concept. , .
Repositório GitHub - https://github.com/HolyMonkey/unity-typed-scenes
Se você estiver interessado, vou pedir a Vladislav no próximo artigo para lhe contar como ele trabalhou com o Code Dom no Unity e como trabalhar com o pós-processamento usando o exemplo do que discutimos hoje.