¿Cuándo debo representar puntos y tamaños como estructuras?

9

Como parte de mi simple marco de desarrollo de juegos Ruby 2D, mis objetos de juego tienen posición (valores x e y) y tamaño (ancho y alto).

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

Otro enfoque que he visto fue tratar la posición como una Pointestructura y el tamaño como una Sizeestructura:

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

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

Algunos marcos usan el primero (creo que GDX, Gosu ...). Otros usan este último (cocos2d-iphone). El problema es que no tengo del todo claras las ventajas y desventajas de ambos comportamientos (en el desarrollo del juego). No sé por qué algunos marcos eligieron uno y no el otro.

¿Hay diferencias significativas que debería considerar?

Óxido
fuente

Respuestas:

8

Algunos incluso usan la Rectangleclase:

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

Es solo una elección de diseño, realmente no importa. Si está haciendo su propio código, haga que se sienta más cómodo. Si está utilizando alguna API, marco o motor, o editando / modificando un juego, intente ser coherente con el resto del código y haga lo mismo que está en el código cercano.

Yo diría que vaya con dos vectores 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;
}

De esta manera, puede manejar cosas como el ángulo entre objetos más fácilmente, así:

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

en lugar de tener que extraer los vectores de los rectángulos, o crearlos a partir de flotadores simples.

Gustavo Maciel
fuente
2

En general, use siempre una estructura de datos separada. Hace que su código sea significativamente más fácil de usar, leer y mantener. ¿Con qué frecuencia necesita xsepararse de yvs con qué frecuencia necesita calcular un desplazamiento vectorial, longitud, producto de puntos, etc.? Apunta al caso común; hacer que el código que escriba repetidamente sea más fácil de trabajar, lo que para puntos y vectores, generalmente será operaciones en todo el "objeto" en lugar de operaciones en componentes individuales.

La única excepción que haría es que, después de realizar un perfil adecuado , encuentra que la estructura separada es demasiado lenta. Los lenguajes como Ruby no hacen posible un "valor por valor" simple definido por el usuario y, en mi experiencia, tener puntos y vectores como tipos "por referencia" es a la vez un dolor y puede ser una desaceleración masiva sin una cuidadosa atención a los temporales. . Puede ser ventajoso, por ejemplo, tener dos matrices de entradas, una para xy otra para y, y luego tener una única matriz de Pointobjetos; Sin embargo, es mucho más difícil trabajar con él, así que solo haga esa división si tiene métricas de rendimiento válidas para indicar que vale la pena.

Sean Middleditch
fuente
+1, pero me gustaría mencionar que la preoptimización es la raíz de todo mal.
Gustavo Maciel
3
@GustavoMaciel: de hecho. Hecho: Cruella de Vil solo estaba tratando de optimizar su vestuario antes de limpiar su personalidad, y mira a dónde la llevó.
Sean Middleditch