Sprite becomes white box when I implement function

2019-07-27 02:06发布

问题:

//Main.c

#include "Engine.h"

int main()
{
    Game app;
    //Menu Class Here
    app.run();
    return 0;
}

//Engine.cpp

#include "Engine.h"

Game::Game() 
{
    DASH = 0, x = 0, y = 0;
    total_enemies = 1;
    p_timer = 0;
    e_timer = 0;
}

Game::~Game()
{
}

void Game::run()
{
    sf::RenderWindow window(sf::VideoMode(SCREEN_X, SCREEN_Y), "Shogun Master");
    srand((unsigned int)time(NULL));

trying to replace the "creates player" here with void game::createPlayer that's located at the bottom of this file.

    //Creates Player    [Makes into function]
    sf::Texture player_texture;
    player_texture.loadFromFile("sprites/player.png");
    sf::Sprite player(player_texture);
    //Creates Enemy [Make into function]
    sf::Texture enemy_texture;
    enemy_texture.loadFromFile("sprites/enemy.png");
    sf::Sprite enemy[MAX_ENEMIES];
    for (int x = 0; x < MAX_ENEMIES; x++)
    {
        enemy[x].setTexture(enemy_texture);
        enemy[x].setPosition(rand_int(100, SCREEN_X - 100), rand_int(100, SCREEN_Y - 100)); //Spawning Point
    }
    //Sets Positions
    player.setPosition(500, 300);

    while (window.isOpen())
    {
        sf::Event event;
        while (window.pollEvent(event))
        {
            check_closeWindows(event, window);  //Closes Game if Executed
            player_movement(event);             //Moves Character
            attack(event);                      //Character's attacks
        }
        border(player);                 //Border so player does not go off screen
        for (int x = 0; x < total_enemies; x++)
        border(enemy[x]);
        movementUpdate(player, enemy);  //Player & Enemy Movement Updates
        collision(player, enemy[0]);

        window.clear();
        window.draw(player);    //Draws Player
        for (int x = 0; x < total_enemies; x++)
        window.draw(enemy[x]);      //Draws Enemy
        window.display();
        }
}

void Game::attack(sf::Event event)
{
    if (event.type == sf::Event::KeyPressed)    //Keyboard Commands
    if (event.key.code == sf::Keyboard::X)      //X = Dash Attack
        DASH = ATTK_SPD;
    if (event.type == sf::Event::JoystickButtonPressed) 
    {   ///Controller Action Buttons
        if (event.joystickButton.button == 0)                   //A = Dash Attack
        DASH = ATTK_SPD;
    }
}

void Game::player_movement(sf::Event event)
{
    if (event.type == sf::Event::KeyPressed)
    {       ///Keyboard Commands
        if (event.key.code == sf::Keyboard::W || event.key.code == sf::Keyboard::Up)    // Move Up
            x = 0, y = -P_SPD;
        if (event.key.code == sf::Keyboard::S || event.key.code == sf::Keyboard::Down)  // Move Down
            x = 0, y = P_SPD;
        if (event.key.code == sf::Keyboard::D || event.key.code == sf::Keyboard::Right) // Move Right
            x = P_SPD, y = 0;
        if (event.key.code == sf::Keyboard::A || event.key.code == sf::Keyboard::Left)      // Move Left
            x = -P_SPD, y = 0;
    }
    else if (event.type == sf::Event::JoystickMoved)
    {   ///Controller Directionals
        if (event.joystickMove.axis == sf::Joystick::PovY && event.joystickMove.position == 100)    //Up
            x = 0, y = -P_SPD;
        if (event.joystickMove.axis == sf::Joystick::PovY && event.joystickMove.position == -100)   //Down
            x = 0, y = P_SPD;
        if (event.joystickMove.axis == sf::Joystick::PovX && event.joystickMove.position == 100)    //Right
            x = P_SPD, y = 0;
        if (event.joystickMove.axis == sf::Joystick::PovX && event.joystickMove.position == -100)   //Left
            x = -P_SPD, y = 0;
    }
}

void Game::movementUpdate(sf::Sprite &player, sf::Sprite enemy[])
{
    //Player's Movements
    playerUpdate(player);
    for (int x = 0; x < total_enemies; x++)
    {
        enemyAiUpdate(player, enemy[x]);
    }
}

void Game::playerUpdate(sf::Sprite &player)
{
    if (DASH != 0)
    {   //Dash acts like a timer, speeds up until 0
        player.move(x * 3, y * 3);  //Dash
        --DASH;                     //Counts down
    }
    else
    player.move(x, y);  //Player Movement
}

void Game::enemyAiUpdate(sf::Sprite &player, sf::Sprite &enemy)
{
    double x = 1, y = 1, speed = .08;   //Enemy Movement towards player
    if (enemy.getPosition().x < player.getPosition().x)
        x = speed;      //Moves to right
    else if (enemy.getPosition().x > player.getPosition().x)
        x = -speed;     //Moves to left
    if (enemy.getPosition().y < player.getPosition().y)
        y = speed;      //Moves up
    else if (enemy.getPosition().y > player.getPosition().y)
        y = -speed;     //Moves down
    if (this->x == 0 && this->y == 0)
        x = 0, y = 0;   //Won't move until player moves
    enemy.move(x, y);
}

void Game::collision(sf::Sprite &player, sf::Sprite &enemy)
{
    int collision = 20, dmg = 100;
    //Enemy Collision (Damage Detection)
    if (enemy.getPosition().x > player.getPosition().x - collision && enemy.getPosition().x < player.getPosition().x + collision
        && enemy.getPosition().y > player.getPosition().y - collision && enemy.getPosition().y < player.getPosition().y + collision) 
    {
    if (DASH != 0) 
    {
        enemy.setColor(sf::Color(255, dmg, dmg));   //Enemy Collision [Damage taken, changes Red]
        e_timer = 400;
    } 
    else
    {
        player.setColor(sf::Color(255, dmg, dmg));  //Player Collision [Damage taken, changes Red]
        p_timer = 400;
    }
    }
    if (e_timer != 0)
        e_timer--;
    else
        enemy.setColor(sf::Color(255, 255, 255));
    if (p_timer != 0)
        p_timer--;
    else
        player.setColor(sf::Color(255, 255, 255));
}

void Game::check_closeWindows(sf::Event event, sf::RenderWindow &window)
{
    if (event.type == sf::Event::Closed)
        window.close();
    if (event.type == sf::Event::KeyPressed)
        if (event.key.code == sf::Keyboard::Escape) // Press Esc to Exit
            window.close();
    if (event.type == sf::Event::JoystickButtonPressed)
        if (event.joystickButton.button == 6)   //Press Back to Exit
            window.close();
}

void Game::border(sf::Sprite &player)
{
    if (player.getPosition().x >= SCREEN_X)                     ///If Player goes off screen, spawns on the other side
        player.setPosition(1, player.getPosition().y);              //Right Border
    if (player.getPosition().x <= 0)
        player.setPosition(SCREEN_X - 1, player.getPosition().y);       //Left Border
    if (player.getPosition().y >= SCREEN_Y)
        player.setPosition(player.getPosition().x - 1, 1);          //Top Border
    if (player.getPosition().y <= 0)
        player.setPosition(player.getPosition().x, SCREEN_Y - 1);   //Bottom Border
}

int Game::rand_int(int min, int quantity)
{
    return rand() % quantity + min;
}

This is what I'm having trouble implementing. I'm trying to get this to work, so I can use this function to replace the "create player" under void game::run() and then use it to create a class, but I can't figure out what's causing it to go out scope. Any help as to how to go about implementing this would be much appreciated.

void Game::createPlayer(sf::Sprite &player)
{   ///Can't get this to work
    sf::Texture player_texture;
    if (!player_texture.loadFromFile("player.png")) 
{
        //Error Loading
}
    player.setTexture(player_texture);
}

//Engine.h

#pragma once
#include <SFML/Graphics.hpp>
#include <SFML/System.hpp>
#include <iostream>
#include <time.h>

#define SCREEN_X 1000   //Size of Memory, can be changed
#define SCREEN_Y 800    //Size of Memory, can be changed
#define ATTK_SPD 250    //Speed of Player Attack
#define P_SPD .2        //Player's Speed
#define MAX_ENEMIES 5

class Game
{
 public:
        Game();
        ~Game();
        void run();
        void attack(sf::Event event);
        void player_movement(sf::Event event);
        void movementUpdate(sf::Sprite &player, sf::Sprite enemy[]);
        void playerUpdate(sf::Sprite &player);
        void enemyAiUpdate(sf::Sprite &player, sf::Sprite &enemy);
        void collision(sf::Sprite &player, sf::Sprite &enemy);
        void check_closeWindows(sf::Event event, sf::RenderWindow &window);
        void border(sf::Sprite &player);
        int rand_int(int min, int quantity);
        //void Game::createPlayer(sf::Sprite &player);
 private:
        int DASH;
        double x, y;
        int total_enemies;
        int p_timer;
        int e_timer;
};

回答1:

void Game::createPlayer(sf::Sprite &player)
{   
    // this variable is local.
    // it will only live to the end of the createPlayer method
    sf::Texture player_texture; 

    if (!player_texture.loadFromFile("player.png")) 
    {
        //Error Loading
    }

    player.setTexture(player_texture);
}

Your player_texture is a local variable. When it goes out of scope at the end of the method, it will be destroyed. Now your player_sprite has a destroyed texture. As it is unknown what was once saved in that texture, SFMl will draw it white.

What you need to do is make sure your player_texture variable lives at least as long as your player variable.

Your could put it in your Game class. But your player seems to live outside of that class. You will soon find that with all the sprites, you need a class to hold them all. Something like a TextureManager or ResourceHolder. Then you will find that it would be more practical to have all your external resources (files) access in one place, in a TextureManager.load() method for example. And then you will need your first loading screen. Welcome to the world of gaming.



标签: c++ scope sfml