Diretrizes de codificação
Este documento descreve as diretrizes de codificação recomendadas para World Locking Tools for Unity. A maioria dessas sugestões segue os padrões recomendados do MSDN.
Cabeçalhos de informações de licença de script
Todos os scripts postados no World Locking Tools for Unity devem ter o cabeçalho de licença padrão anexado, exatamente como mostrado abaixo:
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.
Todos os arquivos de script enviados sem o cabeçalho da licença serão rejeitados.
Cabeçalhos de resumo de função / método
Todas as classes públicas, structs, enums, functions, properties, fields posted devem ser descritas quanto à sua finalidade e uso, exatamente como mostrado abaixo:
/// <summary>
/// The Controller definition defines the Controller as defined by the SDK / Unity.
/// </summary>
public struct Controller
{
/// <summary>
/// The ID assigned to the Controller
/// </summary>
public string ID;
}
Essa regra garante que a documentação seja gerada e disseminada adequadamente para todas as classes, métodos e propriedades.
Todos os arquivos de script enviados sem as tags de resumo adequadas serão rejeitados.
Regras de namespace
Todas as classes e extensões devem ter escopo por namespace, escolhido apropriadamente entre os namespaces a seguir.
Microsoft.MixedReality.WorldLocking.Core - Código básico que cumpre o serviço básico das Ferramentas de Bloqueio Mundial.
Microsoft.MixedReality.WorldLocking.Tools - Recursos opcionais que complementam o desenvolvimento sobre as Ferramentas de Bloqueio Mundial. Exemplos são visualizações de diagnóstico e implementações de linha de base de manipuladores de eventos de aplicativo.
Microsoft.MixedReality.WorldLocking.Examples - Implementações específicas demonstrando como usar os recursos das Ferramentas de Bloqueio Mundial e os benefícios obtidos.
Recursos relacionados dentro de um dos namespaces acima podem ser agrupados estendendo-se para um novo subnamespace.
O que deve fazer
namespace Microsoft.MixedReality.WorldLocking.Examples.Placement
{
// Interface, class or data type definition.
}
Omitir o namespace de uma interface, classe ou tipo de dados fará com que sua alteração seja bloqueada.
Espaços vs separadores
Certifique-se de usar quatro espaços em vez de guias ao contribuir para este projeto.
Além disso, certifique-se de que os espaços são adicionados para funções condicionais / loop como if / while / for
O que não deve fazer
private Foo () // < - space between Foo and ()
{
if(Bar==null) // <- no space between if and ()
{
DoThing();
}
while(true) // <- no space between while and ()
{
Do();
}
}
O que deve fazer
private Foo()
{
if (Bar==null)
{
DoThing();
}
while (true)
{
Do();
}
}
Espaçamento
Não adicione espaços adicionais entre colchetes e parênteses:
O que não deve fazer
private Foo()
{
int[ ] var = new int [ 9 ];
Vector2 vector = new Vector2 ( 0f, 10f );
}
O que deve fazer
private Foo()
{
int[] var = new int[9];
Vector2 vector = new Vector2(0f, 10f);
}
Convenções de nomenclatura
Utilize PascalCase
sempre para propriedades públicas/protegidas/virtuais, e camelCase
para propriedades e campos privados.
A única exceção a isso é para estruturas de dados que exigem que os campos sejam serializados pelo
JsonUtility
.
O que não deve fazer
public string myProperty; // <- Starts with a lower case letter
private string MyProperty; // <- Starts with an uppercase case letter
O que deve fazer
public string MyProperty;
protected string MyProperty;
private string myProperty;
Modificadores de acesso
Sempre declare um modificador de acesso para todos os campos, propriedades e métodos.
Todos os métodos de API Unity devem ser
private
por padrão, a menos que você precise substituí-los em uma classe derivada. Neste casoprotected
deve ser usado.
Os campos devem ser
private
sempre , compublic
ouprotected
acessórios de propriedade.
O que não deve fazer
// protected field should be private
protected int myVariable = 0;
// property should have protected setter
public int MyVariable { get { return myVariable; } }
// No public / private access modifiers
void Foo() { }
void Bar() { }
O que deve fazer
public int MyVariable { get; protected set; } = 0;
private void Foo() { }
public void Bar() { }
protected virtual void FooBar() { }
Usar chaves
Use sempre chaves após cada bloco de instruções e coloque-as na próxima linha.
O que não deve fazer
private Foo()
{
if (Bar==null) // <- missing braces surrounding if action
DoThing();
else
DoTheOtherThing();
}
O que não deve fazer
private Foo() { // <- Open bracket on same line
if (Bar==null) DoThing(); <- if action on same line with no surrounding brackets
else DoTheOtherThing();
}
O que deve fazer
private Foo()
{
if (Bar==true)
{
DoThing();
}
else
{
DoTheOtherThing();
}
}
Classes públicas, estruturas e enums devem ir em seus próprios arquivos.
Se a classe, struct ou enum pode ser tornada privada, então não há problema em ser incluído no mesmo arquivo. Essa inclusão evita problemas de compilação com o Unity e garante que a abstração de código adequada ocorra. Ele também reduz conflitos e alterações de quebra quando o código precisa ser alterado.
O que não deve fazer
public class MyClass
{
public struct MyStruct() { }
public enum MyEnumType() { }
public class MyNestedClass() { }
}
O que deve fazer
// Private references for use inside the class only
public class MyClass
{
private struct MyStruct() { }
private enum MyEnumType() { }
private class MyNestedClass() { }
}
O que deve fazer
MyStruct.cs
// Public Struct / Enum definitions for use in your class. Try to make them generic for reuse.
public struct MyStruct
{
public string Var1;
public string Var2;
}
MyEnumType.cs
public enum MuEnumType
{
Value1,
Value2 // <- note, no "," on last value to denote end of list.
}
MyClass.cs
public class MyClass
{
private MyStruct myStructreference;
private MyEnumType myEnumReference;
}
Encomende Enums para extensão apropriada.
É fundamental que, se um Enum for provável que seja estendido no futuro, ordene a inadimplência no topo do Enum. Essa ordenação garante que os índices Enum não sejam afetados com novas adições.
O que não deve fazer
public enum SDKType
{
WindowsMR,
OpenVR,
OpenXR,
None, <- default value not at start
Other <- anonymous value left to end of enum
}
O que deve fazer
/// <summary>
/// The SDKType lists the VR SDK's that are supported by the MRTK
/// Initially, this lists proposed SDK's, not all may be implemented at this time (please see ReleaseNotes for more details)
/// </summary>
public enum SDKType
{
/// <summary>
/// No specified type or Standalone / non-VR type
/// </summary>
None = 0,
/// <summary>
/// Undefined SDK.
/// </summary>
Other,
/// <summary>
/// The Windows 10 Mixed reality SDK provided by the Universal Windows Platform (UWP), for Immersive MR headsets and HoloLens.
/// </summary>
WindowsMR,
/// <summary>
/// The OpenVR platform provided by Unity (does not support the downloadable SteamVR SDK).
/// </summary>
OpenVR,
/// <summary>
/// The OpenXR platform. SDK to be determined once released.
/// </summary>
OpenXR
}
Finalizar nomes de Enum com "Tipo"
Os nomes Enum devem indicar claramente sua natureza usando o sufixo Tipo.
O que não deve fazer
public enum Ordering
{
First,
Second,
Third
}
public enum OrderingEnum
{
First,
Second,
Third
}
O que deve fazer
public enum OrderingType
{
First = 0,
Second,
Third
}
Rever o uso do Enum para Bitfields
Se houver a possibilidade de um enum exigir vários estados como um valor, por exemplo, Handedness = Left & Right. Em seguida, o Enum precisa ser decorado com BitFlags para permitir que ele seja usado corretamente
O dossiê Handedness.cs tem uma implementação concreta para isso
O que não deve fazer
public enum Handedness
{
None,
Left,
Right
}
O que deve fazer
[flags]
public enum HandednessType
{
None = 0 << 0,
Left = 1 << 0,
Right = 1 << 1,
Both = Left | Right
}
Melhores práticas, incluindo recomendações Unity
Algumas das plataformas-alvo deste projeto devem ter em consideração o desempenho. Com isso em mente, sempre tenha cuidado ao alocar memória em códigos frequentemente chamados em loops de atualização apertados ou algoritmos.
Encapsulamento
Sempre use campos privados e propriedades públicas se o acesso ao campo for necessário de fora da classe ou struct. Certifique-se de co-localizar o campo privado e a propriedade pública. Essa localização torna mais fácil ver, de relance, o que respalda a propriedade e que o campo é modificável por script.
Se você precisar ter a capacidade de editar seu campo no inspetor, é uma prática recomendada seguir as regras de Encapsulamento e serializar seu campo de suporte.
A única exceção a isso é para estruturas de dados que exigem que os campos sejam serializados pelo
JsonUtility
, onde uma classe de dados é necessária para ter todos os campos públicos para que a serialização funcione.
O que não deve fazer
public float MyValue;
O que deve fazer
// private field, only accessible within script (field is not serialized in Unity)
private float myValue;
O que deve fazer
// Enable private field to be configurable only in editor (field is correctly serialized in Unity)
[SerializeField]
private float myValue;
O que não deve fazer
private float myValue1;
private float myValue2;
public float MyValue1
{
get{ return myValue1; }
set{ myValue1 = value }
}
public float MyValue2
{
get{ return myValue2; }
set{ myValue2 = value }
}
O que deve fazer
// Enable field to be configurable in the editor and available externally to other scripts (field is correctly serialized in Unity)
[SerializeField]
[ToolTip("If using a tooltip, the text should match the public property's summary documentation, if appropriate.")]
private float myValue; // <- Notice we co-located the backing field above our corresponding property.
/// <summary>
/// If using a tooltip, the text should match the public property's summary documentation, if appropriate.
/// </summary>
public float MyValue
{
get{ return myValue; }
set{ myValue = value }
}
Utilizar for
em vez de foreach
quando possível
Em alguns casos, um foreach é necessário, por exemplo, ao fazer looping sobre um IEnumerable. Mas, para benefício de desempenho, evite foreach quando puder.
O que não deve fazer
foreach(var item in items)
O que deve fazer
int length = items.length; // cache reference to list/array length
for(int i=0; i < length; i++)
Armazene valores em cache e serialize-os na cena/pré-fabricados sempre que possível.
Com o HoloLens em mente, é melhor otimizar o desempenho e as referências de cache na cena ou pré-fabricados para limitar as alocações de memória em tempo de execução.
O que não deve fazer
void Update()
{
gameObject.GetComponent<Renderer>().Foo(Bar);
}
O que deve fazer
[SerializeField] // To enable setting the reference in the inspector.
private Renderer myRenderer;
private void Awake()
{
// If you didn't set it in the inspector, then we cache it on awake.
if (myRenderer == null)
{
myRenderer = gameObject.GetComponent<Renderer>();
}
}
private void Update()
{
myRenderer.Foo(Bar);
}
Cache referências a materiais, não chame o ".material" cada vez.
Unity criará um novo material cada vez que você usar ".material", que causará um vazamento de memória se não for limpo corretamente.
O que não deve fazer
public class MyClass
{
void Update()
{
Material myMaterial = GetComponent<Renderer>().material;
myMaterial.SetColor("_Color", Color.White);
}
}
O que deve fazer
// Private references for use inside the class only
public class MyClass
{
private Material cachedMaterial;
private void Awake()
{
cachedMaterial = GetComponent<Renderer>().material;
}
void Update()
{
cachedMaterial.SetColor("_Color", Color.White);
}
private void OnDestroy()
{
Destroy(cachedMaterial);
}
}
Como alternativa, use a propriedade "SharedMaterial" do Unity, que não cria um novo material cada vez que ele é referenciado.
Use a compilação dependente da plataforma para garantir que o Toolkit não interrompa a compilação em outra plataforma
- Use
WINDOWS_UWP
para usar APIs específicas da UWP e não Unity. Essa definição impedirá que eles tentem executar no Editor ou em plataformas não suportadas. Esta definição é equivalente eUNITY_WSA && !UNITY_EDITOR
deve ser usada a favor. - Use
UNITY_WSA
para usar APIs Unity específicas da UWP, como oUnityEngine.XR.WSA
namespace. Isso será executado no Editor quando a plataforma estiver definida como UWP e em aplicativos UWP criados.
Este gráfico pode ajudá-lo a decidir qual #if
usar, dependendo dos seus casos de uso e das configurações de compilação esperadas.
Definir | UWP IL2CPP | UWP .NET | Editor |
---|---|---|---|
UNITY_EDITOR |
False | False | True |
UNITY_WSA |
True | True | True |
WINDOWS_UWP |
True | True | Falso |
UNITY_WSA && !UNITY_EDITOR |
True | True | Falso |
ENABLE_WINMD_SUPPORT |
True | True | False |
NETFX_CORE |
False | True | False |
Prefira DateTime.UtcNow a DateTime.Now
DateTime.UtcNow é mais rápido do que DateTime.Now. Em investigações de desempenho anteriores, descobrimos que o uso de DateTime.Now adiciona uma sobrecarga significativa, especialmente quando usado no loop Update(). Outros acertaram na mesma questão.
Prefira usar DateTime.UtcNow, a menos que você realmente precise das horas localizadas (um motivo legítimo pode ser você querer mostrar a hora atual no fuso horário do usuário). Se você estiver lidando com horários relativos (ou seja, o delta entre alguma última atualização e agora), é melhor usar DateTime.UtcNow para evitar a sobrecarga de fazer conversões de fuso horário.