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!
ich schreib gerade für SFML eine kleine Engine bzw ein kleines Framework und hab
1. ein Performanceproblem für Tilemaps:
Das größte Tilemap ist 64x64 Felder groß - besteht also aus 4096 einzelne Sprites. Diese Sprites werden einzeln zugewiesen und gerendert.
Beim Debug Mode komm ich mit einem 64x64 Tilemap nur auf ~8 FPS
(Notebook, 2,2 GHz Dual Core, 4 GB Ram)
Beim Release komm ich zwar auf Stolze ~50 FPS aber irgendwie ist mir das immer noch zu wenig. Gibt es eine Möglichkeit die Geschwindigkeit zu verbessern?
//////////////////////////////////////////////////////////////////////////////
// Map darstellen 64x64 Anfang
void esTilemap::ShowTilemap(int iMapArray[64][64],float fXPos, float fYPos)
{
int iSpriteNumbers = m_iSpritesY * m_iSpritesX; // Gesamtanzahl aller Sprites
int iTilePosX =0; // Position X eines Tiles im Tileset
int iTilePosY =0; // Position Y eines Tiles im Tileset
int iSpriteNumber =0; // Bei welcher Sprite Nummer ist der Rendervorgang?
int iHeight =64; // Höhe des Feldes
int iWidth =64; // Breite des Feldes
int iZaehler =1;
// To Do: Überprüfen ob ein höherer Tilewert eingegeben wurde als exisitert -> Exception !!
// !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Leseschleife start
for (int y =0; y < iHeight; y++)
{
for (int x =0; x < iWidth; x++)
{
for (int pos =0; pos <= iSpriteNumbers; pos++)
{
// iMapArray auslesen
// Werte holen
if (pos == iMapArray[y][x])
{
// Gesuchter Wert der koord Struktur entnehmen und dem SetSubRect übergeben:
sf::IntRect Rect(tile[pos]->iLeftKoord, tile[pos]->iTopKoord, tile[pos]->iRightKoord, tile[pos]->iBottomKoord);
// Gefundener Wert in erstes Sprite schieben
Sprite[iZaehler]->SetSubRect(Rect);
iZaehler++;
break;
}
}
}
}
// Leseschleife Ende
float ZaehlerX =0.0f;
float ZaehlerY =0.0f;
// Renderschleife:
for (int i =1; i <64*64+1; i++)
{
// Auf der X Achse verschieben bis diese zu Ende ist.
if (ZaehlerX < iWidth)
{
Sprite[i]->SetPosition(m_fWidth * ZaehlerX + fXPos, m_fHeight * ZaehlerY + fYPos);
ZaehlerX++;
}
else
{
ZaehlerX =1.0f;
// Wenn X Achse zu Ende ist auf Y Achse springen
ZaehlerY++;
Sprite[i]->SetPosition(0.0f + fXPos, m_fHeight * ZaehlerY + fYPos);
}
esWindow->GetApp()->Draw(*Sprite[i]);
}
}
// Map darstellen 64x64 Ende
//////////////////////////////////////////////////////////////////////////////
Zu meinem 2. Problem:
Bei bestimmte Auflösungen (Eigentlich bei allen außer bei Fullscreen und X*600 Pixeln) wird mein Bild um 10-30 Pixel nach oben verschoben:
Die Sache ist ganz klar: Wenn du 64x64 Tiles einzelnt zeichnest und damit 4096 Drawcalls hast, dann kann die Grafikkarte und Prozessor das gar nicht packen.
Wenn du es schaffst, alles in einem DrawCall zu machen, kanns gut sein,dass du wieder 100 fps oder noch deutlich mehr hast.
@ zera
weil hier die Position von jedem Sprite festgelegt wird.
Ein Arrayindex ist ein Sprite welches bestandteil von der map ist.
na dann die ganze Klasse:
(wobei ich glaub das es eine weile dauert bis mans versteht)
// Edit: Hier siehts schöner aus: http://rafb.net/p/HQHuwt75.html
@ TM: Wüsst ich nicht
@ Jonathan: Wie soll das gehn das ich alle in ein "Drawcall" reinpacke?! Alle einzelne Sprites zu einem Bild zusammenpacken und das dann rendern?!
Dann gibts halt ein Prooblem wenn ich ein Sprite von der Map bewegen will o.ä.
Wie wäre es, wenn du einfach nur die Tiles darstellst die auch auf dem Monitor angezeigt werden? Die anderen brauchste doch nicht rendern bzw. durchlaufen.
Naja, eine Tilemap kannst du ja als zusammenhängendes Polygongitter rendern. Dazu müssten halt sämtliche Tiles die selbe Textur benutzen, aber das kannst du ja per Texturkoordinaten lockerhinbekommen.
Und die Objekte die sich bewegen kann man dann ja noch extra Zeichnen, dürften ja deutlich weniger als 4k sein. Wenn man dann noch so 20 Stück einzelnt zeichnet,ist das kein Problem.
Wenn du aber sehr sehr viele Objekte hast, die sich bewegen, könnte Instancing eine Lösung sein.
// Renderschleife:
for (int i =1; i <64*64+1; i++)
{
// Auf der X Achse verschieben bis diese zu Ende ist.
if (ZaehlerX < iWidth)
{
Sprite[i]->SetPosition(m_fWidth * ZaehlerX + fXPos, m_fHeight * ZaehlerY + fYPos);
ZaehlerX++;
}
else
{
ZaehlerX =1.0f;
// Wenn X Achse zu Ende ist auf Y Achse springen
ZaehlerY++;
Sprite[i]->SetPosition(0.0f + fXPos, m_fHeight * ZaehlerY + fYPos);
}
esWindow->GetApp()->Draw(*Sprite[i]);
}
lässt sich auch gut in die obere einbauen, dabei kannst du auch direkt die 4000 sprite-Instanzen sparen
C-/C++-Quelltext
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
sf::Sprite dummySprite;
dummySprite.setImage(*Image);
for (int y =0; y < iHeight; y++)
{
for (int x =0; x < iWidth; x++)
{
sf::IntRect Rect(tile[ iMapArray[y][x]]->iLeftKoord, tile[iMapArray[y][x]]->iTopKoord, tile[ iMapArray[y][x]]->iRightKoord, tile[iMapArray[y][x]]->iBottomKoord);
// Gefundener Wert in erstes Sprite schieben
dummySprite->SetSubRect(Rect);
dummySprite->SetPosition(m_fWidth *x + fXPos, m_fHeight* y+ fYPos);
esWindow->GetApp()->Draw(dummySprite)
}
}