Stratos: Punto de Encuentro de Desarrolladores

¡Bienvenido a Stratos!

Acceder

Foros





mover un objeto

Iniciado por divmas, 08 de Marzo de 2011, 06:06:29 PM

« anterior - próximo »

divmas

Buenas,

estoy tratando de hacer una clase que me permita mover un objeto que está compuesto por una imagen y un texto.

Ésta es la clase que tengo hecha que entiendo tiene lógica pero que no realiza bien lo que quiero:

Código (vbnet) [Seleccionar]
Public Class ficha

    Private top As Long, left As Long
    Private texto As String
    Private rec_zona_impacto As GFX_Rect
    Private fnt_system1 As Long
    Private gfx_ficha As Long

    Public Sub New()
        fnt_system1 = m_gfx.FONT_LoadSystemFontFromFile("fonts\proman10.ttf", "proman", 8, False, False, False, False)
        gfx_ficha = m_gfx.MAP_Load("img\ficha.png", 0)
    End Sub

    Public Sub posicionar(ByVal x As Long, ByVal y As Long)
        top = y : left = x
        nueva_zona_impacto()
    End Sub

    Public Sub draw(ByVal texto As String)
        m_gfx.DRAW_Map(gfx_ficha, left, top, -8, 0, 0)
        m_gfx.DRAW_Text(fnt_system1, texto, left, top + 35, -8, m_gfx.ARGB_Set(255, 0, 0, 0), Text_Align.Align_Left)

        'update

        If m_system.MATH_PointInRect(m_input.Mouse.X, m_input.Mouse.Y, rec_zona_impacto) Then

            Cursor.Current = Cursors.Hand

            If HitEvent.Mouse_Hit(Mouse_Button.Left_Button) And m_input.Mouse_Press = 1 Then

                left = m_input.Mouse.X
                top = m_input.Mouse.Y
                m_gfx.DRAW_Map(gfx_ficha, left, top, -8, 0, 0)
                m_gfx.DRAW_Text(fnt_system1, texto, left, top + 35, -8, m_gfx.ARGB_Set(255, 0, 0, 0), Text_Align.Align_Left)
                nueva_zona_impacto()

            End If

        End If

    End Sub
    Private Sub nueva_zona_impacto()
        rec_zona_impacto.X = left : rec_zona_impacto.Y = top
        rec_zona_impacto.Width = 30 : rec_zona_impacto.Height = 30
    End Sub
    Protected Overrides Sub Finalize()
        MyBase.Finalize()

        m_gfx.FONT_UnloadSystemFont(fnt_system1)
        m_gfx.MAP_Unload(gfx_ficha)

    End Sub



End Class


Alguien podria ayudarme a encontrar donde fallo.

Gracias

Hechelion

#1
Así al ojo y sin probar veo un par de errores:

       fnt_system1 = m_gfx.FONT_LoadSystemFontFromFile("fonts\proman10.ttf", "proman", 8, False, False, False, False)
       gfx_ficha = m_gfx.MAP_Load("img\ficha.png", 0)

Salvo que me esté perdiendo alguna característica del LOAD, es necesario indicar la ruta además del archivo, si es VB6, entonces tus rutas son:

gfx_ficha = m_gfx.MAP_Load(App.Path & "\img\ficha.png", 0)

Puedes comprobarlo mirando el valor de gfx_ficha, si es igual o superior a 0 luego de la carga, es porque la imagen se cargó. Si tiene un valor negativo, es porque no se puedo cargar (lo más normal es por un error en la ruta)


Tampoco veo que estés definiendo la zona de impacto, pues no le ingresas ningún valor, la forma de definir un área sería:

nueva_zona_impacto.X = 100
nueva_zona_impacto.Y = 50
nueva_zona_impacto.With = 200
nueva_zona_impacto.Height = 200

Eso te define un área de 200*200 en la posición (100,50).

Por último, cuando crees clases, debes tratar que sean lo más autónomas posibles (hay un nombre técnico pero no lo recuerdo ahora), en tu caso, la clase necesita de variables creadas en el proyecto y que no se ven en el código y que pueden estar con problemas. Además, si quieres portar tu clase a otro proyecto, estás obligado a declarar y usar las mismas variables que estás usando en este. Tal vez ahora no te parezca la gran cosa, pero cuando intentas reutilizar una clase y vez que necesitas meterle mucho tiempo para reutilizarla te vas a acordar.

Edit:
No te aseguro que la clase no tenga otros errores porque no la he probado, si te sigue sin funcionar avisa para darle una leída más a fondo.

[EX3]

Edit: No he terminado ni de revisar mi respuesta y ya se me adelanto Hechelion :D

Cita de: divmas en 08 de Marzo de 2011, 06:06:29 PM
estoy tratando de hacer una clase que me permita mover un objeto que está compuesto por una imagen y un texto.
Unos consejos :) Yo primero separaría lógica de dibujo. Tu método Draw solo deberia tener llamadas a las funciones dibujo, osea, dibujar sprite y dibujar texto. Luego tendria un método Update(), que siempre se deberia llamar antes de realizar cualquier operacion de dibujo y no despues, donde actualizaría toda la lógica del objeto en base a variables/propiedades que declare el objeto, por ejemplo su posicion, de tipo Vertex, que es mas logico que tener un Left y un Top separados, que sera el valor que usaran tanto el sprite como la cadena de texto al dibujarse. La idea seria que siempre ejecutes primero en una pasada toda la logica de todos los objetos y despues otra pasada para dibujarlos todos, esto te garantiza que la logica siempre vaya sincronizada con todos los objetos y los graficos no muestren acciones incorrectas o desincronizadas con la accion real (se hace asi en cualquier sistema).

Tu codigo Update deberia quedar similar a esto:
Public Sub Update()
If m_system.MATH_PointInRect(m_input.Mouse.X, m_input.Mouse.Y, rec_zona_impacto) Then

Cursor.Current = Cursors.Hand

If HitEvent.Mouse_Hit(Mouse_Button.Left_Button) And m_input.Mouse_Press = 1 Then
left = m_input.Mouse.X
top = m_input.Mouse.Y
End If

' Actualizar el rectangulo aqui te garantiza aunque cambie la posicion fuera de
' este codigo tu rectangulo maracara el area correcta siempre:
rec_zona_impacto.X = left : rec_zona_impacto.Y = top
rec_zona_impacto.Width = 30 : rec_zona_impacto.Height = 30
End If
End Sub

El codigo que genera el area del rectangulo nunca lo inicializas en tu codigo, por lo tanto nunca podras evaluar correctamente la condicion del If si te fijas. He puesto el codigo de actualizacion del rectangulo fuera del If para que siempre se actualice, de esta forma, aunque no lo hayas inicializado este siempre tendra el valor actual del area respecto a Left y Top cada vez que se llame a Update().

Tu codigo de dibujo simplemente deberia ser esto:
Public Sub Draw()
m_gfx.DRAW_Map(gfx_ficha, left, top, -8, 0, 0)
m_gfx.DRAW_Text(fnt_system1, texto, left, top + 35, -8, Color, Text_Align.Align_Left)
End Sub


Tu llamada m_gfx.ARGB_Set(255, 0, 0, 0) la haria solo una vez en el constructor. Piensa que cada vez que llamas a esta funcion estas calculando siempre el valor del color cuando este es invariable (siempre el mismo) y en caso de que este variase lo pondria como una propiedad o funcion a la que pasaras los valores del color y este los calculase solo en esa llamada, almacenando el valor en una variable llamada por ejemplo Color, como la que he puesto en tu codigo de dibujo si te fijas.

Otra cosa, yo no cargaria recursos en el constructor de la clase ni los destruiria en su destructor ya que siendo una clase que entiendo por su nombre se van a crear varias instancias con ese codigo estarias duplicando recursos, la textura y la fuente cuando solo tendrias que tenerlos cargados una vez para todas las fichas que generes (tendrias que hacerte una lista de recursos que cargas y asignarle una clave por ejemplo, para eso te interesaria usar un objeto Dictionary<Type>), si no vas a despilfarrar mucha memoria de forma innecesaria. Los recursos yo los trataría fuera de cualquier objeto que los use, eso deberia ser gestion de la escena del juego, no sus elementos :)

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

divmas

La ruta de la fuente y del mapa las encuentra bien porque tengo los archivos en el mismo directorio si bien deberia anteponerle el app.path (en vb .net-> Application.StartupPath).

La zona de impacto se crea cuando se posiciona haciendo una llamada al método:

Código (vbnet) [Seleccionar]
Public Sub posicionar(ByVal x As Long, ByVal y As Long)
        top = y : left = x
        nueva_zona_impacto()
    End Sub


Código (vbnet) [Seleccionar]

    Private Sub nueva_zona_impacto()
        rec_zona_impacto.X = left : rec_zona_impacto.Y = top
        rec_zona_impacto.Width = 30 : rec_zona_impacto.Height = 30
    End Sub


y se actualiza cuando se dibuja y se clica y pulsa a la vez:

Código (vbnet) [Seleccionar]
Public Sub draw(ByVal texto As String)
        m_gfx.DRAW_Map(gfx_ficha, left, top, -8, 0, 0)
        m_gfx.DRAW_Text(fnt_system1, texto, left, top + 35, -8, m_gfx.ARGB_Set(255, 0, 0, 0), Text_Align.Align_Left)

        'update

        If m_system.MATH_PointInRect(m_input.Mouse.X, m_input.Mouse.Y, rec_zona_impacto) Then

            Cursor.Current = Cursors.Hand

            If HitEvent.Mouse_Hit(Mouse_Button.Left_Button) And m_input.Mouse_Press = 1 Then

                left = m_input.Mouse.X
                top = m_input.Mouse.Y
                m_gfx.DRAW_Map(gfx_ficha, left, top, -8, 0, 0)
                m_gfx.DRAW_Text(fnt_system1, texto, left, top + 35, -8, m_gfx.ARGB_Set(255, 0, 0, 0), Text_Align.Align_Left)
                nueva_zona_impacto()
            End If

        End If

    End Sub



por otra parte no entiendo eso que dices de hacer la clase lo más autonoma posible si las variables las tengo declaradas dentro de la propia clase...

Gracias

divmas

He seguido tus consejos y a falta de mirarme los dictionary para descargar recursos la clase quedaria asi pero sigue sin funcionar, podria ser del press? :

Código (vb) [Seleccionar]

Public Class ficha

    Private top As Long, left As Long
    Private texto As String
    Private rec_zona_impacto As GFX_Rect
    Private fnt_system1 As Long
    Private gfx_ficha As Long
    Private color As Integer = m_gfx.ARGB_Set(255, 0, 0, 0)

    Public Sub New()
        fnt_system1 = m_gfx.FONT_LoadSystemFontFromFile(Application.StartupPath & "fonts\proman10.ttf", "proman", 8, False, False, False, False)
        gfx_ficha = m_gfx.MAP_Load(Application.StartupPath & "img\ficha.png", 0)
    End Sub

    Public Sub posicionar(ByVal x As Long, ByVal y As Long)
        left = x : top = y
        nueva_zona_impacto()
    End Sub

    Public Sub draw(ByVal texto As String)
        m_gfx.DRAW_Map(gfx_ficha, left, top, -8, 0, 0)
        m_gfx.DRAW_Text(fnt_system1, texto, left, top + 35, -8, color, Text_Align.Align_Left)
    End Sub

    Public Sub update()
        If m_system.MATH_PointInRect(m_input.Mouse.X, m_input.Mouse.Y, rec_zona_impacto) Then

            Cursor.Current = Cursors.Hand

            If HitEvent.Mouse_Hit(Mouse_Button.Left_Button) And m_input.Mouse_Press = 1 Then
                left = m_input.Mouse.X
                top = m_input.Mouse.Y
            End If
            rec_zona_impacto.X = left : rec_zona_impacto.Y = top
            rec_zona_impacto.Width = 30 : rec_zona_impacto.Height = 30

        End If
    End Sub

    Private Sub nueva_zona_impacto()
        rec_zona_impacto.X = left : rec_zona_impacto.Y = top
        rec_zona_impacto.Width = 30 : rec_zona_impacto.Height = 30
    End Sub
    Protected Overrides Sub Finalize()
        MyBase.Finalize()

        m_gfx.FONT_UnloadSystemFont(fnt_system1)
        m_gfx.MAP_Unload(gfx_ficha)

    End Sub



End Class

[EX3]

Pon un punto de control en el If y evalua si se esta cumpliendo la condicion.

Depurando linea a linea es como podras encontrar el error y donde se produce.

Salu2...
José Miguel Sánchez Fernández
.NET Developer | Game Programmer | Unity Developer

Blog | Game Portfolio | LinkedIn | Twitter | Itch.io | Gamejolt

Hechelion

Sigues teniendo error en la ruta del recurso y da igual que estén en el mismo directorio, por lo que sé (salvo que Ex3 diga otra cosa) en el metodo LOAD debes colocar la ruta absoluta no la relativa.

gfx_ficha = m_gfx.MAP_Load(Application.StartupPath & "\img\ficha.png", 0)


Ve paso a paso y mira el valor de gfx_ficha después de cargar, si te valor negativo es porque cargo mal, haz el cambio que te marque arriba y vuelve a revisar el valor, debería ser 0 o superior.

divmas

Ya he hecho unos pequeño arreglitos a la clase y lista....

Gracias a todos

divmas

El problema con el que me encuentro ahora es que con el objeto pulsado lo puedo mover libremente pero si paso por encima de otro objeto como se produce el mouse_press me "absorbe" ese objeto.

No se me ocurre una condicion que esté dentro de la propia clase para que esto no ocurra.

¿Se os ocurre algo?

Gracias

Hechelion

Yo trabajo con Focos, sólo un objeto puede tener el foco en un mismo momento y el foco se entrega en el evento HIT del mouse y se entrega según el orden en que se encuentran en la lista. o sea, se recorre la lista de objetos (ClsVentana en mi caso) hasta encontrar el primer objeto que tenga colisión con el mouse y se le entrega el foco. Así lo hago yo por lo menos.

divmas

Hechelion,

podrias poner un ejemplo de código del tema focos para que me aclare?

Gracias






Stratos es un servicio gratuito, cuyos costes se cubren en parte con la publicidad.
Por favor, desactiva el bloqueador de anuncios en esta web para ayudar a que siga adelante.
Muchísimas gracias.