News:

Function Finder  Find all the functions within source code files

Main Menu

Trouble with maps and cameras

Started by kanifox, June 07, 2006, 03:26:54 PM

Previous topic - Next topic

kanifox

I'm familiar with the basics, I've done a pong and a simple platformer, and now I really want to make a scrolling game.  I understand that it's usually done with arrays, and I've done that already, but it was slow because I was moving the entire level every loop.  I couldn't figure out a way to just load the tiles I needed.

Now I'm guessing PB's map and camera commands take care of all that, but I can't figure out how to use them.  I've even read all the documentation.  This is how I understand it...  You get your sprites, make a map, load everything into the world buffer, make a camera and position it, then load what you need into the scene buffer, then draw everything and sync it.  I don't get why you have to draw everything, and then the camera too.  It seems like the camera should just automatically pick up everything that's drawn where it's looking.. and I don't see the reason for the scene buffer.  In my mind, I should just be able to position the camera where I want it in relation to the world buffer.

And another thing... what exactly IS a map in PB anyway?

kanifox

Please, if someone could help me understand this stuff, I would really appreciate it

kevin

QuoteI don't get why you have to draw everything, and then the camera too.

 Your not drawing anything twice.  Your capturing whatever dynamic items you want as a draw request to the 'scene'.    These events are clipped/sorted and render in display order regardless of draw order for you.   Which is what the camera does.  
 
QuoteIt seems like the camera should just automatically pick up everything that's drawn where it's looking.. and I don't see the reason for the scene buffer. In my mind, I should just be able to position the camera where I want it in relation to the world buffer.

  You can. but, worlds are for managing the static elements in your game world.   While a world can be made of anything really, those elements captured into a world can not move.  Therefore it can't work as your assuming   The world describes the game worlds bigger environment, not the dynamic objects within it.  

  Dynamic objects can be anything.  Sprites are obviously dynamic objects, but you can also use images, polygons, vector art, text even maps dynamically.  So we need something to grab these items and process them in relation to world items.    Even combined content from various worlds if the user desires.  

  Since PB exposes the scene (which is needed regardless), data can take any path(s) the user chooses.  Without it, you only worlds/sprites could be drawn.

 ie.



World    /  Sprites /  Maps / Other User Objects

\/
Scene

\/
Camera

kanifox

I think I'm starting to see...

So you would put your basic landscape - floors, walls, and ceilings - into the world buffer, then put enemies, items, and other interactive stuff into the scene buffer (which is kind of like an overlay on the world buffer, right?), and then the camera calculates what to load from the world and scene buffers based on its position and viewport size.  Is that right?

kevin

#4
Yep pretty much.  

 The scene is simply a list of captured draw events.   All were doing really is shoveling data into the scene (our main list of draw events), and then using a camera (a processing routine)  to sift through it for us.   Which allows us to mix different types of graphics together, while it works out the visibility/clipping & draw order for us.  

 Worlds are virtually the same as the scene buffer really.  They also hold a list of draw events.  The difference is that world buffer data is held in a partitioned format.   Hence why their for static purposes really.  

 So to render a view from a world, we're piping data into the scene buffer from whatever world(s) we choose.  The partitioning is used to to grab a 'camera' full of items quicker.    Worlds also have a dual purpose.. Namely collision.

 To confuse the issue even further, your game doesn't necessary have use worlds at all.  A good example of that are games that just render a tile map + some sprites.  (i.e. like the platform game example)   Where the environment is simply a map level with some characters running around it.    

 While we could always do the old skool thing and translate everything to the viewport ourselves, it's less work to just capture the draw events to the scene buffer, position the camera and tell it to handle that for us.

 Ie.

PlayBASIC Code: [Select]
  CaptureToScene; Turn off drawing mode and activate capture mode
ClsScene; clear the scene buffer list.
CaptureDepth 100; Set the current capture depth for items in capture mode.
DrawMap MyMap,MyLevel,Xpos,Ypos
DrawAllSprites; Pipe the sprtes in
DrawCamera MyCamera; Sort/ clip/ render scene.


kanifox

Okay, thanks for your help  :)

kanifox

#6
Would you mind clarifying some things about maps for me?

First you create a map, and you declare the maximum number of layers you might want the map to have.  Then you import graphics for the map to use, which become tiles which are each assigned an index number, but they don't actually go into the map, at least not a part of the map that you will see, but are somehow stored off to the side for that map specifically to call on.  Then you create a level, where the actual graphics will go, and put the tiles you imported into it with pokeleveltile, using tile coordinates rather than pixel coordinates.  Am I getting it right?


Also..

QuoteWorlds also have a dual purpose.. Namely collision.

Are you saying you can't do collision in the scene buffer?  Or what?

kevin

Partly.
 
 
 A map in PB is really a collection of 3 elements.

 1) GFX Blocks
 2) Level arrays
 3) Animations data (optional)

 When we create map we're initializing the main MAP structure.  We can then create (append) a set of GFX blocks for this map.  The Block graphics are stored internally.  Their nothing more than a list of blocks of whatever Width/height was specified.  

 When we create a level, the level is basically an array.  Where each cell in that array is an index to this maps internal block list.   Setting a tile to 0,  means draw block zero at this position,  a 1 means block 1 etc.

 The distinction is that Creating a Level does not create a huge image made up of the maps blocks,  it only an array of what blocks are used at each position..

kanifox

#8
I made a tile editor
I...am so...happy  :(

PlayBASIC Code: [Select]
mapwidth=96
mapheight=96
layers=1
currentmap=1
currentlevel=1
currenttile=1
tilesize=32

mapx=0
mapy=0

SetFPS 30
ScreenVsync On
CreateCamera 1

Ink RGB(255,0,255)
Box 0,0,32,32,1
Ink RGB(200,200,200)
Box 32,0,64,64,1
GetImage 1,0,0,64,32

CaptureToScene
CreateMap 1,layers
MakeMapGFX 1,1,tilesize,tilesize,2,RGB(255,0,255)
CreateLevel 1,1,mapwidth,mapheight
DeleteImage 1

Do

If MouseX()>0 And MouseY()>0 And MouseX()<GetScreenWidth() And MouseY()<GetScreenHeight()

If LeftMouseButton()=1 Then PokeLevelTile currentmap,currentlevel,(MouseX()/tilesize)+mapx,(MouseY()/tilesize)+mapy,currenttile
If RightMouseButton()=1 Then PokeLevelTile currentmap,currentlevel,(MouseX()/tilesize)+mapx,(MouseY()/tilesize)+mapy,0
EndIf


If RightKey()=1 And mapx<mapwidth-24
MoveCamera 1,32,0
mapx=mapx+1
EndIf

If LeftKey()=1 And mapx>0
MoveCamera 1,-32,0
mapx=mapx-1
EndIf

If DownKey()=1 And mapy<mapheight-24
MoveCamera 1,0,32
mapy=mapy+1
EndIf

If UpKey()=1 And mapy>0
MoveCamera 1,0,-32
mapy=mapy-1
EndIf


DrawMap 1,1,0,0
DrawCamera 1
Sync

Loop



One thing I couldn't figure out was how to make it stop at the edges of the map.. so for now I just did the minus 24 thing.

Also...at first I was capturing everything to the world, but that was going really really slow.  I guess I don't understand how to use it

Next step is getting maps to save.

kevin

#9
That's pretty good.  Here's some tweeks


PlayBASIC Code: [Select]
mapwidth=96
mapheight=96
layers=1
currentmap=1
currentlevel=1
currenttile=1
tilesize=32

mapx=0
mapy=0

SetFPS 30
ScreenVsync On
CreateCamera 1

Ink RGB(255,0,255)
Box 0,0,32,32,1
Ink RGB(200,200,200)
Box 32,0,64,64,1
GetImage 1,0,0,64,32

CaptureToScene
CreateMap 1,layers
MakeMapGFX 1,1,tilesize,tilesize,2,RGB(255,0,255)
CreateLevel 1,1,mapwidth,mapheight
DeleteImage 1

; limit the cameras movement to within this zone
Limitcamera 1,true
limitcamerabounds 1,0,0,TileSize*MapWidth,TileSize*MapHeight

Do

if RightKey() then MoveCamera 1,TileSize,0
if LeftKey() then MoveCamera 1,-TileSize,0
if UpKey() then MoveCamera 1,0,-TileSize
if DownKey() then MoveCamera 1,0,TileSize

if pointovercamera(1,mousex(),mousey())
; Convert thwe mouse coord t world space and divide by the tile size
TileX=(int(GetCameraX(1))+MouseX())/TileSize
TileY=(int(GetCameraY(1))+MouseY())/TileSize

If LeftMouseButton()=1 Then PokeLevelTile currentmap,currentlevel,TileX,TileY,currenttile
If RightMouseButton()=1 Then PokeLevelTile currentmap,currentlevel,TileX,TileY,0

EndIf



; Build the scene
CapturetoScene
Clsscene
DrawMap 1,1,0,0

DrawCamera 1
Sync

Loop







kanifox

#10
Hey thanks, just what it needed  :)  Those are some nifty camera commands

What's the Capturetoscene in the loop do?  I can see it doesn't work without it, but my code did work without it

I've now gotten it to write the tile numbers to a file, seperated by commas, so I can just paste it into a data statement.  Next step:  Collision

Thanks for helping me understand this stuff  :)   Really, thanks a lot

kevin

QuoteWhat's the Capturetoscene in the loop do? I can see it doesn't work without it, but my code did work without it
Actually, no it doesn't.   It has a common logical error it in. Your code ends up drawing the map twice per update.

 Upon first execution through the Do/Loop the DrawMap command will be capture to  the scene buffer event que.  So the scene now has 1 item in it. Our map Level

 by default after the camera is drawn, PB reverts to DrawGfxImmediate mode.  

 So, on the second (etc) loops, the map is being drawn immediately to the frame buffer, then it's being erased by the draw camera + it's render.  Doubling up the work load.

To load/ save,

#include "Map"
 LoadLevel Filename$,ThisMap,Level
 SaveLevel Filename$,ThisMap,Level

kanifox

Ah, I see.  I didn't know it automatically switched off capturetoscene

And wow, I didn't know there were already commands for saving and loading  :P   Oh well, I got to learn a bit about writing to files