Создание небольшой 2D-игры с использованием Direct3D 9 и C ++. Я столкнулся с проблемой, которую не видел раньше. Игра основана на магазине, поэтому у меня есть класс покупателей. Я создал объект в игре, и он рендерится и ведет себя так, как я хочу на минуту. Я решил вместо этого поместить объект в Vector, потому что в какой-то момент мне понадобится их коллекция в любой момент. Однако моя проблема в том, что когда я помещаю объект в вектор, он больше не виден на экране!
Я не получаю ошибок. Я вывел все коды возврата из функций DirectX в тестовый файл, и ничего не вышло. Он работал нормально, его просто не видно на экране! Ничего не изменилось, кроме как поместить его в Вектор.
Я изменил Вектор на Вектор указателей, потому что мне сказали, что Вектор просто создает объект, копирует его и удаляет оригинал. Однако теперь может показаться, что мои указатели 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, ¢er, &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, ¢er, &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 для этого проекта и узнать немного позже об указателях и векторах … но уже слишком поздно 🙁
Спасибо
Вектор хранит элементы, копируя их. Итак, когда вы делаете vector.push_back(Customer())
вы на самом деле делаете следующее:
Шаг № 3 — проблема, потому что теперь у вектора есть копия недопустимого объекта: все его ресурсы были освобождены. Могу поспорить, что это проблема, но ваш код не определяет деструктор 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
метод вы используете эти неинициализированные поля. Попробуйте исправить это и надеюсь, что это поможет.
Других решений пока нет …