Jump to content
Xtreme .Net Talk

Recommended Posts

Posted (edited)

Howdy there,

This is my first post here, but I've been on this site quite often recently, since I've been working with VB.NET. I normally code in C++.

 

I'm making a map maker for my 2D tile-based RPG in Allegro.

 

I've a 2D array of images, and I display them on a panel. When I call the sub that draws them again, to update (it loads the data from a file), nothing appears to happen. I am wondering if I need to clear the panel first, then draw, or if it's related to my using a StreamReader twice or more.

 

Here's a bit of my code:

 

   Public Sub draw_map()
       ' Load the image preferences
       Dim imgprf_file As New FileStream(imgprf_filename, FileMode.Open, FileAccess.Read, FileShare.None)
       Dim imgprf_file_reader As New StreamReader(imgprf_file)

       Dim location As String
       unique_images.Clear()
       While Not imgprf_file_reader.EndOfStream
           Dim unique As Image
           location = imgprf_file_reader.ReadLine()
           unique = Image.FromFile(location)
           unique_images.Add(unique)
       End While

       imgprf_file_reader.Close()
       imgprf_file.Close()

       ' Declare the array
       ReDim map(map_width, map_height)
       Dim pbMap As New PictureBox
       pbMap.Image = New Bitmap(map_height * tile_height, map_width * tile_width)
       pbMap.Location() = New Point(0, 23)
       pbMap.Size = New Size(map_height * tile_height, map_width * tile_width)
       pbMap.BackColor = Color.LightYellow
       Dim g = Graphics.FromImage(pbMap.Image)

       ' Calculate each tile's worth (progress bar)
       barLoading.Maximum = (map_width * map_height)
       barLoading.Value = 0

       ' Setup the coordinates of the boxes
       Dim offset As Integer = 0 ' How much the pics are offset from the top... creating new row

       Dim map_file As New FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.None)
       Dim map_file_reader As New StreamReader(map_file)
       Dim tmp As String
       Dim tmp2(map_width - 1) As String


       For x As Integer = 0 To map_width - 1
           tmp = map_file_reader.ReadLine()
           tmp2 = tmp.Split(" "c)
           For y As Integer = 0 To map_height - 1
               If tmp2(y) > unique_images.Count - 1 Then
                   g.DrawImageUnscaled(unique_images(0), y * tile_width, offset, tile_width, tile_height)
               Else
                   g.DrawImageUnscaled(unique_images(tmp2(y)), y * tile_width, offset, tile_width, tile_height)
               End If

               If y = map_height - 1 Then
                   offset += tile_height
               End If

               ' Add to the progress bar
               barLoading.Value += 1

           Next y
       Next x

       ' If they want, draw the grid
       If grid = True Then
           If map_width > map_height Then
               For i As Integer = 0 To map_width
                   g.DrawLine(Pens.Black, i * tile_width, 0, i * tile_width, map_width * tile_height)
                   g.DrawLine(Pens.Black, 0, i * tile_height, map_height * tile_width, i * tile_height)
               Next
           Else
               For i As Integer = 0 To map_height
                   g.DrawLine(Pens.Black, i * tile_width, 0, i * tile_width, map_width * tile_height)
                   g.DrawLine(Pens.Black, 0, i * tile_height, map_height * tile_width, i * tile_height)
               Next
           End If
       End If

       map_file_reader.Close()
       map_file.Close()

       Me.pnlMain.Controls.Add(pbMap)

       ' Set the progress bar back to empty for the next routine
       barLoading.Value = 0
       setup = True

       lblTitle.Text = filename
       lblMapDat.Text = Convert.ToString(map_height) + ", " + Convert.ToString(map_width) + "  " + Convert.ToString(tile_width) + ", " + Convert.ToString(tile_height)

   End Sub

 

It is this function that is called again, in hopes of updating the map. It loads from the map file, which is updated in a different form.

 

Thanks for any help,

 

Lorgon Jortle

Edited by LorgonJortle
  • Leaders
Posted

A couple of things:

 

It seems you are creating a new control and image each time you render. Unless the map changes size (or, more specifically, becomes larger than the current buffer), I don't see the need for a new image, and unless you need two maps shown simultaneously, there is no need for more than one picturebox. It also doesn't look like you are disposing the images. If possible, it would be best to re-use the control and image.

 

Also, you should probably break the code up into more functions. You have numerous subtasks thrown into the single function and it makes it much harder to understand.

 

Also, if you are done with the images in unique_images at the end of the sub, you should dispose of them there and then (before exiting the sub). As is, it looks like you never dispose of them.

 

Finally, I believe that when you add a control to a form, by default it appears beneath all other controls (this is standard Windows behavior). That being the case, since you are creating a new control each time, it will be concealed beneath the previous picturebox. So, you can either re-use the existing picturebox or remove the old one.

[sIGPIC]e[/sIGPIC]
Posted

Marble_Eater, would changing the map to static fix the problem, or does it need to be global?

 

Also, I'll try to remove the pictureboxes, or reuse them. I'm on Linux now, so I can't try it yet, but I really appreciate the response.

 

Also, about the code... I know it looks like crap. I just want to get things working, then I'll do a total cleanup of it.

 

One question, do I need to dispose of things? Like I said, I generally code in C++, and I'm used to a corresponding "delete" with every "new", but I was told I don't need to dispose of anything with VB.NET.

 

Thanks again.

 

LJ

  • Leaders
Posted
Marble_Eater, would changing the map to static fix the problem, or does it need to be global?

Do you mean the map variable? I don't even see where it is used. Regardless, I would stay away from static variables. It's a holdover from VB6 and amounts to a class-level variable that can only be accessed from one method. Instead, if a variable is to be used later by the same class, I'd recommend declaring the variable as a class member rather than in the function.

 

Also, I see you sizing the array with ReDim. This does work fine, but a DotNet purist might whine about it. Just FYI, the alternative would be:

 

map = New ElementType(map_width, map_height) {} 'Don't know the type; don't see it used

 

 

Also, I'll try to remove the pictureboxes, or reuse them. I'm on Linux now, so I can't try it yet, but I really appreciate the response.

I would recommend creating one and re-using it each time. Also, unless the image needs to become larger, there is no reason you can't reuse the Image too.

 

One question, do I need to dispose of things? Like I said, I generally code in C++, and I'm used to a corresponding "delete" with every "new", but I was told I don't need to dispose of anything with VB.NET.

This is a good question. DotNet does do automatic garbage collection. The problem is that it can only collect what it creates. Objects or memory allocated by Windows or other unmanaged (non-DotNet) code won't be garbage collected.

 

Eventually, a discarded DotNet object will be garbage collected, and if the object was thoughtfully coded it will free up unmanaged resources when it is collected, but when it comes to unmanaged resources it is best to free them up deterministically via their Dispose method. (Some objects use a different name. For instance, a Stream has a Close method instead of a Dispose method. The point is that objects that implement IDisposable should be released.) This applies to Controls, Images, Streams, and more.

 

As your program is written now, the picture boxes and the images they directly contain are still all present on the form and can never be garbage collected. If you re-use the PictureBox (and, preferably, the Image when possible), this problem goes away anyways.

[sIGPIC]e[/sIGPIC]
Posted

Man, I really appreciate the help. I've changed my code to remove the control from the panel before the images are draw, so it doesn't keep building up. I don't know if I would've ever thought of that.

 

Now, I've another rather bothersome problem:

When I draw my images, they are in, what seems to be, completely arbitrary scaling. Some tiles are tiny, and some a huge. All of my tiles are the same size, 40x40, and I'm using DrawimageUnscaled.

 

Any ideas?

 

Thanks!

 

LJ

  • Leaders
Posted

The name DrawImageUnscaled is very misleading. It doesn't draw the image pixel-for-pixel. It tries to draw them at their "correct physical dimensions." In other words, it takes the image's DPI and the display's DPI and scales the image to get the correct physical size.

 

I don't know where your images are coming from, but if their resolution (DPI) varies, they will be rendered differently. The best way to actually draw an image unscaled is with one of the DrawImage overloads that accepts a source rectangle, destination rectangle, and what kind of unit to use. You would want to specify GraphicsUnit.Pixel. If the source rectangle and destination rectangle are the same size, the output won't be scaled.

[sIGPIC]e[/sIGPIC]
Posted

2D array of images wont refresh

 

A flash based intro would allow you to have images shown in the movie at any time youd like. Plus, it gives you more options and nyou can make it look really cool.

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...