Tengo un juego terminado, que quiero rechazar en otras versiones. Estos serían juegos similares, con más o menos el mismo tipo de diseño, pero no siempre, básicamente las cosas pueden cambiar, a veces poco, a veces a lo grande.
Me gustaría que el código principal se versione por separado del juego, de modo que si digo que soluciono un error encontrado en el juego A, la solución estará presente en el juego B.
Estoy tratando de encontrar la mejor manera de manejar eso. Mis ideas iniciales son las siguientes:
- Crear un
engine
módulo / carpeta / lo que sea, que contenga todo lo que se pueda generalizar y sea 100% independiente del resto del juego. Esto incluiría algo de código, pero también activos genéricos que se comparten entre los juegos. - Coloque este motor en su propio
git
repositorio, que se incluirá en los juegos comogit submodule
La parte con la que estoy luchando es cómo administrar el resto del código. Digamos que tiene su escena de menú, este código es específico del juego, pero también la mayoría tiende a ser genérico y podría reutilizarse en otros juegos. No puedo ponerlo en el engine
, pero volver a codificarlo para cada juego sería ineficiente.
Tal vez usar algún tipo de variación de ramas git podría ser efectivo para manejar eso, pero no creo que esta sea la mejor manera de hacerlo.
¿Alguien tiene algunas ideas, experiencia para compartir o algo al respecto?
Respuestas:
Eso es exactamente lo que hago y funciona muy bien. Tengo un marco de aplicación y una biblioteca de renderizado, y cada uno de estos se trata como submódulos de mis proyectos. Encuentro SourceTree es útil cuando se trata de submódulos, ya que los maneja bien y no le permite olvidar nada, por ejemplo, si actualizó el submódulo del motor en el proyecto A, le notificará que retire los cambios en el proyecto B.
Con la experiencia viene el conocimiento de qué código debe estar en el motor frente a qué debe ser por proyecto. Sugiero que si está un poco inseguro, lo mantenga en cada proyecto por ahora. A medida que pase el tiempo, verá entre sus diversos proyectos lo que sigue siendo el mismo y luego podrá incorporarlo gradualmente en el código del motor. En otras palabras: duplica el código hasta el momento en que estés casi 100% seguro de que no está cambiando discretamente por proyecto, luego generalízalo.
Nota sobre control de origen y binarios
Solo recuerde que si espera que sus activos binarios cambien con frecuencia, es posible que no desee ponerlos en el control de fuente basado en texto como git. Solo digo ... hay mejores soluciones para binarios. Lo más simple que puede hacer por ahora para ayudar a mantener limpio y eficiente su repositorio "fuente de motor" es tener un repositorio "binarios de motor" separado que contenga solo binarios, que también incluye como submódulo en su proyecto. De esta manera, usted mitiga el daño de rendimiento causado a su repositorio "motor-fuente", que está cambiando todo el tiempo y por lo tanto necesita iteraciones rápidas: commit, push, pull, etc. Los sistemas de gestión de control de fuente como git operan en deltas de texto , y tan pronto como introduce binarios, introduce deltas masivos desde una perspectiva de texto, lo que finalmente le cuesta tiempo de desarrollo.Anexo GitLab . Google es tu amigo.
fuente
En algún momento, un motor DEBE especializarse y saber cosas sobre el juego. Iré por una tangente aquí.
Tomar recursos en un RTS. Un juego puede tener
Credits
yCrystal
otroMetal
yPotatoes
Debes usar los conceptos de OO correctamente y elegir max. reutilización de código. Está claro que
Resource
aquí existe un concepto de .Entonces decidimos que los recursos tienen lo siguiente:
int
)¡Tenga en cuenta que esta noción de a
Resource
podría representar asesinatos o puntos en un juego! No es muy poderoso.Ahora pensemos en un juego. Podemos tener moneda al negociar centavos y agregar un punto decimal a la salida. Lo que no podemos hacer son recursos "instantáneos". Como decir "generación de red eléctrica"
Digamos que agrega una
InstantResource
clase con métodos similares. Ahora está (comenzando) a contaminar su motor con recursos.El problema
Tomemos el ejemplo de RTS nuevamente. Supongamos que el jugador dona lo que sea
Crystal
a otro jugador. Quieres hacer algo como:Sin embargo, esto es realmente bastante desordenado. Es de uso general, pero desordenado. ¡Aunque ya impone una
resourceDictionary
que significa que ahora tus recursos tienen que tener nombres! Y es por jugador, por lo que ya no puede tener recursos del equipo.Esta es una abstracción "demasiado" (no es un ejemplo brillante, lo admito), en su lugar, debe llegar a un punto en el que acepte que su juego tiene jugadores y cristal, y luego puede tener (por ejemplo)
Con una clase
Player
y una claseCurrentPlayer
dondeCurrentPlayer
elcrystal
objeto mostrará automáticamente las cosas en el HUD para la transferencia / envío de donaciones.Esto contamina el motor con cristal, la donación de cristal, los mensajes en el HUD para los jugadores actuales y todo eso. Es más rápido y fácil de leer / escribir / mantener (lo cual es más importante, ya que no es significativamente más rápido)
Observaciones finales
El caso de los recursos no es brillante. Sin embargo, espero que todavía puedas ver el punto. En todo caso, he demostrado que "los recursos no pertenecen al motor", ya que lo que un juego específico necesita y lo que es aplicable a todas las nociones de recursos son cosas MUY diferentes. Lo que generalmente encontrarás son 3 (o 4) "capas"
creature
oship
osquad
. El uso de la herencia que obtendrá clases que abarcan las 3 capas (por ejemplo,Crystal
es unaResource
la cual es unGameLoopEventListener
ejemplo)Hacer un nuevo juego a partir de un motor viejo
Esto es MUY común. La fase 1 es extraer las capas 3 y 4 (y 2 si el juego es de un tipo TOTALMENTE diferente) Supongamos que estamos haciendo un RTS a partir de un viejo RTS. Todavía tenemos recursos, simplemente no cristal y demás, por lo que las clases base en las capas 2 y 1 todavía tienen sentido, todo ese cristal al que se hace referencia en 3 y 4 se puede descartar. Así lo hacemos Sin embargo, podemos verificarlo como referencia de lo que queremos hacer.
Contaminación en la capa 1
Esto puede suceder. La abstracción y el rendimiento son enemigos. UE4, por ejemplo, proporciona muchos casos de composición optimizados (por lo que si desea X e Y, alguien escribió un código que hace X e Y juntos muy rápido, sabe que está haciendo ambas cosas) y, como resultado, es REALMENTE bastante grande. Esto no es malo, pero lleva mucho tiempo. La capa 1 decidirá cosas como "cómo pasar los datos a los sombreadores" y cómo animar las cosas. Hacerlo de la mejor manera para su proyecto SIEMPRE es bueno. Simplemente intente y planifique para el futuro, reutilizar el código es su amigo, herede donde tenga sentido.
Clasificar capas
POR ÚLTIMO (lo prometo) no tengas demasiado miedo a las capas. Motor es un término arcaico de los viejos tiempos de las tuberías de funciones fijas donde los motores funcionaban casi de la misma manera gráfica (y como resultado tenían mucho en común) la tubería programable le dio vueltas y como tal la "capa 1" se contaminó con los efectos que los desarrolladores quisieran lograr. La IA era la característica distintiva (debido a la gran cantidad de enfoques) de los motores, ahora es la IA y los gráficos.
Su código no debe archivarse en estas capas. Incluso el famoso motor de Unreal tiene MUCHAS versiones diferentes, cada una específica para un juego diferente. Hay pocos archivos (aparte de las estructuras de datos similares) que no habrían cambiado. ¡Esto esta bien! Si quieres hacer un juego nuevo desde otro, te llevará más de 30 minutos. La clave es planificar, saber qué bits copiar y pegar y qué dejar atrás.
fuente
Mi sugerencia personal sobre cómo manejar el contenido que es una mezcla de genérico y específico es hacerlo dinámico. Tomaré la pantalla de tu menú como ejemplo. Si entendí mal lo que pedías, avísame qué querías saber y adaptaré mi respuesta.
Hay 3 cosas que (casi) siempre están presentes en una escena del menú: el fondo, el logotipo del juego y el menú en sí. Estas cosas suelen ser diferentes según el juego. Lo que puede hacer por este contenido es crear un MenuScreenGenerator en su motor, que toma 3 parámetros de objeto: BackGround, Logo y Menú. La estructura básica de estas 3 partes también es parte de su motor, pero su motor en realidad no dice cómo se generan estas partes, solo qué parámetros debe darles.
Luego, en su código de juego real, crea objetos para un BackGround, un Logo y un Menú, y lo pasa a su MenuScreenGenerator. Nuevamente, tu juego en sí no maneja cómo se genera el menú, eso es para el motor. Tu juego solo necesita decirle al motor cómo debería ser y dónde debería estar.
Esencialmente, su motor debe ser una API que el juego le dice qué mostrar. Si se hace correctamente, su motor debería hacer el trabajo duro y su juego solo debería decirle al motor qué activos usar, qué acciones tomar y cómo se ve el mundo.
fuente