2011-04-04 5 views
12

Actualmente estoy desarrollando un pequeño motor 2D de Real Time Strategy. Y Me pregunto cómo manejar los muchos sprites siempre cambiantes que eventualmente cubrirán mi pantalla.Qt: ¿Maneja eficientemente QGraphicsItems que tienen "muchos pixmaps"? (RTS)

FYI, no estoy apuntando a nada a nivel AAA, solo estoy tratando de implementar algunos métodos de aprendizaje automático. Por lo tanto, seleccioné los ISO abandonware de Warcraft II, tomé descaradamente algunos gráficos y me caí en los primeros números.

http://img263.imageshack.us/img263/1480/footman.png

Como se puede ver arriba, incluso el simple lacayo de Warcraft II tiene alrededor de 50 sprites para su animación. Que es mucho Y cambiará los sprites muy a menudo. (La línea negra solo estaba comprobando si mi canal alfa era correcto)

Por lo tanto, la última pregunta: ¿Cómo implemento de manera eficiente un QGraphicsObject que sigue cambiando? ¿Cómo implemento eficientemente un QGraphicsItem que cambia su apariencia repetidamente?

¿Simplemente sobrecargo el método paint() de QGraphicsPixmapItem y sigo cambiando el Pixmap utilizado en la pantalla? ¿Causará algo de "tartamudeo"? He oído que, a veces, es sensato/posible crear uno todos los mapas de puntos, ocultarlos y duplicarlos cuando sea necesario. (La copia es menos costosa que otras operaciones) ¿Hay alguna otra idea inteligente?

¡Gracias por cualquier entrada! (Tutorial para motores de estrategia en tiempo real, las cosas complejidad, etc ...)

+0

sugiero que usar Qt no es la mejor biblioteca que podrías haber elegido para desarrollar un juego. ¿Has explorado algunas de las otras alternativas? Concedido que qt hace MUCHO para ti, como recorte, transformaciones fáciles de los sprites, etc. pero también hace muchas cosas que realmente no necesitas al mismo tiempo ... después de un poco de google que encontré esto: http://www.libsdl.org/ que podría satisfacer sus necesidades mejor que las cosas qgraphics – Tom

+0

@Tom: gracias por la entrada, de hecho, el SDL es realmente una excelente biblioteca C para aplicaciones 2D. Sin embargo, y tiene razón porque no lo dije, estoy más interesado en el aprendizaje automático y en la arquitectura de RTS que en el desarrollo de aplicaciones. Podrías reformular mi pregunta en: ¿cómo manejan las bibliotecas buenas un objeto con muchos sprites? (Y así, ¿cómo debería implementarlo con Qt, que es una biblioteca absolutamente necesaria para este proyecto?) – Fezvez

+1

Si configura su ventana gráfica para un QGLWidget y pinta manualmente() pixmaps que ya ha almacenado en memoria usted mismo, debería estar bien. En cuanto al rendimiento. – Chris

Respuesta

15

(Voy a empezar con la idea general en primer lugar, una posible aplicación Qt seguirá)

No sé cómo son almacenados los sprites WCII , pero deberías usar una hoja de sprites (construyéndola tú mismo si es necesario). Asociado a esta hoja, tendrá una descripción del sprite que contiene como mínimo la lista de animaciones, y para cada animación, su identificador/nombre, así como una lista de marcos.

El nivel de detalle que pones al describir los cuadros de esa animación depende de ti, pero debe contener como mínimo el rectángulo de la hoja de elementos para mostrar.

Como ejemplo, eche un vistazo a this sprite sheet (claramente no optimizado, pero para un ejemplo, está bien :)). Aquí está el animations descriptions asociado (línea 12 a 39). Todas las animaciones no están incluidas, pero tendrás la idea.

Puede ver que la animación "inactiva" está hecha de 3 fotogramas, que coincide con los primeros 3 fotogramas de la hoja de sprites. Asociado al siguiente, hay 2 más información en este ejemplo:

  • duración: ¿cuánto tiempo debe visualizarse el marco antes de pasar al siguiente?
  • origen: ¿cuál es el punto de anclaje del marco?

Ahora, ¿cómo iría a implementar eso en Qt?

El formato del archivo de descripción de las animaciones es totalmente suya, pero recomiendo algún formato de archivo de jerarquía. Como Qt proporciona el analizador XML, puede ser perfecto. Si está acostumbrado a impulsar y prefiere un formato ligero como JSon, puede usar boost.Preeree analizar indiferentemente archivos XML/JSon y tener una interfaz común para extraer datos de ellos.

Para la representación gráfica, que tendrá que utilizar algunas clases:

  • QPixmap: desde donde se podrá dibujar rectángulos sub-tramas juego animaciones,
  • un QTimer a actualizar sus sprites,
  • su propia clase de pantalla, por ejemplo AnimatedSprite (deriva de una QGraphicsObject, tendrá la señal s/ranuras upport),
  • y una clase de soporte, por ejemplo TimerProxy (derivado de QObject).

Comenzaré describiendo el rol TimerProxy. Su función es enviar mensajes de actualización de tiempo. Está aquí porque los objetos de Qt Graphics no proporcionan ningún tipo de actualización "temporizada" (es decir, actualización (float dt) donde se da dt es su unidad de tiempo favorita). Puede preguntarse por qué estamos usando una clase proxy para manejar el tiempo. Esto es para limitar la cantidad de QTimer activo; si tiene uno de estos por AnimatedSprite, puede terminar teniendo toneladas de temporizadores activos, lo que claramente es un gran no-no.

Por lo tanto, cumple 2 funciones:

  • en el momento de la construcción de la escena: todo AnimatedSprite registrará a sí mismos a una señal que proporciona, vamos a lo nombra UPDATETIME (int milisegundos),
  • en la escena del tiempo de ejecución, se iniciará un QTimer cuyo tiempo de espera se establece en la granularidad que necesita (puede continuar con 16ms para aproximadamente 60 fps). La señal de QTimer timeout() se asociará a ranuras privadas que dispararán updateTime (int msecs) donde msecs se establece en la granularidad del temporizador que configuró antes.

Ahora, para el núcleo de la solución: AnimatedSprite. Esta clase tiene las siguientes funciones:

  • lectura & almacenar Descripción de las animaciones que va a necesitar,
  • de partida, la actualización de & animaciones de parada
  • dibujo marco del sprite activa en la QGraphicScene

En la inicialización, debe darle la siguiente información:

  • una instancia de TimerProxy (propiedad de su escena, o la clase propietaria de la escena).Cuando se proporciona este caso, usted sólo tiene que conectar la señal TimerProxy :: UPDATETIME (int) a una slots privados que actualizará la animación actual,
  • la QPixmap la celebración de la spritesheet,
  • y las descripciones animaciones

Durante el tiempo de ejecución, los métodos de actualización será parecida:

  • una privada timeUpdated (int) ranura que comprobará si el marco de la animación actual debe ser actualizada, y actualizar en consecuencia,
  • método animaciones público, como startAnim (QString & animName), que cambiará la animación actual, restablecer el contador de tiempo transcurrido, y actualizar el actual sub-rect para dibujar para que coincida el primer cuadro de la nueva animación.

En el timeUpdated (int) ranura, que desea actualizar el tiempo transcurrido, y comprobar si se debe realizar la animación proceder al siguiente fotograma. Si es así, simplemente actualice el puntero de marco actual al nuevo marco.

Por último, para hacer, sólo reimplementar QGraphicsItem :: pintura (...) método para dibujar la subrect actual, que podría parecerse a:

void AnimatedSprite::paint(QPainter *painter, 
          const QStyleOptionGraphicsItem * /*option*/, 
          QWidget * /*widget*/) 
{ 
    painter->drawImage(mCurrentAnim.mCurrentFrame->mOrigin, 
         mSpriteSheet, 
         mCurrentAnim.mCurrentFrame->mSubRect); 
} 

Espero que ayude (y no es demasiado grande, guau: s)

+3

¡Guau! ¡Gracias! ¡Ese es el tipo de marco que quería! – Fezvez

Cuestiones relacionadas