Original Post
Hey, I've been messing with the gametutorials 2d map ediotr series for a while and I am trying to add the ability to scroll the map over to view larger maps. But every time I set the map width and height to higher then 20 it gives me an access violation and crashes. But when the map is set to below 20x20 and you try to scroll it leaves streaks on the bg and scrolls beyond what it should be able to. heres all the code: CBitmap.cpp CBitmap.h Init.cpp main.cpp main.h CTile.cpp CTile.h errors Access Violation occured, the debug came up with this: HBITMAP GetBitmap() { return m_bmpTile; } If anyone could help me out with finding whats wrong, it would be really appreciated. Thanx.
#include "main.h"
#include "Bitmap.h"
//the constructor for the CBuffer class
CBuffer::CBuffer():hWnd(0),hCompBitmap(0),hOldBitmap(0),hdcFront(0),hdcBack(0),oldPen(0),oldBrush(0)
{
memset(&scrnRect, 0, sizeof(RECT));
}
//deconstructor for the CBuffer class
CBuffer::~CBuffer()
{
// We need to make sure if we used a pen or brush the original
// pen and brushes are restored so there isn't a memory leak.
if(oldPen)
{
HPEN setPen = (HPEN)SelectObject(hdcBack, oldPen);
DeleteObject(setPen);
}
if(oldBrush)
{
HBRUSH setBrush = (HBRUSH)SelectObject(hdcBack, oldBrush);
DeleteObject(setBrush);
}
// Free our back buffer information
FreeBuffers();
}
//creates a double buffer. Pass in a buffer struct.
void CBuffer::CreateDoubleBuffering(HWND hWndNew)
{
// Assign the window handle to our structure
hWnd = hWndNew;
// Store the client rectangle in our structure
GetClientRect(hWnd, &(scrnRect));
// Get a handle to the device context and store it as the front buffer
hdcFront = GetDC(hWnd);
// Create a compatible device context for the backbuffer
hdcBack = CreateCompatibleDC(hdcFront);
// Create another hdc to store the bitmap in before the backbuffer
hdcBitmap = CreateCompatibleDC(hdcFront);
// Create a dummy bitmap handle to store in the front buffer
hCompBitmap = CreateCompatibleBitmap(hdcFront, scrnRect.right,
scrnRect.bottom);
// Select the dummy bitmap handle into the back buffer to make it like the front hdc
hOldBitmap = (HBITMAP)SelectObject(hdcBack, hCompBitmap);
}
//loads a bitmap and returns a handle to it
HBITMAP CBuffer::LoadABitmap(LPSTR szFileName)
{
// Load the bitmap and return the handle to the bitmap we just loaded
return (HBITMAP)LoadImage(NULL, szFileName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);
}
//puts a bitmap in the back buffer
void CBuffer::DisplayBitmap(HBITMAP hBitmap, int x, int y)
{
// Select the bitmap handle into the extra hdc that holds the bitmap
HBITMAP hOldBitmap = (HBITMAP) SelectObject(hdcBitmap, hBitmap);
// Blit the bitmap hdc into the backbuffer
BitBlt(hdcBack, x, y, scrnRect.right,
scrnRect.bottom, hdcBitmap, 0, 0, SRCCOPY);
// Select the old handle to the bitmap back where it was to clean up
SelectObject(hdcBitmap, hOldBitmap);
}
//takes a portion of a bitmap and puts it in the back buffer
void CBuffer::DisplayBitmap(HBITMAP hBitmap, int x, int y, RECT rPortion)
{
// Assign the width and height to shorten variables.
int width = rPortion.right - rPortion.left, height = rPortion.bottom - rPortion.top;
// Select the bitmap handle into the extra hdc that holds the bitmap
HBITMAP hOldBitmap = (HBITMAP) SelectObject(hdcBitmap, hBitmap);
// Blit the bitmap hdc into the backbuffer using the transparent color 0 (black)
BOOL result = BitBlt(hdcBack, x, y, width, height,
hdcBitmap, rPortion.left, rPortion.top, SRCCOPY);
// Select the old handle to the bitmap back where it was to clean up
SelectObject(hdcBitmap, hOldBitmap);
}
//displays a bitmap with transparentcy to the screen
void CBuffer::TransparentBlit(HDC hdc, int destX, int destY, int destWidth, int destHeight,
HDC hdc2, int srcX, int srcY, UINT transparency)
{
unsigned char* pImageBits = NULL;
unsigned char* pBackBits = NULL;
BITMAPINFO bmBitmapInfo = {0};
HBITMAP hBitmap, hBitmap2, hOldBitmap, hOldBitmap2;
HDC compHDC;
HDC compHDC2;
// Fill in our BitmapInfo structure (we want a 24 bit image)
bmBitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmBitmapInfo.bmiHeader.biCompression = BI_RGB;
bmBitmapInfo.bmiHeader.biHeight = destHeight;
bmBitmapInfo.bmiHeader.biWidth = destWidth;
bmBitmapInfo.bmiHeader.biBitCount = 24;
bmBitmapInfo.bmiHeader.biClrUsed = 0;
bmBitmapInfo.bmiHeader.biPlanes = 1;
// Create 2 DIB Sections. One for the Front Buffer and one for the BackBuffer
hBitmap = CreateDIBSection(hdc, &bmBitmapInfo, DIB_RGB_COLORS,(void **)&pImageBits, 0,0);
hBitmap2 = CreateDIBSection(hdc, &bmBitmapInfo, DIB_RGB_COLORS,(void **)&pBackBits, 0,0);
// Create a compatible DC for the front buffer and Select our Dib Section into it
compHDC = CreateCompatibleDC(hdc);
hOldBitmap = (HBITMAP)SelectObject(compHDC, hBitmap);
// Create a compatible DC for the back buffer and Select our Dib Section into it
compHDC2 = CreateCompatibleDC(hdc2);
hOldBitmap2 = (HBITMAP)SelectObject(compHDC2, hBitmap2);
// Blit the front buffer to our compatible DC that will hold the destination bits
BitBlt(compHDC, 0, 0, destWidth, destHeight, hdc, destX, destY, SRCCOPY);
// Blit the back buffer to our compatible DC that will hold the source bits
BitBlt(compHDC2, 0, 0, destWidth, destHeight, hdc2, srcX, srcY, SRCCOPY);
// Loop through the 24 bit image (Times 3 for R G and B)
for(int i = 0; i < destHeight * destWidth * 3; i += 3)
{
// Check if the current pixel being examined isn't the transparent color
// Remember, the image bits are stored (Blue, Green, Red), not (Red, Green, Blue)
// We use the system macros to abstract the R G B data
if((pBackBits != GetBValue(transparency)) ||
(pBackBits[i+1] != GetGValue(transparency)) ||
(pBackBits[i+2] != GetRValue(transparency)))
{
// Assign the desired pixel to the foreground
pImageBits = pBackBits;
pImageBits[i + 1] = pBackBits[i + 1];
pImageBits[i + 2] = pBackBits[i + 2];
}
}
// Blit the transparent image to the front buffer (Voila!)
BitBlt(hdc, destX, destY, destWidth, destHeight, compHDC, 0, 0, SRCCOPY);
// Cleanup the monochrome bitmaps
SelectObject(compHDC, hOldBitmap);
SelectObject(compHDC2, hOldBitmap2);
// Free GDI Resources
DeleteObject(hBitmap);
DeleteObject(hBitmap2);
DeleteDC(compHDC);
DeleteDC(compHDC2);
}
//This takes a bitmap and puts it in the backbuffer
//BUT, not displaying any color with rgb values of (0, 0, 0).
void CBuffer::DisplayTransparentBitmap(HBITMAP hBitmap, int x, int y, RECT rPortion)
{
// Assign the width and height to shorten variables.
int width = rPortion.right - rPortion.left, height = rPortion.bottom - rPortion.top;
// Select the bitmap handle into the extra hdc that holds the bitmap
HBITMAP hOldBitmap = (HBITMAP) SelectObject(hdcBitmap, hBitmap);
// Blit the bitmap hdc into the backbuffer using the transparent color 0 (black)
TransparentBlit(hdcBack, x, y, width, height,
hdcBitmap, rPortion.left, rPortion.top, TRANSPARENT_COLOR);
// Select the old handle to the bitmap back where it was to clean up
SelectObject(hdcBitmap, hOldBitmap);
}
//draws and stretches a bitmap to the backbuffer
void CBuffer::DrawBackgroundImage(HBITMAP hBitmap)
{
// This will hold our information on the bitmap
BITMAP bitmapInfo;
// Select the bitmap handle into the extra hdc that holds the bitmap
HBITMAP hOldBitmap = (HBITMAP) SelectObject(hdcBitmap, hBitmap);
// Get the width and height of the background bitmap
GetObject(hBitmap, sizeof(BITMAP), &bitmapInfo);
// Blit the bitmap hdc into the backbuffer using the transparent color 0 (black)
BOOL result = StretchBlt(hdcBack, 0, 0, scrnRect.right, scrnRect.bottom,
hdcBitmap, 0, 0, bitmapInfo.bmWidth, bitmapInfo.bmHeight, SRCCOPY);
// Select the old handle to the bitmap back where it was to clean up
SelectObject(hdcBitmap, hOldBitmap);
}
//clears the screen
void CBuffer::ClearScreen(int color)
{
// Fill the backbuffer with white to erase the previous position of the bitmap
FillRect(hdcBack, &scrnRect, (HBRUSH)GetStockObject(color));
}
//sets a pen
void CBuffer::SetPen(int type, int thickness, COLORREF color)
{
// First create a brush that is hollow for shapes
LOGBRUSH logBrush = {BS_HOLLOW, DIB_RGB_COLORS, NULL};
// Set our new brush and our desired pen type
HBRUSH hBrush = CreateBrushIndirect(&logBrush);
HPEN hPen = CreatePen(type, thickness, color);
// Make sure we only store the old original pen if we haven't yet
if(!oldPen)
{
// Select both into our HDC
oldPen = (HPEN)SelectObject(hdcBack,hPen);
oldBrush = (HBRUSH)SelectObject(hdcBack, hBrush);
}
else
{
HPEN lastPen = (HPEN)SelectObject(hdcBack,hPen);
DeleteObject(lastPen);
}
}
//swaps the back buffer with the front
void CBuffer::SwapBackBuffer(BOOL bClearBackBuffer)
{
// Blit the whole backbuffer to the screen (The front buffer)
BitBlt(hdcFront, scrnRect.left, scrnRect.top,
scrnRect.right, scrnRect.bottom, hdcBack, 0, 0, SRCCOPY);
// If we want to clear the screen afterwards, set the background to white
if(bClearBackBuffer)
ClearScreen(BLACK_BRUSH);
}
//resets the back and front buffer to the client window
void CBuffer::ResizeBuffers()
{
// Get the new client rectangle of the window
GetClientRect(hWnd, &(scrnRect));
// Select the old bitmap back into the back buffer
SelectObject(hdcBack, hOldBitmap);
// Delete the old compatible bitmap
DeleteObject(hCompBitmap);
// Create a new compatible bitmap with the new size of the window
hCompBitmap = CreateCompatibleBitmap(hdcFront, scrnRect.right, scrnRect.bottom);
// Select the new compatible bitmap into the backbuffer and store the old one again
hOldBitmap = (HBITMAP) SelectObject(hdcBack, hCompBitmap);
}
//frees the buffers for the window
void CBuffer::FreeBuffers()
{
// Set the back buffer to it's original bitmap (This is necessary for clean-up)
SelectObject(hdcBack, hOldBitmap);
// Free the hbitmaps
if(hOldBitmap) DeleteObject(hOldBitmap);
if(hCompBitmap) DeleteObject(hCompBitmap);
// Free all the HDC's
if(hdcBack) ReleaseDC(hWnd, hdcBack);
if(hdcBitmap) ReleaseDC(hWnd, hdcBitmap);
if(hdcFront) ReleaseDC(hWnd, hdcFront);
}
#ifndef _BITMAP_H
#define _BITMAP_H
#include "main.h"
#define TRANSPARENT_COLOR RGB(255, 255, 255) // the transparent color
//backbuffer class
class CBuffer
{
public:
CBuffer();
~CBuffer();
// Create the double buffering for all of our bitmaps
void CreateDoubleBuffering(HWND hWnd);
// This loads a bitmap (ie. "Bitmap.bmp") and returns a handle to that bitmap
HBITMAP LoadABitmap(LPSTR szFileName);
// This displays the bitmap to the screen at a X and a Y location
void DisplayBitmap(HBITMAP hBitmap, int x, int y);
// This display a portion of a bitmap with a transparency to (0, 0, 0) (pure black)
void DisplayTransparentBitmap(HBITMAP hBitmap, int x, int y);
// Displays a portion of a bitmap to the backbuffer (Used from one bitmap animation)
void DisplayBitmap(HBITMAP hBitmap, int x, int y, RECT rPortion);
// This does the dirty pixel work to make the bitmap a transparent image
void TransparentBlit(HDC hdc, int destX, int destY, int destWidth, int destHeight,
HDC hdc2, int srcX, int srcY, UINT transparency);
// This display a portion of a bitmap with a transparency to (0, 0, 0) (pure black)
void DisplayTransparentBitmap(HBITMAP hBitmap, int x, int y, RECT rPortion);
// This stretches the image to the window rectangle to fill up the background
void DrawBackgroundImage(HBITMAP hBitmap);
// Clears the backbuffer to what ever color is passed in
void ClearScreen(int color);
void SetPen(int type, int thickness, COLORREF color);
// Swaps the back buffer to the screen
void SwapBackBuffer(BOOL bClearBackBuffer);
// This resizes the buffers to the current window size
void ResizeBuffers();
// This frees the back buffer information
void FreeBuffers();
// This returns the back buffer hdc
HDC GetHDC() { return hdcBack; };
private:
HWND hWnd; // This holds the current window's handle
RECT scrnRect; // This holds the client rectangle of the window
HANDLE hCompBitmap; // This holds the compatible bitmap for the backbuffer
HANDLE hOldBitmap; // This is used for storage to free when the program quits
HDC hdcFront; // This is the front buffer (The part we see)
HDC hdcBack; // This is the back buffer (the part we draw to, then flip)
HDC hdcBitmap; // This is a temp buffer to swap the bitmap back and forth from
HPEN oldPen; // This holds the original pen stored by windows
HBRUSH oldBrush; // This holds the original brush stored by windows
};
#endif
#include "main.h"
HWND CreateMyWindow(LPSTR strWindowName, int width, int height, DWORD dwStyle, HINSTANCE hInstance)
{
HWND hWnd;
WNDCLASS wndclass;
int positionFlag = CW_USEDEFAULT;
memset(&wndclass, 0, sizeof(WNDCLASS)); // Init the size of the class
wndclass.style = CS_HREDRAW | CS_VREDRAW; // Regular drawing capabilities
wndclass.lpfnWndProc = WndProc; // Pass our function pointer as the window procedure
wndclass.hInstance = hInstance; // Assign our hInstance
wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); // General icon
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); // An arrow for the cursor
wndclass.hbrBackground = (HBRUSH) (COLOR_WINDOW+1); // A white window
wndclass.lpszClassName = "MEclass"; // Assign the class name
wndclass.lpszMenuName = "EditorMenu";
RegisterClass(&wndclass); // Register the class
if(!dwStyle) // Assign styles to the window depending on the choice
dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
g_hInstance = hInstance; // Assign our global hInstance to the window's hInstance
RECT rWindow;
rWindow.left = 0; // Set Left Value To 0
rWindow.right = width; // Set Right Value To Requested Width
rWindow.top = 0; // Set Top Value To 0
rWindow.bottom = height; // Set Bottom Value To Requested Height
AdjustWindowRect( &rWindow, dwStyle, false); // Adjust Window To True Requested Size
// Create the window
hWnd = CreateWindow("MEclass", strWindowName, dwStyle, positionFlag , positionFlag,
rWindow.right - rWindow.left, rWindow.bottom - rWindow.top,
NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, SW_SHOWNORMAL); // Show the window
UpdateWindow(hWnd); // Draw the window
SetFocus(hWnd); // Sets Keymap Focus To The Window
return hWnd;
}
HWND CreateToolWindow(HWND hWndParent, LPSTR strWindowName, int width, int height, DWORD dwStyle, HINSTANCE hInstance)
{
WNDCLASSEX wndclassEx;
memset(&wndclassEx, 0, sizeof(WNDCLASS)); // Init the size of the class
wndclassEx.cbSize = sizeof(wndclassEx);
wndclassEx.style = CS_HREDRAW | CS_VREDRAW; // Regular drawing capabilities
wndclassEx.lpfnWndProc = WndProcPopup; // Pass our function pointer as the window procedure
wndclassEx.hInstance = hInstance; // Assign our hInstance
wndclassEx.hIcon = LoadIcon(NULL, IDI_APPLICATION); // General icon
wndclassEx.hCursor = LoadCursor(NULL, IDC_ARROW); // An arrow for the cursor
wndclassEx.hbrBackground = (HBRUSH) (COLOR_WINDOW+1); // A white window
wndclassEx.lpszClassName = "ToolWindowClass"; // Assign the class name
wndclassEx.hIconSm = 0;
RegisterClassEx(&wndclassEx);
RECT rWindow;
rWindow.left = 0; // Set Left Value To 0
rWindow.right = width; // Set Right Value To Requested Width
rWindow.top = 0; // Set Top Value To 0
rWindow.bottom = height; // Set Bottom Value To Requested Height
AdjustWindowRect( &rWindow, dwStyle, false); // Adjust Window To True Requested Size
RECT rParentWindow = {0};
GetWindowRect(hWndParent, &rParentWindow); // Get the window position of the main window
// Set the tool bar on the right of the main window
HWND hWnd = CreateWindowEx(WS_EX_TOOLWINDOW, "ToolWindowClass", strWindowName, dwStyle,
rParentWindow.right, rParentWindow.top, rWindow.right - rWindow.left,
rWindow.bottom - rWindow.top, hWndParent, NULL, hInstance, NULL);
ShowWindow(hWnd, SW_SHOWNORMAL); // Show the window
UpdateWindow(hWnd); // Draw the window
return hWnd;
}
void DeInit()
{
for(int i = 0; i < (int)g_vTiles.size(); i++)
DeleteObject(g_vTiles.GetBitmap());
UnregisterClass("ToolWindowClass", g_hInstance);
UnregisterClass("MEclass", g_hInstance);
PostQuitMessage(0);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hprev, PSTR cmdline, int ishow)
{
// Create the main window and offset the height by the menu pixel height
HWND hWnd = CreateMyWindow("Map-Editor nojutsu",
SCREEN_WIDTH, SCREEN_HEIGHT + MENU_OFFSET,
WS_HSCROLL | WS_VSCROLL, hInstance);
// If we never got a valid window handle, quit the program
if(hWnd == NULL) return TRUE;
// Create our tool bar window offset by the scroll bar pixel width and to compensate
// for the small title bar we offset the height with the menu offset
g_hWndTool = CreateToolWindow(hWnd, "", TILE_WIDTH + SCROLL_BAR_OFFSET, 32*15 + MENU_OFFSET,
WS_POPUP| WS_SYSMENU | WS_CAPTION , hInstance);
// Initialize our important things after the window is created
Init(hWnd);
// Run our message loop and after it's done, return the result
return (int)MainLoop();
}
#include "main.h" // Include our main header file
HWND g_hWnd; // This is a global handle for the window
HWND g_NewDlg; // This is a global handle for the toolbar window
HWND g_hWndTool;
HINSTANCE g_hInstance; // This holds the global hInstance for UnregisterClass() in DeInit()
CBuffer g_Buffer; // Create a buffer for the main window
CBuffer g_ToolBuffer; // Create a buffer for the tool bar window
vector<CTile> g_vTiles; // Create a list for the map tiles to be loaded
// This stores our scroll bar information. For more info on scroll bars
// check out our scroll bar tutorial.
SCROLLINFO g_ScrollInfo = {0};
int g_scrollBarPosY = 0; // Set the current scroll bar position to 0
SCROLLINFO g_mapscrollx = {0};
int g_mapsx = 0;
SCROLLINFO g_mapscrolly = {0};
int g_mapsy = 0;
//current map
CMap *g_pCurrentMap = NULL;
// This is our map class which holds all the information for the current map. When we load
// a map, all that information is stored here. This is the most important class in our editor.
CMap g_Map;
//curser and curser tile info
CTile *g_pCursorTile = NULL;
POINT g_cursorPos = {0};
bool g_bLButtonDown = false;
// Create our global variables for our open file dialog box
OPENFILENAME g_OpenInfo = {0};
char g_szFileName[MAX_PATH] = {0};
//curser tile drawing function
void DrawCursorTile()
{
// Create a rect to specify what part of our bitmaps we want to draw
RECT rPortion = {0, 0, TILE_WIDTH, TILE_HEIGHT};
// Here we update our cursor position and convert it to client
// coordinates (our window coordinates), not the screen coordinates.
GetCursorPos(&g_cursorPos);
ScreenToClient(g_hWnd, &g_cursorPos);
// Since exits dont have a bitmap associated with them, we need
// to tell this function it's okay if there isn't a valid cursor tile
// only if the current type selected is exits.
if(g_pCurrentMap->GetCurrentType() != EXIT_TYPE)
if(!g_pCursorTile) return;
// If the current type is a normal map tile, draw it with no transparency.
// We line up the cursor bitmap so that it's dead center on the cursor.
if(g_pCurrentMap->GetCurrentType() == TILE_TYPE)
g_Buffer.DisplayBitmap(g_pCursorTile->GetBitmap(),
g_cursorPos.x - TILE_WIDTH/2, g_cursorPos.y - TILE_HEIGHT/2, rPortion);
// Otherwise draw a transparent bitmap for the rest
else
g_Buffer.DisplayTransparentBitmap(g_pCursorTile->GetBitmap(),
g_cursorPos.x - TILE_WIDTH/2, g_cursorPos.y - TILE_HEIGHT/2, rPortion);
// If the left button is still held down
if(g_bLButtonDown)
{
// Grab the index on our 2D map depending on our cursor position
int mapIndexX = g_cursorPos.x / TILE_WIDTH;
int mapIndexY = g_cursorPos.y / TILE_HEIGHT;
// Insert the tile type into our map according to it's index
g_pCurrentMap->InsertTile(g_pCursorTile, mapIndexX, mapIndexY);
}
}
void RenderScene()
{
// Make sure we have a current map pointer before we go shootin' blanks
if(!g_pCurrentMap) return;
// Here we set the portion of our bitmaps that we want to draw.
// Since there is no animation in our tile editor we need only display 1 tile.
RECT rPortion = {0, 0, TILE_WIDTH, TILE_HEIGHT};
// Next we draw the current map (Default is just all green grass tiles)
g_pCurrentMap->Draw();
// Grab the size of the current tool bar type list (Not our map's placed tile lists)
int size = g_pCurrentMap->GetCurrentTypeSize();
// Go through our tiles in the tool bar and draw them, but subtract the scroll bar position
// from the size. This makes it so we only draw the tiles that can be seen in the tool bar.
for(int i = 0; i < size - g_scrollBarPosY; i++)
{
// Depending on "i" and the scroll bar position, get the current tile's bitmap to draw
HBITMAP bitmap = g_pCurrentMap->GetCurrentTypeTile(i + g_scrollBarPosY)->GetBitmap();
// If the tool bar is showing map tiles then draw the tiles with no transparency
if(g_pCurrentMap->GetCurrentType() == TILE_TYPE)
g_ToolBuffer.DisplayBitmap(bitmap, 0, TILE_WIDTH * i, rPortion);
else
// Draw the current tiles with a transparency (white) (i.e. items, monsters, etc...)
g_ToolBuffer.DisplayTransparentBitmap(bitmap, 0, TILE_WIDTH * i, rPortion);
}
DrawCursorTile();
g_Buffer.SwapBackBuffer(FALSE);
g_ToolBuffer.SwapBackBuffer(TRUE);
}
WPARAM MainLoop()
{
MSG msg;
HACCEL hAccelTable = LoadAccelerators(g_hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));
while(1) // Do our infinite loop
{ // Check if there was a message
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if(msg.message == WM_QUIT) // If the message wasn't to quit
break;
// Check if there was keyboard command - if not, process messages like normal
if(!TranslateAccelerator(g_hWnd, hAccelTable, &msg))
{
TranslateMessage(&msg); // Find out what the message does
DispatchMessage(&msg); // Execute the message
}
RenderScene(); // Since no animation, only render when the user does something
}
}
DeInit(); // Clean up and free all allocated memory
return(msg.wParam); // Return from the program
}
void CheckTileType(int menuID)
{
// Grab a handle to our menu
HMENU hMenu = GetMenu(g_hWnd);
// Uncheck all of the menu items for the Tiles menu
CheckMenuItem(hMenu, ID_TILES_TILES, MF_UNCHECKED);
CheckMenuItem(hMenu, ID_TILES_EXITS, MF_UNCHECKED);
// Put a check by the desired menu item
CheckMenuItem(hMenu, menuID, MF_CHECKED);
}
void HandleMenu(int menuID)
{
if(menuID == ID_FILE_QUIT) // If the user chose File->Quit
{
PostQuitMessage(0); // Quit the program
}
else if(menuID == ID_FILE_OPENUP) // If the user chose File->Open
{
// Have windows bring up the Open File dialog box and Load the file chosen
if(GetOpenFileName(&g_OpenInfo))
g_Map.Load(g_OpenInfo.lpstrFile);
}
else if(menuID == ID_FILE_SAVEIT) // If the user chose File->Save
{
// If we have a n valid name for our map already, do a normal save
if(strlen(g_Map.GetMapName()) > 3)
g_Map.Save(g_Map.GetMapName());
else
{
// If haven't given our map a name yet, do a "SaveAs" and bring up the save dlg box
if(GetSaveFileName(&g_OpenInfo))
g_Map.Save(g_OpenInfo.lpstrFile);
}
}
else if(menuID == ID_FILE_SAVEAS) // If the user chose File->SaveAs
{
// Bring up the save dlg box and allow the user to type in a new map name and save it
if(GetSaveFileName(&g_OpenInfo))
g_Map.Save(g_OpenInfo.lpstrFile);
}
else if(menuID == ID_FILE_RESET) // If the user chose File->Reset
g_Map.SetDefault(); // Destroy all the tiles on the map and start over
else if(menuID == ID_TILES_TILES) // If the user chose Tiles->Tiles
g_Map.SetCurrentType(TILE_TYPE); // Set the tool bar tile type to tiles
else if(menuID == ID_HELP_ABOUT) // If the user chose Help->About
// Instead of creating a help dialog box, we can just use a simple system MessageBox() call
MessageBox(g_hWnd, "www.GameTutorials.com Map Editor\n\n"
"\t- Choose the desired tile type from the Tiles menu,\n"
"\t then click on a tile in the tile window. You can\n"
"\t then draw the tiles on the map with the left mouse button.\n\n"
"\t- Hit Esc to quit the program.", "About", MB_OK | MB_ICONINFORMATION);
// Over assuming that a tile type was changed, reset the scroll bar size.
// The -1 is because the tool bar window's title size offsets it a bit (being smaller).
g_ScrollInfo.nMax = g_Map.GetCurrentTypeSize() - MAP_HEIGHT - 1;
// If there isn't enough (or any) tiles to fill up the tool bar window, disable the scroll bar
if(g_ScrollInfo.nMax < 0)
{
g_ScrollInfo.nMax = 0;
EnableScrollBar(g_hWndTool, SB_VERT, ESB_DISABLE_BOTH);
}
else
EnableScrollBar(g_hWndTool, SB_VERT, ESB_ENABLE_BOTH); // Enable the scroll bar if it's needed
// Reset the scroll bar info
g_scrollBarPosY = 0;
g_ScrollInfo.nPage = 0;
// Update the current scroll bar information with no need to redraw (FALSE)
SetScrollInfo(g_hWndTool, SB_VERT, &g_ScrollInfo, FALSE);
ShowScrollBar(g_hWndTool, SB_VERT, TRUE);
// If we chose a tile type, put a check box next to it
switch(menuID)
{
case ID_TILES_TILES:
g_pCursorTile = NULL;
CheckTileType(menuID);
break;
}
}
void HandleScrollBar(WPARAM wParam)
{
switch(LOWORD(wParam))
{
case SB_LINEUP: case SB_PAGEUP: // If we choose the up button or click above the middle button
g_scrollBarPosY = g_scrollBarPosY - 1; // Decrease the scroll bar position
break;
case SB_LINEDOWN: case SB_PAGEDOWN: // If we choose the down button or click below the middle button
g_scrollBarPosY = g_scrollBarPosY + 1; // Increase the scroll bar position
break;
case SB_THUMBPOSITION: case SB_THUMBTRACK: // If we dragged the middle button (thumb)
g_scrollBarPosY = HIWORD(wParam); // Update it's new position
break;
default:
break;
}
SCROLLINFO scrollInfo; // Create a new temporary scroll bar info variable
scrollInfo.cbSize = sizeof(SCROLLINFO); // Initialize it's size
scrollInfo.fMask = SIF_POS | SIF_RANGE; // Set the flags so that we get the position and range updates
scrollInfo.nPage = 1; // Set the page size to 1 (a page increases by 1 tile)
GetScrollInfo(g_hWndTool, SB_VERT, &scrollInfo); // Retrieve the current scroll info
if(g_scrollBarPosY != scrollInfo.nPos) // If the scroll bar position has changed
{
if(g_scrollBarPosY > scrollInfo.nMax) // If we have gone past the first page of the scroll bar
g_scrollBarPosY = scrollInfo.nMax; // Set the current position
else if(g_scrollBarPosY < scrollInfo.nMin) // If go below the minimum value of the scroll bar set it back
g_scrollBarPosY = scrollInfo.nMin;
scrollInfo.nPos = g_scrollBarPosY; // Set the current scroll position and then update the scroll bar
SetScrollInfo(g_hWndTool, SB_VERT, &scrollInfo, TRUE);
InvalidateRect(g_hWndTool, NULL, FALSE); // Update the tool bar as we scroll with the thumb button
}
}
LRESULT CALLBACK WndProc (HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
// Check which message was passed in
switch (iMsg)
{
case WM_HSCROLL:
switch(LOWORD(wParam))
{
case SB_LINELEFT:
if(g_mapsx<0)
g_mapsx = 0;
else
g_mapsx = g_mapsx + 1;
break;
case SB_LINERIGHT:
if(g_mapsx>WIDTH)
g_mapsx = 0;
else
g_mapsx = g_mapsx - 1;
break;
case SB_THUMBPOSITION:
if(g_mapsx>WIDTH || g_mapsx<0)
g_mapsx = 0;
else
g_mapsx = HIWORD(wParam);
break;
default:
break;
}
break;
case WM_VSCROLL:
switch(LOWORD(wParam))
{
case SB_LINEUP:
if(g_mapsy>HEIGHT)
g_mapsy = 0;
else
g_mapsy + 1;
break;
case SB_LINEDOWN:
if(g_mapsy<0)
g_mapsy=0;
else
g_mapsy = g_mapsy - 1;
break;
case SB_THUMBPOSITION:
if(g_mapsy<0 || g_mapsy>HEIGHT)
g_mapsy = 0;
else
g_mapsy = HIWORD(wParam);
break;
default:
break;
}
break;
g_mapscrollx.cbSize = sizeof(SCROLLINFO);
g_mapscrolly.cbSize = sizeof(SCROLLINFO);
g_mapscrollx.fMask = SIF_POS | SIF_RANGE;
g_mapscrolly.fMask = SIF_POS | SIF_RANGE;
GetScrollInfo(g_hWnd, SB_HORZ, &g_mapscrollx);
GetScrollInfo(g_hWnd, SB_VERT, &g_mapscrolly);
if(g_mapsx != g_mapscrollx.nPos && g_mapsy != g_mapscrolly.nPos)
{
if(g_mapsx > g_mapscrollx.nMax)
g_mapsx = g_mapscrollx.nMax;
else if(g_mapsx < g_mapscrollx.nMin)
g_mapsx = g_mapscrollx.nMin;
g_mapscrollx.nPos = g_mapsx;
SetScrollInfo(g_hWnd, SB_HORZ, &g_mapscrollx, true);
if(g_mapsy > g_mapscrolly.nMax)
g_mapsy = g_mapscrolly.nMax;
else if(g_mapsy < g_mapscrolly.nMin)
g_mapsy = g_mapscrolly.nMin;
g_mapscrolly.nPos = g_mapsy;
SetScrollInfo(g_hWnd, SB_VERT, &g_mapscrolly, true);
InvalidateRect(g_hWnd,NULL,TRUE);
}
return 0;
case WM_COMMAND: // Check if we have a command from the user
HandleMenu(LOWORD(wParam)); // Pass in the command ID to our menu function
break;
case WM_KEYDOWN:
switch (wParam)
{
case VK_ESCAPE:
// Tell the window we want to QUIT
PostQuitMessage(0);
break;
}
break;
case WM_LBUTTONDOWN: // If we hit the left mouse button
g_bLButtonDown = true; // Set our global boolean to true
break;
case WM_LBUTTONUP: // If we let off of the left button
g_bLButtonDown = false; // Set our global boolean value to false
break;
case WM_RBUTTONDOWN: // If we click the right button
if(g_pCursorTile == NULL) // If we don't have a current cursor tile
{
// Here we delete the tile at our current mouse position from the map
g_pCurrentMap->DeleteTile(g_cursorPos.x/TILE_WIDTH, g_cursorPos.y/TILE_HEIGHT);
}
else
g_pCursorTile = NULL; // Otherwise remove the cursor tile
break;
case WM_PAINT: // If we need to paint the screen
RenderScene(); // Update the screen and draw the map
break;
// Since we created a child window for our tool bar, we want both windows
// to be constantly active. By return TRUE in DefWindowProc() we can have
// the window not go inactive when we click on another window.
case WM_NCACTIVATE:
return DefWindowProc(hWnd, iMsg, TRUE, lParam);
// By return 1 when this message is called we eliminate have our window background
// redrawn. This makes it so we don't see flicker when our tool bar window is
// dragged over our main window. Cool little trip huh :)
case WM_ERASEBKGND:
return 1;
// This message is sent when the window is destroyed
case WM_DESTROY:
// Tell the window we need to close
PostQuitMessage(0);
break;
}
// Process/handle the default messages
return DefWindowProc (hWnd, iMsg, wParam, lParam);
}
LRESULT CALLBACK WndProcPopup(HWND hWnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
{
// Check which message was passed in
switch (iMsg)
{
// Draw the scene when necessary
case WM_PAINT:
RenderScene();
break;
case WM_LBUTTONDOWN: // If we click the left button in the tool bar
g_cursorPos.x = LOWORD(lParam); // Grab the x and y position of the cursor
g_cursorPos.y = HIWORD(lParam);
// Here we grab a pointer to the tile type that we clicked on (used for drawing on the cursor)
g_pCursorTile = g_pCurrentMap->GetCurrentTypeTile(g_cursorPos.y/TILE_HEIGHT + g_scrollBarPosY);
break;
// Check if we need to handle a scroll bar message
case WM_VSCROLL:
HandleScrollBar(wParam);
break;
// By sending TRUE in DefWindowProc in this message we always maintain an active window
case WM_NCACTIVATE:
return DefWindowProc(hWnd, iMsg, TRUE, lParam);
// This message is sent when the window is destroyed
case WM_DESTROY:
PostQuitMessage(0);
break;
}
// Process/handle the default messages
return DefWindowProc (hWnd, iMsg, wParam, lParam);
}
void Init(HWND hWnd)
{
// Set our global window handle to our main window
g_hWnd = hWnd;
// Create our double buffering for each window
g_Buffer.CreateDoubleBuffering(hWnd);
g_ToolBuffer.CreateDoubleBuffering(g_hWndTool);
// Set the map to default
g_Map.SetDefault();
// Load the tiles into the global lists and then get the scroll bar max scroll position
g_ScrollInfo.nMax = LoadTiles();
// By default set the current tile type to map tiles
g_Map.SetCurrentType(TILE_TYPE);
// Set our current map to .... our current map :)
g_pCurrentMap = &g_Map;
// Initialize the scroll bar information
g_ScrollInfo.cbSize = sizeof(SCROLLINFO);
g_ScrollInfo.nMin = 0;
g_ScrollInfo.nPage = 1;
g_ScrollInfo.fMask = SIF_PAGE | SIF_RANGE;
SetScrollInfo(g_hWndTool, SB_VERT, &g_ScrollInfo, FALSE);
g_mapscrollx.cbSize = sizeof(SCROLLINFO);
g_mapscrollx.nMin = 0;
g_mapscrollx.nMax = WIDTH;
g_mapscrollx.nPage = 1;
g_mapscrollx.fMask = SIF_PAGE | SIF_RANGE;
SetScrollInfo(g_hWnd,SB_HORZ,&g_mapscrollx,false);
g_mapscrolly.cbSize = sizeof(SCROLLINFO);
g_mapscrolly.nMin = 0;
g_mapscrolly.nMax = HEIGHT;
g_mapscrolly.nPage = 1;
g_mapscrolly.fMask = SIF_PAGE | SIF_RANGE;
SetScrollInfo(g_hWnd, SB_VERT, &g_mapscrolly, false);
// Here we initialize our open file information
g_OpenInfo.lStructSize = sizeof(OPENFILENAME); // Set the size of the structure
g_OpenInfo.nMaxFile = MAX_PATH; // Set the max characters for a file name
g_OpenInfo.lpstrFile = g_szFileName; // Give a string to store the file name
g_OpenInfo.lpstrFilter = "Map Files (*.map)\0*.map"; // Only accept .map files to load
g_OpenInfo.hwndOwner = g_hWndTool; // Assign the window owner and give it desired flags
g_OpenInfo.Flags = OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR;
g_Buffer.SetPen(PS_SOLID,2,RGB(255,0,0));
// Set the backbuffer to black first (This clears the backbuffer)
g_Buffer.ClearScreen(BLACK_BRUSH);
g_ToolBuffer.ClearScreen(BLACK_BRUSH);
}
#ifndef _MAIN_H
#define _MAIN_H
#include <vector>
#include <iostream>
#include <Windows.h>
#include <string>
#include "bitmap.h"
#include "resource.h"
using namespace std;
#include "tile.h"
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 500
#define SCROLL_BAR_OFFSET 16
#define MENU_OFFSET 16
#define SCROLLOFFSET 25
extern int g_mapsx;
extern int g_mapsy;
extern HWND g_hWnd;
extern HWND g_hWndTool;
extern HINSTANCE g_hInstance;
extern CBuffer g_Buffer;
extern CBuffer g_ToolBuffer;
extern CMap g_Map;
extern CMap *g_pCurrentMap;
extern vector<CTile> g_vTiles;
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
LRESULT CALLBACK WndProcPopup(HWND, UINT, WPARAM, LPARAM);
void Init(HWND hWnd);
WPARAM MainLoop();
void DeInit();
#endif
#include "main.h"
#include "tile.h"
//Tile class init
CTile::CTile():m_bmpTile(0),m_type(0)
{
memset(m_szFile, 0, MAX_PATH);
}
//Map class init
CMap::CMap():m_currentTypeFlag(TILE_TYPE)
{
memset(m_szMapName, 0, MAX_PATH);
}
//draws all the placed tiles
void CMap::Draw()
{
// Here we set the portion to draw for our transparent tiles
int x = 0, y = 0;
// Go through and draw all the normal map tiles
for(int i = 0; i < (int)m_vTiles.size(); i++)
{
x = m_vTiles.GetIndex().x * TILE_WIDTH + g_mapsx;
y = m_vTiles.GetIndex().y * TILE_HEIGHT + g_mapsy;
g_Buffer.DisplayBitmap(m_vTiles.GetBitmap(), x, y);
}
}
//sets up a default map with just grass tiles
void CMap::SetDefault()
{
char szFile[MAX_PATH] = {0};
// Here we setup the file to load as the default texture (grass)
sprintf(szFile, "%s\\%s", TILES_DIR, DEFAULT_TILE);
// Load the default tile file
HBITMAP bmpDefault = g_Buffer.LoadABitmap(szFile);
CTile temp;
// Use a temporary tile for the default tile (Set it's type and name)
temp.SetFileName(szFile);
temp.SetType(FLOOR);
// Make sure we and release all the data with our global lists
m_vTiles.clear();
// Reset the current map's name so we know for the Save As / Save menu items
strcpy(m_szMapName, "");
// Go through the whole map (make it like a 2D array) and assign the
// map a tile for every spot (the default tile with grass). Set it's index too.
for(int y = 0; y < MAP_HEIGHT; y++)
{
for(int x = 0; x < MAP_WIDTH; x++)
{
// Set the current index for the map and add it to the tile list
temp.SetIndex(x, y);
m_vTiles.push_back(temp);
}
}
// Go through all the tiles that were just assigned and load the default bitmap
for(int i = 0; i < (int)m_vTiles.size(); i++)
m_vTiles.SetBitmap( g_Buffer.LoadABitmap( m_vTiles.GetFileName() ) );
}
//returns the size of the current global vector
int CMap::GetCurrentTypeSize()
{
return (int)m_vTiles.size();
}
//This function returns a tile from the current global vector being used
CTile *CMap::GetCurrentTypeTile(int index)
{
return &g_vTiles[index];
}
//This function returns a tile from the current <map> list being used
CTile *CMap::GetCurrentListTile(int index)
{
return &m_vTiles[index];
}
//takes a filename and returns the type
char SetTileType(char *szFile)
{
// See if the substring "*_FILE" is in the current file, then return type
if(strstr(szFile, WALL_FILE))
return WALL;
else if(strstr(szFile, DOOR_FILE))
return DOOR;
else
return FLOOR; // It must be a normal floor tile then
}
//This takes a path and loads the tiles from that path (i.e. items)
void LoadTileType(char *szDir, int type)
{
WIN32_FIND_DATA findFileData;
HANDLE hFind;
char szFile[MAX_PATH] = {0};
// We copy the file to a temp variable and add a * so that
// FindFirstFile() knows to look in the desired directory at all files.
strcpy(szFile, szDir);
strcat(szFile, "*");
// Find the first file in the directory (usually "." or "..")
hFind = FindFirstFile(szFile, &findFileData);
// Make sure we have a valid handle and a file was found
if(hFind == INVALID_HANDLE_VALUE)
{
// Print an error message so we know we need to add files, then quit
sprintf(szFile, "Unable to find tiles in %s", szDir);
MessageBox(g_hWnd, szFile, "Error", MB_OK);
PostQuitMessage(0);
}
else
{
// Continue to look in this directory until we run out of files
while (FindNextFile(hFind, &findFileData) != 0)
{
// Store the current file found with it's respective directory
sprintf(szFile, "%s\\%s", szDir, findFileData.cFileName);
// Check if it's a bmp file using a simple substring check
if(strstr(findFileData.cFileName, ".bmp"))
{
// Initialize a temp tile and add it to our global list
CTile temp;
temp.SetFileName(szFile);
temp.SetType( SetTileType( temp.GetFileName() ) );
g_vTiles.push_back(temp);
}
}
// Destroy the handle and close the files
FindClose(hFind);
}
}
//This function loads all the tiles information and bitmaps
int LoadTiles()
{
// Here we load all the tile types from their respective directories
LoadTileType(TILES_DIR, TILE_TYPE);
// Here we go through all of the global tiles and load their bitmaps
for(int i = 0; i < (int)g_vTiles.size(); i++)
g_vTiles.SetBitmap(g_Buffer.LoadABitmap(g_vTiles.GetFileName()));
// We return the tile's size because that is our default type.
// We also subtract the MAP_HEIGHT - 1 to offset the scroll bar max position.
return (int)g_vTiles.size() - MAP_HEIGHT - 1;
}
void CMap::InsertTile(CTile *pTile, int x, int y)
{
char type = 'e'; // Set a type for exit since exit's don't have tiles
// Since the CTile *pTile isn't always going to be a CTile, we need to
// do some type casting depending on each type that we are inserting.
// We first do a cast to the desired type, and then de-reference the tile
// since the vector class member function push_back() does not take a pointer.
type = pTile->GetType();
// Since every spot on our map has a tile, we don't need to add a tile,
// but replace the current tile in the spot we chose to draw on.
// So, go through all of the tiles and check for the desired index and change the data.
for(int i = 0; i < (int)m_vTiles.size(); i++)
{
// Get the current index of the tile we are checking
POINT index = m_vTiles.GetIndex();
// If this tile is under our cursor, we can then replace it's data
if(index.x == x && index.y == y)
{
// Set the data of the tile on the map with the new inserted tile data
m_vTiles = *pTile;
m_vTiles.SetIndex(index.x, index.y);
break;
}
}
}
void CMap::DeleteTile(int mapX, int mapY)
{
// Since we only delete tiles of the current type selected, we need to do a
// check for the current type of tile, then delete the tile under the cursor.
// We don't delete normal map tiles so we don't check for TILE_TYPE.
}
//This function returns a bitmap handle for a tile type when loading a map
HBITMAP CMap::FindHBitmap(char *szFile, int type)
{
// So that we only load the bitmaps once and not duplicate any unnecessary
// memory, we use this function to search the global tile lists and
// gives us back an HBITMAP with the same file name. We then share that
// between the map tile lists and the tool bar tile lists.
// Go through all of the tiles in the global tile list
for(int i = 0; i < (int)g_vTiles.size(); i++)
{
// If the file name is the same then return it's bitmap handle
if(strcmp(szFile, g_vTiles.GetFileName()) == 0)
return g_vTiles.GetBitmap();
}
// Return default 0
return 0;
}
//This function loads a map from a file
void CMap::Load(char *szFile)
{
// Open our map that we want to load in "read" and "binary" mode
FILE *fp = fopen(szFile, "rb");
// In this function we want to load all of the data from a specified map.
// We do this by first opening the file, then clearing our map tile lists.
// We read the tile size for each list so we know how many tiles of that
// type to read in. Using our vector lists it's easy to allocate the
// memory we need for each list. Lastly, we go through the global lists
// and get a bitmap handle to each tile that we load. This way we save
// some memory and don’t need to worry about freeing more memory.
// (* IMPORTANT *) It's probably common sense, but you have to make sure
// you load the file the SAME exact order it was saved. For instance, if
// you load the map tiles first, you cant save the items first. "Capish"?
// If we couldn’t load the file report an error message
if(!fp)
{
MessageBox(g_hWnd, "Can't Find File", "Error", MB_OK);
return;
}
// Reset all of our map list data before we load more in
m_vTiles.clear();
int tileSize = 0, exitSize = 0;
// Read in the sizes of each of the lists (the tile count of each list)
fread(&tileSize, sizeof(int), 1, fp);
// Depending on the list size, reallocate the memory for our map lists
m_vTiles.resize(tileSize);
// Go through all the lists in our map and load their tile information
for(int i = 0; i < tileSize; i++)
fread(&m_vTiles, sizeof(CTile), 1, fp);
// Assign bitmap handles to each of the tiles
for(int i = 0; i < tileSize; i++)
m_vTiles.SetBitmap( FindHBitmap(m_vTiles.GetFileName(), TILE_TYPE) );
// Close our file that we opened, a success!
fclose(fp);
// Let's create some string variables to store just the file name, not including the path
char szTemp[255] = {0};
char szFileName[255] = {0};
LPSTR pFileName = szFileName;
// Here we use a good win32 function to extract just the file name from the path.
// The file name will be stored in pFileName. This way it's not hard coded to a path.
GetFullPathName(szFile, 255, (LPSTR)szTemp, &pFileName);
// Set the name of this map
strcpy(m_szMapName, pFileName);
}
//This function saves a map to a file
void CMap::Save(char *szFile)
{
FILE *fp = NULL;
// Just like the Load() function, to save the map we will be doing pretty
// much the same things, except instead of fread() we will use fwrite() to
// write the information to disk for our .map file.
// Check if the file doesn't have a .map extension. If not, add it at no extra charge :)
if(!strstr(szFile, MAP_EXT))
strcat(szFile, MAP_EXT);
// Open our file to "write" and in "binary".
fp = fopen(szFile, "wb");
// If we couldn’t create or open the file report an error
if(!fp)
{
MessageBox(g_hWnd, "Can't Write File", "Error", MB_OK);
return;
}
// Store all the sizes for each of the map's lists
int tileSize = (int)m_vTiles.size();
// Save the sizes for each of the map lists
fwrite(&tileSize, sizeof(int), 1, fp);
// Go through all the lists and save each tile to disk
for(int i = 0; i < tileSize; i++)
fwrite(&m_vTiles, sizeof(CTile), 1, fp);
// Close the file, the file is saved!
fclose(fp);
// Set the file name for this map that we just saved
strcpy(m_szMapName, szFile);
}
#ifndef _TILE_H
#define _TILE_H
#include "main.h"
#define MAP_WIDTH 10
#define MAP_HEIGHT 10
#define TILE_WIDTH 32
#define TILE_HEIGHT 32
#define MAX_NAME_LEN 50
#define HEIGHT (TILE_HEIGHT * MAP_HEIGHT)
#define WIDTH (TILE_WIDTH * MAP_WIDTH)
#define TILES_DIR "Tiles\\"
#define DEFAULT_TILE "grass_f.bmp"
#define MAP_EXT ".map"
// The normal map tiles have these written in the file name
#define FLOOR_FILE "_f"
#define WALL_FILE "_w"
#define DOOR_FILE "_d"
// The defines are stored in the CTile: m_type variable
#define FLOOR 'f'
#define WALL 'w'
#define DOOR 'd'
#define EXIT 'e'
#define TILE_TYPE 0
#define EXIT_TYPE 4
// Our <Base Class> for each tile type.
// This is then inherited from to create other tile types.
class CTile
{
public:
CTile(); // The constructor (initializing function)
// Our standard "Set" functions for our protected data
void SetBitmap(HBITMAP bmpNew) { m_bmpTile = bmpNew; }
void SetFileName(char *szNew) { strcpy(m_szFile, szNew); }
void SetType(char newType) { m_type = newType; }
void SetIndex(int x, int y) { m_index.x = x; m_index.y = y; }
// Our standard "Get" functions for the protected data
HBITMAP GetBitmap() { return m_bmpTile; }
char *GetFileName() { return m_szFile; }
char GetType() { return m_type; }
POINT GetIndex() { return m_index; }
// Set it protected so that inherited classes can access if necessary
private:
HBITMAP m_bmpTile; // The handle to the tile's bitmap
char m_szFile[MAX_PATH]; // The file name of the bitmap
char m_type; // The type of the tile
POINT m_index; // The index on the map of the tile
};
// This class handles most of our map functionality
class CMap
{
public:
CMap(); // The constructor
// This resets the map to green grass
void SetDefault();
// This draws our map
void Draw();
// These set and get the map name
void SetMapName(char *szName) { strcpy(m_szMapName, szName); }
char *GetMapName() { return m_szMapName; }
// These set and get the current tile type being used
void SetCurrentType(int type) { m_currentTypeFlag = type; }
int GetCurrentType() { return m_currentTypeFlag; }
// These get the current global list's size and specific tile
int GetCurrentTypeSize();
CTile *GetCurrentTypeTile(int index);
// These get the current map list's size and specific tile
int GetCurrentListSize();
CTile *GetCurrentListTile(int index);
void InsertTile(CTile *pTile, int x, int y);
void DeleteTile(int mapX, int mapY);
// This returns a handle to a bitmap from the global lists for the same file name
HBITMAP FindHBitmap(char *szFile, int type);
// This loads a file
void Load(char *szFile);
// This saves a file
void Save(char *szFile);
private:
char m_szMapName[MAX_PATH]; // The name of the map
int m_currentTypeFlag; // The flag that determines the list type in the tool bar
vector<CTile> m_vTiles; // The normal map tiles list on our map
};
// This loads the tiles for the global tile lists and returns the size for the scroll bar
int LoadTiles();
#endif