You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++ SFML迁移精灵代码至Player类后显示白框求助

SFML精灵迁移到Player类后显示白框问题解决

问题描述

原本在Main.cpp中编写的精灵纹理代码可正常运行,但将逻辑迁移至Player类后,精灵显示为白框。目前仅使用方向静止精灵,需先解决该问题再进行动画开发。

提供代码

Main.cpp

#include <SFML/Graphics.hpp>
#include <iostream>
#include "Initialise.h"
#include"Player.h"

using namespace sf;


int main()
{
    sf::RenderWindow window(sf::VideoMode(1920, 1080, 32), "Game Demo", sf::Style::Default);

    sf::Texture txt_playerIdle;

    if (!txt_playerIdle.loadFromFile("[removed from post, is correct directory]")) {
        std::cout << "Error loading the image!" << std::endl;
    }

    Player player(1.f, 2.f, 0.f, txt_playerIdle);

    player.GetPlayerSprite().setTextureRect({ 0, 0, 32, 32 });

    const float f_FPS = 60.0f;
    bool b_redraw = true;

    sf::Clock clock;

    sf::Event event;

    while (window.isOpen())
    {
        if (clock.getElapsedTime().asSeconds() >= 1.0f / f_FPS)
        {
            b_redraw = true;
            clock.restart();
        }

        player.MovePlayer();

        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed) {
                window.close();
            }
        }

        if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
        {
            player.GetPlayerSprite().setTextureRect({ 0, 32, 32, 32 });
        }
        else if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
        {
            player.GetPlayerSprite().setTextureRect({ 0, 96, 32, 32 });
        }
        else if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
        {
            player.GetPlayerSprite().setTextureRect({ 0, 0, 32, 32 });
        }
        else if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
        {
            player.GetPlayerSprite().setTextureRect({ 0, 64, 32, 32 });
        }

        if (b_redraw)
        {
            window.clear();
            window.draw(player.GetPlayerSprite());
            window.display();
            b_redraw = false;
        }
    }

    return 0;
}

Player.cpp

#include "Player.h"


void Player::SetPlayerSpeed(float NewSpeed)
{
    PlayerSpeed = NewSpeed;
}

float Player::GetPlayerSpeed()
{
    return this->PlayerSpeed;
}

void Player::SetPlayerSprite(sf::Sprite sprite)
{
    PlayerSprite = sprite;
}

sf::Sprite& Player::GetPlayerSprite()
{
    return PlayerSprite;
}

void Player::MovePlayer()
{
    if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
    {
        PlayerSprite.setPosition(PlayerSprite.getPosition().x, PlayerSprite.getPosition().y - PlayerSpeed);
    }

    if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
    {
        PlayerSprite.setPosition(PlayerSprite.getPosition().x - PlayerSpeed, PlayerSprite.getPosition().y);
    }

    if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) {
        PlayerSprite.setPosition(PlayerSprite.getPosition().x, PlayerSprite.getPosition().y + PlayerSpeed);

    }

    if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) {
        PlayerSprite.setPosition(PlayerSprite.getPosition().x + PlayerSpeed, PlayerSprite.getPosition().y);
    }
}

Player.h

#pragma once
#include "GameObject.h"

using namespace std;

class Player :public GameObject {
private:
    int PlayerHealth;
    int PlayerMaxHealth;
    float PlayerSpeed;
    sf::Texture PlayerTexture;
    sf::Sprite PlayerSprite;

public:

    void SetPlayerHealth(int NewPlayerHealth);
    int GetPlayerHealth();

    void SetPlayerMaxHealth(int NewPlayerMaxHealth);
    int GetPlayerMaxHealth();

    void SetPlayerSpeed(float NewPlayerSpeed);
    float GetPlayerSpeed();

    void SetPlayerSprite(sf::Sprite NewPlayerSprite);
    /*sf::Sprite GetPlayerSprite();*/
    sf::Sprite& GetPlayerSprite();
    void MovePlayer();

    Player(float speed, float scale, float rotation, sf::Texture texture)
    {
        this->SetScale(scale);
        this->SetRotation(rotation);
        PlayerSpeed = speed;
        PlayerTexture = texture;
        PlayerSprite.setTexture(texture);

    }

};

问题根源

SFML的sf::Sprite并不存储纹理数据,仅持有纹理的引用。你的代码存在两个核心问题:

  1. Player构造函数的参数是sf::Texture texture(传值方式),会创建Main中txt_playerIdle的临时副本。
  2. 调用PlayerSprite.setTexture(texture)时,Sprite保存的是这个临时纹理的引用。构造函数执行完毕后,临时纹理被销毁,Sprite的纹理引用失效,导致渲染时显示白框。
  3. 类中的PlayerTexture成员完全没用,因为你没让Sprite绑定这个成员纹理。

修复方案

方案1:传递纹理引用(推荐,保留Main中的纹理加载逻辑)

修改Player类的构造函数,让Sprite绑定到Main中持久存在的纹理:

  1. 修改Player.h中的构造函数声明与实现:
// 构造函数参数改为引用
Player(float speed, float scale, float rotation, sf::Texture& texture)
{
    this->SetScale(scale);
    this->SetRotation(rotation);
    PlayerSpeed = speed;
    // 直接绑定传入的纹理引用,无需复制
    PlayerSprite.setTexture(texture);
}
  1. 删除Player类中无用的PlayerTexture成员变量。

方案2:让Player类自行管理纹理

如果希望Player类独立负责纹理加载,可改为接收文件路径:

  1. 修改Player.h:
// 保留PlayerTexture成员,构造函数改为接收路径
private:
    int PlayerHealth;
    int PlayerMaxHealth;
    float PlayerSpeed;
    sf::Texture PlayerTexture; // 保留,用于存储纹理
    sf::Sprite PlayerSprite;

public:
    Player(float speed, float scale, float rotation, const std::string& texturePath)
    {
        this->SetScale(scale);
        this->SetRotation(rotation);
        PlayerSpeed = speed;
        // 内部加载纹理
        if (!PlayerTexture.loadFromFile(texturePath)) {
            std::cerr << "Failed to load texture: " << texturePath << std::endl;
        }
        PlayerSprite.setTexture(PlayerTexture);
    }
  1. 修改Main.cpp中的实例化代码:
// 移除Main中的txt_playerIdle变量,直接传入路径
Player player(1.f, 2.f, 0.f, "[removed from post, is correct directory]");

额外优化(可选)

避免在Main中直接操作Player的Sprite,封装纹理矩形设置逻辑,符合面向对象原则:
在Player.h中添加:

void SetTextureRect(const sf::IntRect& rect)
{
    PlayerSprite.setTextureRect(rect);
}

然后Main中的代码改为:

player.SetTextureRect({0, 0, 32, 32});
// 按键判断部分也同步修改为调用SetTextureRect

内容的提问来源于stack exchange,提问作者RelCade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 06:15:02