[C++] Timer Problem

V1tzl1

Lt. Junior Grade
Registriert
Sep. 2004
Beiträge
384
Hi ich hab mal ne Frage bzgl. der C++ Timer.
Ich möchte ein kleines Spiel Programmieren mit dem PacMan Grundgerüst. Später möchte ich dazu noch eigene Ideen hinzufügen und das ganze etwas abändern.
Aber zur Zeit möchte ich erstmal das Grundgerüst zum Laufen bekommen.
Damit der Pacman sich immer im gleichen Tempo bewegt und nicht entsprechenmd dem Rhytmus, indem auf die Tastatur gehämmert wird.
Desshalb hab ich einen Timer gesetzt der jdesmal den PMan bewegt.

Den Rhytmus, indem der Timer ausgelöst wird, hab ich in einer Konstaten definiert, damit ich wärend der Entwicklung die Geschwindigkeit variieren kann.
Jetz habe ich lange ausgeholt und bin nu zu meinem Problem gekommen. Egal was ich Intervalle ich dem timer gebe, mein PMan bewegt sich immer gleich schnell/langsam, seis nun mit dem Intervall 1 oder 500.
Hier ist der Code.
Ich weiß ihr gebt gerne Ratschläge, wie man den Code efizienter gestalten könnte und das ist natürlich auch gut so, denn ich will dabei ja was lernen, aber versucht bitte erst mein kleines Problem zu lösen und dann Vorschläge über effizienters Programmieren geben.
Schonmal Danke im Vorraus, V1tzl1
Code:
#include <windows.h>

#define WA 0 // Wand
#define PO 1 // Punkt
#define GA 2 // Gang
#define PM 3 // PacMan

#define FAKTOR  30  // Pixel pro Kachel
#define PADDING 150 // Pixel li,ob Abstand

#define PM_TIMER 500 // Timer für PMan

/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

/*  Make the class name into a global variable  */
char szClassName[ ] = "WindowsApp";
int area = 1, menuenumber = 1, level = 1, move;
HDC hdc;
HWND hwnd;
int x_max = 16, y_max = 12;
int pmanX = 8, pmanY = 6;
int map1[13][18] = {
                    {WA, WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA, WA},
                    {WA, PO,PO,PO,WA,PO,PO,PO,WA,WA,PO,PO,PO,PO,WA,PO, WA},
                    {WA, PO,WA,PO,PO,PO,WA,PO,PO,WA,WA,PO,WA,PO,PO,PO, WA},
                    {WA, PO,WA,WA,PO,WA,WA,WA,PO,WA,PO,PO,WA,WA,WA,PO, WA},
                    {WA, PO,PO,WA,PO,PO,PO,PO,PO,PO,PO,WA,WA,PO,PO,PO, WA},
                    {WA, WA,PO,WA,PO,WA,PO,WA,WA,WA,PO,PO,PO,PO,WA,WA, WA},
                    {WA, PO,PO,PO,PO,WA,PO,PO,PO,PO,PO,WA,WA,PO,PO,WA, WA},
                    {WA, PO,WA,WA,WA,WA,PO,WA,WA,WA,PO,PO,PO,WA,PO,WA, WA},
                    {WA, PO,PO,PO,PO,WA,PO,PO,PO,PO,PO,WA,PO,PO,PO,PO, WA},
                    {WA, PO,WA,WA,PO,PO,PO,WA,WA,WA,PO,WA,WA,WA,WA,PO, WA},
                    {WA, PO,WA,PO,PO,WA,PO,WA,PO,WA,PO,PO,PO,PO,WA,PO, WA},
                    {WA, PO,PO,PO,WA,WA,PO,PO,PO,PO,PO,WA,WA,PO,PO,PO, WA},
                    {WA, WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA, WA}
                   }; 

void map_ini(int level);
void keydown(WPARAM wParam);
void clear(int x, int y, int x2, int y2);
void hauptmenue(), game(), optionen(), show(), draw(int x, int y, int art);
void move_pman(int direction); // 1 => oben, 2 => rechts, 3 => unten, 4 => links

int WINAPI WinMain (HINSTANCE hThisInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR lpszArgument,
                    int nFunsterStil)

{
    HWND hwnd;               /* This is the handle for our window */
    MSG messages;            /* Here messages to the application are saved */
    WNDCLASSEX wincl;        /* Data structure for the windowclass */

    /* The Window structure */
    wincl.hInstance = hThisInstance;
    wincl.lpszClassName = szClassName;
    wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
    wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
    wincl.cbSize = sizeof (WNDCLASSEX);

    /* Use default icon and mouse-pointer */
    wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
    wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
    wincl.lpszMenuName = NULL;                 /* No menu */
    wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
    wincl.cbWndExtra = 0;                      /* structure or the window instance */
    /* Use Windows's default color as the background of the window */
    wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

    /* Register the window class, and if it fails quit the program */
    if (!RegisterClassEx (&wincl))
        return 0;

    /* The class is registered, let's create the program*/
    hwnd = CreateWindowEx (
           0,                   /* Extended possibilites for variation */
           szClassName,         /* Classname */
           "V1tzl1's Pacman",       /* Title Text */
           WS_POPUP, /* default window */
           0,       /* Windows decides the position */
           0,       /* where the window ends up on the screen */
           800,                 /* The programs width */
           600,                 /* and height in pixels */
           HWND_DESKTOP,        /* The window is a child-window to desktop */
           NULL,                /* No menu */
           hThisInstance,       /* Program Instance handler */
           NULL                 /* No Window Creation data */
           );

    /* Make the window visible on the screen */
    ShowWindow (hwnd, nFunsterStil);
    DEVMODE dmScreenSettings = {}; 
    dmScreenSettings.dmSize=sizeof(dmScreenSettings); 
    dmScreenSettings.dmPelsWidth = 800; 
    dmScreenSettings.dmPelsHeight = 600; 
    dmScreenSettings.dmBitsPerPel = 32; 
    dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; 
    ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
    
    /* Run the message loop. It will run until GetMessage() returns 0 */
    while (GetMessage (&messages, NULL, 0, 0))
    {
        /* Translate virtual-key messages into character messages */
        TranslateMessage(&messages);
        /* Send message to WindowProcedure */
        DispatchMessage(&messages);
    }

    /* The program return-value is 0 - The value that PostQuitMessage() gave */
    return messages.wParam;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND handle, UINT message, WPARAM wParam, LPARAM lParam)
{
 hwnd = handle;
    switch (message)                  /* handle the messages */
    {
        case WM_CREATE:
            hdc = GetDC(hwnd);
            SetBkMode(hdc, TRANSPARENT);
            break;
        case WM_PAINT:
            clear(0,0,800,600);
            switch(area)
             {
              case 1:
                hauptmenue();
                break;
              case 2:
                game();
                break;
              case 3:
                optionen();
                break;
             }
            ValidateRect(hwnd, 0);
            break;
        case WM_KEYDOWN:
            keydown(wParam);
            break;
        case WM_TIMER:
          switch(wParam)
           {
            case 0: // Pacman Timer
            move_pman(move);
            break;
           }
          break;
        case WM_DESTROY:
            PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
            break;
        default:                      /* for messages that we don't deal with */
            return DefWindowProc (hwnd, message, wParam, lParam);
    }

    return 0;
}

void keydown(WPARAM wParam)
 {
  switch(wParam)
    {
     case VK_ESCAPE:
        if(area != 1)
         {
          clear(0, 0, 800, 600);
          if(area == 2)
           {
            KillTimer(hwnd, 0); // Löscht den PMan Timer
           }
          hauptmenue();
         }
        break;
     case VK_DOWN:
        if(area == 1)
         {
          if(menuenumber < 3)
           {
            menuenumber++;
            hauptmenue();
           }
          else
           {
            menuenumber = 1;
            hauptmenue();
           }
         }
        if(area == 2)
          move = 3;
        break;
      case VK_UP:
        if(area == 1)
         {
          if(menuenumber > 1)
           {
            menuenumber--;
            hauptmenue();
           }
          else
           {
            menuenumber = 3;
            hauptmenue();
           }
         }
        if(area == 2)
          move = 1;
        break;
      case VK_RETURN:
        if(area == 1)
         {
          switch(menuenumber)
           {
            case 1:
              game();
              break;
            case 2:
              optionen();
              break;
            case 3:
              SendMessage(hwnd, WM_DESTROY, 0, 0);
              break;
           }
         }
        break;
      case VK_LEFT:
        if(area == 2)
          move = 4;
        break;
      case VK_RIGHT:
        if(area == 2)
          move = 2;
        break;
     }
 }
 
void clear(int x, int y, int x2, int y2)
 {
  HBRUSH background = CreateSolidBrush(RGB(255,255,255));
  HPEN pen = CreatePen(PS_SOLID,1,RGB(255,255,255));
  SelectObject(hdc, background);
  SelectObject(hdc, pen);
  Rectangle(hdc, x, y, x2, y2);
  return;
 }
 
void hauptmenue()
 {
  area = 1;
  TextOut(hdc, 300, 50, "V1tzl1's Pacman", 15);
  TextOut(hdc, 350, 80, "#:- Hauptmenü -:#", 17);
  if(menuenumber == 1)
   {
    SetTextColor(hdc, RGB(100, 100, 255));
   }
  TextOut(hdc, 250, 150, "Spiel starten", 13);
  SetTextColor(hdc, 0);
  if(menuenumber == 2)
   {
    SetTextColor(hdc, RGB(100, 100, 255));
   }
  TextOut(hdc, 250, 180, "Optionen", 8);
  SetTextColor(hdc, 0);
  if(menuenumber == 3)
   {
    SetTextColor(hdc, RGB(100, 100, 255));
   }
  TextOut(hdc, 250, 210, "Spiel beenden", 13);
  SetTextColor(hdc, 0);
  return;
 }
 
void game()
 {
  SetTimer(hwnd, 0, PM_TIMER, 0);
  area = 2;
  clear(0,0,800,600);
  show();
  return;
 }
 
void optionen()
 {
  area = 3;
  clear(0,0,800,600);
  TextOut(hdc, 150, 150, "Optionen", 8);
  return;
 }
 
void  move_pman(int direction) // 1 => oben, 2 => rechts, 3 => unten, 4 => links
 {
  move = 0;
  int newX = pmanX, newY = pmanY;
  switch(direction)
   {
    case 0:  // Falls keine Taste gedrueckt
      return;
      break;
    case 1:
      newY = pmanY - 1;
      break;
    case 2:
      newX = pmanX + 1;
      break;
    case 3:
      newY = pmanY + 1;
      break;
    case 4:
      newX = pmanX - 1;
      break;
   }
  if(newX < x_max && newX > 0 && newY < y_max && newY > 0 && map1[newY][newX] == PO)
   {
    draw(newX, newY, 3);
    draw(pmanX, pmanY, 2);
     
    pmanX = newX;
    pmanY = newY;
   }
  else
   SendMessage(hwnd, WM_TIMER, 0, 0);
   return;
  return ;
 }

void show()
 {
  
  // Rahmen
  HPEN   pschwarz   = CreatePen(PS_SOLID,2,RGB(0,0,0));
  SelectObject(hdc, pschwarz);
  Rectangle(hdc, 179,179,(x_max * 30 + 152),(y_max * 30 + 152));
  
  // Map
  int x, y;
  for(y = 1; y < y_max; y++)
   {
    for(x = 1; x < x_max; x++)
     {
      switch(map1[y][x])
       {
        case WA:
          draw(x,y,0);
          break;
        case PO:
          draw(x,y,1);
          break;
       }
     }
   }  
  draw(pmanX, pmanY, 3);
 }
 
void map_ini(int level)
 {
  switch(level)
   {
    case 1:
       // Start Level 1
       x_max = 15;
       y_max = 11;
       
       // End   Level 1
    break;
   }
  return;
 }

void draw(int x, int y, int art)
 {
  int x1, x2, y1, y2;
  HPEN   pen;
  HBRUSH brush;
  x1 = (x  )*FAKTOR+PADDING;
  x2 = (x+1)*FAKTOR+PADDING;
  y1 = (y  )*FAKTOR+PADDING;
  y2 = (y+1)*FAKTOR+PADDING;
  switch(art)
   {
    case 0:
      pen   = CreatePen(PS_SOLID,1,RGB(255,0,0));
      brush = CreateSolidBrush(RGB(255,0,0));
      SelectObject(hdc, pen);
      SelectObject(hdc, brush);
      Rectangle(hdc, x1, y1, x2, y2);
      break;
    case 1:
      pen   = CreatePen(PS_SOLID,1,RGB(0,255,0));
      brush = CreateSolidBrush(RGB(0,255,0));
      SelectObject(hdc, pen);
      SelectObject(hdc, brush);
      Rectangle(hdc, x1, y1, x2, y2);
      break;
    case 2:
      pen   = CreatePen(PS_SOLID,1,RGB(0,0,255));
      brush = CreateSolidBrush(RGB(0,0,255));
      SelectObject(hdc, pen);
      SelectObject(hdc, brush);
      Rectangle(hdc, x1, y1, x2, y2);
      break;
    case 3:
      pen   = CreatePen(PS_SOLID,1,RGB(0,0,255));
      brush = CreateSolidBrush(RGB(0,0,255));
      SelectObject(hdc, pen);
      SelectObject(hdc, brush);
      Rectangle(hdc, x1, y1, x2, y2); 
      pen   = CreatePen(PS_SOLID,1,RGB(255,255,0));
      brush = CreateSolidBrush(RGB(255,255,0));
      SelectObject(hdc, pen);
      SelectObject(hdc, brush);
      Ellipse(hdc, x1+2, y1+2, x2-2, y2-2);   
      break;
   }
 }

So und da das ne ganze menge Code ist, hab ich den auch nochmal als CPP Datei hochgeladen, damit ihr euch dsas in nem Editor anschauen könnt.
Ich benutze übrigens DevC++
 

Anhänge

  • PacMan.zip
    3,8 KB · Aufrufe: 375
Hallo V1tzl1,

also ich habe mal Deinen Code kompiliert. Aber der Pacman bewegt sich bei mir nicht automatisch.

Code:
void  move_pman(int direction) // 1 => oben, 2 => rechts, 3 => unten, 4 => links
 {
//  move = 0;
  int newX = pmanX, newY = pmanY;
  switch(direction)
   {
    case 0:  // Falls keine Taste gedrueckt
      return;
      break;
    case 1:
      newY = pmanY - 1;
      break;
    case 2:
      newX = pmanX + 1;
      break;
    case 3:
      newY = pmanY + 1;
      break;
    case 4:
      newX = pmanX - 1;
      break;
   }
  if(newX < x_max && newX > 0 && newY < y_max && newY > 0 && map1[newY][newX] == PO)
   {
    draw(newX, newY, 3);
    draw(pmanX, pmanY, 2);
     
    pmanX = newX;
    pmanY = newY;
   }
  else
//   SendMessage(hwnd, WM_TIMER, 0, 0);
   return;
  return ;
 }

Das hier wirkt aber Wunder :-). Danach rast der Pacman auch mit 100ms durch die Gegend.

Ansonsten das Spiel gefällt mir. Die Übersichtlichkeit des Codes ist aber noch zu verbessern.

MfG

Arnd
 
Hall Arnd, erstmal vorweg, vielen Dank, dass du dir den, ja nicht gerade kurzen Quelltext mal angesehen hast.
hmm ja was soll ich sagen, war ja eigentlich nen blöder Fehler mit dem move = 0.
Mit dem Send_Message wollte ich bewirken, dass wenn man gegen eine Wand laufen wollte, dass man dann gleich weiter laufen kann und nicht erst warten muss.
Und ohne die move = 0 zeile, geht das auch wunderbar.

Zum Thema übersichtlichkeit, habe ich ja in meinem ersten Post schon gesagt, dass konstruktive kritik immer gern gesehen ist und da das Problem ja jetz gelöst ist, schieß los, wo würdest du was besser/übersichtlicher machen?

MfG V1tzl1
 
Hallo V1tzl1,

- hauptsächlich habe ich die Formatierung geändert und die lokalen Variablen auf 0 initialisiert.

- Im WM_PAINT den Timer dauernd neu zu starten ist nicht gut, daher eine neue Funktion startTimer().
Ein Timer sollte auch nicht die ID 0 verwenden.
Wenn Du Dir selber WM_TIMER Events schickst, musst Du auf Stackoverflows achten.
Das war das erste was ich bekomme habe.

- Du legst dauernd neue Objekte mit CreatePen an, die müssen auch deleted werden.
Das gibt sonst einen Ressourcenfresser. Das kann man auch einfach mit dem Taskmanager kontrollieren in dem man die verbrauchten Objekte/Handles mit anzeigen lässt.

- Die WindowProc sollte auch öfter mal das DefWindowProc aufrufen.

- Im WM_PAINT sollte man BeginPaint und EndPaint aufrufen.

- Einen DC den man mit GetDC holt muss man auch mit ReleaseDC wieder freigeben.

- Ausserdem habe ich ein Header File eingeführt.
Das schafft Übersicht über die vorhandenen Funktionen.

- Das ChangeDisplaySettings habe ich auskommentiert und dafür das Fenster grösser gemacht.
Zum debuggen ist das sehr lästig.
Da Du auch das Programmumschalten mit ALT+TAB nicht abfängst, wäre es sinnvoller das Fenster dem aktuellen Desktop anzupassen und die Zeichenroutinen auf variable Fenstergrössen auszulegen.
Entweder indem man einfach die Klötze grösser macht, oder einfach das vorhandene Pacman Fenster zentriert.

main.cpp
Code:
#include "main.h"

int map1[13][18]    = {
	{WA, WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA, WA},
	{WA, PO,PO,PO,WA,PO,PO,PO,WA,WA,PO,PO,PO,PO,WA,PO, WA},
	{WA, PO,WA,PO,PO,PO,WA,PO,PO,WA,WA,PO,WA,PO,PO,PO, WA},
	{WA, PO,WA,WA,PO,WA,WA,WA,PO,WA,PO,PO,WA,WA,WA,PO, WA},
	{WA, PO,PO,WA,PO,PO,PO,PO,PO,PO,PO,WA,WA,PO,PO,PO, WA},
	{WA, WA,PO,WA,PO,WA,PO,WA,WA,WA,PO,PO,PO,PO,WA,WA, WA},
	{WA, PO,PO,PO,PO,WA,PO,PO,PO,PO,PO,WA,WA,PO,PO,WA, WA},
	{WA, PO,WA,WA,WA,WA,PO,WA,WA,WA,PO,PO,PO,WA,PO,WA, WA},
	{WA, PO,PO,PO,PO,WA,PO,PO,PO,PO,PO,WA,PO,PO,PO,PO, WA},
	{WA, PO,WA,WA,PO,PO,PO,WA,WA,WA,PO,WA,WA,WA,WA,PO, WA},
	{WA, PO,WA,PO,PO,WA,PO,WA,PO,WA,PO,PO,PO,PO,WA,PO, WA},
	{WA, PO,PO,PO,WA,WA,PO,PO,PO,PO,PO,WA,WA,PO,PO,PO, WA},
	{WA, WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA,WA, WA}
}; 

int WINAPI WinMain (HINSTANCE hThisInstance,
					HINSTANCE hPrevInstance,
					LPSTR lpszArgument,
					int nFunsterStil)
{
	HWND       hwnd = 0;               /* This is the handle for our window */
	int        lRet = 0;
	MSG        messages;            /* Here messages to the application are saved */
	WNDCLASSEX wincl;        /* Data structure for the windowclass */

	ZeroMemory( &wincl, sizeof wincl );
	/* The Window structure */
	wincl.hInstance     = hThisInstance;
	wincl.lpszClassName = szClassName;
	wincl.lpfnWndProc   = WindowProcedure;      /* This function is called by windows */
	wincl.style         = CS_DBLCLKS;                 /* Catch double-clicks */
	wincl.cbSize        = sizeof (WNDCLASSEX);

	/* Use default icon and mouse-pointer */
	wincl.hIcon         = LoadIcon   (NULL, IDI_APPLICATION);
	wincl.hIconSm       = LoadIcon   (NULL, IDI_APPLICATION);
	wincl.hCursor       = LoadCursor (NULL, IDC_ARROW);
	wincl.lpszMenuName  = NULL;                 /* No menu */
	wincl.cbClsExtra    = 0;                      /* No extra bytes after the window class */
	wincl.cbWndExtra    = 0;                      /* structure or the window instance */
	/* Use Windows's default color as the background of the window */
	wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

	/* Register the window class, and if it fails quit the program */
	if (!RegisterClassEx (&wincl))
		return 0;

	HWND lWnd   = GetDesktopWindow();
	HDC  lDC    = GetDC(lWnd);
	gDesktop.cx = GetDeviceCaps(lDC, HORZRES);
	gDesktop.cy = GetDeviceCaps(lDC, VERTRES);
	gWndSize.cx = gDesktop.cx; // 800;
	gWndSize.cy = gDesktop.cy; // 600;
	ReleaseDC(lWnd, lDC);
	lDC = 0;

	/* The class is registered, let's create the program*/
	hwnd = CreateWindowEx (
		0,                   /* Extended possibilites for variation */
		szClassName,         /* Classname */
		"V1tzl1's Pacman",   /* Title Text */
		WS_POPUP,            /* default window */
		gDesktop.cx / 2 - gWndSize.cx / 2,       /* Windows decides the position */
		gDesktop.cy / 2 - gWndSize.cy / 2,       /* where the window ends up on the screen */
		gWndSize.cx,         /* The programs width */
		gWndSize.cy,         /* and height in pixels */
		HWND_DESKTOP,        /* The window is a child-window to desktop */
		NULL,                /* No menu */
		hThisInstance,       /* Program Instance handler */
		NULL                 /* No Window Creation data */
		);

	if( hwnd ) 
	{
		/* Make the window visible on the screen */
		ShowWindow (hwnd, nFunsterStil);

		DEVMODE dmScreenSettings;
		ZeroMemory( &dmScreenSettings, sizeof dmScreenSettings );
		dmScreenSettings.dmSize       = sizeof(dmScreenSettings); 
		dmScreenSettings.dmPelsWidth  = gWndSize.cx; 
		dmScreenSettings.dmPelsHeight = gWndSize.cy; 
		dmScreenSettings.dmBitsPerPel = 32; 
		dmScreenSettings.dmFields     = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT; 
		//    ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);

		/* Run the message loop. It will run until GetMessage() returns 0 */
		while (GetMessage (&messages, NULL, 0, 0))
		{
			/* Translate virtual-key messages into character messages */
			TranslateMessage(&messages);
			/* Send message to WindowProcedure */
			DispatchMessage(&messages);
		}

		/* The program return-value is 0 - The value that PostQuitMessage() gave */
		lRet = (int) messages.wParam;
	}
	return lRet;
}


/*  This function is called by the Windows function DispatchMessage()  */

LRESULT CALLBACK WindowProcedure (HWND handle, UINT message, WPARAM wParam, LPARAM lParam)
{
	hwnd = handle;
	switch (message)                  /* handle the messages */
	{
	case WM_CREATE:
		hdc = GetDC(hwnd);
		SetBkMode(hdc, TRANSPARENT);
		break;
	case WM_PAINT:
		{
			PAINTSTRUCT lPaint;

			BeginPaint(handle, &lPaint);
			clear(0,0,gWndSize.cx,gWndSize.cy);
			switch(area)
			{
			case 1:
				hauptmenue();
				break;
			case 2:
				game();
				break;
			case 3:
				optionen();
				break;
			}
			EndPaint(handle, &lPaint );
		}
		break;
	case WM_KEYDOWN:
		keydown(wParam);
		break;
	case WM_TIMER:
		if(wParam == gTimerHandle )
			move_pman(move);
		break;
	case WM_DESTROY:
		ReleaseDC(hwnd, hdc);
		PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
		break;
	}

	return DefWindowProc (hwnd, message, wParam, lParam);
}

void keydown(WPARAM wParam)
{
	switch(wParam)
	{
	case VK_ESCAPE:
		if(area != 1)
		{
			clear(0, 0, gWndSize.cx, gWndSize.cy);
			if(area == 2 && gTimerHandle && IsWindow( hwnd ) )
			{
				KillTimer(hwnd, gTimerHandle); // Löscht den PMan Timer
				gTimerHandle = 0;
			}

			hauptmenue();
		}
		break;
	case VK_DOWN:
		if(area == 1)
		{
			if(menuenumber < 3)
			{
				menuenumber++;
				hauptmenue();
			} else
			{
				menuenumber = 1;
				hauptmenue();
			}
		}
		if(area == 2)
			move = 3;
		break;
	case VK_UP:
		if(area == 1)
		{
			if(menuenumber > 1)
			{
				menuenumber--;
				hauptmenue();
			} else
			{
				menuenumber = 3;
				hauptmenue();
			}
		}
		if(area == 2)
			move = 1;
		break;
	case VK_RETURN:
		if(area == 1)
		{
			switch(menuenumber)
			{
			case 1:
				startTimer();
				game();
				break;
			case 2:
				optionen();
				break;
			case 3:
				SendMessage(hwnd, WM_DESTROY, 0, 0);
				break;
			}
		}
		break;
	case VK_LEFT:
		if(area == 2)
			move = 4;
		break;
	case VK_RIGHT:
		if(area == 2)
			move = 2;
		break;
	}
}

void clear(int x, int y, int x2, int y2)
{
	HBRUSH background = CreateSolidBrush(RGB(255,255,255));
	HPEN   pen        = CreatePen(PS_SOLID,1,RGB(255,255,255));
	HPEN   penOld     = (HPEN)   SelectObject(hdc, pen);
	HBRUSH brushOld   = (HBRUSH) SelectObject(hdc, background);

	Rectangle(hdc, x, y, x2, y2);

	SelectObject(hdc, penOld);
	SelectObject(hdc, brushOld);
	DeleteObject( pen );
	DeleteObject( background );
}

void hauptmenue()
{
	area = 1;
	TextOut(hdc, 300, 50, "V1tzl1's Pacman", 15);
	TextOut(hdc, 350, 80, "#:- Hauptmenü -:#", 17);

	if(menuenumber == 1)
		SetTextColor(hdc, RGB(100, 100, 255));
	TextOut(hdc, 250, 150, "Spiel starten", 13);
	SetTextColor(hdc, 0);

	if(menuenumber == 2)
		SetTextColor(hdc, RGB(100, 100, 255));
	TextOut(hdc, 250, 180, "Optionen", 8);
	SetTextColor(hdc, 0);

	if(menuenumber == 3)
		SetTextColor(hdc, RGB(100, 100, 255));
	TextOut(hdc, 250, 210, "Spiel beenden", 13);
	SetTextColor(hdc, 0);
}

void startTimer()
{
	if( gTimerHandle )
		KillTimer( hwnd, gTimerHandle );
	gTimerHandle = SetTimer(hwnd, TIMER_EVENT, PM_TIMER, 0);
}

void game()
{
	area = 2;
	clear(0,0,gWndSize.cx,gWndSize.cy);
	show();
}

void optionen()
{
	area = 3;
	clear(0,0,gWndSize.cx,gWndSize.cy);
	TextOut(hdc, 150, 150, "Optionen", 8);
}

void  move_pman(int direction) // 1 => oben, 2 => rechts, 3 => unten, 4 => links
{
	//  move = 0;
	int newX = pmanX;
	int newY = pmanY;

	switch(direction)
	{
	case 0:  // Falls keine Taste gedrueckt
		return;
	case 1:
		newY = pmanY - 1;
		break;
	case 2:
		newX = pmanX + 1;
		break;
	case 3:
		newY = pmanY + 1;
		break;
	case 4:
		newX = pmanX - 1;
		break;
	}
	if(newX < x_max && newX > 0 && newY < y_max && newY > 0 && map1[newY][newX] == PO)
	{
		draw(newX, newY, 3);
		draw(pmanX, pmanY, 2);

		pmanX = newX;
		pmanY = newY;
	}
// Das gibt sonst einen Stackoverflow SendMessage(hwnd, WM_TIMER, 0, 0);
}

void show()
{
	// Rahmen
	HPEN pschwarz = CreatePen(PS_SOLID,2,RGB(0,0,0));
	HPEN lPenOld  = (HPEN) SelectObject(hdc, pschwarz);

	Rectangle(hdc, 179,179,(x_max * 30 + 152),(y_max * 30 + 152));

	// Map
	int x;
	int y;

	for(y = 1; y < y_max; y++)
	{
		for(x = 1; x < x_max; x++)
		{
			switch(map1[y][x])
			{
			case WA:
				draw(x,y,0);
				break;
			case PO:
				draw(x,y,1);
				break;
			}
		}
	}  
	draw(pmanX, pmanY, 3);

	SelectObject(hdc, lPenOld);
	DeleteObject( pschwarz );
}

void map_ini(int level)
{
	switch(level)
	{
	case 1:
		// Start Level 1
		x_max = 15;
		y_max = 11;
		// End   Level 1
		break;
	}
}

void draw(int x, int y, int art)
{
	int    x1       = 0;
	int    x2       = 0;
	int    y1       = 0;
	int    y2       = 0;
	HPEN   pen      = 0;
	HBRUSH brush    = 0;
	HPEN   penOld   = 0;
	HBRUSH brushOld = 0;

	x1 = (x  )*FAKTOR+PADDING;
	x2 = (x+1)*FAKTOR+PADDING;
	y1 = (y  )*FAKTOR+PADDING;
	y2 = (y+1)*FAKTOR+PADDING;
	switch(art)
	{
	case 0:
		pen      = CreatePen(PS_SOLID,1,RGB(255,0,0));
		brush    = CreateSolidBrush(RGB(255,0,0));
		penOld   = (HPEN)   SelectObject(hdc, pen);
		brushOld = (HBRUSH) SelectObject(hdc, brush);
		Rectangle(hdc, x1, y1, x2, y2);
		SelectObject(hdc, penOld);
		SelectObject(hdc, brushOld);
		DeleteObject( pen );
		DeleteObject( brush );
		break;
	case 1:
		pen      = CreatePen(PS_SOLID,1,RGB(0,255,0));
		brush    = CreateSolidBrush(RGB(0,255,0));
		penOld   = (HPEN)   SelectObject(hdc, pen);
		brushOld = (HBRUSH) SelectObject(hdc, brush);
		Rectangle(hdc, x1, y1, x2, y2);
		SelectObject(hdc, penOld);
		SelectObject(hdc, brushOld);
		DeleteObject( pen );
		DeleteObject( brush );
		break;
	case 2:
		pen      = CreatePen(PS_SOLID,1,RGB(0,0,255));
		brush    = CreateSolidBrush(RGB(0,0,255));
		penOld   = (HPEN)   SelectObject(hdc, pen);
		brushOld = (HBRUSH) SelectObject(hdc, brush);
		Rectangle(hdc, x1, y1, x2, y2);
		SelectObject(hdc, penOld);
		SelectObject(hdc, brushOld);
		DeleteObject( pen );
		DeleteObject( brush );
		break;
	case 3:
		pen      = CreatePen(PS_SOLID,1,RGB(0,0,255));
		brush    = CreateSolidBrush(RGB(0,0,255));
		penOld   = (HPEN)   SelectObject(hdc, pen);
		brushOld = (HBRUSH) SelectObject(hdc, brush);
		Rectangle(hdc, x1, y1, x2, y2); 
		SelectObject(hdc, penOld);
		SelectObject(hdc, brushOld);
		DeleteObject( pen );
		DeleteObject( brush );
		pen      = CreatePen(PS_SOLID,1,RGB(255,255,0));
		brush    = CreateSolidBrush(RGB(255,255,0));
		penOld   = (HPEN)   SelectObject(hdc, pen);
		brushOld = (HBRUSH) SelectObject(hdc, brush);
		Ellipse(hdc, x1+2, y1+2, x2-2, y2-2);   
		SelectObject(hdc, penOld);
		SelectObject(hdc, brushOld);
		DeleteObject( pen );
		DeleteObject( brush );
		break;
	}
}

Main.h
Code:
#ifndef _MAIN_H_INCLUDED
#define _MAIN_H_INCLUDED

#include <windows.h>

#define WA 0 // Wand
#define PO 1 // Punkt
#define GA 2 // Gang
#define PM 3 // PacMan

#define FAKTOR    30 // Pixel pro Kachel
#define PADDING  150 // Pixel li,ob Abstand
#define PM_TIMER 100 // Timer für PMan
#define TIMER_EVENT 100

/*  Make the class name into a global variable  */
char szClassName[ ]   = "WindowsApp";
int area              = 1;
int menuenumber       = 1;
int level             = 1;
int move              = 0;
HDC hdc               = 0;
HWND hwnd             = 0;
int x_max             = 16;
int y_max             = 12;
int pmanX             = 8;
int pmanY             = 6;
UINT_PTR gTimerHandle = 0;
SIZE gDesktop;
SIZE gWndSize;


/*  Declare Windows procedure  */
LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

void map_ini(int level);
void keydown(WPARAM wParam);
void clear(int x, int y, int x2, int y2);
void hauptmenue();
void game();
void startTimer();
void optionen();
void show();
void draw(int x, int y, int art);
void move_pman(int direction); // 1 => oben, 2 => rechts, 3 => unten, 4 => links

#endif

Das ist jetzt noch nicht perfekt, aber imho ein bisschen übersichtlicher.
Die Initialisierung der globalen Variablen sollte noch aus dem Headerfile raus und in eine init Funktion.

MfG

Arnd
 
Zuletzt bearbeitet:
Hallo Arnd
vielen Dank für deine Vorschläge.
Ich habe (zur Zeit) auch nur noch eine frage und zwar warum man die globalenvariablen in einer funktion initialisieren sollte und nicht so, wie in deinem code beispiel?
MfG V1tzl1
 
Zuletzt bearbeitet: (Manchmal ist man echt blind ...)
Hallo V1tzl1,

in ein Headerfile gehören nur die Deklarationen. Wenn man in dem Headerfile auch die Variablen gleich initialisiert und z.B. das #define in der ersten Zeile weglässt, gibt es beim mehrfachen einbinden des Headerfiles Probleme.

Das ich es so gemacht, liegt nur an meiner Faulheit :-) und weil ich den Code nachträglich nicht noch mal ändern wollte.

Solche Sachen können eine Rolle spielen wenn das selbe Headerfile von mehreren Klassen benötigt wird.

So wie es jetzt ist, funktioniert es sicher auch. Die Aufteileung der Zuständigkeiten erleichtert das Leben aber.

Nimm mal an die Funktion init() initialisiert alle Variablen. So kann man diese auch später wieder aufrufen um einen definierten Ausgangszustand herzustellen. Erfolgen die Initialisierungen im Headerfile geht das nicht.

Auch noch allgemein zu den globalen Variablen. Es ist übersichtlicher wenn möglichst keine globalen Variablen verwendet werden. Wenn Dein Programm grösser wird und immer mehr globale Variablen dazu kommen, dann wird es richtig interessant :-).

Z.B. die Variable hdc und hwnd, würde ich eher lokal halten und als Parameter übergeben, auch wenn es langsamer ist.

Oder alternativ alle globalen Variablen in eine Struktur stecken, dann wird deutlicher das diese zusammengehören.

Eine weitere Möglichkeit zur Optimierung liegt sicher noch in der Menusteuerung. Das sind ein paar zuviele ifs und Variablen. Das zu kapieren und z.B. in einem Jahr später zu ändern ist ziemlich aufwendig.

Auch Deine Zeichenroutinen könnte man noch zusammenfassen. Schau Dir den Code nochmal an. Du findest sehr oft den selben Code nur mit unterschiedlichen Parametern. Das lässt sich noch in eine Funktion auslagern.

MfG

Arnd
 
Hallo Arnd, vielen Dank für deine Antworten, hab jetz leider keine Zeit, werde das wohl aufs WE verschieben.
Ich meld mich dann nochmal, wenn da fragen auftauchen
 

Ähnliche Themen

W
  • Gesperrt
  • Frage
2 3
Antworten
45
Aufrufe
2.661
Antworten
10
Aufrufe
761
Antworten
12
Aufrufe
2.105
Antworten
18
Aufrufe
2.212
Zurück
Oben