¿Qué es el "código lógico del juego"?

50

Estoy usando C # / XNA y me han dicho varias veces que no mezcle el código de actualización con el código de dibujo, ¡y estoy seguro de que no lo soy! Pero, ¿podría alguien describir qué es exactamente el "código lógico"?

Como se ve aquí: http://blogs.msdn.com/b/shawnhar/archive/2007/07/25/understanding-gametime.aspx

[...] asegúrate de poner toda la lógica del juego dentro del método de actualización (¡no en Draw!) y todo funcionará a una velocidad constante y agradable.

Lo pregunto ya que la velocidad de mi juego fluctúa en relación con el FPS. Slow FPS equivale a objetos que se mueven lentamente y viceversa. Y sí, estoy incluyendo el position += speed * (float)gt.ElapsedGameTime.TotalSeconds;código esperado .

Esta es probablemente una gran pregunta para los novatos, pero solo quiero ser absolutamente claro en la definición de esto.

Chico tímido
fuente
Creo que quisiste decir position = speed * ...TotalSeconds. Note que =no lo es +=. Si fuera +=tal como lo escribió, su posición saldría volando de la pantalla casi instantáneamente.
DrZ214
Tengo un código que se ve como 'posición + = dirección * velocidad * ... TotalSeconds' y eso funciona muy bien. Puede que haya escrito mal algo, pero position = speed lo asignaría a cada actualización. Su camino puede funcionar, pero tengo mi código funcionando así. (Tenga en cuenta que la dirección está normalizada)
Shyy Guy
Pensé que gt.ElapsedGameTime.TotalSecondses el número de segundos transcurridos desde el inicio del programa (juego). Si está multiplicando su velocidad por eso, luego de 5 segundos de juego, su velocidad será 5 veces más rápida (excepto el caso especial donde la velocidad se establece en 0). No estoy seguro de qué más podría tener que haga que eso sea falso, pero estoy intrigado.
DrZ214
1
Ajá, es desde la última actualización. gamedev.stackexchange.com/questions/67968/…
Shyy Guy
2
Fascinante, nunca lo habría adivinado. Nunca tuve necesidad de tal cosa en segundos, porque personalmente uso mi propia variable llamada iiique incremente manualmente cada actualización, porque no la quiero en segundos, quiero pasos o marcos. Sin embargo, puedo ver que tu camino es una forma válida de codificar cosas.
DrZ214

Respuestas:

102

¿Cambia el estado de tu mundo de juego? Es un código lógico.

¿Muestra el estado del mundo del juego? Es el código de representación.

Nils Ole Timm
fuente
Echaré un vistazo a mi código para estar 100% seguro. Buena explicación, gracias.
Shyy Guy el
38
¿Maneja la entrada? Su código de controlador. Separe el control de la lógica, de modo que pueda usar la misma lógica con diferentes tipos de controles. Por ejemplo, un FPSInputController + CharacterMotor vs. AIInputController + CharacterMotor vs NetworkInputController (por ejemplo, otros jugadores en una instancia de multijugador) + CharacterMotor. Al motor (código lógico) no le importa cómo obtiene las instrucciones que recibe, solo que se proporcionan (este tipo de desacoplamiento permite una fácil transición del jugador al robot AI (piense en Left 4 Dead y jugadores inactivos) y viceversa, entre otras cosas).
Draco18s el
10
Draco saca un buen punto. Hay muchas divisiones diferentes que puede poner en el código. La división de Nils es lo que yo consideraría la división arquetípica entre lógica y renderizado, pero hay muchas otras capas que verás. La verdadera razón para separarlos en capas es que cada capa consiste en acciones similares que requieren un estilo de código similar con requisitos similares. Por ejemplo, en muchos juegos, puede salirse con la lógica del juego tomando 2 o 3 cuadros para completar, pero si no procesa cada cuadro, el ojo del usuario lo notará rápidamente.
Cort Ammon
Mantenerlos distintos lo ayudará a administrar sus requisitos cuando comiencen a convertirse en una fuente de tensión.
Cort Ammon
66
Y recuerde que si le arroja demasiado MVC, puede reducir la velocidad, por lo que siempre debe buscar un equilibrio entre la capacidad de mantenimiento y la optimización. Pero no optimice demasiado pronto, a menos que esté absolutamente seguro de lo que está haciendo. Y recuerda que siempre puedes refactorizar. Y ... Uh, haz muchos juegos y aprende de tus errores.
Maurycy
24

Su separación es correcta si:

  • Llamar a Draw () varias veces seguidas sin llamadas intercaladas a Update () nunca daría lugar a ningún cambio visible entre las llamadas.
  • Llamar a Update () varias veces seguidas sin una llamada intercalada a Draw () sería como jugar el juego con la pantalla apagada: todo se mueve de manera perfecta y consistente, simplemente no se puede ver.
Thomas
fuente
55
Correctamente escrito Draw()puede dibujar diferentes imágenes a medida que pasa el tiempo. Por ejemplo, los cuadros de sprites animados pueden seguir cambiando. Además, los objetos pueden continuar avanzando visualmente si el código de representación utiliza un truco común y se agrega velocity * time since last update / period of updatea la posición visible de los objetos (mientras su posición real permanece sin cambios).
HolyBlackCat
2
ifflo que significa si y solo si?
BalinKingOfMoria
3
@HolyBlackCat: eso es discutible. ¿Qué pasa si quiero pausar gráficos? ¿Qué pasa si los cuadros de animación afectan el juego (animaciones de ataque correspondientes a hitboxes, etc.)? La interpolación visual todavía implica que el "tiempo" (como en el tiempo delta del juego) está pasando, pero si el tiempo pasa y no estás pasando, ¿ Updatequé más está saliendo de la sincronización? ¿Se han perdido las entradas del reproductor, los eventos de red no se están procesando, etc.? El juego debe ser impulsado desde un solo reloj, con "ticks" fijos para la lógica o física del juego derivadas de ese reloj, y el estado gráfico derivado también impulsado por ese mismo reloj.
Sean Middleditch el
@SeanMiddleditch Estoy de acuerdo, casi siempre puedes escribir Draw()de tal manera que siempre dibuja la misma imagen cuando se te llama varias veces seguidas. Uno debería hacer eso si es posible. Pero hay casos en los que no sabe a qué frecuencia Draw()se llamará. Por ejemplo, si desea soporte completo (120 FPS reales) para los nuevos monitores de 120Hz y activa vsync. What if I want to pause graphics?Luego pasa 0 en lugar del tiempo delta real al Draw().
HolyBlackCat
2
@HolyBlackCat: Nada de lo que estaba entendiendo impediría el uso de renderizado de 120Hz. Absolutamente no estaba recomendando una tasa de extracción fija; Eso es solo aficionado. Debería haber un reloj de juego global cuyo delta se mide en términos de cuadros de renderizado que alimentan el valor de acumulación para el tic lógico del juego de tasa fija. Ese reloj global impulsa los gráficos, incluida la interpolación. Puede pausar los gráficos configurando la escala del reloj en 0. Puede tener relojes jerárquicos, por ejemplo, la interfaz de usuario todavía se ejecuta y anima mientras la interpolación de caracteres también se detiene, muy, muy fácilmente.
Sean Middleditch
7

El punto aquí es la separación de las cosas del Modelo que no son el modelo.

La lógica del juego es el modelo mencionado en

Todos estos son patrones de arquitectura de software diferentes y relacionados. Pero en todos los casos, el Modelo es lo mismo, es la lógica real y el estado real.

Es cuando se hace software comercial, a veces se le llama lógica comercial y codifica algunas de las políticas comerciales. Por ejemplo, si está codificando algo para un banco, para calcular las facturas de tarjetas de crédito, entonces la funcionalidad para hacer que alguien no tenga que pagar intereses si cancela su deuda en menos de 30 días, es parte de la lógica comercial, vive en el modelo. Por ejemplo, no vive en una de las capas de visualización. El código para imprimir una factura, por ejemplo, no edita el texto en función de sus acciones. Este ejemplo quizás resalta por qué es posible que desee organizar su código de esa manera.

Similar va para la lógica del juego.

Imagina que en algún momento tu juego fue trasladado a otra consola. Puede ser útil imaginar algo realmente diferente a su objetivo actual. Por ejemplo, si está apuntando a algo con un gamepad / controlador, imagine que su juego se transfiere a una tableta con pantalla táctil. La lógica del juego es la parte del código que no cambia cuando lo portas.

Si tu juego fuera algo así como un juego de estrategia militar, imagina que se convierte en el juego de mesa más complejo del mundo. La lógica del juego son las secciones de código, que corresponden directamente a las líneas del libro de reglas. (No todas las líneas en el libro de reglas, no las que tratan de mover piezas, pero algunas).

La lógica del juego es lo que nunca cambia, sin importar la forma.

Lyndon White
fuente