Problem mit globalem Objekt



  • ch ein Game of life programmiert, anfangs nur für die Konsole, habe es aber letzten Endes doch noch einmal grafisch überarbeitet. Nun bin ich auf folgendes Problem gestoßen:
    Ich erstelle mein Game-Objekt global, damit ich sowohl in der Nachrichtenschleife der WinMain als auch in der WndProc darauf zugreifen kann. In der Nachrichtenschleife führe ich die Generation durch, das sieht wie folgt aus (UpdateWindow(), RegelnAnwenden(), WeltenTasuchen()). Im WM_ PAINT case Block führe ich die Display-Methode meines Objektes aus.. Und genau hier liegt das Problem, nichts passiert... Ändere ich die Display-Methode so ab, dass nichts gezeichnet wird, sondern die Zellen über die MessageBox ausgegeben werden (Nur um mich zu versichern das der Fehler nicht in der Game-Klasse liegt) scheint jede Zelle in meiner Spielwelt tot zu sein (Was sie nicht sind!). Führe ich die Display-Methode nun nicht im WM_PAINT case aus, sondern in der Nachrichtenschleife direkt hinter der Generation stimmt die Ausgabe allerdings.
    Da das Game-Objekt global deklariert wurde müsste der Inhalt der darin befindlichen Spielwelt eigentlich sowohl in der WinMain als auch in der WndProc übereinstimmen?! Stehe grade echt auf dem Schlauch.. Wo könnt der Fehler liegen?

    // Global
    Game GameOfLife(SCREEN_WIDTH, SCREEN_HEIGHT);
    
    WinMain
    {
        // ...
    	while (true)
    	{
    		if (PeekMessage(&mMessage, NULL, 0, 0, PM_REMOVE))
    		{
    			// Nachrichten übersetzen
    			TranslateMessage(&mMessage);
    
    			// Nachricht zur Fensterprozedur senden
    			DispatchMessage(&mMessage);
    
    			if (mMessage.message == WM_QUIT)
    				break;
    		}
    		else
    		{
    			// ----------------------------------------
    			// Game Code hier einfügen
    			GameOfLife.Generation();
    		}
    	}
    	// ...
    }
    
    WndProc
    {
        // ...
        case WM_PAINT:
        {
            Paintstruct ps;
            HDC hDc = BeginPaint(hWnd, &ps);
    
            GameOfLife.Display(hDc);
    
            hDc = EndPaint(hWnd, &ps);
        } break;
        // ...
    }
    

    Bitte um Hilfe... MfG Inv151673 🙂



  • // delete



  • Poste bitte Code der 1:1 aus deinem Projekt rauskopiert worden ist. In modifiziertem Code Fehler suchen ist einfach uninteressant.



  • GameOfLife.cpp

    #include <GameOfLife.h>
    
    Game GameOfLife(SCREEN_WIDTH, SCREEN_HEIGHT);
    
    int WINAPI WinMain(
    	HINSTANCE	hInstance,
    	HINSTANCE	hPrevInstance,
    	LPSTR		lpCmdLine,
    	int			iCmdShow
    	)
    {
    	HWND		hWnd;
    	WNDCLASSEX	WndClass;
    	RECT		WindowRect;
    	MSG			mMessage;
    
    	ZeroMemory(&WndClass, sizeof(WNDCLASSEX));
    	WndClass.cbSize = sizeof(WNDCLASSEX);
    	WndClass.style = CS_HREDRAW | CS_VREDRAW;
    	WndClass.lpfnWndProc = WndProc;
    	WndClass.hInstance = hInstance;
    	WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    	// WndClass.hbrBackground	= (HBRUSH)COLOR_WINDOW;
    	WndClass.lpszClassName = L"MainWindow";
    
    	RegisterClassEx(&WndClass);
    
    	// Fenstergröße korrigieren
    	WindowRect = { 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT };
    	AdjustWindowRect(
    		&WindowRect,
    		WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
    		NULL
    		);
    
    	hWnd = CreateWindowEx(
    		NULL,
    		L"MainWindow",		// Fensterklasse
    		L"Game of life",	// Fenstertitel
    		WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,	// Fenster-Styles
    		CW_USEDEFAULT,		// X-Position
    		CW_USEDEFAULT,		// Y-Position
    		SCREEN_WIDTH,		// Breite
    		SCREEN_HEIGHT,		// Höhe
    		NULL,
    		NULL,				// Menü
    		hInstance,			// Instanz
    		NULL
    		);
    
    	ShowWindow(hWnd, iCmdShow);
    
    	// Spiel initialisieren
    	GameOfLife.Initialize(1, hWnd);	// 1 = Conway
    
    	while (true)
    	{
    		if (PeekMessage(&mMessage, NULL, 0, 0, PM_REMOVE))
    		{
    			// Nachrichten übersetzen
    			TranslateMessage(&mMessage);
    
    			// Nachricht zur Fensterprozedur senden
    			DispatchMessage(&mMessage);
    
    			if (mMessage.message == WM_QUIT)
    				break;
    		}
    		else
    		{
    			// ----------------------------------------
    			GameOfLife.Generation();
    		}
    	}
    
    	return mMessage.wParam;
    }
    
    LRESULT CALLBACK WndProc(
    	HWND	hWnd,
    	UINT	uiMessage,
    	WPARAM	wParam,
    	LPARAM	lParam
    	)
    {
    	switch (uiMessage)
    	{
    	case WM_PAINT:
    	{
    		PAINTSTRUCT ps;
    		HDC hDc = BeginPaint(hWnd, &ps);
    
    		GameOfLife.Display(hDc);
    
    		EndPaint(hWnd, &ps);
    	} break;
    	case WM_DESTROY:
    		PostQuitMessage(0);
    		return 0;
    		break;
    	}
    
    	// Alle Nachrichten "bearbeiten", welche nicht im 
    	// switch-Block abgefangen wurden
    	return DefWindowProc(hWnd, uiMessage, wParam, lParam);
    }
    

    Die Display-Methode aus Game.cpp

    void Game::Display(HDC hDc)
    {
    	int iWidth = pWorld->GetWidth(),
    		iHeight = pWorld->GetHeight();
    	for (int y = 0; y < iHeight; y++)
    	{
    		for (int x = 0; x < iWidth; x++)
    		{
    			if (pWorld->GetCell(x, y).uiCell)
    				SetPixel(hDc, x, y, RGB(0, 0, 255));
    			else
    				SetPixel(hDc, x, y, RGB(225, 255, 255));
    		}
    	}
    }
    


  • Wm_paint wird nur wenn nötig aufgerufen, du bräuchtest also einen timer, welcher das fenster ständig invalidiert, wenn du die malarbeiten in wm_paint erledigen möchtest. Anstatt der messageBox empfehle ich dir einen richtigen Debugger.



  • Soweit ich weiss solltest du die DefWindowProc nicht aufrufen wenn du WM_PAINT selbst behandelst. Statt dessen einfach 0 zurückgeben.
    Wird aber an deinem Problem nix ändern.

    Wirf mal ein InvalidateRect(hWnd, 0, false); nach dem GameOfLife.Generation(); rein.

    Und das

    roflo schrieb:

    Anstatt der messageBox empfehle ich dir einen richtigen Debugger.

    würde ich dir auf empfehlen. Lern so früh wir möglich mit dem Debugger umzugehen. Der ist nicht nur beim Fehler-Finden nützlich, sondern hilft mMn. auch gut zu verstehen was in einem Programm abgeht - gerade wenn man noch Anfänger ist.


  • Mod

    Was erwartest Du? Das Programm läuft ja nicht weiter...

    Also was passiert:
    Dein Programm läuft durch die Nachrichtenschelifen, holt Input Nachrichten und verteilt diese.
    Auf diesem Weg werden dann auch zwischendrin WM_PAINT Nachrichten erzeugt.

    Wenn DU jetzt eine Messagebox anzeigst, dann muss Dir klar sein, dass diese eine eigene Nachrichtenschleife hat. Das heißt es werden weiterhin WM_PAINT Nachrichten erzeugt und Input Nachrichten abgerufen und verarbeitet, aber Deine Nachrichtenschleife läuft nicht mehr...

    Da Dein Update aber in der Nachrichtenschleife läuft wird entsprechend auch keine nächste Generation erzeugt.

    Damit Dein Spiel auch nicht in jedem Nachrichten Zyklus eine Generation erzeugt, würde ich Dir raten auch die Erzeugung der Generation in einen WM_TIMER Handler zu verlagern in die Fensterklasse oder über einen globalen Timer Callback abzuhandeln.


Anmelden zum Antworten