Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

1

01.11.2015, 12:25

C++ / sfml - Problem mit Sprite Vererbung

Hallo zusammen!
Ich habe ein Problem mit meinem "Spiel". Und zwar habe ich eine Entity Klasse erstellt, die unter anderem Sprite und Textur enthält:

EDIT: Ich habe keinen Schimmer wieso im folgenden Code die Zeilenumbrüche nicht richtig angezeigt werden. Ich hoffe man erkennt es trotzdem einigermaßen.

C-/C++-Quelltext

1
2
3
class Entity{public:
    sf::RectangleShape rect;    sf::Texture texture;    sf::Sprite sprite;  sf::Text text;  Entity();
private:protected:};



Nun habe ich eine Player Klasse, die von Entity erbt:

C-/C++-Quelltext

1
2
3
class Player : public Entity{public:
    enum Direction { DOWN, LEFT, RIGHT, UP };   sf::Vector2i source;        int attackDamage = 5;   float playerMovementSpeed = 2;  bool reverseAnimation = false;  bool isMoving = false;  sf::Time tempClock; Animation playerAnim;
    Player();   void update(sf::Time elapsed);};


Im Player Konstruktor definiere ich nun sprite und textur der übergeordneten Entity Klasse:

C-/C++-Quelltext

1
2
3
4
5
Player::Player(){   rect.setSize(sf::Vector2f(32, 32)); rect.setPosition(400, 200); rect.setFillColor(sf::Color::Blue);
    source.x = 0;   source.y = DOWN;
    if (!texture.loadFromFile("Resources/character_spritesheet.png"))       cout << "Das Bild \"character_spritesheet.png\" konnte nicht geladen werden!" << endl;
    sprite.setTexture(texture); sprite.setTextureRect(sf::IntRect(0, 0, 32, 32));   sprite.setPosition(400, 300);
    Player::playerAnim.init(texture, sprite, sf::Vector2i(32, 32), 0.2f);}


Ansließend lasse ich mir in der main.cpp player.sprite anzeigen:

C-/C++-Quelltext

1
    window.draw(player.sprite);


Und ich fürchte da irgendwo muss schon das Problem liegen. Ich erhalte eine Fehlermeldung: Zugriffsverletzung beim Lesen an Pos ....
Der Debugger sagt mir, er könne den Speicher von player.Sprite nicht lesen.
Ich denke mal das Problem wird irgendwo in der falschen Verwendung der Entity::sprite liegen, denn wenn ich eine separate playerSprite in der Player-Klasse erstelle, funktioniert alles.

Meine Frage ist nun, wieso kann ich nicht die vererbte Sprite aus der Entity Klasse benutzen um die Sprite vom Player auszugeben?
Bzw. wo steckt da der Fehler?

Es wäre sehr nett, wenn ihr mir helfen könntet :)

LG

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

2

01.11.2015, 13:19

Vermutung: Du benutzt irgendwo Player* statt Player und hast da keinen Speicher zugewiesen.

Davon mal abgesehen solltest Du niemals eine sf::Texture als normalen Member einer Klasse deklarieren. Das bringt massive Probleme. Nimm eine Referenz oder einen Pointer. Alles andere wird zu Fehlern führen, die Du Dir nicht erklären kannst.

Damit die Zeilenumbrüche richtig dargestellt werden, wähle beim Verfassen Deiner Beiträge bitte den "Quellcode-Modus" (Tab gleich über dem Eingabefeld) und *nicht* den Editor-Modus.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

3

01.11.2015, 13:34

Danke für die schnelle Antwort.
Also Pointer habe ich im gesamten Code noch nicht benutzt (waren mir nicht ganz geheuer :S ).

Ich verstehe das Problem nicht so ganz. Meine Entity Klasse hat eine Texture und ein Sprite.
Wenn ich jetzt eine Player Instanz erstelle und die von Entity erbt, hat diese doch eine player.texture und player.sprite, richtig?
Und wenn ich jetzt das Sprite vom Spieler rendern will, sollte ich doch über player.sprite auf dieses Sprite Zugriff haben, oder nicht?
Denn genau da bekomme ich einen Fehler.

Wenn ich hingegen in der Player Klasse eine eigene playerSprite anlege und nicht das sprite aus der Entity nehme, dann funktioniert alles!
Wieso also klappt es nicht mit dem vererbten sprite aus der Entity Klasse? ?(

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

4

01.11.2015, 13:53

Da wirst Du wohl mal mehr Code zeigen müssen. Allein durch die Klassen sehe ich da nicht (was eventuell auch der Formatierung geschuldet sein könnte).
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

5

01.11.2015, 14:40

Alles klar. Ich versuche es mal mit dem Quellcode. Und danke für die Hilfsbereitschaft!

main.cpp

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
int main()
{
    // Clock
    sf::Clock clock;
    sf::Time elapsed;

    sf::RenderWindow window(sf::VideoMode(800, 600), "Simple Dungeon Crawler", sf::Style::Close | sf::Style::Titlebar);
    window.setFramerateLimit(120);

    sf::Image icon;
    if (!icon.loadFromFile("Resources/skull.jpg"))
        cout << "Das Bild \"skull.jpg\" konnte nicht geladen werden!" << endl;

    window.setIcon(icon.getSize().x, icon.getSize().y, icon.getPixelsPtr());

    // Start the clock
    clock.restart();

    // Create Player
    Player player;

    while (window.isOpen())
    {
        elapsed = clock.restart();


        sf::Event event;

        while (window.pollEvent(event))
        {
            switch (event.type)
            {
                case sf::Event::Closed:
                    window.close();
                    break;
            }
        }

        // Update Player
        player.update(elapsed);

        // draw everything
        window.clear(sf::Color::Black);

        window.draw(player.sprite);

        window.display();

    }

    return 0;
}


Entity.hpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#pragma once

#include <SFML/Graphics.hpp>

class Entity
{
public:

    sf::RectangleShape rect;
    sf::Texture texture;
    sf::Sprite sprite;
    sf::Text text;

private:
protected:
};


Player.hpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#pragma once

#include <SFML\Graphics.hpp>
#include "Entity.h"
#include "Animation.h"


class Player : public Entity
{
public:

    enum Direction { DOWN, LEFT, RIGHT, UP };
    sf::Vector2i source;
    
    int attackDamage = 5;
    float playerMovementSpeed = 2;
    bool reverseAnimation = false;
    bool isMoving = false;
    sf::Time tempClock;
    Animation playerAnim;

    Player();
    void update(sf::Time elapsed);
};


Player.cpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <SFML\Graphics.hpp>
#include <iostream>
#include "Player.h"
#include "Animation.h"

using namespace std;

Player::Player()
{
    rect.setSize(sf::Vector2f(32, 32));
    rect.setPosition(400, 200);
    rect.setFillColor(sf::Color::Blue);

    source.x = 0;
    source.y = DOWN;

    if (!texture.loadFromFile("Resources/character_spritesheet.png"))
        cout << "Das Bild \"character_spritesheet.png\" konnte nicht geladen werden!" << endl;

    sprite.setTexture(texture);
    sprite.setTextureRect(sf::IntRect(0, 0, 32, 32));
    sprite.setPosition(400, 300);

    Player::playerAnim.init(texture, sprite, sf::Vector2i(32, 32), 0.2f);
}

void Player::update(sf::Time elapsed)
{
    sprite.setPosition(rect.getPosition());

    // player movement...
}



Und hier nochmal der Fehler beim Debuggen:


(Link)

6

01.11.2015, 14:52

Zeig bitte mal noch die Klasse Animation da die ja auch mit rein spielt.
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

7

01.11.2015, 14:55

Alles klar. Gleich vorweg: Das ist wahrscheinlich ziemlich unkonventionell, weil ich nicht wusste wie man sowas normalerweise macht ^^
Animation.hpp

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#pragma once

#include <SFML\Graphics.hpp>

class Animation
{
public:
    // Variablen
    sf::Texture textureSheet;
    sf::Sprite sprite;
    sf::Vector2i spriteSize;
    sf::Time tempClock;
    float animSpeed;
    int counter;
    bool reverseAnimation;

    // Konstruktoren
    Animation();
    Animation(sf::Texture textureSheet, sf::Sprite sprite, sf::Vector2i spriteSize, float animSpeed);

    // Funktionen
    void init(sf::Texture textureSheet, sf::Sprite sprite, sf::Vector2i spriteSize, float animSpeed);
    sf::Sprite updateSprite(sf::Sprite sprite, int line, sf::Time elapsed);
};


Animation.cpp:

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include "Animation.h"

Animation::Animation()
{

}

Animation::Animation(sf::Texture textureSheet, sf::Sprite sprite, sf::Vector2i spriteSize, float animSpeed)
{
    Animation::textureSheet = textureSheet;
    Animation::sprite = sprite;
    Animation::spriteSize.x = spriteSize.x;
    Animation::spriteSize.y = spriteSize.y;
    Animation::animSpeed = animSpeed;
    reverseAnimation = false;
    counter = 0;
}

void Animation::init(sf::Texture textureSheet, sf::Sprite sprite, sf::Vector2i spriteSize, float animSpeed)
{
    Animation::textureSheet = textureSheet;
    Animation::sprite = sprite;
    Animation::spriteSize.x = spriteSize.x;
    Animation::spriteSize.y = spriteSize.y;
    Animation::animSpeed = animSpeed;
    reverseAnimation = false;
    counter = 0;
}

sf::Sprite Animation::updateSprite(sf::Sprite sprite, int line, sf::Time elapsed)
{
    tempClock += elapsed;

    // slow down animation + reverse it
    if (tempClock.asSeconds() >= animSpeed)
    {
        if (reverseAnimation)
            counter--;
        else counter++;

        tempClock = tempClock.Zero;
    }
    
    if (counter * spriteSize.x >= textureSheet.getSize().x - spriteSize.x)
        reverseAnimation = true;

    if (counter <= 0)
        reverseAnimation = false;

    Animation::sprite = sprite;

    sprite.setTextureRect(sf::IntRect(counter * Animation::spriteSize.x, line * Animation::spriteSize.y, Animation::spriteSize.x, Animation::spriteSize.y));

    return sprite;
}

BlueCobold

Community-Fossil

Beiträge: 10 738

Beruf: Teamleiter Mobile Applikationen & Senior Software Engineer

  • Private Nachricht senden

8

01.11.2015, 15:03

Da hast Du auf jeden Fall wieder das Problem, dass Texturen kopiert werden, weil Du sie nicht als Referenz oder Pointer übergibst. Ich wünschte mir wirklich, dass die Jungs von SFML das von vorn herein verboten hätten.
Teamleiter von Rickety Racquet (ehemals das "Foren-Projekt") und von Marble Theory

Willkommen auf SPPRO, auch dir wird man zu Unity oder zur Unreal-Engine raten, ganz bestimmt.[/Sarkasmus]

9

01.11.2015, 15:10

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
sf::Sprite Animation::updateSprite(sf::Sprite sprite, int line, sf::Time elapsed)
{
    ...
    Animation::sprite = sprite;

    sprite.setTextureRect(sf::IntRect(counter * Animation::spriteSize.x, line * Animation::spriteSize.y, Animation::spriteSize.x, Animation::spriteSize.y));

    return sprite;
}


Habe den hier in Verdacht, wo bekommt die Funktion ihren Sprite her? Und wer bekommt ihn dann wieder?

Edit:
Da hast Du auf jeden Fall wieder das Problem, dass Texturen kopiert werden, weil Du sie nicht als Referenz oder Pointer übergibst.

BC sein Hinweis solltest du auf jeden fall beachten und beheben.
Wer aufhört besser werden zu wollen hört auf gut zu sein!

aktuelles Projekt:Rickety Racquet

10

01.11.2015, 17:23

Die Funktion bekommt den Sprite von der player.update() Funktion. Die Zeile sieht so aus:

C-/C++-Quelltext

1
sprite = playerAnim.updateSprite(sprite, source.y, elapsed);


Zu der Sache mit den Zeigern:

Ich habe gerade alle Funktionen die sprite und texture übergeben bekommen stattdessen die Adressen übergeben und mit Zeigern gearbeitet. Das Problem ist leider immer noch da

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Lardos« (01.11.2015, 17:48)


Werbeanzeige