Tema Gráficos. Movimientos Sprite. Visual Basic 2013 (Solucionado)

Iniciado por Tazmania40, 21 Octubre 2016, 14:02 PM

0 Miembros y 1 Visitante están viendo este tema.

Tazmania40

Buenas a todos, estoy intentando mejorar el tema de movimientos de Sprites, puesto que lo utilizado hasta ahora todavia veo reflejo, aún poniendo DoubleBuffered = True en el Formulario y buscando información y probando veo que la mejor forma es utilizando "Protected Overrides Sub OnPaint". Naturalmente con DirectX o OpenGL sería otra cosa, pero no tengo ni idea.
Pongo código y lo explico (programa compilado con .NET Framework 4.0)

Código (vb.net) [Seleccionar]

Imports System.Threading

Public Class Form1

' Tenemos un fondo de pantalla jpg 800x600 y dos imágenes transparentes png 50x50
' DECLARACIONES de los Objetos

Private Grafico As Graphics         ' Declaramos Objeto principal del GDI+
Private BitGrafico As Bitmap        ' Declaramos Bitmap que se copia en Objeto principal
Private Fondo As Bitmap             ' Imagen de fondo que utilizamos
Private Structure DSprite           ' Declaramos el Sprite (imagen y posición)
   Dim Imagen As Bitmap
   Dim Pos As Point
End Structure
Private Bola1, Bola2 As DSprite   ' Objetos de tipo Sprite

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
   ' Cargamos los Gráficos
   Fondo = My.Resources.Tierra
   Bola1.Imagen = My.Resources.Bola
   Bola1.Pos = New Point(0, 100)
   Bola2.Imagen = My.Resources.Bola2
   Bola2.Pos = New Point(0, 300)

   ' Inicializamos los Objetos GDI+
   Grafico = Me.CreateGraphics()
   BitGrafico = New Bitmap(800, 600)
   Grafico = Graphics.FromImage(BitGrafico)
End Sub


Hasta aquí todo bien, ahora es cuando utilizo OnPaint y mi primera pregunta (más bien duda y confirmación). ¿Este evento impide que se ejecuten los demás eventos Paint? (sobre todo del Formulario), que para eso tendríamos que llamarlo con MyBase.OnPaint(e), al colocar evento te lo coloca automáticamente, por eso sino hace falta llamarlo ¿se puede eliminar? ¿Es bueno llamar a los eventos Paint de otros controles desde aquí?.
En el juego que realice no voy a llamar a ningún otro evento Paint y tan solo voy a tener gráficos en el Formulario principal, solo por confirmar.

Código (vb.net) [Seleccionar]

Protected Overrides Sub OnPaint(e As PaintEventArgs)
   MyBase.OnPaint(e)                                 ' Esto se prodría omitir ??
   Dim de As Graphics = e.Graphics
   MOVER()
   DIBUJAR(de)
   Thread.Sleep(100)                                  ' Retardo
End Sub

Private Sub MOVER()
   Bola1.Pos.X = Bola1.Pos.X + 5
   Bola2.Pos.X = Bola2.Pos.X + 10

   If Bola1.Pos.X >= 800 Then Bola1.Pos.X = 0
   If Bola2.Pos.X >= 800 Then Bola2.Pos.X = 0
   Invalidate()                                  ' Vuelva a dibujar el control
End Sub

Private Sub DIBUJAR(ByVal d As Graphics)
   d.DrawImage(Fondo, 0, 0)                ' Dibujamos el fondo de pantalla
   d.DrawImage(Bola1.Imagen, Bola1.Pos)    ' Dibujamos Sprite1
   d.DrawImage(Bola2.Imagen, Bola2.Pos)    ' Dibujamos Sprite2
End Sub
 
End Class


El programa va bien y se ve fluido (naturalmente el Formulario utilizo Doble buffer puesto que sino se ve el reflejo), pero al iniciar se ejecuta 2 veces OnPaint y aunque puedes variar el tema de coordenadas, parece que de inicio no informa bien si pongo unos label

Código (vb.net) [Seleccionar]

Label1.Text = "Obj1 PosX = " & Bola1.Pos.X
Label2.Text = "Obj2 PosX = " & Bola2.Pos.X


Estoy con pruebas y con un botón para parar. Veo que esta forma no hay que poner nada en diseño, a no ser por código porque hace cosas extrañas con las coordenadas. En principio estoy probando y mi segunda pregunta es ¿Es la forma correcta para saber el tema de coordenadas de los Sprites que coloque en Formulario? ¿Se puede mejorar algo para saber exactamente el tema de coordeandas x, y de los Sprites?

Colocare una nave y mas objetos y quería saber si me va a dar problemas con las coordenadas, la nave la muevo yo y los objetos como en el ejemplo se mueven automáticamente.
Gracias y saludos


El Benjo

Hola.

Respecto a tu primera pregunta: No, el evento OnPaint no impide que se ejecuten los demás eventos OnPaint. Lo que ocurre es que se "sobreescribe" lo que ya habías dibujado.

Lo de MyBase.OnPaint(e) no es necesario, lo que es más, no es de utilidad. Recuerda que MyBase hace referencia a la clase padre del control y por lo general, esta propiedad la llamas dentro del código de una clase que hereda el método que quieres sobreescibir.

Lo de los parpadeos y el doble buffer, como comentas sería otra cosa si usaras DirectX u OpenGL, pero puedes mejorar muchísmo si implementas el doble buffer en tu código mediante la clase BufferedGraphics.

https://msdn.microsoft.com/en-us/library/b367a457(v=vs.110).aspx

En esa página hay una sección llamada "Manually Displaying Buffered Graphics" donde te explican cómo hacerlo.
www.es.neftis-ai.com

Sí hay un mejor lenguaje de programación y es ese con el que puedes desarrollar tus objetivos.

Tazmania40

#2
Buenas he realizado pruebas, pongo ejemplo

Código (vb.net) [Seleccionar]

Public Class Form1
   Private Conta As Short = 0

   Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
       e.Graphics.DrawString("Texto", New Font("Tahoma", 16, FontStyle.Bold), _
                              Brushes.Blue, New Point(100, 30))
       Conta += 1
       Label1.Text = "Ejecución = " & Conta.ToString 'Aqui muestra 2 ejecución
   End Sub
End Class


Veo que el evento Paint se ejecuta 2 veces cuando iniciamos el Formulario, si colocamos OnPaint

Código (vb.net) [Seleccionar]

Protected Overrides Sub OnPaint(e As PaintEventArgs)
   MyBase.OnPaint(e)
End Sub


efectivamente no impide que se ejecute eventos Paint, pero siempre y cuando dejemos la llamada al método base "MyBase.OnPaint(e)", si lo quitamos no vemos nada (en este caso el color Texto de color azul), por eso lo vemos por defecto. Ampliamos ejemplo:

Código (vb.net) [Seleccionar]

Private Conta As Short = 0

Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
    e.Graphics.DrawString("Texto", New Font("Tahoma", 16, FontStyle.Bold), _
                               Brushes.Blue, New Point(100, 30))
    Conta += 1
    Label1.Text = "Ejecución = " & Conta.ToString
End Sub

Protected Overrides Sub OnPaint(e As PaintEventArgs)
    MyBase.OnPaint(e)
    e.Graphics.DrawString("Texto", New Font("Tahoma", 16, FontStyle.Bold), _
                              Brushes.Red, New Point(100, 80))
    Conta += 1
    Label1.Text = "Ejecución = " & Conta.ToString 'Aqui muestra 4 ejecución
End Sub


Ahora muestra los dos textos y el contador es igual a 4. Quitamos "MyBase.OnPaint(e)" y solo mostrará el texto en color rojo y contador a 2. Esta claro que se ejecuta 2 veces tanto evento Paint como OnPaint al inicio del Formulario. Pero siguiendo el ejemplo de arriba, el tema de coordenadas parece que de inicio no lo muestra bien (seguiré con pruebas).

El código que he expuesto como he comentado utilizo el Doble Buffering activando en el Formulario o bien con código y ampliando opciones. Veo que es lo mejor y casi apenas se nota, ha mejorado mucho respecto a métodos que utilizaba anteriormente. La clase que comentas El Benjo, BufferedGraphics dice "Proporciona un búfer gráfico para el doble búfer", deduzco que sería un triple búfer porque ya el Formulario había activado la propiedad. Es como lo hacía con un timer, copiando imagen en un objeto y luego representandola por ejemplo en otro objeto como un PictureBox. Las dos han sido probadas y este código (primero) es lo mejor que veo sin utilizar DirectX u OpenGL.

Tan solo veo cosas extrañas con las coordenadas (Pos.X, PosY), si alguien ha realizado juegos 2D y sabe la mejor manera de posicionar los objetos y que te den el valor exacto, incluso cuando inicias el juego implementado el código expuesto al principio se lo agradecería, aunque seguiré haciendo pruebas. Gracias "El Benjo" por tu comentario.

También si alguien sabe de algún manual sencillo y que lo explique bien desde el principio (en español) sobre el tema DirectX , para 2D solamente en Visual Basic 2013 se lo agradezco. Normalmento lo que encontraba es bastante difícil (inglés) y para tener una base se debe empezar por lo más fácil.

Saludos y gracias

okik

#3
hola, aquí puedes descargar el DirectX End-User Runtimes (June 2010).

Puedes descargar  el DirectX SDK (DirectX Software Development Kit)


Una vez instalado dirígete a:
C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Samples\C++

Ahí encontrarás ejemplos de uso de DirectX con Visual Studio.  Desde movimientos en 3D sobre una escena, luces, manejo de modelos 3D, etc. Lo malo es código C++ y la última versión de compilado es de 2010, de modo que al abrirlo con VS tendrás que actualizarlo aceptando el cuadro que ofrece actualizar el compilador y las bibliotecas si usas una versión posterior. También te pedirá antes reiniciar con nuevas credenciales.

Este es el ejemplo ShowVolume. Se generan luces y sombras a partir del objeto y puedes moverte en el entorno usando las flechas del teclado (la cámara, no el modelo). Para cambiar el punto de enfoque, click con el botón izquierdo del ratón y arrastrar



También hay ejemplos para 2D y un tutorial:
C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Samples\C++\Direct3D10\Tutorials


El Benjo

Sobre el tema de las coordenadas, explica exactamente qué es lo que hace 'raro' el código. Lo digo porque las coordenadas son exactas no son aproximaciones. Es decir que si tienes un objeto en la posición X=100 - Y=100, El valor que obtendrás al recoger sus coordenadas será 100 y 100. En todo caso creo que tu problema con las coordenas es porque los sprites que utilizas son círculos y lo que quieres es obtener un punto determinado dentro de la circunferencia, ¿no? Si es así entonces necesitas aplicar funciones trigonométricas.

El tema de DirectX lo puedes manejar mediante XNA que es algo así como una interface entre .NET y DirectX.

https://www.microsoft.com/en-us/download/details.aspx?id=23714

Creo que al instalar el SDK de XNA se te instalan ejemplos de juegos. Yo lo llegué a utilizar y la verdad es que es bastante fluido.
www.es.neftis-ai.com

Sí hay un mejor lenguaje de programación y es ese con el que puedes desarrollar tus objetivos.

Tazmania40

#5
Buenas, voy a comenzar por okik respondiendote y preguntando para aclararme el tema de DirectX, aunque de momento no lo voy a utilizar pero para avanzar y mejorar creo que es lo próximo a utilizar o bien XNA.

Me baje hace un tiempo DXSDK_Jun10.exe que veo que es el enlace que me has puesto. Mis preguntas son si lo instalo.

1º Estas son las ultimas librerias de DirectX para Visual Studio 2010, yo tengo el Visual Studio 2013 update 5, si lo instalo no tendré problemas, me podrá servir, tan solo como comentas actualizar los componentes cuando lo solicite o bien en Herramientas, elegir elementos del cuadro de herramientas. Luego en el código importar las librerias que vayas a utilizar (que de momento no tengo ni idea), pero es así??

2º Si todo esta bien (punto 1), al realizar un programa con DirectX, me imagino que la versión DXSDK_Jun10.exe que es la última será para el DirectX 11, en ordenadores de otros usuarios tan solo tienen que tener instalado DirectX 11, al igual que las librerias Net Framework, es decir no tienen que instalarse nada puesto que casi todos los ordenadores llevan esto instalado ??

3º Para Windows 10, vale también. De momento los programa que he realizado y publicado (con versión 3.5 de Net Framework) se ha ejecutado sin problemas para esta plataforma. En Windows 10 tengo entendido que ya utiliza DirectX 12, pero me imagino que programas creado con versiones antiguas de DirectX se ejecutarán sin problemas, es así ??

Como bien dices la mayor parte de ejemplos de DirectX es para Visual C++, hace mucho tiempo estudie C y bueno se entiende algo, al igual que C#, a lo mejor es preferible pasarse alguno de esos lenguajes para el tema de juegos, pero como programo por hobby y siempre me gustó Visual Basic prefiero seguir con el hasta donde llegue, ya lo abandoné hace años el Visual Basic 6.0 y el año pasado cuando empezé de nuevas con VB2013 me estoy adaptando bien y no quiero dejarlo, además que ha mejorado mucho y se va pareciendo a Visual C++ en su estructura de código, abandonando las formas antiguas de programar y que dicen que son malas. Gracias okik


Respecto El Benjo responderte que al principio utilizaba lo tipico label para saber coordenadas y no veo que sea correcto en un objeto gráfico GDI+, aqui solamente hay que emplear métodos gráficos y representar mediante "d.DrawString" para hacer pruebas con las coordenadas.

La verdad que el juego que estoy haciendo me está quedando muy bien y bastante satisfecho con el código principal expuesto del principio. Puedo cambiar los fondos de pantalla (he creado un pequeño scroll horizontal) y los Sprites que he colocado se mueven fluidamente, al igual que el Objeto principal (Nave), no se ven reflejos al emplear DobleBuffering del Formulario. Todavía no he llegado a la parte de colisiones, decir que los Objetos empleados son casi cuadrados y aplicaré la técnica

Código (vb.net) [Seleccionar]

Objeto1.Bounds.IntersectsWith(Objeto2.Bounds)


Conozco algo de la técnica del pixel, aunque aqui no lo voy a emplear por ser casi cuadrados los objetos. Cuando empleaba solía mirar 20-30 puntos (GetPixel) del Objeto principal como marcando su referencia, aunque no era exacto pero evitaba la ralentización mirando todos los puntos del Sprite. Me pondre con ello y comentaré aqui si me ha ido bien las Colisiones.

Respecto al XNA leí algo y veo que aunque está en desuso porque se realizó para la consola Xbox 360, Windows Phone y Visual Studio me imagino versión 2010. Quería preguntarte si ese enlace que facilitas que veo que es la última versión vale igual para Visual Studio 2013, porque tengo entendido que XNA esta pensado para utilizarlo en Visual C#, aunque a lo mejor se puede implementar también en Visual Basic 2013. Es a modo de consulta, puede que me lo baje tambien para tenerlo, pero seguramente en un futuro me decante por DirectX, me imagino que me servirá mejor para Windows 10.

Por último preguntarte si hay que implementar el método Dispose, paso enlace de ejemplo https://msdn.microsoft.com/es-es/library/bb972198.aspx
Yo lo que hacía era en el Form1_FormClosing eliminar los objetos que había creado al cerrar el Formulario. Como véis en el ejemplo del post1 cargo los gráficos y los voy a emplear durante todo el juego. Dicen que se eliminan automáticamente o al cerrar el Formulario, la verdad estoy un poco verde en el método Dispose, si podéis aclararme un poco pero de un modo sencillo. Yo suelo ser lento para coger las cosas, pero al final de tanto insistir o probar doy con ello y lo comprendo, aqui veo mucho nivel, jeje. Gracias y saludos

okik

#6
Cita de: Tazmania40 en 25 Octubre 2016, 22:05 PM
Buenas, voy a comenzar por okik respondiendote y preguntando para aclararme el tema de DirectX, aunque de momento no lo voy a utilizar pero para avanzar y mejorar creo que es lo próximo a utilizar o bien XNA.

Me baje hace un tiempo DXSDK_Jun10.exe que veo que es el enlace que me has puesto. Mis preguntas son si lo instalo.

1º Estas son las ultimas librerias de DirectX para Visual Studio 2010, yo tengo el Visual Studio 2013 update 5, si lo instalo no tendré problemas, me podrá servir, tan solo como comentas actualizar los componentes cuando lo solicite o bien en Herramientas, elegir elementos del cuadro de herramientas. Luego en el código importar las librerias que vayas a utilizar (que de momento no tengo ni idea), pero es así??

2º Si todo esta bien (punto 1), al realizar un programa con DirectX, me imagino que la versión DXSDK_Jun10.exe que es la última será para el DirectX 11, en ordenadores de otros usuarios tan solo tienen que tener instalado DirectX 11, al igual que las librerias Net Framework, es decir no tienen que instalarse nada puesto que casi todos los ordenadores llevan esto instalado ??

3º Para Windows 10, vale también. De momento los programa que he realizado y publicado (con versión 3.5 de Net Framework) se ha ejecutado sin problemas para esta plataforma. En Windows 10 tengo entendido que ya utiliza DirectX 12, pero me imagino que programas creado con versiones antiguas de DirectX se ejecutarán sin problemas, es así ??

Personalmente no creo que su instalación afecte a la versión más reciente del sistema.

De todos modos me equivoqué, los ejemplos no están en el redistribuible, que es el que te he puesto, si no en  el DirectX SDK (DirectX Software Development Kit) que contiene las librerías, y archivos  para desarrolladores y soporte para VS. También contiene el Redist.

El EXE (DXSDK_Jun10.exe) puedes abrirlo con un WinRar y extraer el contenido directamente. Encontrarás igualmente la carpeta Samples, con los ejemplos en C++ para VS.

Si lo instalas DXSDK_Jun10.exe, en la instalación puedes elegir lo que quieres instalar. Si no quieres instalar el Runtime, lo desactivas y listo. El Redist no se instala, solo se guardan los archivos  y el Setup en [C:\Program Files (x86)\Microsoft DirectX SDK (June 2010)\Redist]


Las carpetas que contiene el  SDK  son:

\Developer Runtime
\Documentation
\Extras
\Include
\Redist
\Samples
\Utilities



Desarrollar juegos
...Con C++, se puede escribir código de alto rendimiento con línea directa a la GPU, la CPU y servicios de plataformas de bajo nivel.




Para poder importar DirectX a un proyecto VB.NET tienes que referenciar la librería Microsoft.DirectX.Direct3DX.dll

Si no encuentras en la lista de referencias Microsoft.DirectX, encontrarás la librería en:
C:\Windows\Microsoft.NET\DirectX for Managed Code\1.0.xxxx.0

El Benjo

Puedes utilizar la clase de XNA en Visual Basic sin ningún problema (según sé) igual que se pueden utilizar dll's porque al final de cuentas es código de .NET. Pero si lo que quieres es desarrollar juegos entonces te convendría utilizar DirectX desde el comienzo, pues XNA es una plataforma 'muerta'.

Lo que comentas sobre el método Dispose(), no sé que tanto te pueda ayudar pues mi experiencia en eso no es muy amplia, sin embargo, tengo entendido que el método Dispose() se utiliza para liberar recursos 'no administrados'. Los recursos que son administrados por el propio .NET Framework son liberados automáticamente cuando las variables salen de alcance (variable scope). Es decir que al salir de un método .NET elimina todas la variables locales y el garbage collector libera el espacio en memoria que ocupaba dicha variable.

http://stackoverflow.com/questions/2926869/do-you-need-to-dispose-of-objects-and-set-them-to-null

Te dejo la respuesta que le dieron a alguien con una pregunta similar.
www.es.neftis-ai.com

Sí hay un mejor lenguaje de programación y es ese con el que puedes desarrollar tus objetivos.

Tazmania40

#8
Buenas, gracias okik por toda la información y es un comienzo para empezar por DirectX aunque de momento lo que estoy utilizando me gusta y he eliminado los reflejos por completo, pero esta claro que si quiero añadir por ejemplo más de un sonido wav al mismo tiempo tendría que usar DirectX y sus librerias, es uno de los problemas que siempre te encuentras (aunque solucioné en un juego que hice con la dll del Windows Media Player, pero no es la forma correcta de representar más de un sonido al mismo tiempo). Esta claro que casi toda la ayuda y lo que encuentras es para Visual C++, yo intentaré primero con Visual Basic porque creo que con Visual C++ además de Net Framework los usuarios que quieran emplear juegos realizados con DirectX se tienen que instalar las runtime de Visual C++ 2010 y por experiencia cuando un juego ocupa mucho y encima se tienen que instalar algo entonces pasan de bajarselo.

Ya he probado el tema de colisiones y perfecto, aunque la sintaxis que puse no era la correcta (es para un objeto de tipo control), se que a muchos que hacéis esto no os gusta poner el código de un ejemplo pero bueno después de probar informo como es, corregirme si alguien lo emplea de otra forma.

Código (vb.net) [Seleccionar]

Private ObjP As Rectangle               ' Objeto principal, por ejemplo puede ser una Nave
Private Obj(6) As Rectangle             ' Objetos secundarios, demás Sprites que comprobamos

' Colisión de 2 objetos
ObjP = New Rectangle(Nave.Pos.X, Nave.Pos.Y, 40, 40)
For B As Short = 0 To 6
   Obj(B) = New Rectangle(Bola(B).Pos.X, Bola(B).Pos.Y, 40, 40)
   If ObjP.IntersectsWith(Obj(B)) = True Then
       My.Computer.Audio.Stop()          
       My.Computer.Audio.Play(My.Resources.Explosion1, AudioPlayMode.Background)
       Nave.Imagen = My.Resources.Explo1             ' Explota Nave
       ...
        Exit For                          
   End If
Next B


Si quisieramos comprobar por pixel, en vez de establecer el codigo de finalización anterior podriamos llamar a otra rutina pasandole el objeto 2 a comprobar y aquí miramos el color del pixel
con el objeto principal que es la Nave, si es transparente no hacemos nada y si no lo es es cuando ponemos el código de finalización. Es así como yo lo hago, aunque como digo en este juego que realizo al ser los gráficos casi cuadrados y en continuo movimiento no me hace falta.

El Benjo mirare Dispose, naturalmente los objetos que yo declaro son "no administrativos" por eso la buena costumbre de liberar recursos. También lo decía porque en este juego no son muchos los Sprites que utilizo y siempre estan en memoria hasta que finalice juego, pero por ejemplo no se como hacéis el borrado de un Objeto (lo que es visible = false), en mi caso o bien suelo situarlo en límites fuera del recuadro de juego para que no se vea o utilizar un Switch en las propiedades del Sprite de tipo Booleano y pintarlo con una imagen transparente, por eso comentaba también el método dispose si se puede eliminar objeto y crear nuevamente de una forma correcta y rápida o bien si hay alguna otra forma correcta.

Por cierto otra pregunta ¿Como utilizáis el tema de retardos de tiempo en las animaciones?, está claro que el timer lo eliminamos, el Thread.Sleep si lo utilizo es para toda la carga (afecta a todo el programa) y de momento yo utilizo contadores normales y claro por ejemplo el juego probado en un i5 y un dual core apenas hay mucha diferencia aunque este último va un poquito más lento, pero si lo pruebo en el Pentium IV que tengo en casa de mi padre (todavía no lo he hecho) me imagino que si se apreciará.

Gracias y saludetes

El Benjo

Lo que comentas sobre el "borrado" de un objeto tienes lo consigues simplemente decidiendo si se dibuja o no el objeto, es decir, que no necesitas ni dejarlo fuera de los límites del área visible ni dibujarlo como transparente. Recuerda que eliminas los objetos cuando no los vas a utilizar más, pero si lo que quieres es que no sean visibles simplemente elijes no dibujarlos.

Y lo que comentas sobre el retardo de tiempo, deja decirte que se realiza precisamente mediante el thread.Sleep(). La forma en que funciona un juego es básicamente obteniendo los movimientos del usuario y después dibujando la escena, todo eso precisamente dentro del bucle.
www.es.neftis-ai.com

Sí hay un mejor lenguaje de programación y es ese con el que puedes desarrollar tus objetivos.