带有列表问题的 C++ 多态性
C++ Polymorphism with Lists issue
首先感谢您抽出宝贵的时间,对于这么长的时间我深表歉意post,但我找不到任何其他方法来缩短它,而且对我来说也是英语!有什么不明白的就问吧^^。希望你能找到错误,因为这让我发疯。
我目前正在学习 DirectX 11 并且我正在从该网站制作 This Little Game 但应用 OOP 和 DirectX 11 而不是 9 只是从该项目中获取某些东西。
好的,现在你已经了解了一些上下文,这就是问题所在。
我制作了一个名为 GameObject 的抽象 class,它封装了与渲染有关的所有功能,例如存储图像、动画、帧之间的过渡等。使用此 GameObject class定义将在我的游戏中交互的所有其他对象。
游戏对象Class
////////////////////////////////////////////////////////////////////////////////
// Filename: GameObject.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _GAME_OBJECT_H_
#define _GAME_OBJECT_H_
///////////////////////
// MY CLASS INCLUDES //
///////////////////////
#include "Sprite.h"
#include "InputHandler.h"
#include "Timer.h"
class GameObject
{
public:
GameObject();
GameObject(const GameObject& other);
~GameObject();
virtual bool Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen) = 0;
bool Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen, WCHAR* spriteFileName, Bitmap::DimensionType bitmap, Bitmap::DimensionType sprite, int numberOfFramesAcross, int initialFrame, bool useTimer);
virtual void Shutdown();
virtual bool Render(ID3D11DeviceContext* deviceContext, D3DXMATRIX wordMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix);
void Move();
void Move(const D3DXVECTOR2 vector);
virtual void Frame(const InputHandler::ControlsType& controls);
void SortFrameArray(const int* framesOrder, int size);
void SetPosition(const POINT& position);
const POINT GetPosition();
void SetVelocity(const D3DXVECTOR2& velocity);
const D3DXVECTOR2 GetVelocity();
void SetStatus(const bool status);
bool GetStatus();
float GetMovementDelayTime();
void ResetMovementDelayTime();
float GetAnimationDelayTime();
void ResetAnimationDelayTime();
//Both of this objects i think i'll remove them from this class. I don't think they belong here.
ID3D11Device* GetDevice();
HWND GetHWND();
Sprite* GetSprite();
protected:
ID3D11Device* m_device;
HWND m_hwnd;
Sprite* m_Sprite;
Timer* m_Timer;
POINT m_position;
D3DXVECTOR2 m_velocity;
bool m_active;
float m_movementDelay;
float m_animationDelay;
};
#endif
Cpp
////////////////////////////////////////////////////////////////////////////////
// Filename: GameObject.cpp
////////////////////////////////////////////////////////////////////////////////
#include "GameObject.h"
GameObject::GameObject()
{
this->m_Sprite = nullptr;
this->m_Timer = nullptr;
this->m_movementDelay = 0.0f;
this->m_animationDelay = 0.0f;
}
GameObject::GameObject(const GameObject& other)
{
}
GameObject::~GameObject()
{
}
bool GameObject::Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen, WCHAR* spriteFileName, Bitmap::DimensionType bitmap, Bitmap::DimensionType sprite, int numberOfFramesAcross, int initialFrame, bool useTimer)
{
bool result;
this->m_device = device;
this->m_hwnd = hwnd;
this->m_Sprite = new Sprite();
if (!this->m_Sprite)
{
return false;
}
result = this->m_Sprite->Initialize(device, hwnd, screen, spriteFileName, bitmap, sprite, numberOfFramesAcross, initialFrame);
if (!result)
{
return false;
}
if (useTimer)
{
this->m_Timer = new Timer();
if (!this->m_Timer)
{
return false;
}
result = this->m_Timer->Initialize();
if (!result)
{
return false;
}
}
return true;
}
void GameObject::Shutdown()
{
SAFE_SHUTDOWN(this->m_Sprite);
SAFE_DELETE(this->m_Timer);
}
bool GameObject::Render(ID3D11DeviceContext* deviceContext, D3DXMATRIX wordMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix)
{
return this->m_Sprite->Render(deviceContext, this->m_position, wordMatrix, viewMatrix, projectionMatrix);
}
void GameObject::Move()
{
this->m_position.x += this->m_velocity.x;
this->m_position.y += this->m_velocity.y;
}
void GameObject::Move(const D3DXVECTOR2 vector)
{
this->m_position.x += vector.x;
this->m_position.y += vector.y;
}
void GameObject::Frame(const InputHandler::ControlsType& controls)
{
if (this->m_Timer)
{
this->m_Timer->Frame();
this->m_movementDelay += this->m_Timer->GetTime();
this->m_animationDelay += this->m_Timer->GetTime();
}
}
void GameObject::SortFrameArray(const int* framesOrder, int size)
{
this->m_Sprite->SortFrameArray(framesOrder, size);
}
void GameObject::SetPosition(const POINT& position)
{
this->m_position = position;
}
const POINT GameObject::GetPosition()
{
return this->m_position;
}
void GameObject::SetVelocity(const D3DXVECTOR2& velocity)
{
this->m_velocity = velocity;
}
const D3DXVECTOR2 GameObject::GetVelocity()
{
return this->m_velocity;
}
void GameObject::SetStatus(const bool status)
{
this->m_active = status;
}
bool GameObject::GetStatus()
{
return this->m_active;
}
Sprite* GameObject::GetSprite()
{
return this->m_Sprite;
}
float GameObject::GetAnimationDelayTime()
{
return this->m_animationDelay;
}
void GameObject::ResetMovementDelayTime()
{
this->m_movementDelay = 0.0f;
}
float GameObject::GetMovementDelayTime()
{
return this->m_animationDelay;
}
void GameObject::ResetAnimationDelayTime()
{
this->m_animationDelay = 0.0f;
}
ID3D11Device* GameObject::GetDevice()
{
return this->m_device;
}
HWND GameObject::GetHWND()
{
return this->m_hwnd;
}
然后我制作了派生的 class Fighter 代表我的宇宙飞船并且有一个我认为与问题无关的 FighterFlame,以及指向 Bullet 指针的指针列表(m_Bullets) 这将是从飞船中射出的子弹。
////////////////////////////////////////////////////////////////////////////////
// Filename: Fighter.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _FIGHTER_H_
#define _FIGHTER_H_
//////////////
// INCLUDES //
//////////////
#include <list>
///////////////////////
// MY CLASS INCLUDES //
///////////////////////
#include "GameObject.h"
#include "Bullet.h"
#include "FighterFlame.h"
class Fighter : public GameObject
{
public:
Fighter();
Fighter(const Fighter& other);
~Fighter();
virtual bool Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen) override;
virtual void Shutdown();
virtual bool Render(ID3D11DeviceContext* deviceContext, D3DXMATRIX wordMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix) override;
virtual void Frame(const InputHandler::ControlsType& controls) override;
private:
void GenerateTriBullet();
void ValidateBulletsBounds();
private:
int m_life;
int m_lives;
FighterFlame* m_FighterFlame;
std::list<Bullet**> m_Bullets;
const int SHIP_SPEED = 3;
const float MOVEMENT_DELAY = 16.0f;
const float ANIMATION_DELAY = 20.0f;
const float SHOOT_DELAY = 30.0f;
};
#endif
Cpp
////////////////////////////////////////////////////////////////////////////////
// Filename: Fighter.cpp
////////////////////////////////////////////////////////////////////////////////
#include "Fighter.h"
Fighter::Fighter() : GameObject()
{
this->m_life = 100;
this->m_lives = 3;
this->m_FighterFlame = nullptr;
}
Fighter::Fighter(const Fighter& other)
{
}
Fighter::~Fighter()
{
}
bool Fighter::Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen)
{
bool result;
this->m_life = 100;
this->m_lives = 3;
result = GameObject::Initialize(device, hwnd, screen, L"Fighter.dds", Bitmap::DimensionType{ 1152, 216 }, Bitmap::DimensionType{ 144, 108 }, 8, 7, true);
if (!result)
{
MessageBox(hwnd, L"Could not initialize Fighter", L"Error", MB_OK);
return false;
}
this->m_position = POINT{ 0, 0 };
int order[16] = { 7, 6, 5, 4, 3, 2, 1, 0, 8, 9, 10, 11, 12, 13, 14, 15 };
GameObject::SortFrameArray(order, 16);
this->m_FighterFlame = new FighterFlame();
if (!this->m_FighterFlame)
{
return false;
}
result = this->m_FighterFlame->Initialize(device, hwnd, screen);
if (!result)
{
MessageBox(hwnd, L"Could not initialize FighterFlame", L"Error", MB_OK);
return false;
}
return true;
}
bool Fighter::Render(ID3D11DeviceContext* deviceContext, D3DXMATRIX wordMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix)
{
bool result;
result = GameObject::Render(deviceContext, wordMatrix, viewMatrix, projectionMatrix);
if (!result)
{
return false;
}
result = this->m_FighterFlame->Render(deviceContext, wordMatrix, viewMatrix, projectionMatrix);
if (!result)
{
return false;
}
for (Bullet** bullet : this->m_Bullets)
{
if (bullet)
{
result = (*bullet)->Render(deviceContext, wordMatrix, viewMatrix, projectionMatrix);
if (!result)
{
return false;
}
}
}
return true;
}
void Fighter::Shutdown()
{
GameObject::Shutdown();
SAFE_SHUTDOWN(this->m_FighterFlame);
for (Bullet** bullet : this->m_Bullets)
{
SAFE_SHUTDOWN(*bullet);
}
this->m_Bullets.clear();
}
void Fighter::Frame(const InputHandler::ControlsType& controls)
{
GameObject::Frame(controls);
this->m_FighterFlame->SetPosition(POINT{ this->m_position.x - 26, this->m_position.y + 47});
this->m_FighterFlame->Frame(controls);
for (Bullet** bullet : this->m_Bullets)
{
(*bullet)->Frame(controls);
}
if (GameObject::GetMovementDelayTime() > MOVEMENT_DELAY)
{
if (controls.up ^ controls.down)
{
if (controls.up)
{
if (GameObject::GetPosition().y > 0)
{
GameObject::Move(D3DXVECTOR2(0, -SHIP_SPEED));
}
if (GameObject::GetAnimationDelayTime() > ANIMATION_DELAY)
{
GameObject::GetSprite()->IncrementFrame();
GameObject::ResetAnimationDelayTime();
}
}
else if (controls.down)
{
if (GameObject::GetPosition().y < (GameObject::GetSprite()->GetBitmap()->GetScreenDimensions().height - GameObject::GetSprite()->GetBitmap()->GetBitmapDimensions().height))
{
GameObject::Move(D3DXVECTOR2(0, SHIP_SPEED));
}
if (GameObject::GetAnimationDelayTime() > ANIMATION_DELAY)
{
GameObject::GetSprite()->DecrementFrame();
GameObject::ResetAnimationDelayTime();
}
}
}
else
{
if (GameObject::GetSprite()->GetCurrentFrame() > (GameObject::GetSprite()->GetAmountOfFrames() / 2))
{
if (GameObject::GetAnimationDelayTime() > ANIMATION_DELAY)
{
GameObject::GetSprite()->DecrementFrame();
GameObject::ResetAnimationDelayTime();
}
}
if (GameObject::GetSprite()->GetCurrentFrame() < (GameObject::GetSprite()->GetAmountOfFrames() / 2))
{
if (GameObject::GetAnimationDelayTime() > ANIMATION_DELAY)
{
GameObject::GetSprite()->IncrementFrame();
GameObject::ResetAnimationDelayTime();
}
}
}
if (controls.right ^ controls.left)
{
if (controls.right)
{
if (GameObject::GetPosition().x < (GameObject::GetSprite()->GetBitmap()->GetScreenDimensions().width - GameObject::GetSprite()->GetBitmap()->GetBitmapDimensions().width))
{
GameObject::Move(D3DXVECTOR2(SHIP_SPEED, 0));
}
}
else if (controls.left)
{
if (GameObject::GetPosition().x > 0)
{
GameObject::Move(D3DXVECTOR2(-SHIP_SPEED, 0));
}
}
}
GameObject::ResetMovementDelayTime();
}
if (controls.spaceBar)
{
Fighter::GenerateTriBullet();
}
Fighter::ValidateBulletsBounds();
}
void Fighter::GenerateTriBullet()
{
Bullet* upBullet = new Bullet();
upBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
upBullet->SetVelocity(D3DXVECTOR2(20, 2));
upBullet->SetPosition(GameObject::GetPosition());
upBullet->Move();
this->m_Bullets.push_back(&upBullet);
Bullet* middleBullet = new Bullet();
middleBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
middleBullet->SetVelocity(D3DXVECTOR2(20, 0));
middleBullet->SetPosition(GameObject::GetPosition());
middleBullet->Move();
this->m_Bullets.push_back(&middleBullet);
Bullet* downBullet = new Bullet();
downBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
downBullet->SetVelocity(D3DXVECTOR2(20, -2));
downBullet->SetPosition(GameObject::GetPosition());
downBullet->Move();
this->m_Bullets.push_back(&downBullet);
}
void Fighter::ValidateBulletsBounds()
{
for (std::list<Bullet**>::iterator it = this->m_Bullets.begin(); it != this->m_Bullets.end(); it++)
{
if ((*(*(&(it)._Ptr->_Myval)))->GetPosition().x > GameObject::GetSprite()->GetBitmap()->GetScreenDimensions().width)
{
SAFE_SHUTDOWN(**it);
this->m_Bullets.erase(it);
}
}
}
最后是有问题的子弹 class,它也派生自 GameObject,代表 space飞船可以发射的子弹。
////////////////////////////////////////////////////////////////////////////////
// Filename: Bullet.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _BULLET_H_
#define _BULLET_H_
///////////////////////
// MY CLASS INCLUDES //
///////////////////////
#include "GameObject.h"
class Bullet : public GameObject
{
public:
Bullet();
Bullet(const Bullet& other);
~Bullet();
virtual bool Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen) override;
virtual void Frame(const InputHandler::ControlsType& controls) override;
private:
const float MOVEMENT_DELAY = 16.0f;
};
#endif
Cpp
////////////////////////////////////////////////////////////////////////////////
// Filename: Bullet.cpp
////////////////////////////////////////////////////////////////////////////////
#include "Bullet.h"
Bullet::Bullet() : GameObject()
{
}
Bullet::Bullet(const Bullet& other)
{
}
Bullet::~Bullet()
{
}
bool Bullet::Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen)
{
bool result;
result = GameObject::Initialize(device, hwnd, screen, L"Bullet.dds", Bitmap::DimensionType{ 18, 3 }, Bitmap::DimensionType{ 18, 3 }, 1, 0, true);
if (!result)
{
return false;
}
return true;
}
void Bullet::Frame(const InputHandler::ControlsType& controls)
{
GameObject::Frame(controls);
if (GameObject::GetMovementDelayTime() > MOVEMENT_DELAY)
{
GameObject::Move();
}
}
还有问题:
当 Gameloop 处于 运行ning 并且我按下 space 栏时,会发生这种情况
// this if is from Fighter::Frame
if (controls.spaceBar)
{
Fighter::GenerateTriBullet();
}
Fighter::ValidateBulletsBounds();
进入GenerateTriBullet方法,在m_Bullets列表中存储3颗子弹
void Fighter::GenerateTriBullet()
{
Bullet* upBullet = new Bullet();
upBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
upBullet->SetVelocity(D3DXVECTOR2(20, 2));
upBullet->SetPosition(GameObject::GetPosition());
upBullet->Move();
this->m_Bullets.push_back(&upBullet);
Bullet* middleBullet = new Bullet();
middleBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
middleBullet->SetVelocity(D3DXVECTOR2(20, 0));
middleBullet->SetPosition(GameObject::GetPosition());
middleBullet->Move();
this->m_Bullets.push_back(&middleBullet);
Bullet* downBullet = new Bullet();
downBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
downBullet->SetVelocity(D3DXVECTOR2(20, -2));
downBullet->SetPosition(GameObject::GetPosition());
downBullet->Move();
this->m_Bullets.push_back(&downBullet);
}
当它离开方法时,我检查了列表,项目符号仍然存在,就像在进入 ValidateBulletsBound 之前一样,但是一旦它进入方法并且在执行之前ANYTHING,列表中的项目符号完全消失了,我的意思是,m_Bullets 列表仍然有三个对象,但是碰巧它们都是NULL。
为了更好地解释我自己,我想做的是每次我按下 space-bar 3 颗子弹出现在屏幕上,我试图通过询问是否 space-bar值为true,在m_Bullet列表中添加3个Bullets,然后验证列表中的bullets还在屏幕之间space , 否则删除它。
But as you can see, i successfully store the bullets on the list and as soon as i enter to validate, they are gone... poof!
我不知道为什么会发生这种情况,它们是 class 的不同实例,它们之间不共享任何东西(从内存方面来说),没有共享静态方法或指针到那时,即使他们愿意,考虑到他们只是进入另一种方法并且在 "entering the another method" 部分的中间或其他任何地方都没有进行任何操作,所以这应该不是问题。它们甚至处于相同的 class、相同的上下文中,没有复杂的操作或泄漏(据我所知)。真不知道怎么回事!
我想在结束时承认存在一些严重的设计问题,例如 GenerateTriBullet 上的问题,以及我没有使用矩阵来移动对象这一事实。我只是想先完成它(这是我在 DirectX 上制作的第一款游戏,顺便说一句真的退出了!!!),然后当我能看到大局时,开始把所有东西都放在它所属的地方。另外,我如何从列表迭代器中获取值,我读到它是 (*it) 用于简单值,但我有一个指向指针的指针,所以我认为它会是 **it,但它总是解析为nullptr.
我真的希望你能帮助我。
这是项目,如果你觉得你不明白并且想更进一步。你只需要运行这个项目,就会出现一个小黑window的飞船,在Fighterclass的第182行打个断点然后按spacebar游戏 window,然后从那里查看 m_Bullets 在离开 GenerateTriBullet 并进入 ValidateBulletsBounds.[=21 时会发生什么=]
THANK YOU!
一个明确的问题:
m_Bullets
是一个 list<Bullet**>
。当您添加到它时,您正在添加局部变量的地址,例如
Bullet* upBullet = new Bullet();
...
this->m_Bullets.push_back(&upBullet);
使用此方法 returns,从 &upBullet
表达式存储的地址不再有效,因为该变量不再存在。
我想你的意思是将 m_Bullets
设为 list<Bullet*>
,然后添加:
Bullet* upBullet = new Bullet();
...
this->m_Bullets.push_back(upBullet);
我认为最好的解决方案是让 list
处理内存管理,只将 m_Bullets
作为 list<Bullet>
,然后:
this->m_Bullets.emplace_back();
然而,这可能需要重新考虑一些多态性。
首先感谢您抽出宝贵的时间,对于这么长的时间我深表歉意post,但我找不到任何其他方法来缩短它,而且对我来说也是英语!有什么不明白的就问吧^^。希望你能找到错误,因为这让我发疯。
我目前正在学习 DirectX 11 并且我正在从该网站制作 This Little Game 但应用 OOP 和 DirectX 11 而不是 9 只是从该项目中获取某些东西。
好的,现在你已经了解了一些上下文,这就是问题所在。
我制作了一个名为 GameObject 的抽象 class,它封装了与渲染有关的所有功能,例如存储图像、动画、帧之间的过渡等。使用此 GameObject class定义将在我的游戏中交互的所有其他对象。
游戏对象Class
////////////////////////////////////////////////////////////////////////////////
// Filename: GameObject.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _GAME_OBJECT_H_
#define _GAME_OBJECT_H_
///////////////////////
// MY CLASS INCLUDES //
///////////////////////
#include "Sprite.h"
#include "InputHandler.h"
#include "Timer.h"
class GameObject
{
public:
GameObject();
GameObject(const GameObject& other);
~GameObject();
virtual bool Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen) = 0;
bool Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen, WCHAR* spriteFileName, Bitmap::DimensionType bitmap, Bitmap::DimensionType sprite, int numberOfFramesAcross, int initialFrame, bool useTimer);
virtual void Shutdown();
virtual bool Render(ID3D11DeviceContext* deviceContext, D3DXMATRIX wordMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix);
void Move();
void Move(const D3DXVECTOR2 vector);
virtual void Frame(const InputHandler::ControlsType& controls);
void SortFrameArray(const int* framesOrder, int size);
void SetPosition(const POINT& position);
const POINT GetPosition();
void SetVelocity(const D3DXVECTOR2& velocity);
const D3DXVECTOR2 GetVelocity();
void SetStatus(const bool status);
bool GetStatus();
float GetMovementDelayTime();
void ResetMovementDelayTime();
float GetAnimationDelayTime();
void ResetAnimationDelayTime();
//Both of this objects i think i'll remove them from this class. I don't think they belong here.
ID3D11Device* GetDevice();
HWND GetHWND();
Sprite* GetSprite();
protected:
ID3D11Device* m_device;
HWND m_hwnd;
Sprite* m_Sprite;
Timer* m_Timer;
POINT m_position;
D3DXVECTOR2 m_velocity;
bool m_active;
float m_movementDelay;
float m_animationDelay;
};
#endif
Cpp
////////////////////////////////////////////////////////////////////////////////
// Filename: GameObject.cpp
////////////////////////////////////////////////////////////////////////////////
#include "GameObject.h"
GameObject::GameObject()
{
this->m_Sprite = nullptr;
this->m_Timer = nullptr;
this->m_movementDelay = 0.0f;
this->m_animationDelay = 0.0f;
}
GameObject::GameObject(const GameObject& other)
{
}
GameObject::~GameObject()
{
}
bool GameObject::Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen, WCHAR* spriteFileName, Bitmap::DimensionType bitmap, Bitmap::DimensionType sprite, int numberOfFramesAcross, int initialFrame, bool useTimer)
{
bool result;
this->m_device = device;
this->m_hwnd = hwnd;
this->m_Sprite = new Sprite();
if (!this->m_Sprite)
{
return false;
}
result = this->m_Sprite->Initialize(device, hwnd, screen, spriteFileName, bitmap, sprite, numberOfFramesAcross, initialFrame);
if (!result)
{
return false;
}
if (useTimer)
{
this->m_Timer = new Timer();
if (!this->m_Timer)
{
return false;
}
result = this->m_Timer->Initialize();
if (!result)
{
return false;
}
}
return true;
}
void GameObject::Shutdown()
{
SAFE_SHUTDOWN(this->m_Sprite);
SAFE_DELETE(this->m_Timer);
}
bool GameObject::Render(ID3D11DeviceContext* deviceContext, D3DXMATRIX wordMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix)
{
return this->m_Sprite->Render(deviceContext, this->m_position, wordMatrix, viewMatrix, projectionMatrix);
}
void GameObject::Move()
{
this->m_position.x += this->m_velocity.x;
this->m_position.y += this->m_velocity.y;
}
void GameObject::Move(const D3DXVECTOR2 vector)
{
this->m_position.x += vector.x;
this->m_position.y += vector.y;
}
void GameObject::Frame(const InputHandler::ControlsType& controls)
{
if (this->m_Timer)
{
this->m_Timer->Frame();
this->m_movementDelay += this->m_Timer->GetTime();
this->m_animationDelay += this->m_Timer->GetTime();
}
}
void GameObject::SortFrameArray(const int* framesOrder, int size)
{
this->m_Sprite->SortFrameArray(framesOrder, size);
}
void GameObject::SetPosition(const POINT& position)
{
this->m_position = position;
}
const POINT GameObject::GetPosition()
{
return this->m_position;
}
void GameObject::SetVelocity(const D3DXVECTOR2& velocity)
{
this->m_velocity = velocity;
}
const D3DXVECTOR2 GameObject::GetVelocity()
{
return this->m_velocity;
}
void GameObject::SetStatus(const bool status)
{
this->m_active = status;
}
bool GameObject::GetStatus()
{
return this->m_active;
}
Sprite* GameObject::GetSprite()
{
return this->m_Sprite;
}
float GameObject::GetAnimationDelayTime()
{
return this->m_animationDelay;
}
void GameObject::ResetMovementDelayTime()
{
this->m_movementDelay = 0.0f;
}
float GameObject::GetMovementDelayTime()
{
return this->m_animationDelay;
}
void GameObject::ResetAnimationDelayTime()
{
this->m_animationDelay = 0.0f;
}
ID3D11Device* GameObject::GetDevice()
{
return this->m_device;
}
HWND GameObject::GetHWND()
{
return this->m_hwnd;
}
然后我制作了派生的 class Fighter 代表我的宇宙飞船并且有一个我认为与问题无关的 FighterFlame,以及指向 Bullet 指针的指针列表(m_Bullets) 这将是从飞船中射出的子弹。
////////////////////////////////////////////////////////////////////////////////
// Filename: Fighter.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _FIGHTER_H_
#define _FIGHTER_H_
//////////////
// INCLUDES //
//////////////
#include <list>
///////////////////////
// MY CLASS INCLUDES //
///////////////////////
#include "GameObject.h"
#include "Bullet.h"
#include "FighterFlame.h"
class Fighter : public GameObject
{
public:
Fighter();
Fighter(const Fighter& other);
~Fighter();
virtual bool Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen) override;
virtual void Shutdown();
virtual bool Render(ID3D11DeviceContext* deviceContext, D3DXMATRIX wordMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix) override;
virtual void Frame(const InputHandler::ControlsType& controls) override;
private:
void GenerateTriBullet();
void ValidateBulletsBounds();
private:
int m_life;
int m_lives;
FighterFlame* m_FighterFlame;
std::list<Bullet**> m_Bullets;
const int SHIP_SPEED = 3;
const float MOVEMENT_DELAY = 16.0f;
const float ANIMATION_DELAY = 20.0f;
const float SHOOT_DELAY = 30.0f;
};
#endif
Cpp
////////////////////////////////////////////////////////////////////////////////
// Filename: Fighter.cpp
////////////////////////////////////////////////////////////////////////////////
#include "Fighter.h"
Fighter::Fighter() : GameObject()
{
this->m_life = 100;
this->m_lives = 3;
this->m_FighterFlame = nullptr;
}
Fighter::Fighter(const Fighter& other)
{
}
Fighter::~Fighter()
{
}
bool Fighter::Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen)
{
bool result;
this->m_life = 100;
this->m_lives = 3;
result = GameObject::Initialize(device, hwnd, screen, L"Fighter.dds", Bitmap::DimensionType{ 1152, 216 }, Bitmap::DimensionType{ 144, 108 }, 8, 7, true);
if (!result)
{
MessageBox(hwnd, L"Could not initialize Fighter", L"Error", MB_OK);
return false;
}
this->m_position = POINT{ 0, 0 };
int order[16] = { 7, 6, 5, 4, 3, 2, 1, 0, 8, 9, 10, 11, 12, 13, 14, 15 };
GameObject::SortFrameArray(order, 16);
this->m_FighterFlame = new FighterFlame();
if (!this->m_FighterFlame)
{
return false;
}
result = this->m_FighterFlame->Initialize(device, hwnd, screen);
if (!result)
{
MessageBox(hwnd, L"Could not initialize FighterFlame", L"Error", MB_OK);
return false;
}
return true;
}
bool Fighter::Render(ID3D11DeviceContext* deviceContext, D3DXMATRIX wordMatrix, D3DXMATRIX viewMatrix, D3DXMATRIX projectionMatrix)
{
bool result;
result = GameObject::Render(deviceContext, wordMatrix, viewMatrix, projectionMatrix);
if (!result)
{
return false;
}
result = this->m_FighterFlame->Render(deviceContext, wordMatrix, viewMatrix, projectionMatrix);
if (!result)
{
return false;
}
for (Bullet** bullet : this->m_Bullets)
{
if (bullet)
{
result = (*bullet)->Render(deviceContext, wordMatrix, viewMatrix, projectionMatrix);
if (!result)
{
return false;
}
}
}
return true;
}
void Fighter::Shutdown()
{
GameObject::Shutdown();
SAFE_SHUTDOWN(this->m_FighterFlame);
for (Bullet** bullet : this->m_Bullets)
{
SAFE_SHUTDOWN(*bullet);
}
this->m_Bullets.clear();
}
void Fighter::Frame(const InputHandler::ControlsType& controls)
{
GameObject::Frame(controls);
this->m_FighterFlame->SetPosition(POINT{ this->m_position.x - 26, this->m_position.y + 47});
this->m_FighterFlame->Frame(controls);
for (Bullet** bullet : this->m_Bullets)
{
(*bullet)->Frame(controls);
}
if (GameObject::GetMovementDelayTime() > MOVEMENT_DELAY)
{
if (controls.up ^ controls.down)
{
if (controls.up)
{
if (GameObject::GetPosition().y > 0)
{
GameObject::Move(D3DXVECTOR2(0, -SHIP_SPEED));
}
if (GameObject::GetAnimationDelayTime() > ANIMATION_DELAY)
{
GameObject::GetSprite()->IncrementFrame();
GameObject::ResetAnimationDelayTime();
}
}
else if (controls.down)
{
if (GameObject::GetPosition().y < (GameObject::GetSprite()->GetBitmap()->GetScreenDimensions().height - GameObject::GetSprite()->GetBitmap()->GetBitmapDimensions().height))
{
GameObject::Move(D3DXVECTOR2(0, SHIP_SPEED));
}
if (GameObject::GetAnimationDelayTime() > ANIMATION_DELAY)
{
GameObject::GetSprite()->DecrementFrame();
GameObject::ResetAnimationDelayTime();
}
}
}
else
{
if (GameObject::GetSprite()->GetCurrentFrame() > (GameObject::GetSprite()->GetAmountOfFrames() / 2))
{
if (GameObject::GetAnimationDelayTime() > ANIMATION_DELAY)
{
GameObject::GetSprite()->DecrementFrame();
GameObject::ResetAnimationDelayTime();
}
}
if (GameObject::GetSprite()->GetCurrentFrame() < (GameObject::GetSprite()->GetAmountOfFrames() / 2))
{
if (GameObject::GetAnimationDelayTime() > ANIMATION_DELAY)
{
GameObject::GetSprite()->IncrementFrame();
GameObject::ResetAnimationDelayTime();
}
}
}
if (controls.right ^ controls.left)
{
if (controls.right)
{
if (GameObject::GetPosition().x < (GameObject::GetSprite()->GetBitmap()->GetScreenDimensions().width - GameObject::GetSprite()->GetBitmap()->GetBitmapDimensions().width))
{
GameObject::Move(D3DXVECTOR2(SHIP_SPEED, 0));
}
}
else if (controls.left)
{
if (GameObject::GetPosition().x > 0)
{
GameObject::Move(D3DXVECTOR2(-SHIP_SPEED, 0));
}
}
}
GameObject::ResetMovementDelayTime();
}
if (controls.spaceBar)
{
Fighter::GenerateTriBullet();
}
Fighter::ValidateBulletsBounds();
}
void Fighter::GenerateTriBullet()
{
Bullet* upBullet = new Bullet();
upBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
upBullet->SetVelocity(D3DXVECTOR2(20, 2));
upBullet->SetPosition(GameObject::GetPosition());
upBullet->Move();
this->m_Bullets.push_back(&upBullet);
Bullet* middleBullet = new Bullet();
middleBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
middleBullet->SetVelocity(D3DXVECTOR2(20, 0));
middleBullet->SetPosition(GameObject::GetPosition());
middleBullet->Move();
this->m_Bullets.push_back(&middleBullet);
Bullet* downBullet = new Bullet();
downBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
downBullet->SetVelocity(D3DXVECTOR2(20, -2));
downBullet->SetPosition(GameObject::GetPosition());
downBullet->Move();
this->m_Bullets.push_back(&downBullet);
}
void Fighter::ValidateBulletsBounds()
{
for (std::list<Bullet**>::iterator it = this->m_Bullets.begin(); it != this->m_Bullets.end(); it++)
{
if ((*(*(&(it)._Ptr->_Myval)))->GetPosition().x > GameObject::GetSprite()->GetBitmap()->GetScreenDimensions().width)
{
SAFE_SHUTDOWN(**it);
this->m_Bullets.erase(it);
}
}
}
最后是有问题的子弹 class,它也派生自 GameObject,代表 space飞船可以发射的子弹。
////////////////////////////////////////////////////////////////////////////////
// Filename: Bullet.h
////////////////////////////////////////////////////////////////////////////////
#ifndef _BULLET_H_
#define _BULLET_H_
///////////////////////
// MY CLASS INCLUDES //
///////////////////////
#include "GameObject.h"
class Bullet : public GameObject
{
public:
Bullet();
Bullet(const Bullet& other);
~Bullet();
virtual bool Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen) override;
virtual void Frame(const InputHandler::ControlsType& controls) override;
private:
const float MOVEMENT_DELAY = 16.0f;
};
#endif
Cpp
////////////////////////////////////////////////////////////////////////////////
// Filename: Bullet.cpp
////////////////////////////////////////////////////////////////////////////////
#include "Bullet.h"
Bullet::Bullet() : GameObject()
{
}
Bullet::Bullet(const Bullet& other)
{
}
Bullet::~Bullet()
{
}
bool Bullet::Initialize(ID3D11Device* device, HWND hwnd, Bitmap::DimensionType screen)
{
bool result;
result = GameObject::Initialize(device, hwnd, screen, L"Bullet.dds", Bitmap::DimensionType{ 18, 3 }, Bitmap::DimensionType{ 18, 3 }, 1, 0, true);
if (!result)
{
return false;
}
return true;
}
void Bullet::Frame(const InputHandler::ControlsType& controls)
{
GameObject::Frame(controls);
if (GameObject::GetMovementDelayTime() > MOVEMENT_DELAY)
{
GameObject::Move();
}
}
还有问题:
当 Gameloop 处于 运行ning 并且我按下 space 栏时,会发生这种情况
// this if is from Fighter::Frame
if (controls.spaceBar)
{
Fighter::GenerateTriBullet();
}
Fighter::ValidateBulletsBounds();
进入GenerateTriBullet方法,在m_Bullets列表中存储3颗子弹
void Fighter::GenerateTriBullet()
{
Bullet* upBullet = new Bullet();
upBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
upBullet->SetVelocity(D3DXVECTOR2(20, 2));
upBullet->SetPosition(GameObject::GetPosition());
upBullet->Move();
this->m_Bullets.push_back(&upBullet);
Bullet* middleBullet = new Bullet();
middleBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
middleBullet->SetVelocity(D3DXVECTOR2(20, 0));
middleBullet->SetPosition(GameObject::GetPosition());
middleBullet->Move();
this->m_Bullets.push_back(&middleBullet);
Bullet* downBullet = new Bullet();
downBullet->Initialize(this->m_FighterFlame->GetDevice(), this->m_FighterFlame->GetHWND(), this->m_FighterFlame->GetSprite()->GetBitmap()->GetScreenDimensions());
downBullet->SetVelocity(D3DXVECTOR2(20, -2));
downBullet->SetPosition(GameObject::GetPosition());
downBullet->Move();
this->m_Bullets.push_back(&downBullet);
}
当它离开方法时,我检查了列表,项目符号仍然存在,就像在进入 ValidateBulletsBound 之前一样,但是一旦它进入方法并且在执行之前ANYTHING,列表中的项目符号完全消失了,我的意思是,m_Bullets 列表仍然有三个对象,但是碰巧它们都是NULL。
为了更好地解释我自己,我想做的是每次我按下 space-bar 3 颗子弹出现在屏幕上,我试图通过询问是否 space-bar值为true,在m_Bullet列表中添加3个Bullets,然后验证列表中的bullets还在屏幕之间space , 否则删除它。 But as you can see, i successfully store the bullets on the list and as soon as i enter to validate, they are gone... poof!
我不知道为什么会发生这种情况,它们是 class 的不同实例,它们之间不共享任何东西(从内存方面来说),没有共享静态方法或指针到那时,即使他们愿意,考虑到他们只是进入另一种方法并且在 "entering the another method" 部分的中间或其他任何地方都没有进行任何操作,所以这应该不是问题。它们甚至处于相同的 class、相同的上下文中,没有复杂的操作或泄漏(据我所知)。真不知道怎么回事!
我想在结束时承认存在一些严重的设计问题,例如 GenerateTriBullet 上的问题,以及我没有使用矩阵来移动对象这一事实。我只是想先完成它(这是我在 DirectX 上制作的第一款游戏,顺便说一句真的退出了!!!),然后当我能看到大局时,开始把所有东西都放在它所属的地方。另外,我如何从列表迭代器中获取值,我读到它是 (*it) 用于简单值,但我有一个指向指针的指针,所以我认为它会是 **it,但它总是解析为nullptr.
我真的希望你能帮助我。 这是项目,如果你觉得你不明白并且想更进一步。你只需要运行这个项目,就会出现一个小黑window的飞船,在Fighterclass的第182行打个断点然后按spacebar游戏 window,然后从那里查看 m_Bullets 在离开 GenerateTriBullet 并进入 ValidateBulletsBounds.[=21 时会发生什么=]
THANK YOU!
一个明确的问题:
m_Bullets
是一个 list<Bullet**>
。当您添加到它时,您正在添加局部变量的地址,例如
Bullet* upBullet = new Bullet();
...
this->m_Bullets.push_back(&upBullet);
使用此方法 returns,从 &upBullet
表达式存储的地址不再有效,因为该变量不再存在。
我想你的意思是将 m_Bullets
设为 list<Bullet*>
,然后添加:
Bullet* upBullet = new Bullet();
...
this->m_Bullets.push_back(upBullet);
我认为最好的解决方案是让 list
处理内存管理,只将 m_Bullets
作为 list<Bullet>
,然后:
this->m_Bullets.emplace_back();
然而,这可能需要重新考虑一些多态性。