[C++/directX] scrolende Karte funktioniert nicht

daemon777

Lt. Commander
Registriert
Dez. 2003
Beiträge
1.371
Hi,

Ich hab mal wieder ein Problem. Diesmal ein etwas komplizierteres würde ich mal sagen. Und zwar geht es um DirectDraw in Directx. Ich habe ein paar texturen im Format 64*64 und möchte die auf den Bildschirm zaubern. Zu erst habe ich das einfach so gemacht dass ich so viele von einer Textur auf den Bildschirm knalle wie es geht. Allerdings möchte ich nun eine Art Karte wie in einem Computerspiel erstellen.
Also der Player hat zB am anfang die Position 0. Der Player befindet sich immer in der Bildschirm Mitte. Also werden die ersten 10 Bilder der Karte dargestellt. Wenn der Player allerdings dann weitergeht sollen die Bilder 2-11 gezeichnet werden. Allerdings funktioniert das nicht so ganz.

Ich denke mal dass ich irgendwo ein Logikproblem drinn habe.

Ich habe die Karte in verschiedene Tiles aufgeteilt. Ein Tile entspricht einem begehbaren Bereich für den Player und einer Textur. Hier ist die Definition eines Tiles:

Code:
 Tiles
# define chess  0
# define star   1

class tile
{
  public:
	int texture;
	int walkable;
	int isaktion;
	int aktion;

	tile();
	tile(int mtexture,int mwalkable,int misaktion,int maktion);
};

tile::tile()
{
	texture=chess;
	walkable=1;
	isaktion=0;
}

tile::tile(int mtexture,int mwalkable,int misaktion,int maktion)
{
	texture=mtexture;
	walkable=mwalkable;
	isaktion=misaktion;
	aktion=maktion;
}

Dann habe ich eine Karte erstellt die diese Tiles in eine Map lädt:

Code:
 DIe Karte

class lvl1
{
	//map level1;
  public:
	int sizex;
	int sizey;
	
	tile alletiles[/*sizex*/32][/*sizey*/20];
	lvl1();
	~lvl1();

};

lvl1::lvl1()
{	
	for(int y=0;y<20;y++)
	{
		for(int x=0;x<32;x++)
		{
			alletiles[x][y].texture=chess;
			alletiles[x][y].walkable=1;
			alletiles[x][y].isaktion=0;
			alletiles[x][y].aktion=0;
		}
	}

	alletiles[16][5].texture=star;
	alletiles[16][5].texture=star;
	alletiles[16][5].texture=star;
	alletiles[16][5].texture=star;
	alletiles[16][5].texture=star;
}

lvl1::~lvl1()
{
	
}

Dann ist noch die Player klasse wichtig. Ist zum glück bisher relativ kurz:

Code:
 Player

class player
{
private:
	int relxpos;
	int relypos;
public:
	player();
	int getrelxpos(){return relxpos;}
	int getrelypos(){return relypos;}
	void setrelxpos(){relxpos++;}
	void setrelypos(){relypos++;}
};

player::player()
{
	relxpos=0;
	relypos=0;
}

Das sind die wichtigen Klassen und Strukturen des Programms. Jetzt kommen noch die wichtigen Teile des Hauptprogramms:

Code:
 main

//includes und andere unwichtige definitionen

tile sichtfeld[16][12];
tile aktlvl[3000][3000];

player dplayer;
lvl1 mlvl1;    

int getmap()
{
	if(anzahl_levels<=level)
	{
		return 2;
	}

	switch(level)
	{
		case 1:
			for(int x=0;x<32;x++)
			{
				for(int y=0;y<20;y++)
				{
					aktlvl[x][y]=mlvl1.alletiles[x][y];
				}
			}
			aktx=32;
			akty=16;
	}
	level++;
	return 1;
}


int getkartenausschnitt()
{
	for(int x=0;x<aktx && x<15;x++)
	{
		for(int y=0; y<akty && y<11;y++)
		{
			sichtfeld[x][y]=aktlvl[x+dplayer.getrelxpos()][y+dplayer.getrelypos()];
		}
	}

	return 1;	
}

//in einer Klasse namens Display steht nun folgendes:

void hintergrund(){dsply.Blt(0,0,hgrnd);}
	void tex(int px,int py){dsply.Blt(px*64,py*64,mtex);}
	void check(int px, int py){dsply.Blt(px*64,py*64,mcheck);}
	void player(){dsply.Blt(rpggame_nettobreite/2-32,rpggame_nettohoehe/2-32,mplayer);}

//Im Callback Handler sind denke ich mal WM_PAINT und IDM_RIGHT wichtig
//IDM_Right wird aufgerufen wenn die entrpechende taste gedrückt wird

case IDM_RIGHT:
			dplayer.setrelxpos();
			dplayer.setrelypos();
		
			PostMessage(hWnd,WM_PAINT,0,0);

case WM_PAINT:
			getkartenausschnitt();
			rpggame_display.hintergrund();
						
			for(int ypos=0;ypos<12;ypos++)
			{
				for(int xpos=0;xpos<15;xpos++)
				{
					if(sichtfeld[xpos][ypos].texture==chess)
					{
						rpggame_display.check(xpos,ypos);
					}
					else
						rpggame_display.tex(xpos,ypos);
		
				}
			}
			
			
			rpggame_display.player();
			rpggame_display.present();	
	}

Nun das wars. Ich kann leider nicht den Fehler finden. Ich bekomme keine Fehlermeldung oder so aber es ändert sich eifnach nicht wenn cih auf die entsprechende taste drücke. Ich hatte mal eine Message Box unter IDM_RIGHT eingefügt und dieser Part wurde auch aufgerufen aber dennoch hat sich das Bild aufm Bildschirm sich nicht geändert. WM_PAINT wurde danach auch aufgerufen allerdings ist irgendwie nichts passiert.

Ich weiß das ist jetzt ziemilch viel Code aber ich weiß einfach nicht mehr weiter.

Vielleicht kann mir ja doch jemand helfen. Jedenfalls schonmal danke auch wenns eventuell nur fürs durchlesen ist.
 
Hallo daemon777,

ob es daran liegt weiss ich nicht, aber hier fehlt ein break:

case IDM_RIGHT:
dplayer.setrelxpos();
dplayer.setrelypos();

-> UpdateWindow() oder InvalidateRect() wäre auch einen Versuch Wert

PostMessage(hWnd,WM_PAINT,0,0);

--> break;

case WM_PAINT:

MfG

Arnd
 
Hm. Das break ist sicherlich eine gute Idee allerdings hat es leider auch nichts geändert :(
Trotzdem danke.

Was hat es denn mit UpdateWindow und InvalidRect auf sich ? Kenn mich leider noch nicht so mit directx aus.
 
Hallo daemon777,

WM_PAINT zeichnet nur die Bereiche neu die auch geändert worden sind. Diese Bereich werden intern in Rechtecken verwaltet.

Wenn dein Problem jetzt ist, das Du keine Änderungen am Bildschirm siehst, kann ein kompletter Refresh des Fensters da schon helfen.
InvalidateRect(0) markiert das gesamte Fenster als ungültig und damit wird das ganze Fenster beim nächsten WM_PAINT neu gezeichet.

Da das break fehlt wurde die Logik für WM_PAINT ja bereits durchlaufen.
Daher ist es schon denkbar das ein darauf folgendes reales WM_PAINT, das durch dein Postmessage() ausgelöst wurde dann ins leere greift.

Und das unabsichtliche WM_PAINT kann fehlgeschlagen haben, weil der falsche Gerätekontext zum zeichnen benutzt wurde. Weil der eigentliche Event ja ein rechter Mausklick war.

Der zweite mögliche Fehler wäre einfach eine fehlerhafte Koordinaten Berechnung.
Sprich das Du ausserhalb des sichtbaren Fensters zeichnest und deshalb keine Änderung siehst.

Da hilft eine Ausgabe der berechneten Koordinaten in diesem Fall.

Allerdings müsstest Du auch Deine Aussage "es geht nicht" etwas genauer formulieren.

Weil den Code habe ich nur überflogen und nicht ausprobiert.

MfG

Arnd

PS: Ich habe gerade gesehen das Du kein VC benutzt sondern den Gnu C Compiler.
Von daher würde sich die Onlinehilfe von MS anbieten. Da müssten alle Ausrufe ausführlich beschrieben sein.
 
Zuletzt bearbeitet:
Erstmal zum Compiler: Ich habe einmal den Dev_c++ von früher und noch einmal aus einem Buch den VC++ autoren Version ;)

Mit es geht nicht meine ich dass einfach nichts passiert. Sprich das Bild auf dem Bildschirm bleibt das selbe. Es wird zwar das Anfangsbild gezeichnet aber nicht mehr. Das ich auserhalb des sichtbaren Bereichs zeichne will ich mit meinem Code ja gerade verhindern :D Deswegen die scrollende Karte. Und es kann eigentlich nicht sein weil dann die Schleife abbrechen müsste.

Das mit dem Update kram und so werde ich mal ausprobieren Danke ! :freaky:


Argh ich könnte mir in den A**** beißen. Das mit dem UpdateWindow und so weiter ist möglicher weiße auch erforderlich. Allerdings war mein Fehler ganz wo anders. Bei der loadmap funktion hatte ich nämlich eine Abfrage drinn die verhindert dass eine Map geladen wird die es gar nicht gibt. Allerdings verhindert sie auch dass die letzte Map des Spieles geladen wird. Grund ist ein einfaches '<='. daraus wird einfach ein '='.
Trotzdem Danke für deine Hilfe.
 
Zuletzt bearbeitet:
Prima, wenn es jetzt geht.

Der Aufruf von dem loadmap ist aber in Deinem Beispielcode nicht enthalten, oder?

MfG

Arnd
 
Doch :D
Heißt aber hier getmap() ;)
 
Zurück
Oben