二维地图查看器未处理的异常

2D Map Viewer Unhandled Exception

目前我正在尝试正确加载 Tiled 地图。我花了一天的大部分时间寻找帮助,包括在这里,但我一无所获。所以我决定继续我的直觉,根据我认为它应该如何工作重写代码,并忽略我拥有的游戏编程入门书,因为涉及瓦片地图的章节使用 LPDIRECT3DSURFACE9 而不是 LPDIRECT3DTEXTURE9,我需要透明度。

所以我删除了所有额外的代码,剩下的就是我的直觉告诉我应该渲染瓦片地图,如果它没有抛出异常的话。我一整天都在渲染地图上取得了不同程度的成功,这就是为什么我将其剥离到最低限度的原因。

Unhandled exception at 0x00893eaa in Platformer.exe: 0xC0000005: Access violation reading location 0x008a9000.

这个错误指向的具体函数是这样的:

void BuildGameWorld()
{
    int x, y;
    LPDIRECT3DTEXTURE9 tiles = nullptr;

    //load the texture file
    tiles = LoadTexture("tiles_spritesheet.png", D3DCOLOR_XRGB(255, 0, 255));

    for(y = 0; y < GAMEWORLDHEIGHT; y++)
    {
        for(x = 0; x < GAMEWORLDWIDTH; x++)
        {
                    /****** THIS LINE HERE ******/
            DrawTile(tiles, MAPDATA[y * MAPWIDTH + x], 2, 70, 70, 12, backbuffer, x * 70, y * 70, D3DCOLOR_XRGB(255,255,255));
        }
    }

    //release the texture file
    tiles->Release();
}

其余的源代码在这里

//Filename: MyDirectX.h
#pragma once

//header files
#define WIN32_EXTRA_LEAN
#include <windows.h>
#include <d3d9.h>
#include <d3dx9.h>
#include <ctime>
#include <iostream>
#include <sstream>
#include <iomanip>
using namespace std;

//libraries
#pragma comment(lib,"winmm.lib")
#pragma comment(lib,"user32.lib")
#pragma comment(lib,"gdi32.lib")
#pragma comment(lib,"dxguid.lib")
#pragma comment(lib,"d3d9.lib")
#pragma comment(lib,"d3dx9.lib")

//program values
extern const string APPTITLE;
extern const int SCREENW;
extern const int SCREENH;
extern bool gameover;

//Direct3D objects
extern LPDIRECT3D9 d3d; 
extern LPDIRECT3DDEVICE9 d3ddev; 
extern LPDIRECT3DSURFACE9 backbuffer;
extern LPD3DXSPRITE spriteobj;

//Direct3D functions
bool Direct3D_Init(HWND hwnd, int width, int height, bool fullscreen);
void Direct3D_Shutdown();

LPDIRECT3DSURFACE9 LoadSurface(string filename);
void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source);

LPDIRECT3DTEXTURE9 LoadTexture(string filename, D3DCOLOR transcolor = D3DCOLOR_XRGB(0,0,0));
//game functions
bool Game_Init(HWND window);
void Game_Run(HWND window);
void Game_End();

void DrawTile(LPDIRECT3DTEXTURE9 source, int frame,int spacing, int width, int height, int columns, LPDIRECT3DSURFACE9 dest, int destx, int desty, D3DCOLOR color);
void BuildGameWorld();


//Filename: MyDirectX.cpp
#include "MyDirectX.h"
#include <iostream>
using namespace std;

//Direct3D variables
LPDIRECT3D9 d3d = NULL; 
LPDIRECT3DDEVICE9 d3ddev = NULL; 
LPDIRECT3DSURFACE9 backbuffer = NULL;
LPD3DXSPRITE spriteobj;

bool Direct3D_Init(HWND window, int width, int height, bool fullscreen)
{
    //initialize Direct3D
    d3d = Direct3DCreate9(D3D_SDK_VERSION);
    if (!d3d) return false;

    //set Direct3D presentation parameters
    D3DPRESENT_PARAMETERS d3dpp; 
    ZeroMemory(&d3dpp, sizeof(d3dpp));
    d3dpp.hDeviceWindow = window;
    d3dpp.Windowed = (!fullscreen);
    d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
    d3dpp.EnableAutoDepthStencil = 1;
    d3dpp.AutoDepthStencilFormat = D3DFMT_D24S8;
    d3dpp.Flags = D3DPRESENTFLAG_DISCARD_DEPTHSTENCIL;
    d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
    d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
    d3dpp.BackBufferCount = 1;
    d3dpp.BackBufferWidth = width;
    d3dpp.BackBufferHeight = height;

    //create Direct3D device
    d3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, window,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &d3ddev);
    if (!d3ddev) return false;


    //get a pointer to the back buffer surface
    d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);

    //create sprite object
    D3DXCreateSprite(d3ddev, &spriteobj);

    return 1;
}
void Direct3D_Shutdown()
{
    if (spriteobj) spriteobj->Release();

    if (d3ddev) d3ddev->Release();
    if (d3d) d3d->Release();
}

void DrawSurface(LPDIRECT3DSURFACE9 dest, float x, float y, LPDIRECT3DSURFACE9 source)
{
    //get width/height from source surface
    D3DSURFACE_DESC desc;
    source->GetDesc(&desc);

    //create rects for drawing
    RECT source_rect = {0, 0, (long)desc.Width, (long)desc.Height };
    RECT dest_rect = { (long)x, (long)y, (long)x+desc.Width, (long)y+desc.Height};

    //draw the source surface onto the dest
    d3ddev->StretchRect(source, &source_rect, dest, &dest_rect, D3DTEXF_NONE);

}
LPDIRECT3DSURFACE9 LoadSurface(string filename)
{
    LPDIRECT3DSURFACE9 image = NULL;

    //get width and height from bitmap file
    D3DXIMAGE_INFO info;
    HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info);
    if (result != D3D_OK)
        return NULL;

    //create surface
    result = d3ddev->CreateOffscreenPlainSurface(
        info.Width,         //width of the surface
        info.Height,        //height of the surface
        D3DFMT_X8R8G8B8,    //surface format
        D3DPOOL_DEFAULT,    //memory pool to use
        &image,             //pointer to the surface
        NULL);              //reserved (always NULL)

    if (result != D3D_OK) return NULL;

    //load surface from file into newly created surface
    result = D3DXLoadSurfaceFromFile(
        image,                  //destination surface
        NULL,                   //destination palette
        NULL,                   //destination rectangle
        filename.c_str(),       //source filename
        NULL,                   //source rectangle
        D3DX_DEFAULT,           //controls how image is filtered
        D3DCOLOR_XRGB(0,0,0),   //for transparency (0 for none)
        NULL);                  //source image info (usually NULL)

    //make sure file was loaded okay
    if (result != D3D_OK) return NULL;

    return image;
}

LPDIRECT3DTEXTURE9 LoadTexture(std::string filename, D3DCOLOR transcolor)
{  
    LPDIRECT3DTEXTURE9 texture = NULL;

    //get width and height from bitmap file
    D3DXIMAGE_INFO info;
    HRESULT result = D3DXGetImageInfoFromFile(filename.c_str(), &info);
    if (result != D3D_OK) return NULL;

    //create the new texture by loading a bitmap image file
    D3DXCreateTextureFromFileEx( 
        d3ddev,                //Direct3D device object
        filename.c_str(),      //bitmap filename
        info.Width,            //bitmap image width
        info.Height,           //bitmap image height
        1,                     //mip-map levels (1 for no chain)
        D3DPOOL_DEFAULT,       //the type of surface (standard)
        D3DFMT_UNKNOWN,        //surface format (default)
        D3DPOOL_DEFAULT,       //memory class for the texture
        D3DX_DEFAULT,          //image filter
        D3DX_DEFAULT,          //mip filter
        transcolor,            //color key for transparency
        &info,                 //bitmap file info (from loaded file)
        NULL,                  //color palette
        &texture );            //destination texture

    //make sure the bitmap textre was loaded correctly
    if (result != D3D_OK) return NULL;

    return texture;
}

//Filename: MyGame.cpp
#include "MyDirectX.h"
using namespace std;

const string APPTITLE = "2D Platformer";
const int SCREENW = 1024;
const int SCREENH = 768;

//settings for the scroller
const int TILEWIDTH = 70;
const int TILEHEIGHT = 70;
const int MAPWIDTH = 30;
const int MAPHEIGHT = 10;

//scrolling window size
const int WINDOWWIDTH = (SCREENW / TILEWIDTH) * TILEWIDTH;
const int WINDOWHEIGHT = (SCREENH / TILEHEIGHT) * TILEHEIGHT;

//entire gameworld dimensions
const int GAMEWORLDWIDTH = TILEWIDTH * MAPWIDTH;
const int GAMEWORLDHEIGHT = TILEHEIGHT * MAPHEIGHT;

int MAPDATA[MAPWIDTH*MAPHEIGHT] = 
{
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,
    10,10,10,10,10,10,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,
    153,153,153,153,153,153,153,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,153,
    153,153,153,153,153,153,153,145,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,133,0,0,153,
    153,153,153,153,153,153,153,10,10,10,10,10,103,103,103,103,103,103,103,103,103,103,103,103,103,10,10,10,10,153,
    153,153,153,153,153,153,153,153,153,153,153,153,44,44,44,44,44,44,44,44,44,44,44,44,44,153,153,153,153,153
};

bool Game_Init(HWND window)
{
    //initialize Direct3D
    Direct3D_Init(window, SCREENW, SCREENH, false);

    //create a pointer to the backbuffer
    d3ddev->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuffer);

    return true;
}
void Game_Run(HWND window)
{
    //make sure the Direct3D device is valid
    if (!d3ddev) return;

    //clear the scene
    d3ddev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0,0,100), 1.0f, 0);

        //start rendering
        if (d3ddev->BeginScene())
        {

           spriteobj->Begin(D3DXSPRITE_ALPHABLEND);

           BuildGameWorld();

           spriteobj->End();

            //stop rendering
            d3ddev->EndScene();
            d3ddev->Present(NULL, NULL, NULL, NULL);
        }

    //exit when escape key is pressed
    if (GetAsyncKeyState(VK_ESCAPE)) 
        gameover = true;

}
void Game_End()
{
    //free memory and shut down
    Direct3D_Shutdown();
}

void DrawTile(LPDIRECT3DTEXTURE9 source, int frame,int spacing, int width, int height, int columns, LPDIRECT3DSURFACE9 dest, int destx, int desty, D3DCOLOR color)
{
    //get dimensions for the tile
    RECT r1;
    r1.left = ((frame % columns) + spacing * frame) * width;
    r1.top = (frame / columns) * height;
    r1.right = r1.left + width;
    r1.bottom = r1.top + height;

    //draw the sprite
    spriteobj->Draw(source, &r1, &D3DXVECTOR3(r1.right / 2, r1.bottom / 2, 0), &D3DXVECTOR3(destx, desty, 0), color);
}

void BuildGameWorld()
{
    int x, y;
    LPDIRECT3DTEXTURE9 tiles = nullptr;

    //load the texture file
    tiles = LoadTexture("tiles_spritesheet.png", D3DCOLOR_XRGB(255, 0, 255));

    for(y = 0; y < GAMEWORLDHEIGHT; y++)
    {
        for(x = 0; x < GAMEWORLDWIDTH; x++)
        {
            DrawTile(tiles, MAPDATA[y * MAPWIDTH + x], 2, 70, 70, 12, backbuffer, x * 70, y * 70, D3DCOLOR_XRGB(255,255,255));
        }
    }

    //release the texture file
    tiles->Release();
}

//Filename: MyWindows.cpp
#include "MyDirectX.h"
using namespace std;
bool gameover = false;


LRESULT WINAPI WinProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
    switch( msg )
    {
        case WM_DESTROY:
            gameover = true;
            PostQuitMessage(0);
            return 0;
    }
    return DefWindowProc( hWnd, msg, wParam, lParam );
}


int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    //initialize window settings
    WNDCLASSEX wc;
    wc.cbSize = sizeof(WNDCLASSEX); 
    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = (WNDPROC)WinProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = NULL;
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = APPTITLE.c_str();
    wc.hIconSm       = NULL;
    RegisterClassEx(&wc);

    //create a new window
    HWND window = CreateWindow( APPTITLE.c_str(), APPTITLE.c_str(),
       WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT,
       SCREENW, SCREENH, NULL, NULL, hInstance, NULL);
    if (window == 0) return 0;

    //display the window
    ShowWindow(window, nCmdShow);
    UpdateWindow(window);

    //initialize the game
    if (!Game_Init(window)) return 0;

    // main message loop
    MSG message;
    while (!gameover)
    {
        if (PeekMessage(&message, NULL, 0, 0, PM_REMOVE)) 
        {
            TranslateMessage(&message);
            DispatchMessage(&message);
        }

        //process game loop 
        Game_Run(window);
    }

    //shutdown
    Game_End();
    return message.wParam;
}

您的地图声明为

int MAPDATA[MAPWIDTH*MAPHEIGHT]

当您使用 x,y 索引时

for(y = 0; y < GAMEWORLDHEIGHT; y++) { 
  for(x = 0; x < GAMEWORLDWIDTH; x++) {  } }

在哪里

const int GAMEWORLDWIDTH = TILEWIDTH * MAPWIDTH; 
const int GAMEWORLDHEIGHT = TILEHEIGHT * MAPHEIGHT;