Qual desses dois códigos é 'melhor'? Fazendo uma variável local ou uma variável de classe?


11

Estou fazendo mais jogos e fazendo mais perguntas estúpidas.

Espero que este seja muito breve. Estou criando uma classe muito básica que apenas move um objeto Player aplicando força a um corpo rígido, mas isso me fez pensar: devo fazer uma referência de classe à rb ou apenas uma variável local dentro de Atualizar todos os quadros? (tendo em mente que ele já existe na classe pai da unidade Monobehaviour.GameObject).

Eu estou querendo saber se fazer muitas variáveis ​​locais atrasaria o loop como um todo (por local, quero dizer dentro da própria função e não no topo da classe - espero estar usando o termo correto).

Aqui está o que eu quero dizer, as duas maneiras que eu estava pensando em fazer isso:

public class Player : MonoBehaviour {

private void FixedUpdate()
{
    Rigidbody rb = GetComponent<Rigidbody>();

    float v = Input.GetAxis("Vertical");

    rb.AddForce(v * rb.transform.forward * Const.walkForce);
}
}

ou...

public class Player : MonoBehaviour {
Rigidbody rb;

private void Awake()
{
    rb = GetComponent<Rigidbody>();
}

private void FixedUpdate()
{
    float v = Input.GetAxis("Vertical");

    rb.AddForce(v * rb.transform.forward * Const.walkForce);
}
}

4
Isso parece mais uma pergunta para a revisão de código SE.
Orphevs

1
Você também pode criar uma propriedade de classe float va.
Chad

Provavelmente, no final, vou realmente Chad, porque vou usá-lo em dois métodos dentro da classe. Na verdade, era apenas um código simples para obter a pergunta sobre variáveis ​​locais versus variáveis ​​de classe sem inchar com muito código. Estou realmente gostando de manter as variáveis ​​locais (e 'fora do caminho', como estão onde!), Mas é claro que devo me certificar de que não comece a duplicar as coisas em vez de ter uma variável de classe para cada uma.
Big T Larrity

Um trecho de código não é 'um código'. Perguntar sobre 'qual código é melhor' faz você parecer um amador.
Route de milhas

1
eu sou um amador, então tudo bem comigo obrigado Miles
Big T Larrity

Respostas:


25

Em geral, descobri que você deve escopo os dados da maneira mais estreita possível para começar e ampliar o escopo conforme você precisar. Isso significa que, se você pode torná-la uma variável local em vez de um membro, provavelmente deve começar por aí.

Isso ocorre porque um escopo mais restrito reduz o número de locais no código em que você deve raciocinar sobre esses dados e, portanto, reduz o número de locais em que você pode raciocinar incorretamente (o que leva a erros).

Na verdade, declarar apenas variáveis ​​locais nunca será praticamente uma preocupação de desempenho: elas são baratas e os compiladores modernos podem até otimizar os "extras".

Inicializá-los pode ser uma preocupação; no seu caso, seu corpo rígido é sempre pesquisado via GetComponent, o que tem um custo diferente de zero. Se você sabe que o componente do corpo rígido não será alterado para esse objeto de jogo específico, procure-o uma vez e armazene o resultado em uma variável de membro e evite um pouco de sobrecarga por chamada.

É improvável que a sobrecarga por chamada seja significativa nesse caso, mas com o tempo, isso pode resultar em muitos componentes. Você deseja aplicar um criador de perfil para ter certeza.

Então, para resumir: em geral, o padrão é tornar as coisas o mais local possível, mas nesse caso é provavelmente razoável criar rbum membro para que você possa realizar a pesquisa uma vez Awakee evitar fazer todas as FixedUpdatechamadas.


1
obrigado Josh, eu senti que seria melhor inicializar a rb apenas uma vez, e muito obrigado por explicar claramente o porquê. É bom saber com certeza, você vê que eu não tinha 100% de certeza de que o GetComponent contava como inicializá-lo a cada vez, ou simplesmente 'pesquisando' no Monobehaviour. Mas agora eu entendo tantas obrigado pela resposta útil super-rápida
Big T Larrity

1
O @SuperMegaBroBro GetComponent é muito rápido - seria difícil fazer qualquer tipo de pesquisa com velocidade comparável. A menos que você tenha dados de desempenho que sugiram que isso é um problema, siga a abordagem "manter as coisas locais". Você sempre pode otimizá-lo mais tarde. Consulte answers.unity.com/questions/185164/… Não esqueça que o cache também não é gratuito - se você armazenar em cache todos os GetComponentjogos do seu jogo, provavelmente será uma perda líquida. A medida. Identifique onde as otimizações valem a pena. Concentre-se em fazer um grande jogo :)
Luaan

1
A principal essência que você deve tirar desta resposta (o que é bastante bom) é: Se você deseja procurar um código que seja mais fácil de raciocinar, testar e garantir que ele esteja livre de erros, use a variável local. Mas, como sempre, às vezes precisamos fazer sacrifícios para aperfeiçoar o código por razões de desempenho, para que um aluno possa ser apropriado (mas primeiro perfil, não basta fazer otimização prematura).
precisa

muito obrigado pessoal, especialmente Luaan, porque eu estava pensando sobre esse problema de 'cache' enquanto escrevia a pergunta original (mas eu realmente não sabia como dizer isso). Certamente adotarei a abordagem 'local' o máximo possível. obrigado por toda a grande ajuda, como sempre.
Big T Larrity

2

A resposta de Josh Petrie é muito boa - aqui está uma perspectiva complementar.

Quando você trabalha com código no qual entende o domínio razoavelmente bem, pode definir variáveis ​​de escopo para onde elas fazem sentido.

Por exemplo, se eu tenho uma Personclasse com um waveGoodbyemétodo, é possível que a minha turma não tinha um handobjeto antes e então eu poderia declarar-lo localmente no waveGoodbye. Agora, aqui é óbvio que uma pessoa tem uma mão, então você pode naturalmente declara-la como membro Personsem pensar nisso, mas o mesmo problema se aplica.

Se você declarar handlocalmente, mais tarde poderá adicionar um karateChopmétodo que também requer uma mão. É quando declarar variáveis ​​localmente pode se tornar problemático - porque os desenvolvedores juniores costumam voltar a copiar / colar a declaração waveGoodbyee agora você tem o mesmo conceito localizado em dois pontos. Quaisquer alterações a hand, em seguida, precisam ser modificados em ambos os lugares e assim começa uma formiga colina bug.

Então tudo em tudo,

  1. Se você estiver confiante no posicionamento da sua declaração, coloque-a no ponto em que faz sentido.

  2. Se você não estiver confiante, inicie o local e refatore quando sentir o cheiro da reutilização de código.

Edit: Ah, e não cometa o mesmo erro que tenho de gastar muito tempo tentando descobrir onde escopo suas declarações. É difícil entender a estrutura dos seus dados antecipadamente e, à medida que você escreve seu código, a estrutura tem uma maneira de se revelar.


2
Também ter coisas naturalmente ordenada, como todo Persondeve ter o membro hand se sua relevante na aplicação, muitas vezes ajuda outros desenvolvedores (na maioria das vezes você 6 meses mais tarde) para entender melhor o código. Nesse caso, parece lógico ter um Rigidbodymembro seu Playere, digo mais, mesmo que isso implique em pior desempenho. Em vídeo-jogos que é um ponto relevante considerar, mas acho que em código , para ficar claro é muitas vezes mais importante
alseether

1
excelentes respostas obrigado pessoal. Não estou tentando parecer um "sabe tudo", mas todas essas respostas acabaram de reafirmar o que eu estava pensando, então, pela primeira vez, estou muito feliz e fazendo um bom progresso em meus jogos. No momento, estou fazendo um jogo de futebol em 3D com animações apropriadas e tudo, dando passos reais: D em breve estarei aqui precisando de ajuda sobre como fazer 2 jogadores e ouso dizer multiplayer online: D divirtam-se e obrigado novamente!
Big T Larrity
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.