Quando devo representar pontos e tamanhos como estruturas?

9

Como parte da minha estrutura simples de desenvolvimento de jogos em Ruby 2D, meus objetos de jogo têm posição (valores x e y) e tamanho (largura e altura).

class MyGameObject
  attr_accessor :x
  attr_accessor :y
  attr_accessor :width
  attr_accessor :height
  ...

Outra abordagem que vi foi tratar a posição como uma Pointestrutura e o tamanho como uma Sizeestrutura:

Point = Struct.new(:x, :y)
Size = Struct.new(:width,:height)

class MyGameObject
  attr_accessor :position   # Point instance
  attr_accessor :size       # Size instance
  ...

Alguns frameworks usam o primeiro (acho que GDX, Gosu ...). Outros usam o último (cocos2d-iphone). O problema é que não está totalmente claro para mim as vantagens e desvantagens de ambos os comportamentos (no desenvolvimento de jogos) - não sei por que alguns frameworks escolheram um e não o outro.

Há diferenças significativas que devo considerar?

Óxido
fonte

Respostas:

8

Alguns até usam a Rectangleclasse:

class Rectangle
{
    float x, y, w, h;
}
class GameObject
{
    Rectangle dimensions;
}

É apenas uma escolha de design, isso realmente não importa. Se você estiver criando seu próprio código, faça o que você sentir mais confortável. Se você estiver usando alguma API, estrutura ou mecanismo ou editando / modificando um jogo, tente ser consistente com o restante do código e faça o mesmo que o código próximo.

Eu diria para ir com dois vetores separados, como este:

class Vector2
{
    float x, y;
    //helper functions like operator overload, dot, length, distance, etc.
}

class GameObject
{
    Vector2 position;
    Vector2 size;
    Vector2 direction;
}

Dessa forma, você pode lidar com coisas como ângulo entre objetos com mais facilidade, da seguinte maneira:

GameObject foe;
GameObject player;
Vector2 dist = player.position - foe.position;
dist.normalize();
float angleBetween = acos(dist.dot(foe.direction));

em vez de precisar extrair os vetores de retângulos ou criá-los a partir de carros alegóricos simples.

Gustavo Maciel
fonte
2

Em geral, sempre use uma estrutura de dados separada. Isso torna seu código significativamente mais fácil de usar, ler e manter. Quantas vezes você precisa xseparar-se yversus quantas vezes você precisa calcular um deslocamento vetorial, comprimento, produto escalar etc.? Apontar para o caso comum; torne o código com o qual você escreve repetidamente mais fácil de trabalhar, o que, para pontos e vetores, normalmente será operações em todo o "objeto", em vez de operações em componentes individuais.

A única exceção que eu faria é que, depois de criar um perfil adequado , você achará a estrutura separada muito lenta. Idiomas como Ruby não tornam possível o "valor por valor" definido pelo usuário e, na minha experiência, ter pontos e vetores como tipos "por referência" é uma dor às vezes e pode ser uma desaceleração maciça sem atenção cuidadosa aos temporários . Pode ser vantajoso, por exemplo, ter duas matrizes de entradas, uma para xe outra para y, e depois ter uma única matriz de Pointobjetos; é muito mais trabalhoso, no entanto, faça isso apenas se você tiver métricas de desempenho válidas para indicar que vale a pena!

Sean Middleditch
fonte
+1, mas eu gostaria de mencionar que a pré-otimização é a raiz de todo mal.
Gustavo Maciel
3
@GustavoMaciel: de fato. Fato: Cruella de Vil estava apenas tentando otimizar seu guarda-roupa antes de limpar sua personalidade e ver onde isso a levou.
Sean Middleditch