Diretrizes de codificação
Este documento descreve as diretrizes de codificação recomendadas do World Locking Tools para 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 para o Unity devem ter o cabeçalho de licença padrão anexado, exatamente conforme 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 de licença serão rejeitados.
Cabeçalhos de resumo de função/método
Todas as classes, structs, enumerações, funções, propriedades e campos públicos postados devem ter sua finalidade e uso descritos, exatamente conforme 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 divulgada adequadamente para todas as classes, métodos e propriedades.
Todos os arquivos de script enviados sem marcas de resumo adequadas serão rejeitados.
Regras de namespace
Todas as classes e extensões devem ter o escopo definido pelo namespace, selecionado adequadamente dos namespaces abaixo.
Microsoft.MixedReality.WorldLocking.Core – código básico que atende ao serviço básico do World Locking Tools.
Microsoft.MixedReality.WorldLocking.Tools – recursos opcionais que complementam o desenvolvimento com o World Locking Tools. As visualizações de diagnóstico e implementações de linha de base de manipuladores de eventos de aplicativo são alguns exemplos.
Microsoft.MixedReality.WorldLocking.Examples – implementações específicas que demonstram como usar recursos do World Locking Tools e os benefícios obtidos.
Os recursos relacionados em um dos namespaces acima podem ser agrupados estendendo a um novo namespace secundário.
O que fazer
namespace Microsoft.MixedReality.WorldLocking.Examples.Placement
{
// Interface, class or data type definition.
}
A omissão do namespace para uma interface, classe ou tipo de dados fará com que a alteração seja bloqueada.
Espaços versus Guias
Certifique-se de usar quatro espaços em vez de guias ao contribuir com este projeto.
Além disso, certifique-se de que os espaços sejam adicionados para funções condicionais/loop como if/while/for
O que não 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 fazer
private Foo()
{
if (Bar==null)
{
DoThing();
}
while (true)
{
Do();
}
}
Espaçamento
Não adicione espaços entre colchetes e parênteses:
O que não fazer
private Foo()
{
int[ ] var = new int [ 9 ];
Vector2 vector = new Vector2 ( 0f, 10f );
}
O que fazer
private Foo()
{
int[] var = new int[9];
Vector2 vector = new Vector2(0f, 10f);
}
Convenções de nomenclatura
Sempre use PascalCase
para propriedades públicas/protegidas/virtuais e camelCase
para propriedades e campos privados.
As estruturas de dados que exigem que os campos sejam serializados por
JsonUtility
são a única exceção.
O que não fazer
public string myProperty; // <- Starts with a lower case letter
private string MyProperty; // <- Starts with an uppercase case letter
O que 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 do Unity devem ser
private
por padrão, a menos seja necessário substituí-los em uma classe derivada. Nesse caso,protected
deve ser usado.
Os campos devem ser sempre
private
, compublic
ouprotected
acessadores de propriedade.
O que não 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 fazer
public int MyVariable { get; protected set; } = 0;
private void Foo() { }
public void Bar() { }
protected virtual void FooBar() { }
Usar chaves
Sempre use chaves após cada bloco de instrução e coloque-as na linha seguinte.
Não
private Foo()
{
if (Bar==null) // <- missing braces surrounding if action
DoThing();
else
DoTheOtherThing();
}
O que não 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 fazer
private Foo()
{
if (Bar==true)
{
DoThing();
}
else
{
DoTheOtherThing();
}
}
Classes, structs e enumerações públicas devem ficar em seus próprios arquivos.
Se a classe, struct ou enumeração puder ser privada, ela pode ser incluída no mesmo arquivo. Essa inclusão evita problemas de compilação com o Unity e garante a abstração de código adequada. Também reduz conflitos e alterações significativas quando o código precisa ser alterado.
O que não fazer
public class MyClass
{
public struct MyStruct() { }
public enum MyEnumType() { }
public class MyNestedClass() { }
}
O que fazer
// Private references for use inside the class only
public class MyClass
{
private struct MyStruct() { }
private enum MyEnumType() { }
private class MyNestedClass() { }
}
O que 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;
}
Ordenar enumerações para a extensão adequada.
Se for provável que uma enumeração seja estendida no futuro, é fundamentar ordenar padrões na parte superior da enumeração. Essa ordenação garante que os índices de enumerações não sejam afetados pelas inclusões.
O que não fazer
public enum SDKType
{
WindowsMR,
OpenVR,
OpenXR,
None, <- default value not at start
Other <- anonymous value left to end of enum
}
O que 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
}
Encerrar os nomes das enumerações com "Tipo"
Os nomes das enumerações devem indicar claramente sua natureza através do sufixo Tipo.
O que não fazer
public enum Ordering
{
First,
Second,
Third
}
public enum OrderingEnum
{
First,
Second,
Third
}
O que fazer
public enum OrderingType
{
First = 0,
Second,
Third
}
Revisar o uso de enumerações para Bitfields
Se houver a possibilidade de um enum exigir vários estados como um valor, por exemplo, Handedness = Left & Right. A enumeração precisa ser decorada com BitFlags para ser usada corretamente
O arquivo Handedness.cs possui uma implementação concreta para esse caso
O que não fazer
public enum Handedness
{
None,
Left,
Right
}
O que fazer
[flags]
public enum HandednessType
{
None = 0 << 0,
Left = 1 << 0,
Right = 1 << 1,
Both = Left | Right
}
Práticas recomendadas, incluindo recomendações do Unity
Algumas plataformas de destino deste projeto precisam levar o desempenho em consideração. Neste sentido, sempre tenha cuidado ao alocar memória no código chamado com frequência em algoritmos ou loops de atualização restritos.
Encapsulamento
Sempre use campos privados e propriedades públicas se o acesso ao campo for necessário de fora da classe ou struct. Colocalize o campo privado e a propriedade pública. A localização facilita a visualização do suporte da propriedade e se o campo pode ser modificado pelo script.
Se a capacidade de editar o campo no inspetor for necessária, é uma prática recomendada seguir as regras de Encapsulamento e serializar o campo de suporte.
As estruturas de dados que exigem que os campos sejam serializados pelo
JsonUtility
são a única exceção a essa regra, onde uma classe de dados precisa ter todos os campos públicos para que a serialização funcione.
O que não fazer
public float MyValue;
O que fazer
// private field, only accessible within script (field is not serialized in Unity)
private float myValue;
Fazer
// Enable private field to be configurable only in editor (field is correctly serialized in Unity)
[SerializeField]
private float myValue;
Não
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 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 }
}
Use for
em vez de foreach
quando possível
Em alguns casos, um foreach é necessário, por exemplo, ao executar um loop em um IEnumerable. Mas, para benefício de desempenho, evite foreach quando possível.
O que não fazer
foreach(var item in items)
O que fazer
int length = items.length; // cache reference to list/array length
for(int i=0; i < length; i++)
Armazene os valores em cache e os serialize na cena/pré-fabricação sempre que possível.
Com o HoloLens em mente, é melhor otimizar as referências de desempenho e cache na cena ou pré-fabricação para limitar as alocações de memória de runtime.
O que não fazer
void Update()
{
gameObject.GetComponent<Renderer>().Foo(Bar);
}
O que 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);
}
O cache faz referência a materiais, não chame ".material" sempre.
O Unity criará um novo material sempre que você usar ".material", o que causará uma perda de memória se não for limpo corretamente.
O que não fazer
public class MyClass
{
void Update()
{
Material myMaterial = GetComponent<Renderer>().material;
myMaterial.SetColor("_Color", Color.White);
}
}
O que 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 sempre que ele é referenciado.
Use a compilação dependente de plataforma para garantir que o kit de ferramentas não interrompa a compilação em outra plataforma
- Use
WINDOWS_UWP
para usar APIs não Unity específicas da UWP. Essa definição impedirá que eles tentarem ser executados no Editor ou em plataformas sem suporte. Essa definição é equivalente aUNITY_WSA && !UNITY_EDITOR
e deve ser usada em seu favor. - Use
UNITY_WSA
para usar APIs do Unity específicas da UWP, como o namespaceUnityEngine.XR.WSA
. Isso será executado no Editor quando a plataforma for definida como UWP e em aplicativos UWP integrados.
Este gráfico pode ajudá-lo a decidir qual #if
usar, dependendo dos casos de uso e das configurações de compilação esperadas.
Definir | UWP IL2CPP | UWP .NET | Editor |
---|---|---|---|
UNITY_EDITOR |
Falso | Falso | True |
UNITY_WSA |
True | True | True |
WINDOWS_UWP |
True | True | False |
UNITY_WSA && !UNITY_EDITOR |
True | True | False |
ENABLE_WINMD_SUPPORT |
True | True | Falso |
NETFX_CORE |
Falso | True | Falso |
Prefira DateTime.UtcNow em vez de DateTime.Now
DateTime.UtcNow é mais rápido que DateTime.Now. Verificamos em investigações de desempenho anteriores que o uso de DateTime.Now adiciona sobrecarga significativa, especialmente quando usado no loop Update(). Outras pessoas encontraram o mesmo problema.
Prefira usar DateTime.UtcNow, a menos que você realmente precise dos horários localizados (um dos possíveis motivos pode ser quando você quiser mostrar a hora atual no fuso horário do usuário). Se você estiver lidando com horas relativas (ou seja, o delta entre alguma última atualização e agora), é melhor usar DateTime.UtcNow para evitar a sobrecarga de conversões de fuso horário.