Making progress =) Time for the next step in maps

Started by Bustaballs, June 07, 2008, 03:56:33 PM

Previous topic - Next topic

Bustaballs

I finally got PB to load my maps made in my VB6 map editor. Now I need to figure out how to use the PB map functions so I can create multiple layers for collision tiles/buildings and sprites.

I could do that with 3 layers, right? And just have it load one map for collision and one map for walking areas. Then another layer for NPCs, Player, event triggers, etc.
QuoteOh please

Bustaballs

Fixed:

IMGNUM=1

For j = 1 To 20
For i = 1 To 15
DrawImage IMGNUM, y, x, 1
Inc IMGNUM
x = x + 32
Next
x = 0
y = y + 32
Next

WaitKey


Forgive me for the unnecessary, over-complicated code.
QuoteOh please

thaaks

Okay, right now you are just drawing the tiles without using maps and layers. That's fine for the start.

What you could improve is the way you read in the images from the file.
You create a new image for each tile. This is not necessary as you only have to read the different images once. So you'd need to use a list of already read filenames and images and reuse the images you've already read.
This will save you tons of memory and image handles especially when using large tiles.

And I think for PB maps and layers you'll need to have all tile graphics in one image file which is "attached" to a map using the command "MakeMapGFX".

Hope that helps,
Tommy

kevin

#3
   Sadly the approach your talking is much less efficient than just storing a picture. 

   If you load each individual (32*32) tile into memory separately, then this eats (32*32*4) * the number tiles in bytes.   In this case, that's going to be (32*32*4*300) = 1,228,800 bytes.  1.2 meg in other words.   So the bigger the map the more memory this going to eat. 

   What you need to do is store a list of the unique tiles graphics the map uses.   Then rather than load the block filenames in each position in the map, keep an index to the filename in the block list.   So the map file could look a bit like this,

Quote
// List of the blocks to load
"/GFX/walkway4.bmp"
"/GFX/walkway2.bmp"
"/GFX/street.bmp"
"/GFX/street2.bmp"
"/GFX/grass.bmp"

// The map array.  Each number represents the block file from the above file list
"0,0,0,0,0,0,0,0"
"1,1,1,1,1,1,1,1"
"2,0,0,0,0,0,0,0"
"2,1,1,1,0,0,0,0"
"0,0,0,0,0,0,0,0"
etc


What this would do, is allow you to reuse the same image wherever it appears on screen.  So the gfx blocks only exist in memory once.  This can then  easily be imported into a PB map and rendered.

Another addition you might want to make is adding something to the map files that tells the loader the width and height of the map.    This way you can write the display map stuff to be generic.  Currently the loader/display routines would have to be changed/customized to the map if the dimensions are changed. 

  Anyway, here's a version of your loader than caches the Block loading into a list of unique blocks.   So we're only ever have a short list of blocks in memory.



OpenScreen 640,480,16,1
Filename$="test.hax"


// Array to hold the list of unique blocks
BlockCount=0
Dim BlockName$(BlockCount)
Dim BlockImages(BlockCount)

// The map
Dim Map(1000)

ReadFile Filename$,1

LineCount=0
Repeat
Inc LineCount
file$=lower$(ReadString$(1))
file$=trim$(file$," "+chr$(34)+chr$(9))
file$=trim$(file$,"/")
if file$<>""
// Check if the file already exists
BlockIndex=FindArrayCell(Blockname$(),0,1,BlockCount,file$)

if BlockIndex=-1
// Does this tile already exsi
BlockIndex=BlockCount

THisimage=LoadNewImage(CurrentDir$()+File$)

// Store the file name and the Image number of this block
BlockName$(BlockCount)=File$
BlockImages(BlockCount)=ThisImage

// Bump the Block Arrays up 1
inc BLockCount
reDim BlockName$(BlockCount)
reDim BlockImages(BlockCount)

endif

Map(LineCount) =BlockIndex
endif
Until EndOfFile(1)=true
CloseFile 1



a = 1
b = 15

Pos=1
For j = 1 To 20
x = 0
For i = a To b
// Read the Block index from the Map array.. Map really should be a 2D array
// but the map fornmat doesn't seem to tell us the size of the map
   ThisBlock=Map(pos)

// draw block image at this X/Y coord on the screen
DrawImage BlockImages(ThisBlock), y, x, 1

// Move to the next block in map
   Inc pos

   // Move X pos across one block
   x = x + 32
Next
y = y + 32
a = b + 1
b = b + 15
Next


WaitKey



Big C.

I wrote a simple Tutorial on this topic here. It helps, the carrying out of to understand kevin better.

Bustaballs

I can understand Big C.'s tutorial just fine. I see how that works.

Kevin. I'll have to look at the code more to understand it better but from what I can tell, and please correct me if I'm wrong, is that in order to adjust to my maps, you have a PB command run the map file and load the tiles the map current has in it into memory only once before loading the map. I don't really understand how the FindArrayCell command works. I look it up and then I don't understand what mean means by element. That's new programming jargon for me.

In task manager:

Kevin's:  15,372 K
Busta's:  15,792 K

Technically, I don't really need to do this because my maps will be very small and load a different map each time. The finished game shouldn't even use close to 32MB of total RAM   However, I know I need to learn good programing habits before I can get better. =)

Now, once I fully understand Kevin's example, I'll work on putting them on PB layers, assuming it's possible. Do I really need to have all of the tiles in one image before using the PB map command?
QuoteOh please

kevin

  Nah,  I'm referring to the consumption of video/graphics memory here.   When we load images with LoadImage/LoadNewImage the actual pixel data doesn't live in computers main memory, it's actual stored in your graphics card memory.   Task manager doesn't take this into consideration.  It's just giving you the amount of system memory.  So it's not an ideal way to monitor the memory foot print of a PB program, or any audio/visual program really.   Since PB programs consume system, video and sound memory.    The same as any game would.

  To calculate the amount of Graphics your Pb rpograms are using (at any given point) use this.  CalcUsedImageMemory

  To learn more about image types (video/fx etc) read this.  Economizing Image Blitting



Bustaballs

Ah, I forgot about that. I never coded much DX in VB so everything was stored in RAM. So, yes. I see the big issue of a small screen using up that much video memory as I'd like the program to use no more than 8MB of video memory so it can run on most older machines. My laptop only has 8MB of video memory.

Thanks for the tips, Kevin.
QuoteOh please

Bustaballs

Hey. Whenever I run and print the CalcUsedImageMemory() function, Memory seems to return 0 as a value.
QuoteOh please

kevin


Post the code, as a result of 0 is impossible.

Bustaballs

It's just the code you posted earlier with the function after the loop and calling+printing the result before WaitKey


OpenScreen 640,480,16,1
Filename$="test.hax"


// Array to hold the list of unique blocks
BlockCount=0
Dim BlockName$(BlockCount)
Dim BlockImages(BlockCount)

// The map
Dim Map(1000)

ReadFile Filename$,1

LineCount=0
Repeat
Inc LineCount
file$=lower$(ReadString$(1))
file$=trim$(file$," "+chr$(34)+chr$(9))
file$=trim$(file$,"/")
if file$<>""
// Check if the file already exists
BlockIndex=FindArrayCell(Blockname$(),0,1,BlockCount,file$)

if BlockIndex=-1
// Does this tile already exsi
BlockIndex=BlockCount

THisimage=LoadNewImage(CurrentDir$()+File$)

// Store the file name and the Image number of this block
BlockName$(BlockCount)=File$
BlockImages(BlockCount)=ThisImage

// Bump the Block Arrays up 1
inc BLockCount
reDim BlockName$(BlockCount)
reDim BlockImages(BlockCount)

endif

Map(LineCount) =BlockIndex
endif
Until EndOfFile(1)=true
CloseFile 1





Pos=1
For j = 1 To 20
x = 0
For i = 1 To 15
// Read the Block index from the Map array.. Map really should be a 2D array
// but the map fornmat doesn't seem to tell us the size of the map
   ThisBlock=Map(pos)

// draw block image at this X/Y coord on the screen
DrawImage BlockImages(ThisBlock), y, x, 1

// Move to the next block in map
   Inc pos

   // Move X pos across one block
   x = x + 32
Next
y = y + 32
Next

CalcUsedImageMemory()
Print Memory
WaitKey


Function CalcUsedImageMemory()
OldSurface=GetSurface()

For Img=0 to GetImageQuantity()
If Img=0 or GetImageStatus(Img)=true
Rendertoimage Img
Lockbuffer
ImgSize= GetImagePitch(Img)*GetIMageHeight(img)
unlockbuffer

// Check for screen. If so, add the second buffer
if Img=0 then ImgSize=ImgSize*2
Memory=Memory+ImgSize
Endif
next

RenderToImage OldSurface
EndFunction Memory

QuoteOh please

kevin


erm, what is this meant to do ?


CalcUsedImageMemory()
Print Memory


I think you mean



Print CalcUsedImageMemory()


Tip.  Read the Functions & Psub Tutorials in the Help

Bustaballs

I did. I read it a couple of weeks ago. >.<

Sorry.
QuoteOh please

Bustaballs

Is this the basics of how the map system would work by step?

MyMap=GetFreeMap()
CreateMap
CreateMapGFX
CreateLevel
-Load images
PokeLevelTile
DrawMap
QuoteOh please

kevin


Yep, you can refine it a little..  But that's the gist.


MyMap=NewMap
CreateMapGFX MyMap   (Create the gfx data in the map)
-Load block data

MyLevel=NewLevel(MyMap)   (create a level an attach it to myMap)
PokeLevelTile
DrawMap


If the player completes this level, and the next level uses the same Block GFX, then all we do is Delete the level and load the next one.

If the player completes the current level and you want to load a new block set,  you just delete the whole Map.  This will destory the Map and anything that was attached to it.  Such as it's private gfx data, the levels and any animations..

So to load the next level we repeat the loading process above.