Thread: Question on how to proceed(Game programming, kinda long).

  1. #1
    Registered User
    Join Date
    Mar 2005
    Posts
    16

    Question on how to proceed(Game programming, kinda long).

    Hi all,

    I'm fairly new to programming in C++, though I've been programming for a while in Java, and am going to begin work on a game(I'm sure you've all heard that quite often). I have a question I'm not certain how to proceed with, and could use some advice.

    The game is going to be a 4x TB strategy game set in space, ala Master's of Orion. My problem is this...

    I need to have a 2d map upon which I will randomly place Stars and other objects like Nebulas throughout. But I'm not sure how to create the map so that I can place these items. I need to have the method flexible enough so that stars can be placed in a way that does not appear like it's just a regular old grid with every star at the exact center of a block.

    The only way I have thought of that I can do this, is by using a 2 dimensional array as the Map. Then designating that a set of 9 entries in the array constitutes another "Block on the grid", so that Items can be placed in varying portions of the "Block on the grid". I.e. the entries on the array corresponding to the numbers below would be one block.

    222
    111
    012

    Giving me a center, and "Compass" points in which to place an object, so that it doesn't appear each star is in the exact center of each "Block" it appears in.

    My question is this.

    Is there an easier way to define a "Grid" based map so that these items could be placed in terms of X,Y coordinates rather than placed in a 2d Array? If so, could someone give me a brief overview on how to do it? I'll also need to be able to save these coordinates to a file.

    Not asking for anyone to code it for me, just give me a brief explanation on how it could be done and I'll work it out for myself, as I believe that doing is the better part of learning

    Thank you all in advance, and thank you for putting up with what's probably the umpteenth "I'm going to make a game" question you've seen this week!

  2. #2
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    Is there an easier way to define a "Grid" based map so that these items could be placed in terms of X,Y coordinates rather than placed in a 2d Array?
    It seems to me that a 2d array is an x,y coordinate system. If your universe is modeled with a 100 x 100 array, then you can place stars at any spot in the array based on their x,y coordinates. I don't know if that means you'll be placing stars at the center of a block because I don't understand what that means.
    Last edited by 7stud; 11-14-2005 at 04:44 AM.

  3. #3
    Registered User
    Join Date
    Jan 2005
    Posts
    847
    Maybe what you want to do is have each grid square store the offset of the object it contains then when you display the grid you draw the object it contains by adding the offsets to x/y co-ordinates of that square.
    Code:
    struct MapSquaire
    {
       int ObjectType;
       int ObjectXOffset;
       int ObjectyOffset;
       //other properties of this location
    }Location[100][100];

  4. #4
    Sweet
    Join Date
    Aug 2002
    Location
    Tucson, Arizona
    Posts
    1,820
    Or If I am reading this right you could do something like this.
    Code:
    #include <iostream>
    
    enum {North, South, East, West};
    enum {Empty, Star, Nebula};
    
    struct area
    {
        area()
        {
            north = NULL;
            south = NULL;
            east  = NULL;
            west  = NULL;
            for(int i = 0; i < 4; i++)
            {
                subArea[i] = i;
            }
        }
        int subArea[4];
        area *north;
        area *south;
        area *east;
        area *west;
    };
    struct player
    {
        player()
        {
            name = "Brian";
            current = NULL;
        }
        std::string name;
        area *current;
        int whereAt;
    }
    int main()
    {
        area *start = new area;
        area *northStar = new area;
        start->north = northStar;
        player theP;
        
        theP.current = start;
        theP.whereAt = SOUTH;
        
        //Do if checks for the players movement psuedo code 
        if(goUp)
        {
            if(theP.whereAt == NORTH)
            {
                if(theP.current->north->subArea[SOUTH] != STAR || NEBULA)
                {
                    theP.current = theP.current->north;
                }
                else
                {
                    std::cout<<"Your path is blocked"<<std::endl;
                }
            }
        }
        return 0;
    }
    And then just fill your subareas accordingly.
    Woop?

  5. #5
    Registered User
    Join Date
    Apr 2003
    Posts
    2,663
    Maybe what you want to do is have each grid square store the offset of the object it contains then when you display the grid you draw the object it contains by adding the offsets to x/y co-ordinates of that square.
    The x,y coordinate is an offset from 0,0. Why create an offset from an offset? Why not just list the total offset from 0,0?

  6. #6
    Registered User
    Join Date
    Jan 2005
    Posts
    847
    Quote Originally Posted by 7stud
    The x,y coordinate is an offset from 0,0. Why create an offset from an offset? Why not just list the total offset from 0,0?
    I was thinking of grid scrolling. The x/y co-ordinates of grid squares would change when the grid is scrolled as would the actual screen co-ordinates of the objects.

  7. #7
    Registered User VirtualAce's Avatar
    Join Date
    Aug 2001
    Posts
    9,607
    Feel free to add to this tilemap class since that is what you really need. The offsetting and making the grid 'invisible' is up to the artists creating the tilesets, not the programmer.

    Code:
    #pragma pack(1)
    
    
    
    struct CMapResourceHeader
    {
      DWORD mrhWidth;
      DWORD mrhHeight;
      DWORD mrhNumMaps;
    };
    
    
    struct CMapFileHeader
    {
      DWORD   mfhWidth;
      DWORD   mfhHeight;
      int     mfhNumBitmapIDs;
      //Bitmap IDs immediately follow - 4 bytes per ID
    };
    #pragma
    
    
    class CMapManager;
    
    class CMap
    {
      protected:
        friend class CMapManager;
    
        DWORD   *m_pMap;
        
        int     m_iNumBitmapIDs;
        DWORD   *m_dwBitmapIDs;
        
        DWORD   m_dwSize;
        DWORD   m_dwWidth;
        DWORD   m_dwHeight;
    
      public:
        CMap(void):m_pMap(NULL),m_dwSize(0),m_dwWidth(0),m_dwHeight(0) {}
        
        virtual ~CMap(void)
        {
          
          
          if (m_pMap)
          {
            delete [] m_pMap;
          }
        }
    
        DWORD *GetMap(void) {return m_pMap;};
        void SetMap(DWORD *pMap) {m_pMap=pMap;};
            
        void Load(CString filename)
        {
          int handle=_open(filename,_O_BINARY | O_RDWR,_S_IREAD);
    
          Clear(0);
    
          CMapFileHeader hdr;
    
          _read(handle,&hdr,sizeof(CMapFileHeader));
    
          m_dwSize=hdr.mfhWidth*hdr.mfhHeight;
          m_dwWidth=hdr.mfhWidth;
          m_dwHeight=hdr.mfhHeight;
    
          
          _read(handle,m_pMap,m_dwSize*sizeof(DWORD));
          
          _close(handle);
          
        }
        
        void Save(CString filename)
        {
          
          int handle=_open(filename,_O_BINARY | _O_RDWR, S_IWRITE);
          CMapFileHeader hdr;
                
          hdr.mfhWidth=m_dwWidth;
          hdr.mfhHeight=m_dwHeight;
    
          
          
          _write(handle,&hdr,sizeof(CMapFileHeader));
    
          _write(handle,m_pMap,m_dwSize*sizeof(DWORD));
                
          _close(handle);
          
        }
    
        void SaveToHandle(int filehandle)
        {
          CMapFileHeader hdr;
          hdr.mfhWidth=m_dwWidth;
          hdr.mfhHeight=m_dwHeight;
          CString text;
          text.Format("%u %u",m_dwWidth,m_dwHeight);
          ::MessageBox(0,text,0,0);
    
    
          _write(filehandle,&hdr,sizeof(CMapFileHeader));
          _write(filehandle,m_pMap,m_dwSize*sizeof(DWORD));
        
        }
    
        void LoadFromHandle(int filehandle)
        {
          CMapFileHeader hdr;
    
          _read(filehandle,&hdr,sizeof(CMapFileHeader));
          m_dwWidth=hdr.mfhWidth;
          m_dwHeight=hdr.mfhHeight;
          m_dwSize=m_dwWidth*m_dwHeight;
    
          //if map exists de-allocate its memory
          if (m_pMap) delete [] m_pMap;
          
          //Create/Re-create map
          Create(m_dwWidth,m_dwHeight);
          
          //Clear map to empty state
          Clear(0xFFFFFFF);
                
          CString text;
          text.Format("Width %u Height %u",m_dwWidth,m_dwHeight);
          ::MessageBox(0,text,0,0);
    
    
          //Read in data from file
          _read(filehandle,m_pMap,m_dwSize*sizeof(DWORD));
        }
    
        void Clear(DWORD value)
        {
          memset(m_pMap,value,m_dwSize*sizeof(DWORD));
        }
    
        bool Create(DWORD dwWidth,DWORD dwHeight)
        {
          //::MessageBox(0,"creating map",0,0);
    
          m_dwSize=dwWidth*dwHeight;
          m_dwWidth=dwWidth;
          m_dwHeight=dwHeight;
          
          m_pMap=new DWORD[m_dwWidth*m_dwHeight];
          return true;
                
        }
    
        bool SetMapXYTo(DWORD dwX,DWORD dwY,DWORD dwValue)
        {
          DWORD dwOffset=dwY*m_dwWidth+dwX;
          if (dwOffset<m_dwSize)
          {
            m_pMap[dwOffset]=dwValue;
            return true;
          } else return false;
        }
    
        bool SetMapOffsetTo(DWORD dwOffset,DWORD dwValue)
        {
          if (dwOffset<m_dwSize)
          {
            m_pMap[dwOffset]=dwValue;
            return true;
          } else return false;
        }
    
        bool GetValueAtXY(DWORD dwX,DWORD dwY,DWORD *outValue)
        {
          DWORD dwOffset=dwY*m_dwWidth+dwX;
          if (dwOffset<m_dwSize)
          {
             *outValue=m_pMap[dwOffset];
             return true;
          } else return false;
        }
    
        bool GetValueAtOffset(DWORD dwOffset,DWORD *outValue)
        {
          if (dwOffset<m_dwSize)
          {
            *outValue=m_pMap[dwOffset];
            return true;
          } else return false;
        }
    
        DWORD GetValueAtXY(DWORD dwX,DWORD dwY)
        {
          DWORD dwOffset=dwY*m_dwWidth+dwX;
          DWORD value=0;
          if (dwOffset<m_dwSize)
          {
            value=m_pMap[dwOffset];
            return value;
          } else return 0xFFFFFFFF;
        }
        
        DWORD GetValueAtOffset(DWORD dwOffset)
        {
          DWORD value=0;
          if (dwOffset<m_dwSize)
          {
            value=m_pMap[dwOffset];
            return value;
          } else return 0xFFFFFFFF;
        }
    
    };
    
    
    class CMapManager
    {
      std::vector<CMap *> Maps;
    
      DWORD m_dwHeight;
      DWORD m_dwWidth;
    
    
      public:
        CMapManager(void) {}
        virtual ~CMapManager(void)
        {
          Maps.empty();
        }
    
        void ResetData(void)
        {
          m_dwHeight=0;
          m_dwWidth=0;
          Maps.empty();
        }
    
        void Add(DWORD dwWidth,DWORD dwHeight)
        {
          m_dwHeight=dwHeight;
          m_dwWidth=dwWidth;
    
          CMap *temp=new CMap();
          temp->Create(dwWidth,dwHeight);
          
          Maps.push_back(temp);
        }
    
        DWORD GetValueAtOffset(int mapnum,DWORD dwOffset)
        {
          if (mapnum<Maps.size())
          {
            return Maps[mapnum]->GetValueAtOffset(dwOffset);
          }
        }
        
        bool SetMapOffsetTo(int mapnum,DWORD dwOffset,DWORD value)
        {
          if (mapnum<Maps.size())
          {
            Maps[mapnum]->SetMapOffsetTo(dwOffset,value);
            return true;
          } else return false;
        }
        //Returns a pointer to a map
        DWORD *GetMap(DWORD ID)
        {
          if (ID<Maps.size())
          {
            return Maps[ID]->GetMap();
          }
        }
    
        CMap *GetMapClass(DWORD ID)
        {
          if (ID<Maps.size())
          {
            return Maps[ID];
          }
        }
    
        DWORD GetNumberOfMaps(void) {return Maps.size();};
        void Clear(DWORD mapnum,DWORD value) 
        {
          if (mapnum<Maps.size())
          {
            Maps[mapnum]->Clear(value);
          }
        }
    
        /*
        struct CMapResourceHeader
        {
          DWORD mrhWidth;
          DWORD mrhHeight;
          DWORD mrhNumMaps;
        };
        */
    
        void Save(CString filename)
        {
          int handle=_open(filename,_O_BINARY | _O_RDWR | _O_CREAT,_S_IWRITE);
    
          if (handle==-1)
          {
            CString errortext;
            CString codetext;
            switch(errno)
            {
              case EACCES:
                codetext="Access error";break;
              case EEXIST:
                codetext="File exists";break;
              case EINVAL:
                codetext="Invalid argument";break;
              case EMFILE:
                codetext="Too many open handles";break;
              case ENOENT:
                codetext="Invalid path";break;
            }
    
            errortext.Format("Error saving %s - %s",filename,codetext);
    
            
    
            ::MessageBox(0,errortext,"ERROR",MB_ICONEXCLAMATION);
            return;
          }
    
          //Fill resource header with info
          CMapResourceHeader hdr;
          hdr.mrhHeight=m_dwHeight;
          hdr.mrhWidth=m_dwWidth;
          hdr.mrhNumMaps=Maps.size();
    
          //CString test;
          //test.Format("Maps: %u",hdr.mrhNumMaps);
          //::MessageBox(0,test,0,0);
    
    
          //Write resource header to disk
          _write(handle,&hdr,sizeof(CMapResourceHeader));
    
          //Loop and write all maps to disk
          for (int i=0;i<Maps.size();i++)
          {
            Maps[i]->SaveToHandle(handle);
          }
          
          _close(handle);
    
        }
    
        DWORD Load(CString filename,DWORD &outWidth,DWORD &outHeight)
        {
          int handle=_open(filename,_O_BINARY | _O_RDWR,_S_IREAD);
    
          if (handle==-1)
          {
            CString errortext;
            errortext.Format("Error loading %s",filename);
    
            ::MessageBox(0,errortext,"ERROR",MB_ICONEXCLAMATION);
            return 0;
          }
    
          //Kill current maps
          Maps.empty();
    
          //Fill resource header with info
          CMapResourceHeader hdr;
          
          //Read resource header from disk
          _read(handle,&hdr,sizeof(CMapResourceHeader));
    
          
          m_dwHeight=hdr.mrhHeight;
          m_dwWidth=hdr.mrhWidth;
          outHeight=m_dwHeight;
          outWidth=m_dwWidth;
          
    
    
          int iMaps=hdr.mrhNumMaps;
          
          //Loop and create all maps from disk
          for (int i=0;i<iMaps;i++)
          {
            Add(m_dwWidth,m_dwHeight);
    
            Maps[i]->LoadFromHandle(handle);
          }
          
          _close(handle);
    
          return iMaps;
        }
    
     //   bool Remove(DWORD ID)
     //   {
     //     if (ID<Maps.size())
     //     {
     //       Maps.remove
    
    };
    This is a work in progress - removing maps from the vector has not been implemented. Feel free to do so.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Base container class question
    By Raigne in forum C++ Programming
    Replies: 8
    Last Post: 11-04-2008, 04:56 PM
  2. struct question
    By ctovb in forum C Programming
    Replies: 3
    Last Post: 08-13-2008, 11:23 AM
  3. Replies: 2
    Last Post: 08-05-2002, 02:19 PM
  4. Peculiar Problem with Printf
    By Unregistered in forum C++ Programming
    Replies: 5
    Last Post: 07-02-2002, 12:34 AM
  5. Peculiar Problem with Printf
    By Unregistered in forum C Programming
    Replies: 5
    Last Post: 07-02-2002, 12:03 AM