¿Cómo hacer un juego sin OOP? [cerrado]


10

Actualmente estoy estudiando desarrollo de juegos y practicando hacer juegos.

Yo uso mucha OOP en mis juegos. Por ejemplo, cada misil que se dispara es una instancia de un Missileobjeto y se agrega a una lista de Missileobjetos. Cada tanque en el juego es un Tankobjeto. Etc.

Todo el diseño del programa se basa en esto. Por ejemplo, tener una lista de Missileobjetos me permite cada cuadro mover los misiles, dibujarlos, etc. Y tener una instancia de un Tankobjeto para cada tanque me permite verificar si cada tanque choca con algo, etc.

Me resulta difícil imaginar cómo se podría programar un juego (que es más complejo que Pac-Man) en un lenguaje que no sea OO. (Sin faltarle el respeto a los programadores que no son OO, por supuesto). No solo en términos de cuánto tiempo llevará, sino principalmente en términos de cómo se podría diseñar un juego de esta manera.

No puedo imaginar diseñar un juego sin usar programación orientada a objetos, porque toda mi comprensión de cómo diseñar un programa de juego se basa en OOP.

Me gustaría preguntar: Hoy, ¿hay algún juego que no esté programado usando OOP, de manera similar a lo que describí anteriormente? ¿Hay algún juego 'profesional' que no use OOP como un factor importante en el proceso de desarrollo?

Si es así, ¿podría darme una idea de cómo, por ejemplo, se podría implementar la detección de colisión entre un tanque y N número de misiles, sin OOP?


66
¿Es esta una pregunta filosófica? Incluso si no llama a sus tanques "objetos", probablemente querrá "entidades", "actores", "agentes", "estructuras" o simplemente algún otro nombre para la misma idea, que es una colección de atributos y comportamientos que forman una cosa cuboide giratoria con una torreta que puede disparar cosas, llamada tanque. Los lenguajes de programación tendrán diferentes formas de formalizar esta misma idea, pero al final, será un tanque.
Anko

Muchos juegos usan un sistema basado en componentes como se describe en esta respuesta: gamedev.stackexchange.com/a/31491/9366
John McDonald

Esto es extremadamente amplio (lo que posiblemente podrías arreglar al reducir el alcance) y no es realmente específico para el desarrollo de juegos (ya que construir software sin técnicas OO no es algo que un desarrollador de juegos te dé una mejor respuesta que cualquier otro desarrollador de software), lo que lo hace fuera de tema aquí, me temo.

Puede ser adecuado para StackOverflow, o puede consultar el centro de ayuda para encontrar una selección de sitios que son específicos del desarrollo del juego (como GDNet) que permitirían este tipo de tema amplio y orientado a la discusión. ¡Buena suerte!

Respuestas:


16

No puedo imaginar diseñar un juego sin usar programación orientada a objetos, porque toda mi comprensión de cómo diseñar un programa de juego se basa en OOP.

Entonces, probablemente sea bueno para usted intentar escribir algunos programas en un estilo que no sea OO. Incluso si descubres que esto no es pragmático para ti, probablemente aprenderás mucho en el camino que te ayudará en el futuro.

El estilo OO es bastante adecuado para los juegos porque los juegos casi siempre se tratan de la manipulación de objetos con estado. Un rayo láser golpea al robot y el estado del robot cambia mientras su identidad permanece igual.

Sin embargo, es posible programar juegos en un estilo funcional . En un estilo funcional, el estado no cambia per se. Los objetos son inmutables. En lugar de cambiar objetos, te preguntas cómo sería diferente el universo si yo cambiara esto. y luego produce un universo completamente nuevo que tiene la propiedad modificada. Por supuesto, puede reutilizar una gran parte del universo existente anteriormente porque es inmutable .

En la programación funcional, cada función debe calcular su valor de retorno únicamente a partir de la información transmitida; no hay lectura del "estado global".

Si hace esto, el problema fundamental que tendrá que resolver es que cada actualización no es destructiva . Cuando el láser golpea al robot, no cambia el estado del robot. En última instancia, calcula un universo completamente nuevo idéntico al antiguo universo, excepto que el robot tiene un estado diferente; si necesitas ese viejo universo, sigue ahí, sin cambios.

Esta serie de artículos de blog tiene más ideas sobre escribir juegos en un estilo funcional:

http://prog21.dadgum.com/23.html

Este artículo aborda específicamente su pregunta "la cáscara golpea un tanque":

http://prog21.dadgum.com/189.html

De hecho, solo lea todo el blog. Hay cosas buenas allí y los artículos son cortos.


12

Cualquier programa orientado a objetos se puede refactorizar a un programa de procedimiento reemplazando todas las clases con estructuras y convirtiendo todas las funciones miembro en funciones independientes que toman el objeto que sería thisun argumento.

Entonces

 missile.setVelocity(100);

se convierte

 setMissileVelocity(missile, 100);

o cuando esa función es trivial, simplemente lo haces

 missile.velocity = 100;

La principal diferencia entre la programación orientada a objetos y la programación de procedimientos es cómo trata sus datos. En OOP, los datos son inteligentes . Se maneja y se manipula a sí mismo. Pero en la programación de procedimientos, los datos son tontos . No hace nada por sí solo y necesita ser manipulado desde el exterior.

Cuando incluso considera estructuras demasiado orientadas a objetos, puede reemplazar una matriz de estructuras con múltiples matrices, una para todo lo que sería una variable de un misil. Entonces

struct Missile {
     int x;
     int y;
     int velocity;
}

Missile missiles[256];

se convierte

int missileX[256];
int missileY[256];
int missileVelocities[256];

En este diseño, una función que realiza una operación que involucra múltiples atributos en el mismo misil ahora tomaría un índice de matriz en lugar de una referencia a una estructura. Su implementación se vería así:

function updateMissilePosition(int index) {
     missileX[index] += missileVelocity[index];
}

1
Pero missilees una instancia de un objeto. En no OOP, no hay instancias, ¿estoy en lo correcto? Si es así, ¿cómo podría establecer setMissileVelocity (misil, 100)?
user3150201

1
@ user3150201 No estás del todo correcto. La mayoría de los lenguajes que no son OOP (y yo diría que cualquiera que sea adecuado para el desarrollo de juegos serios) admite estructuras. Una estructura es como una clase, solo que no contiene nada excepto variables públicas. Por lo que permitirá crear un tipo Missile, que es una estructura con varios campos, como x, y, angley velocity.
Philipp

@ user3150201 Respuesta actualizada con una sección sobre cómo hacerlo sin estructuras.
Philipp

Buena respuesta Philipp, aunque, no entiendo por qué uno no quiere programar orientado a objetos. Es realmente difícil leer idiomas que no sean OOP, y puede ser frustrante. El código puede convertirse en un desastre en poco tiempo.
Zhafur

2
@Zhafur Usted es consciente de que su afirmación es un cebo masivo, ¿verdad?
Philipp

6

Lo hago de la siguiente manera:

  • Todas las clases / métodos de OOP tienen acceso a this. Para utilizar thisen un enfoque que no sea OO, simplemente pase en cualquier caso (vea el siguiente punto) this, como primer parámetro.
  • Ahora, en cuanto a las instancias, puede pasar structs a sus funciones como this, pero creo que la mejor manera de lograr un buen rendimiento de caché para objetos que son prolíficos, como entidades o partículas, es simplemente pasar un único índice a varias matrices de primitivas o pequeño structs. Por lo tanto, este índice se utiliza para cada miembro de datos individual de la clase original. Entonces, por ejemplo, si tuvieras

...

class Entity //let's say you had 100 instances of this
{
   int a;
   char b;
   function foo() 
   {
      .../*can access 'this' herein*/
   }
}

Lo reemplazarías con

int a[100];
char b[100];
function foo(int index);

De modo que ahora está pasando un índice a la función para obtener lo que normalmente sería this.

Tenga en cuenta que es posible que desee utilizar matrices de primitivas como las anteriores o matrices de structs, dependiendo de la mejor manera de intercalar sus datos para una buena localidad de caché (localidad de referencia). Por supuesto, el rendimiento de caché decente depende de mucho más que esto, en particular, en qué idioma / plataforma está escribiendo su código, pero incluso en lenguajes asignados dinámicamente basados ​​en VM como Java, las grandes matrices lineales de primitivas tienden a muestra mejores características de rendimiento que las instancias de objeto. La razón principal de esto es que se accede a los objetos por referencia y esto significa que está saltando por toda la memoria para acceder a los datos, lo que es ineficiente en comparación con el acceso contiguo a las primitivas desde una gran matriz.

Para obtener más información sobre la creación de entidades, etc., como un conjunto de estructuras o primitivas, consulte Evolve your Hierarchy de Mick West .


0

Además de las respuestas existentes, es posible que desee saber cómo hacer polimorfismo en un lenguaje de procedimiento.

Hay dos enfoques:

Almacenar el tipo

En este caso, la estructura tiene un campo para el identificador de tipo, probablemente una enumeración, que se verifica mediante una switchinstrucción cuando es necesario realizar una acción específica de tipo.

La otra forma es:

Almacenamiento de punteros de función

No mencionó en qué lenguaje de programación tiene experiencia, pero en varios idiomas también se denominan devoluciones de llamada, delegados, eventos o funciones de alto orden o simplemente objetos de función.

En este caso, no almacenará un tipo, sino que almacenará un puntero / referencia a una función que realiza la acción particular. Cuando se debe realizar una acción específica de tipo, simplemente llame a esta función. Este se parece mucho a los métodos virtuales comunes.

Al permitir configurar cada función de forma independiente, obtiene el patrón de estrategia libre.


En cuanto a su último párrafo con la detección de colisión. Creo que probablemente tienes múltiples tipos de tanques y tienes varios tipos de misiles, y cada combinación puede tener un resultado diferente cuando chocan. Si esto es lo que busca, tiene un problema que aún no se resuelve ni siquiera con los lenguajes de OOP: envío múltiple y métodos múltiples que pueden tener múltiples thisparámetros de diferentes tipos. Para este problema hay nuevamente dos alternativas:

  • Interruptores anidados para cada combinación de tanque y misil.
  • Arreglos de despacho bidimensionales, que contienen punteros a funciones para cada combinación de tanque y misil.
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.