LorgonJortle Posted November 22, 2009 Posted November 22, 2009 (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 November 22, 2009 by LorgonJortle Quote
Leaders snarfblam Posted November 22, 2009 Leaders Posted November 22, 2009 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. Quote [sIGPIC]e[/sIGPIC]
LorgonJortle Posted November 23, 2009 Author Posted November 23, 2009 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 Quote
Leaders snarfblam Posted November 23, 2009 Leaders Posted November 23, 2009 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. Quote [sIGPIC]e[/sIGPIC]
LorgonJortle Posted November 25, 2009 Author Posted November 25, 2009 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 Quote
Leaders snarfblam Posted November 25, 2009 Leaders Posted November 25, 2009 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. Quote [sIGPIC]e[/sIGPIC]
Odry Posted November 29, 2009 Posted November 29, 2009 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. Quote
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.