C++DirectX11:使用DirectX工具包时出现NullPtr错误

C++ DirectX11: NullPtr error using DirectX tool kit

本文关键字:NullPtr 错误 工具包 使用 DirectX C++DirectX11      更新时间:2023-10-16

我正试图为我的游戏实现一个字体类,但在运行时一直出现以下错误

引发异常:写入访问冲突。这是nullptr。

在Font.cpp 中的init函数中

void Font::Init(ID3D11Device* device, ID3D11DeviceContext* deviceContext)
{
    if (device != NULL && deviceContext != NULL)
    {
        m_spriteBatch = new SpriteBatch(deviceContext);//<----This line
        m_spriteFont = new SpriteFont(device, L"Fonts/Arial.spritefont");
    }
}

这是我的Font.h

#ifndef FONT_H
#define FONT_H

#include <d3d11.h>
#include <directxmath.h>
#include <fstream>
#include "SpriteBatch.h"
#include "SpriteFont.h"
using namespace std;
using namespace DirectX;
class Font
{
public:
    Font();
    ~Font();
    void Init(ID3D11Device* device, ID3D11DeviceContext* deviceContext);
    void Render();
private:
    SpriteFont* m_spriteFont;
    SpriteBatch* m_spriteBatch;
};
#endif

这是我的Font.cpp

#include "Font.h"
#include "SimpleMath.h"
Font::Font()
{
    m_spriteFont = NULL;
    m_spriteBatch = NULL;
}

Font::~Font()
{
    if (m_spriteFont)
    {
        delete m_spriteFont;
        m_spriteFont = NULL;
    }
    if (m_spriteBatch)
    {
        delete m_spriteBatch;
        m_spriteBatch = NULL;
    }
}
void Font::Init(ID3D11Device* device, ID3D11DeviceContext* deviceContext)
{
    if (device != NULL && deviceContext != NULL)
    {
        m_spriteBatch = new SpriteBatch(deviceContext);
        m_spriteFont = new SpriteFont(device, L"Fonts/Arial.spritefont");
    }
}
void Font::Render()
{
    m_spriteBatch->Begin();
    m_spriteFont->DrawString(m_spriteBatch, L"TEST", SimpleMath::Vector2(300, 300));
    m_spriteBatch->End();
}

这是我的GameScene.cpp

#include "GameScene.h"
#include "TextureShader.h"

GameScene::GameScene(void)
{
    prevtime = 0;
    collision = false;
    Sprite_Box_Height = 0;
    Sprite_Box_Width = 0;
}

GameScene::~GameScene(void)
{
    if(m_player)
    {
        delete m_player;
    }
    if (m_enemy)
    {
        delete m_enemy;
    }
    if (m_ball)
    {
        delete m_ball;
    }
    if (m_timer)
    {
        delete m_timer;
    }
}
bool GameScene::Initialize()
{
    TextureShader* shader = (TextureShader*)ResourceManager::GetInstance()->GetShaderByName("texture.fx");
    if(shader == NULL)
    {
        return false;
    }
    //create objects for all entities and initialize them
    m_ball = new Ball();
    m_ball->Initialize(Engine::GetEngine()->GetGraphics()->GetDevice(), Engine::GetEngine()->GetGraphics()->GetDeviceContext(), shader);
    m_player = new Player();
    m_player->Initialize(Engine::GetEngine()->GetGraphics()->GetDevice(), Engine::GetEngine()->GetGraphics()->GetDeviceContext(), shader);
    m_enemy = new Enemy();
    m_enemy->Initialize(Engine::GetEngine()->GetGraphics()->GetDevice(), Engine::GetEngine()->GetGraphics()->GetDeviceContext(), shader);
    m_font->Init(Engine::GetEngine()->GetGraphics()->GetDevice(), Engine::GetEngine()->GetGraphics()->GetDeviceContext());
    return true;
}
void GameScene::Update()
{
    //Updade all Entities collision
    m_player->Update();
    m_enemy->Update();
    m_ball->Update();
    Collision();
}
void GameScene::Render(ID3D11DeviceContext* deviceContext, XMFLOAT4X4 viewMatrix, XMFLOAT4X4 projectionMatrix)
{
    m_font->Render();
}
void GameScene::Collision()
{
    //Get the current position of the ball and the player
    BallPos = m_ball->GetBallPosition();
    PlayerPos = m_player->GetPlayerPosition();
    EnemyPos = m_enemy->GetPlayerPosition();
    BallVel = m_ball->GetBallVelocity();
    ballVelX = BallVel.m128_f32[0];
    ballVelY = BallVel.m128_f32[1];

    //Set the size of the sprite
    Sprite_Box_Height = 50;
    Sprite_Box_Width = 20;
    //if there is a collision between the ball and a paddle get the current time
    //and reverse the ball's velocity.
    if (m_collision)
    {
        float currentTime = m_timer->GetTime();
        //Wait for the ball to exit the area before setting collison back to false
        //to prevent the ball from getting stuck
        if (prevtime > currentTime - 100)
        {
            m_collision = true;
        }
        else
        {
            m_collision = false;
        }
    }
    else
    {
        //#################################################################//
        //set collision to true when the ball is in the area of the Paddle //
        //check if ball is in the player's x vecinity                      //
        //#################################################################//
        //check if ball has near the same position player's paddle
        if (BallPos.m128_f32[0] < PlayerPos.m128_f32[0] + Sprite_Box_Width && BallPos.m128_f32[0] > PlayerPos.m128_f32[0] - Sprite_Box_Width)
        {
            //check if ball hits the top of the player's paddle
            if (BallPos.m128_f32[1] < PlayerPos.m128_f32[1] + Sprite_Box_Height && BallPos.m128_f32[1] > PlayerPos.m128_f32[1] - Sprite_Box_Height)
            {
                prevtime = m_timer->GetTime();
                m_ball->SetBallVelocity(-ballVelX, ballVelY);
                m_collision = true;
            }
        }
        else if (BallPos.m128_f32[0] < PlayerPos.m128_f32[0] + Sprite_Box_Width && BallPos.m128_f32[0] > PlayerPos.m128_f32[0] - Sprite_Box_Width)
        {
            //check if ball is in the player's y vecinity
            if (BallPos.m128_f32[1] < PlayerPos.m128_f32[1] + Sprite_Box_Height && BallPos.m128_f32[1] > PlayerPos.m128_f32[1] - Sprite_Box_Height)
            {
                prevtime = m_timer->GetTime();
                m_ball->SetBallVelocity(-ballVelX, ballVelY);
                m_collision = true;
            }
        }
        else if (BallPos.m128_f32[0] < EnemyPos.m128_f32[0] + Sprite_Box_Width && BallPos.m128_f32[0] > EnemyPos.m128_f32[0] - Sprite_Box_Width)
        {
            //check if ball is in the player's y vecinity
            if (BallPos.m128_f32[1] < EnemyPos.m128_f32[1] + Sprite_Box_Height && BallPos.m128_f32[1] > EnemyPos.m128_f32[1] - Sprite_Box_Height)
            {
                prevtime = m_timer->GetTime();
                m_ball->SetBallVelocity(-ballVelX, ballVelY);
                m_collision = true;
            }
        }
        //###################################################################//
        //set collision to true when the ball hits the edge of the screen    //
        //by checking if ball's position is passed the edge and sets it back //
        //to  a position just inside the screen                              //
        //###################################################################//
        //if the ball hits the TOP edge of the screen change ball's velocity
        if (BallPos.m128_f32[1] > 300.0f)
        {
            prevtime = m_timer->GetTime();
            m_ball->SetBallVelocity(ballVelX, -ballVelY);
            m_collision = true;
        }
        //if the ball hits the BOTTOM edge of the screen change ball's velocity
        else if (BallPos.m128_f32[1] < -300.0f)
        {
            prevtime = m_timer->GetTime();
            m_ball->SetBallVelocity(ballVelX, -ballVelY);
            m_collision = true;
        }
        //if the ball hits the RIGHT edge of the screen change ball's velocity
        else if (BallPos.m128_f32[0] > 400.0f)
        {
            prevtime = m_timer->GetTime();
            m_ball->SetBallVelocity(-ballVelX, ballVelY);
            m_collision = true;
        }
        //if the ball hits the LEFT edge of the screen change ball's velocity
        else if (BallPos.m128_f32[0] < -400.0f)
        {
            prevtime = m_timer->GetTime();
            m_ball->SetBallVelocity(-ballVelX, ballVelY);
            m_collision = true;
        }
    }
}

感谢您的提前帮助!!!

在DirectX工具包教程中,我建议使用std::unique_ptr而不是原始指针的原因之一是它确实简化了代码。

// Font.h
#pragma once
#include <d3d11.h>
#include <directxmath.h>
#include <fstream>
#include <memory>
#include "SpriteBatch.h"
#include "SpriteFont.h"
class Font
{
public:
    Font() {}
    void Init(ID3D11Device* device, ID3D11DeviceContext* deviceContext);
    void Render();
private:
    std::unique_ptr<DirectX::SpriteFont> m_spriteFont;
    std::unique_ptr<DirectX::SpriteBatch> m_spriteBatch;
};
// Font.cpp
#include "Font.h"
#include "SimpleMath.h"
using namespace std;
using namespace DirectX;
void Font::Init(ID3D11Device* device, ID3D11DeviceContext* deviceContext)
{
    if (device != NULL && deviceContext != NULL)
    {
        m_spriteBatch = std::make_unique<SpriteBatch>(deviceContext);
        m_spriteFont = std::make_unique<SpriteFont>(device, L"Fonts/Arial.spritefont");
    }
}
void Font::Render()
{
    m_spriteBatch->Begin();
    m_spriteFont->DrawString(m_spriteBatch.get(), L"TEST", SimpleMath::Vector2(300, 300));
    m_spriteBatch->End();
}

您应该避免在.h文件中使用using namespace语句,因为它基本上会首先破坏使用C++名称空间的整个目的。应该只将using namespace语句放在.cpp文件中,然后在标头中使用完全限定的名称。

从您发布的代码中没有明显的原因可以解释为什么会出现异常。我建议您进入代码,看看异常的真正来源。如果您正在使用NuGet,那么您可能希望使用项目到项目引用。有关详细信息,请参阅DirectX工具包wiki。

您可以尝试使用Fonts\Arial.spritefont而不是Fonts/Arial.spritefont,看看这是否有区别。

对于现代编译器来说,如果#ifndef FONT_H #define FONT_H .. #endif不一定是老派的C风格。只需使用#pragma once

注意:如果您使用的是VS 2012而不是VS 2013或VS 2015,则不能使用std::make_unique。你应该做以下操作:

m_spriteBatch.reset( new SpriteBatch(deviceContext) );
m_spriteFont.reset( new SpriteFont(device, L"Fonts/Arial.spritefont") );