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

24.12.2012, 00:11

list<CSprite>

Hey ich hab da mal ne Frage.
Wisst ihr wie ich es hinkriege eine Liste für Sprites zu erstellen

Mein Ansatz. Nur ich weiß einfach nicht wie ich die Bilder wieder freigeben kann.
Danke schonmal :).

C-/C++-Quelltext

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    list<CSprite> m_SpriteList;
    CSprite Keks;
    Keks.Load("Data/Keks.bmp");
    Keks.SetColorKey(255, 0, 255);
    Keks.SetPos(220, 0);
    m_SpriteList.push_back (Keks);

    list<CSprite>::iterator it = m_SpriteList.begin();

    while (it != m_SpriteList.end ())
    {
        // Einzelne Bilder Rendern
        it->Render();
        it++;
    }

eXpl0it3r

Treue Seele

Beiträge: 386

Wohnort: Schweiz

Beruf: Professional Software Engineer

  • Private Nachricht senden

2

24.12.2012, 00:24

std::list<T> verwendet das RAII Idiom, d.h. Ressourcen in std::list werden automatisch freigegeben, wenn der Scope verlassen wird.

Wenn du nur ein Element zur Laufzeit rausschmeissen willst, dann lohnt sich der Blick in eine C++ Referenz (-> erase()).

Zwei Tipps: Verwende kein C-Präfix für Klassen, es macht keinen Sinn, da es gar keine Rolle spielen soll, was denn nun genau eine Klasse ist und was nicht; es ist alleine ein altes Microsoft Relikt, dass noch viel zu viel verwendet wird...
Je nachdem was du machst ist ein std::vector<T> wohl eine bessere Lösung oder dann std::dequeu<T>. std::list hat so seine Tücken und kann ein echter Performance Killer sein.
Blog: https://dev.my-gate.net/
—————————————————————————
SFML: https://www.sfml-dev.org/
Thor: http://www.bromeon.ch/libraries/thor/
SFGUI: https://github.com/TankOs/SFGUI/

3

24.12.2012, 01:24

Du solltest allerdings beachten, dass die std::list Objekte gerne kopiert, bzw. die in C++11 eingeführte Move-Semantik benutzt. Solange deine Objekte das nicht explizit unterstützten solltest du sie nicht direkt in der Liste speichern. Optionen wären dann, den neuen std::unique_ptr zu benutzen, oder normale Pointer zu benutzen und dann jedes einzelne Element im Destruktor des Objektes, dass die Liste besitzt, per delete zu löschen (die erste Lösung ist allerdings etwas schöner und robuster).
Lieber dumm fragen, als dumm bleiben!

4

24.12.2012, 15:13

Wenn wir schon bei C++11 sind: emplace()
"Theory is when you know something, but it doesn’t work. Practice is when something works, but you don’t know why. Programmers combine theory and practice: Nothing works and they don’t know why." - Anon

5

24.12.2012, 16:45

Danke für die tollen Tipps.
Mein Problem war bisher das mein Programm, wenn ich es beende crasht deswegen bin ich davon ausgegangen das die liste die elemente nicht löscht. Habe auch schon versucht zeiger in die liste zu schieben ging allerdings auch schief. Ich versuche zb. 100 Sprites in eine Liste einzulesen und diese dann in der funktion render zu rendern(Klappte auch nicht mit zeigern in einer Liste).
Ich werde das ganze jetzt mal mit den vectoren testen :).
Außer irgendwer weiß warum mein programm sich beim beenden immer aufhängt :).

Nimelrian

Alter Hase

Beiträge: 1 216

Beruf: Softwareentwickler (aktuell Web/Node); Freiberuflicher Google Proxy

  • Private Nachricht senden

6

24.12.2012, 17:09

Schon mit dem Debugger durchgegangen?
Ich bin kein UserSideGoogleProxy. Und nein, dieses Forum ist kein UserSideGoogleProxyAbstractFactorySingleton.

7

24.12.2012, 20:01

Nein ich wüsste auch nicht wie ich so ein Programm debuggen kann. Wenn es nur ein Quelltext ist ja, aber bei so einem Programm bekomme ich das nicht hin.
Mein Problem ist, dass mein Programm nur am ende abstürzt sobald ich die liste miteinbaue nur weiß ich nicht wieso.

8

24.12.2012, 22:10

Habe das auch schon mit vectoren probiert einmal mit temp variablen und mit zeigern..Löschen im destruktor ohne mit erease...
Ich komme einfach auf keinen grünen Zweig. Hoffe ihr könnt mir da helfen :).
Das ganze sieht bei mir so aus:

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
#ifndef SELECTIONSCREEN_HPP
#define SELECTIONSCREEN_HPP

#include "Sprite.hpp"
#include <list>

class CSelectionScreen
{
    public:
        CSelectionScreen    ();
        ~CSelectionScreen    ();
        void Init            ();
        void Quit            ();
        void Render            ();

    private:
        CSprite *m_pSpriteSel;        // Selcection Screen
        CSprite *m_pSpriteBisasam;    // Bisasam
        list<CSprite> m_SpriteList; 
};

#endif


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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
#include "SelectionScreen.hpp"

// Konstruktor
//
// Aufgabe: Allgemeine Initialisierungen
//
CSelectionScreen::CSelectionScreen()
{
    m_pSpriteSel = NULL;
    m_pSpriteBisasam = NULL;
} // Konstruktor

// Destruktor
CSelectionScreen::~CSelectionScreen    ()
{
    Quit();
} // Destruktor

// Init
//
// Aufgabe: Sprites erzeugen und laden
//
void CSelectionScreen::Init ()
{
    // SelectionScreen
    m_pSpriteSel = new CSprite;
    m_pSpriteSel->Load("Data/SelectionScreen.bmp");

    m_pSpriteBisasam = new CSprite;
    m_pSpriteBisasam->Load("Data/Karten/BisasamBig.bmp");
    m_pSpriteBisasam->SetColorKey (255, 0, 255);
    m_pSpriteBisasam->SetPos(220, 0);

    m_SpriteList.push_back (*m_pSpriteBisasam);

} // Init

// Quit
//
// Aufgabe: Sprites freigeben
//
void CSelectionScreen::Quit ()
{
    // Sel-Sprite freigeben
    if (m_pSpriteSel != NULL)
    {
        delete (m_pSpriteSel);
        m_pSpriteSel = NULL;
    }
    // Sel-Sprite freigeben
    if (m_pSpriteBisasam != NULL)
    {
        delete (m_pSpriteBisasam);
        m_pSpriteBisasam = NULL;
    }
} // Quit

// Rendern
void CSelectionScreen::Render ()
{
    m_pSpriteSel->Render ();

    list<CSprite>::iterator it = m_SpriteList.begin();

    while (it != m_SpriteList.end ())
    {
        // Einzelne Bilder Rendern
        it->Render();
        it++;
    }

} // Rendern

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Chris13« (24.12.2012, 22:34)


eXpl0it3r

Treue Seele

Beiträge: 386

Wohnort: Schweiz

Beruf: Professional Software Engineer

  • Private Nachricht senden

9

25.12.2012, 00:30

Und was ist CSprite für eine Klasse? Ich nehme mal fast an, dass CSprite intern eine Referenz o.ä. auf eine Texture hat und wenn die Instanz gelöscht wird, wird auch die Ressource gelöscht, da du nun aber eine Kopie in die Liste/vector schiebst, hat diese die selbe Referenz und wenn nun versucht wird diese Referenz zweimal zu lösche fliegt alles in die Luft, aber ohne Implementation von CSprite kann man hier nichts sagen.

Überigends solltest du vom manuallen Memory Managment (raw pointers + new/delete) die Finger lassen. Mit C++11 und z.T. bereits mit dem TR1 wurden Smart Pointers eingeführt, welche mit RAII eine klar definierte Lebensdauer haben und somit um einiges sicherer werden.

Weiter existieren De- und Konstruktoren aus einem Grund und das ist nicht um eine andere Methode aufzurufen, welche dann ihren Job ausführt. Quit und Init sind unnötig und es sollte eigentlich immer gelten, dass eine Klasse nach dem Erstellen vollumfänglich initialisiert ist. (Bem. ja es gibt ab und an Verwendungen von Init(), aber das ist hier nicht der Fall und oft wird es aus Faulheit einfach missbraucht um Klassen 'zurück zusetzten' was oft auch von einem schlechten Design spricht.)

Wie bereits erwähnt ist das C vor Klassen ein altes Relikt und sollte nicht (mehr) verwendet werden.

Im Header hast du nur list<CSprite> geschrieben, hast du da jetzt einfach das std:: vergessen oder verwendest du da irgendwo versteckt & 'global' using namespace std;? IMHO sollte man nie using namespace std; verwenden (ausser für mockups o.ä.), weil man mit der absoluten Angabe z.B. std::list direkt sieht, dass es sich um die Liste aus der STL handelt und nicht um eine selbst definierte Liste und zum andere kann man somit jegliche Namenskonflikte verhindern.
Blog: https://dev.my-gate.net/
—————————————————————————
SFML: https://www.sfml-dev.org/
Thor: http://www.bromeon.ch/libraries/thor/
SFGUI: https://github.com/TankOs/SFGUI/

10

25.12.2012, 14:46

Das namespace std hatte ich einfach nur vergessen. Im Sprite Destruktor wird das Bild mittels SDL_FREESURFACE freigeben, wobei dieser auch prüft ob nur ein NULL übergeben wird. Beim nächsten Projekt werde ich darauf achten das C vor dem Klassennamen wegzulassen, nur wäre es zu umständlich es in 16hpps und cpps zu ändern. Das Quit() hatte ich von der Grundidee ünernommen, nur habe auch recht schnell gemerkt das ich doch lieber einen destruktor nutzen will.

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
#ifndef SPRITE_HPP
#define SPRITE_HPP

#include "Framework.hpp"

class CSprite
{
    public:
        CSprite ();
        ~CSprite ();

        void Load           (const string sFilename);
        void Load           (const string sFilename, int NumFrames,
                             int FrameWidth, int FrameHeight);
        void SetColorKey    (int R, int G, int B);
        void SetPos         (float fXPos, float fYPos);
        void Render         ();
        void Render         (float fFrameNumber);
        SDL_Rect GetRect    () {return m_Rect;}
        int GetFrameWidth   () {return m_FrameWidth;}
        int GetFrameHeight  (){return m_FrameHeight;}

    private:
        SDL_Surface *m_pScreen; // Zeiger auf den Screen des Frameworks
        SDL_Surface *m_pImage;  // Das eigentliche Bild des Sprites
        SDL_Rect m_Rect;        // Rect des Sprites
        SDL_Rect m_FrameRect;   // Ausschnitt für Animationsphase
        int m_NumFrames;        // Anzahl der Animationsphasen
        int m_FrameWidth;       // Breite einer Animationsphase
        int m_FrameHeight;      // Höhe einer Animationsphase
        int m_NumFramesX;       // Wie viele Anim-Phasen in X-Richtung?

};

#endif


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
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#include "Sprite.hpp"
// Konstruktor
//
// Aufgabe: Zeiger auf Screen holen
//
CSprite::CSprite ()
{
    // Zeiger auf Screen holen
    m_pScreen = g_pFramework->GetScreen ();

} // Konstruktor

// Destruktor
//
// Aufgabe: Surface des Sprites freigeben
//
CSprite::~CSprite ()
{
    // Surface freigeben
    SDL_FreeSurface (m_pImage);

} // Destruktor

// Load
//
// Aufgabe: Einfaches, nicht animiertes Sprite laden
//
void CSprite::Load (const string sFilename)
{
    // Bitmap laden
    m_pImage = SDL_LoadBMP (sFilename.c_str () );

    // Prüfen, ob alles glatt ging
    if (m_pImage == NULL)
    {
        cout << "Fehler beim Laden von: " << sFilename.c_str ();
        cout << endl;
        cout << "Fehlermeldung: " << SDL_GetError () << endl;

        // Framework herunterfahren
        g_pFramework->Quit ();

        // Gesamtes Spiel beenden
        exit (1);
    }

    // Rect initialisieren
    m_Rect.x = 0;
    m_Rect.y = 0;
    m_Rect.w = m_pImage->w;
    m_Rect.h = m_pImage->h;

} // Load

// Load
//
// Aufgabe: Animiertes Sprite laden
//
void CSprite::Load (const string sFilename, int NumFrames,
                    int FrameWidth, int FrameHeight)
{
    // Bitmap laden
    Load (sFilename);

    // Rect für Animationsphase initialisieren
    m_NumFrames   = NumFrames;
    m_FrameWidth  = FrameWidth;
    m_FrameHeight = FrameHeight;
    m_FrameRect.w = FrameWidth;
    m_FrameRect.h = FrameHeight;
    m_NumFramesX  = m_pImage->w / m_FrameWidth;

} // Load

// SetColorKey
//
// Aufgabe: Transparente Farbe festlegen
//
void CSprite::SetColorKey (int R, int G, int B)
{
    // Colorkey einstellen
    SDL_SetColorKey (m_pImage, SDL_SRCCOLORKEY,
        SDL_MapRGB (m_pImage->format, R, G, B) );

} // SetColorKey

// SetPos
//
// Aufgabe: Position des Sprites festlegen
//
void CSprite::SetPos (float fXPos, float fYPos)
{
    // Rect updaten
    m_Rect.x = static_cast<int>(fXPos);
    m_Rect.y = static_cast<int>(fYPos);

} // SetPos

// Render
//
// Aufgabe: Sprite rendern (ohne Animation)
//
void CSprite::Render ()
{
    // Sprite rendern
    SDL_BlitSurface (m_pImage, NULL, m_pScreen, &m_Rect);

} // Render

// Render
//
// Aufgabe: Ausschnitt des Sprites rendern (Animationsphase)
//
void CSprite::Render (float fFrameNumber)
{
    // Ausschnitt der aktuellen Animationsphase berechnen
    //

    // Spalte berechnen
    int Column = static_cast<int>(fFrameNumber)%m_NumFramesX;

    // Zeile berechnen
    int Row = static_cast<int>(fFrameNumber)/m_NumFramesX;

    // Rect berechnen
    m_FrameRect.x = Column * m_FrameWidth;
    m_FrameRect.y = Row * m_FrameHeight;

    // Ausschnitt rendern
    SDL_BlitSurface (m_pImage, &m_FrameRect, m_pScreen, &m_Rect);

} // Render

Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von »Chris13« (25.12.2012, 14:54)


Werbeanzeige