0

使用 Direct3D 9 和 C++ 创建小型 2D 游戏。我遇到了一个我以前从未见过的问题。该游戏是基于商店的游戏,因此我有一个客户类。我已经在游戏中创建了对象,它呈现并表现出我想要的方式。我决定将对象放入 Vector 中,因为在某些时候,我会随时需要它们的集合。但是,我的问题是,当我将对象放入 Vector 时,它不再在屏幕上可见!

我没有错误。我已将 DirectX 函数的所有返回代码输出到测试文件中,没有任何失败。它运行良好,只是在屏幕上不可见!除了将其放入 Vector 之外,没有任何变化。

我将 Vector 更改为指针向量,因为有人告诉我 Vector 只是创建对象,复制它并删除原始对象。但是,现在看来,使用这种方法,我的 Direct3D 指针很快就会失效。我想我知道出了什么问题,但不确定最好的行动方案。

这是客户类:

#include "Headers.h"
#include "Playercard.h"

class Customer{

private:

LPDIRECT3DTEXTURE9 texture, playerInfoCard;
D3DXVECTOR3 position, direction, playerCardPosition;
D3DXVECTOR3 center;
LPD3DXFONT font;
POINT curPos;

HRESULT rc;

//Playercard playerCard;
int depthBuffer;
int walkingAlternator;

// Some information about the customer

char name[10];
int age;
double cash;

int itemWanted;
char productWanted[20];

bool happy;
bool male;
bool female;
bool displayPlayerCard;

RECT textBox;

Playercard playercard;

void assignNameAndGender()
{
    srand((unsigned int)time(0));
    int name_decider = rand() % 16 + 1;

    switch(name_decider)
    {
    case 1:
        strcpy_s(name, "John");
        male = true; female = false;
        break;
    case 2:
        strcpy_s(name, "Chris");
        male = true; female = false;
        break;
    case 3:
        strcpy_s(name, "Ben");
        male = true; female = false;
        break;
    case 4:
        strcpy_s(name, "Jack");
        male = true; female = false;
        break;
    case 5:
        strcpy_s(name, "Jamie");
        male = true; female = false;
        break;
    case 6:
        strcpy_s(name, "Bill");
        male = true; female = false;
        break;
    case 7:
        strcpy_s(name, "Liam");
        male = true; female = false;
        break;
    case 8:
        strcpy_s(name, "Alex");
        male = true; female = false;
        break;
    case 9:
        strcpy_s(name, "Nikki");
        male = false; female = true;
        break;
    case 10:
        strcpy_s(name, "Alice");
        male = false; female = true;
        break;
    case 11:
        strcpy_s(name, "Lucy");
        male = false; female = true;
        break;
    case 12:
        strcpy_s(name, "Emily");
        male = false; female = true;
        break;
    case 13:
        strcpy_s(name, "Laura");
        male = false; female = true;
        break;
    case 14:
        strcpy_s(name, "Mary");
        male = false; female = true;
        break;
    case 15:
        strcpy_s(name, "Katie");
        male = false; female = true;
        break;
    case 16:
        strcpy_s(name, "Emma");
        male = false; female = true;
        break;
    }
}

void assignAge()
{
    srand((unsigned int)time(0));
    age = rand() % 53 + 12;          // An age between 12 and 65
}

void assignCash()
{
    if(age < 16)
        cash = 5.00;
    if(age >= 16 && age <= 18)
        cash = 15.00;
    if(age >= 19 && age <= 21)
        cash = 20.00;
    if(age >= 22 && age <= 25)
        cash = 25.00;
    if(age >= 26 && age <= 30)
        cash = 30.00;
    if(age > 31)
    {
        int randNum = rand() % 9 + 1;

        switch(randNum)
        {
        case 1:
            cash = 20.00;
            break;
        case 2:
            cash = 25.00;
            break;
        case 3:
            cash = 30.00;
            break;
        case 4:
            cash = 35.00;
            break;
        case 5:
            cash = 40.00;
            break;
        case 6:
            cash = 45.00;
            break;
        case 7:
            cash = 50.00;
            break;
        case 8:
            cash = 55.00;
            break;
        case 9:
            cash = 60.00;
            break;
        }
    }
}

public:

Customer()
{
    direction.x = (float)cos(0.558)*4;    // 30 degree movement
    direction.y = (float)sin(0.558)*4;    // 30 degree movement
    position.x = 500;
    position.y = 500;
    displayPlayerCard = false;  // Only true when mouse clicked
    happy = true;               // A new customer is always happy at first!
    walkingAlternator = 1;      // Help control sprite movement

    strcpy_s(productWanted, "Xbox");
    assignNameAndGender();      // Assign customer a name
    assignAge();                // Assign customer an age
    assignCash();               // Assign customer an amount of cash
    playercard.load(name, male, age, cash, productWanted);
}

~Customer()
{
}


void move()
{
    if(KEY_DOWN(0x57) || KEY_DOWN(VK_UP))
    {
        position.y -= direction.y;
        position.x += direction.x;
        walkingUp();
    }
    else if(KEY_DOWN(0x41) || KEY_DOWN(VK_LEFT))
    {
        position.y -= direction.y;
        position.x -= direction.x;
        walkingLeft();
    }
    else if(KEY_DOWN(0x53) || KEY_DOWN(VK_DOWN))
    {
        position.y += direction.y;
        position.x -= direction.x;
        walkingDown();
    }
    else if(KEY_DOWN(0x44) || KEY_DOWN(VK_RIGHT))
    {
        position.y += direction.y;
        position.x += direction.x;
        walkingRight();
    }
    else
    {
        // Reset the sprite here so that the feet are together in resting position AND so that sprite is facing the way it was going when it stopped
    }
}

void loadGraphics()
{
    D3DXCreateTextureFromFileEx(d3dDevice, "player_information_card.png", D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 0, 0, 
        D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DCOLOR_XRGB(255, 255, 255), NULL, NULL, &playerInfoCard);

    D3DXCreateTextureFromFileEx(d3dDevice, "Characters/female_shopper1.png", D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 0, 0,
        D3DFMT_UNKNOWN, D3DPOOL_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DCOLOR_XRGB(255, 255, 255), NULL, NULL, &texture);

    D3DXVECTOR3 position(100.0f, 100.0f, 0.0f);
    D3DXVECTOR3 center(0.0f, 0.0f, 0.0f);

    D3DXCreateFont(d3dDevice,                   // the D3D Device
               20,                              // font height of 30
               0,                               // default font width
               FW_NORMAL,                       // font weight
               1,                               // not using MipLevels
               false,                           // italic font
               DEFAULT_CHARSET,                 // default character set
               OUT_DEFAULT_PRECIS,              // default OutputPrecision,
               DEFAULT_QUALITY,                 // default Quality
               DEFAULT_PITCH | FF_DONTCARE,     // default pitch and family
               "Georgia",                       // use Facename Arial
               &font);                          // the font object    
}

void draw()
{
    d3dSprite->Draw(texture, NULL, &center, &position, D3DCOLOR_ARGB(255, 255, 255, 255));

    if(displayPlayerCard) 
    {
        playerCardPosition = position;
        playerCardPosition.y -= 128;
        playerCardPosition.x += 32;

        SetRect(&textBox, (int)playerCardPosition.x+5, (int)playerCardPosition.y+5, (int)playerCardPosition.x+256-5, (int)playerCardPosition.y+128-5);

        d3dSprite->Draw(playerInfoCard, NULL, &center, &playerCardPosition, D3DCOLOR_ARGB(255, 255, 255, 255));
        font->DrawTextA(d3dSprite, playercard.plCard().c_str(), -1, &textBox, DT_LEFT, D3DCOLOR_ARGB(255, 255, 255, 255));
    }
}

void walkingDown()
{
    if(walkingAlternator == 1 || walkingAlternator == 2 || walkingAlternator == 3 || walkingAlternator == 4 || walkingAlternator == 5 
        || walkingAlternator == 6 || walkingAlternator == 7 || walkingAlternator == 8 || walkingAlternator == 9 || walkingAlternator == 10)
    {
        D3DXCreateTextureFromFileEx(d3dDevice, "Characters/female_shopper2.png", D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 0, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
        D3DX_DEFAULT, D3DX_DEFAULT, D3DCOLOR_XRGB(255, 255, 255), NULL, NULL, &texture);
        walkingAlternator++;
    }
    else if(walkingAlternator == 11 || walkingAlternator == 12 || walkingAlternator == 13 || walkingAlternator == 14 || walkingAlternator == 15
        || walkingAlternator == 16 || walkingAlternator == 17 || walkingAlternator == 18 || walkingAlternator == 19 || walkingAlternator == 20)
    {
        D3DXCreateTextureFromFileEx(d3dDevice, "Characters/female_shopper3.png", D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 0, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
        D3DX_DEFAULT, D3DX_DEFAULT, D3DCOLOR_XRGB(255, 255, 255), NULL, NULL, &texture);
        walkingAlternator++;
    }

    if(walkingAlternator >= 20)
    {
        walkingAlternator = 1;
    }
}

void walkingUp()
{
    if(walkingAlternator == 1 || walkingAlternator == 2 || walkingAlternator == 3 || walkingAlternator == 4 || walkingAlternator == 5 
        || walkingAlternator == 6 || walkingAlternator == 7 || walkingAlternator == 8 || walkingAlternator == 9 || walkingAlternator == 10)
    {
        D3DXCreateTextureFromFileEx(d3dDevice, "Characters/female_shopper1_back2.png", D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 0, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
        D3DX_DEFAULT, D3DX_DEFAULT, D3DCOLOR_XRGB(255, 255, 255), NULL, NULL, &texture);
        walkingAlternator++;
    }
    else if(walkingAlternator == 11 || walkingAlternator == 12 || walkingAlternator == 13 || walkingAlternator == 14 || walkingAlternator == 15
        || walkingAlternator == 16 || walkingAlternator == 17 || walkingAlternator == 18 || walkingAlternator == 19 || walkingAlternator == 20)
    {
        D3DXCreateTextureFromFileEx(d3dDevice, "Characters/female_shopper1_back1.png", D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 0, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
        D3DX_DEFAULT, D3DX_DEFAULT, D3DCOLOR_XRGB(255, 255, 255), NULL, NULL, &texture);
        walkingAlternator++;
    }

    if(walkingAlternator >= 20)
    {
        walkingAlternator = 1;
    }
}

void walkingLeft()
{
    if(walkingAlternator == 1 || walkingAlternator == 2 || walkingAlternator == 3 || walkingAlternator == 4 || walkingAlternator == 5 
        || walkingAlternator == 6 || walkingAlternator == 7 || walkingAlternator == 8 || walkingAlternator == 9 || walkingAlternator == 10)
    {
        D3DXCreateTextureFromFileEx(d3dDevice, "Characters/female_shopper1_back3.png", D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 0, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
        D3DX_DEFAULT, D3DX_DEFAULT, D3DCOLOR_XRGB(255, 255, 255), NULL, NULL, &texture);
        walkingAlternator++;
    }
    else if(walkingAlternator == 11 || walkingAlternator == 12 || walkingAlternator == 13 || walkingAlternator == 14 || walkingAlternator == 15
        || walkingAlternator == 16 || walkingAlternator == 17 || walkingAlternator == 18 || walkingAlternator == 19 || walkingAlternator == 20)
    {
        D3DXCreateTextureFromFileEx(d3dDevice, "Characters/female_shopper1_back4.png", D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 0, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
        D3DX_DEFAULT, D3DX_DEFAULT, D3DCOLOR_XRGB(255, 255, 255), NULL, NULL, &texture);
        walkingAlternator++;
    }

    if(walkingAlternator >= 20)
    {
        walkingAlternator = 1;
    }
}

void walkingRight()
{
    if(walkingAlternator == 1 || walkingAlternator == 2 || walkingAlternator == 3 || walkingAlternator == 4 || walkingAlternator == 5 
        || walkingAlternator == 6 || walkingAlternator == 7 || walkingAlternator == 8 || walkingAlternator == 9 || walkingAlternator == 10)
    {
        D3DXCreateTextureFromFileEx(d3dDevice, "Characters/female_shopper4.png", D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 0, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
        D3DX_DEFAULT, D3DX_DEFAULT, D3DCOLOR_XRGB(255, 255, 255), NULL, NULL, &texture);
        walkingAlternator++;
    }
    else if(walkingAlternator == 11 || walkingAlternator == 12 || walkingAlternator == 13 || walkingAlternator == 14 || walkingAlternator == 15
        || walkingAlternator == 16 || walkingAlternator == 17 || walkingAlternator == 18 || walkingAlternator == 19 || walkingAlternator == 20)
    {
        D3DXCreateTextureFromFileEx(d3dDevice, "Characters/female_shopper5.png", D3DX_DEFAULT_NONPOW2, D3DX_DEFAULT_NONPOW2, 0, 0, D3DFMT_UNKNOWN, D3DPOOL_DEFAULT,
        D3DX_DEFAULT, D3DX_DEFAULT, D3DCOLOR_XRGB(255, 255, 255), NULL, NULL, &texture);
        walkingAlternator++;
    }

    if(walkingAlternator >= 20)
    {
        walkingAlternator = 1;
    }
}

void checkInteractivity()
{
    GetCursorPos(&curPos);
    if (GetKeyState(VK_LBUTTON) & 0x80 &&                        
        curPos.x >= position.x && curPos.x <= position.x+64 &&   
        curPos.y >= position.y && curPos.y <= position.y+128)    
    {
        displayPlayerCard = true;
    }
    else
    {
        displayPlayerCard = false;
    }
}

D3DXVECTOR3 returnPosition()
{
    return position;
}

D3DXVECTOR3 returnPosition(bool returnCentreOfSprite)
{
    return position;
}

};

这是主要的代码

#include "Headers.h."
#include "Customer.h"
#include "Background.h"
#include "Counter.h"
#include "GameStations.h"
#include "ConsoleCab.h"
#include "ClothesStand.h"
#include "GamePanel.h"

    std::vector<Customer*> customers;

Background background;
Counter counter;
GameStations gameStations;
ConsoleCab consoleCab;
ClothesStand clothesStand;
GamePanel gamePanel;

void initDirectX(HWND hWnd);       // Initializes Direct3D Graphics
void render();                     // Render graphics
void cleanUp();                    // Cleans everything up and releases memory

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    HWND hWnd;                                          // The handle to the window function
    WNDCLASSEX window;                                  // Pointer to window struct
    ZeroMemory(&window, sizeof(WNDCLASSEX));            // Clears window class so we can use it
    window.cbSize = sizeof(WNDCLASSEX);                 // Size of window
    window.style = CS_HREDRAW | CS_VREDRAW;             // Redraws the entire window if a movement or size adjustment changes the height of the client area. 
    window.lpfnWndProc = WindowProc;                    // Pointer to the window procedure
    window.hInstance = hInstance;                       // Handle to current instance
    window.hCursor = LoadCursor(NULL, IDC_ARROW);       // We'll stick with the normal cursor here
    window.lpszClassName = "Window";                    // Gives the class a name
    RegisterClassEx(&window);                           // Registers the window class 

    hWnd = CreateWindowEx(NULL,
        "Window",                     // Name of the class
        "Space Game",                 // Title of the window
        WS_EX_TOPMOST | WS_POPUP,     // Fullscreen
        0, 0,                         // Position of window (0,0 for fullscreen)
        SCREEN_WIDTH, SCREEN_HEIGHT,  // Screen resolution (Uses global declaration)
        NULL,                         // Parent window (None)
        NULL,                         // Menus (None)
        hInstance,                    // Application handle
        NULL);                        // Set to NULL as we aren't using more than 1 window

    ShowWindow(hWnd, nCmdShow);                         // Display window
    initDirectX(hWnd);                                  // Initialises the directX graphics
    MSG msg = {0};                                      // msg holds the Windows events message queue

    customers.push_back(new Customer());

    for (std::vector<Customer*>::iterator customerIT = customers.begin(); customerIT != customers.end(); customerIT++)
    {
         (*customerIT)->loadGraphics();
    } // Object properties become invalid here.

    background.loadGraphics();
    counter.loadGraphics();
    gameStations.loadGraphics();
    consoleCab.loadGraphics();
    clothesStand.loadGraphics();
    gamePanel.loadGraphics();

    /************************************** Main game loop *************************************************/

    while(TRUE)                                         // Main game loop
    {
        if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))     // If messages are waiting
        {
            TranslateMessage(&msg);                      // Translates the keystroke messages into the correct format
            DispatchMessage(&msg);                       // Sends message to the windowsProc function
            if(msg.message == WM_QUIT)                   // If the message was a quit message
                break;                                   // Breaks out of main game loop
        }
        else                  
        {

        for (std::vector<Customer*>::iterator customerIT = customers.begin(); customerIT != customers.end(); customerIT++)
        {
            (*customerIT)->checkInteractivity();
            (*customerIT)->move();
        }

            gamePanel.hoverDetection();
            render();
        }
    }

    /*******************************************************************************************************/

    // We are out of the main game loop (Due to a WM_QUIT signal)
    cleanUp();                                          // Do some housekeeping before quitting
    return msg.wParam;                                  // Return the WM_QUIT message to Windows. End of program
}

LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    switch(message)                                     // Sorts through messages
    {
    case WM_DESTROY:                                // When window has been closed
        {
            PostQuitMessage(0);                     // Closes the application
            return 0;  
        } 
        break;
    }
    return DefWindowProc (hWnd,                         // Returns any messages the switch statement didn't pick up
        message,
        wParam,
        lParam);
}

void initDirectX(HWND hWnd)
{
    d3d = Direct3DCreate9(D3D_SDK_VERSION);              // Create DirectX9 interface
    D3DPRESENT_PARAMETERS d3dParameters;                 // Pointer to DirectX9 parameters

    ZeroMemory(&d3dParameters, sizeof(d3dParameters));   // Clears the structure so we can use it
    d3dParameters.Windowed = FALSE;                      // Fullscreen
    d3dParameters.SwapEffect = D3DSWAPEFFECT_DISCARD;    // Get rid of old framess
    d3dParameters.hDeviceWindow = hWnd;                  // Sets the window to be used by Direct3D
    d3dParameters.BackBufferFormat = D3DFMT_X8R8G8B8;    // Sets the back buffer format to 32-bit
    d3dParameters.BackBufferWidth = SCREEN_WIDTH;        // Sets the width of the buffer
    d3dParameters.BackBufferHeight = SCREEN_HEIGHT;      // Sets the height of the buffer

    d3d->CreateDevice(D3DADAPTER_DEFAULT,                // Creates a device class
        D3DDEVTYPE_HAL,
        hWnd,
        D3DCREATE_SOFTWARE_VERTEXPROCESSING,
        &d3dParameters,
        &d3dDevice);

    D3DXCreateSprite(d3dDevice, &d3dSprite);
}

void render()
{
    d3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(10, 0, 32), 1.0f, 0);   // Clears the screen to a dark blue
    d3dDevice->BeginScene();                                                         // Begins Direct3D scene
    d3dSprite->Begin(D3DXSPRITE_ALPHABLEND);                                         // Begin sprite drawing

    background.draw();

    counter.draw();
    gameStations.draw();
    consoleCab.draw();
    clothesStand.draw();
    gamePanel.updateInformation(564.55, 800.56, 1034.54, "July");


    for (std::vector<Customer*>::iterator customerIT = customers.begin(); customerIT != customers.end(); customerIT++)
    {
        (*customerIT)->draw();
    }

    gamePanel.draw();

    d3dSprite->End();                                                                // End drawing
    d3dDevice->EndScene();                                                           // Ends the Direct3D scene
    d3dDevice->Present(NULL, NULL, NULL, NULL);                                      // Presents the Direct3D scene (Displays to screen)
}

void cleanUp()
{
    d3dDevice->Release();   // Closes the Direct3D device and releases memory
    d3d->Release();         // Closes Direct3D and releases memory
}

如果我没有正确解释某些事情或遗漏了什么,我会提前道歉。我因试图解释事情而臭名昭著!:/ 谁能帮我吗?开始认为我应该在这个项目中坚持使用 XNA 并稍后更深入地了解指针和向量......不过现在为时已晚:(

谢谢

4

1 回答 1

2

Vector 通过复制元素来存储元素。所以,当你这样做时,vector.push_back(Customer())你实际上做了以下事情:

  1. 创建新的客户对象。
  2. 将其复制到向量中。由于您不覆盖赋值运算符,所有成员都按值复制,包括 D3D 指针。
  3. 销毁原始客户对象。析构函数释放所有资源。

第 3 步是问题,因为现在 vector 有一个无效对象的副本:它的所有资源都被释放了。我敢打赌这是问题所在,但您的代码没有定义 Customer 的析构函数(或者您没有粘贴它)所以,我不确定。但无论如何,设计远非完美。

我可能建议的是存储指向客户的指针。如果我的理论是正确的,这将有助于运行这个特定的代码示例。

std::vector<Customer*> customers;
customers.push_back(new Customer());

当然,您必须处理分配的内存的释放。

顺便说一下,开始检查 D3D 调用结果。没有这个,任何调试都将是一场噩梦(而且已经是)。我的猜测是d3dSprite->Draw由于缺少纹理而失败,您可以从那里开始检查。

另一个问题在于loadGraphics方法。这段代码:

D3DXVECTOR3 position(100.0f, 100.0f, 0.0f);
D3DXVECTOR3 center(0.0f, 0.0f, 0.0f);

可能应该为对象字段设置初始值,但实际上在这里您构造了新的本地对象,这些对象在退出时被销毁。字段Customer::position/Customer::center实际上未初始化。然后,在Draw方法中使用这些未初始化的字段。尝试解决这个问题,希望这会有所帮助。

于 2013-02-07T19:02:14.497 回答