Thread: Direct3D8 Tile-Map

  1. #1
    Registered User
    Join Date
    Jun 2003
    Posts
    361

    Direct3D8 Tile-Map

    Hullo all, I'm working on converting and expanding my VB Tile Game into C++. The problem is that in VB I used BitBlt, but now I'm looking to use DirectX. My question is how do I set up an array to hold all the vertices for each tile.

    My thoughts have been:
    Use a Triangle Strip

    So, for a 5 by 5 board:

    SEE DIAGRAM 1 (BELOW)

    There are 36 "Vertices", I was thinking that I would be able to just use a Triangle Strip of 36 Vertices, but I after thinking about it, I decided I'd need 4 vertices per tile:

    SEE DIAGRAM 2 (BELOW)

    But, my problem is that if it's a Strip, then vertices (3, 4, and 5) will make a rather useless triangle. So, I thought of something like...

    SEE DIAGRAM 3 (ABOVE...I MEAN BELOW)

    Which works rather well for a column (or row) if I turn off back-face culling, but, I run into problems when trying to slide over to the next column.

    So, I'm wondering, what kinds of suggestions/methods have you guys used in the past when making a 2d-Tiled Board? Or just what ideas do ya have on it? Any insight is appreciated Thanks
    Last edited by Epo; 03-02-2004 at 08:14 PM.

  2. #2
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    I ran into the same problem while trying to use Direct3D to render tiles. The scrolling was all messed up because I could not control the rendering of each tile.

    My advice is to keep your DirectX very simple for this task. Create two buffers - the primary and the attached secondary as the back buffer. Lock the back_buffer and get a pointer to it. From that point on, simply access the back_buffer as you would in any old DOS graphic engine.

    To do tiling right, you really need total control over the pixels and rendering of each tile.

    I will attach my DOS tiling code for you to look at. This will convert directly to DirectX - if you simply retrieve the aforementioned pointer and store your bitmaps in a similar fashion.

    You will notice that even the hardware blitter is not going to be used, nor do you need to attach a clipper to any of the surfaces. Those are all mute points because we will control the blits and the clipping in one function.

    Also it is interesting to note that when a tile is offscreen, if you simply take the negative values in x and y for how far offscreen the tile is and make them positive - you have the exact pixel locations within that bitmap to begin drawing at.

    For instance if the upper left bitmap's starting point is at -10,-10 then you need to start drawing your pixels at offset 10,10 in the bitmap.

    For this small sample, scroll by moving the cursor bitmap to the edges of the screen and exit by clicking the LMB. This only demo's one tile, but it could just as easily be a map of tiles after I add a couple of lines of code.
    This flies in DOS so I know it will scream in DirectX - and even perhaps writing the entire blitting in assembly would help. The DOS version is 320x200x256 but in DirectX you can have much more than that. My DirectX version is still being coded, but it should be done soon.

  3. #3
    Registered User
    Join Date
    Jun 2003
    Posts
    361
    Here are the Diagrams for each of those crazy things above (this is what I was TRYING to draw)

  4. #4
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Yes, I already have code that draws a triangle strip via Direct3D.

    Code:
    int TileEngine::Render(int offset_x,int offset_y)
    {
    	
      D3DTLVERTEX Vertex[4];
      Vertex[0].color=D3DRGB(1.0f,1.0f,1.0f);
      Vertex[1].color=D3DRGB(1.0f,1.0f,1.0f);
      Vertex[2].color=D3DRGB(1.0f,1.0f,1.0f);
      Vertex[3].color=D3DRGB(1.0f,1.0f,1.0f);
    	
      Vertex[0].tu = 0.0f; 
      Vertex[0].tv = 0.0f; 
    
      Vertex[1].tu = 1.0f; 
      Vertex[1].tv = 0.0f; 
    	
      Vertex[2].tu = 0.0f; 
      Vertex[2].tv = 1.0f; 
    
      Vertex[3].tu = 1.0f; 
      Vertex[3].tv = 1.0f;
    
      Vertex[0].rhw=1.0f;
      Vertex[1].rhw=1.0f;
      Vertex[2].rhw=1.0f;
      Vertex[3].rhw=1.0f;
    	
      D3DDevice->BeginScene();
      D3DDevice->SetRenderState
         (D3DRENDERSTATE_FILLMODE,D3DFILL_SOLID);
      D3DDevice->SetTexture(0,SampleTexture->GetSurface());
    
    	
      int screen_x=offset_x;
      int screen_y=offset_y;
      int tile_x=0,tile_y=0;
      while (screen_y<ScreenHeight)
      {
         screen_x=-offset_x;
         while (screen_x<ScreenWidth)
         {
            Vertex[0].dvSX=screen_x;
            Vertex[0].dvSY=screen_y;
            Vertex[1].dvSX=screen_x+64;
            Vertex[1].dvSY=screen_y;
            Vertex[2].dvSX=screen_x;
            Vertex[2].dvSY=screen_y+64;
            Vertex[3].dvSX=screen_x+64;
            Vertex[3].dvSY=screen_y+64;
            D3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,
    	 D3DFVF_TLVERTEX,Vertex,4,0);
            screen_x+=64;
            tile_x++;
         }
          tile_y++;
          tile_x=0;
          screen_y+=64;
      }
    		
       D3DDevice->EndScene();
       return(0);
    }

  5. #5
    Registered User
    Join Date
    Jun 2003
    Posts
    361
    I'm having some troubles with the program, I think it's locking up because I don't see a cursor, nor does the left mouse button do anything (I have to Alt+Tab out of it), but, I like what I see! Hehe, the mouse isn't the important part. Do you happen to have the source kicking around somewhere that I could take a look at too?

  6. #6
    Registered User
    Join Date
    Jun 2003
    Posts
    361
    Are you just creating one "Tile" and recopying it all over the screen??

  7. #7
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Essentially, yes. But with two more lines of code I could create a tile map. I simply need to increase tile_x and tile_y based on the coordinates of the pixels. If your tile is 20x20 then when (pixelx %20)==0 you will have moved one column over - so increment the column. Basically the same with the vertical.


    Currently only renders 1 bmp, but if all bmps are loaded into an array it could do a tile map. Merely have to divide the x and y byt the tile size to get the current tile and check what number is in the tile map then render [tilenumber][tiledata].
    Code:
    void Render(BMPImage *testimage)
    {
      WORD screenoffset=0;
      int imgwidth=testimage->GetWidth();
      int screenx=0,screeny=0;
      int spritepixelx=scrollx % 20;
      int spritepixely=scrolly % 20;
      int spritepixeloffset=(spritepixely*20)+spritepixelx;
    
      for (screeny=0;screeny<=199;screeny++)
      {
        screenoffset=(screeny*320)+screenx;
        for (screenx=0;screenx<=319;screenx++)
        {
          Surface[screenoffset]=testimage->GetImageData(spritepixeloffset);
          screenoffset++;
          spritepixeloffset++;
          if ((spritepixeloffset % imgwidth)==0)
          {
            spritepixeloffset-=imgwidth;
          }
        }
         spritepixely++;
         if (spritepixely>=20) spritepixely=0;
         spritepixeloffset=(spritepixely*20)+spritepixelx;
      }
    }
    If you are in XP it's quite possible that sample I gave you will have several issues. It uses interrupts for the mouse and for the video, but XP should theoretically run it in virtual 8086 mode.

  8. #8
    Registered User
    Join Date
    Jun 2003
    Posts
    361
    I'm really liking this code, but I have just one question about the D3D and D3DDevice objects that I always come up to whenever I try to incorporate Classes into my D3D Programs.

    In my main .cpp file, I do my window creation, which also requires a D3D and D3DDevice to initialise Direct3D.

    Then, in the .cpp for my class (or even your example above) for a method such as Class::Render I need D3D and D3DDevice objects as well. Now, do I need to initalise a separate set of these objects? Or can I somehow use the objects from my main .cpp file? Or, by making the objects Global in my main .cpp file, are they also just useable as they are in my other .cpp files?

    I haven't been able to come across the answer to this one yet, and any help is appreciated (if you can figure out what it is that I'm asking anyways) Thanks ahead

  9. #9
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Well for this code you don't need Direct3D. Just get DirectX up and running to the point that you have two buffers or surfaces - the primary and the attached surface also known as the back buffer.

    Then lock each surface and get the pointer to them. The rest can be done by simply plotting pixels just as you would in DOS via the pointers. You really do not need anything else for rendering other than a simple bitmap renderer so that you can place things like explosions, characters, etc. on your map and not be restricted to the tiles. Your tiles make up the world and your characters should be free to move anywhere in those tiles and anywhere in the map. If not, then your characters will look like they are chess pieces moving square to square which is more than ugly.

    If you need help setting DirectX up, I've got a simple framework that should get you going. From there the sky is the limit. I'm also working on re-coding all the input and sound portions as well so that the framework is easier to use.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Smooth walking on tile based map system
    By abraham2119 in forum C Programming
    Replies: 8
    Last Post: 07-10-2009, 10:33 AM
  2. Polynomials and ADT's
    By Emeighty in forum C++ Programming
    Replies: 20
    Last Post: 08-19-2008, 08:32 AM
  3. Need testers for editor
    By VirtualAce in forum Game Programming
    Replies: 43
    Last Post: 07-10-2006, 08:00 AM
  4. New editor updates
    By VirtualAce in forum Game Programming
    Replies: 8
    Last Post: 11-05-2005, 03:26 PM
  5. Tile map loading/saving
    By sand_man in forum Game Programming
    Replies: 16
    Last Post: 04-23-2005, 09:38 PM