Visual C++ ile Görsel Programlama 3 (Win32)

Visual C++ ile , Kontroller ve Şekiller ve çizim

Visual C++ ile Görsel Programlama 3 ( Kontroller ve Şekiller)

önceki derslerde pencere yapmayı ve mesaj almayı öğrendik. Bu kısımda ise iki boyutlu oyunlar için gerekli olan temel bilgileri öğreneceğiz. öncelikle tüm oyunlarda gerekli olan kontrollere bakalım

Klavyeden ve Fare ile Oyun Kontrolu

Klavyeden giriş yapılırken case WM_KEYDOWN isimli mesaj alınarak değerlendirme yapılır. Aşağıdaki Kod ile sadece Enter tuşu ile işlem yapılırken görünüyor. Diğer tüm mesajlarda olduğu gibi bu da LRESULT CALLBACK kısmında alınacaktır.


 case WM_KEYDOWN:
  switch (wParam)
  {
      case VK_RETURN:
          //Enter tuşuna basıldı
      break;
  }

 break;

Bu kısımda switch (wParam) isimli bölüme dikkatinizi çekeyim.LRESULT CALLBACK fonksiyonuna bakarsak parantez içinde fonksiyona gelen mesajdan başka parametreler olduğunu görüyoruz ( alttaki wParam ve lParam). Bu parametreler her mesaj için farklı değerler almaktadır.

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)

bunu bir örnekle daha iyi anlatabilirim. diyelim ki LRESULT CALLBACK fonksiyonuna WM_KEYDOWN( TuşBasıldı ) mesajı geliyor, bu durumda wParam isimli değişken hangi tuşun basıldığını belirtir. bunların sayı olarak listesini aaşğıya yazdım. lParam değişkeni ise tuşun tekrarlama sayısı veya Alt Ctrl tuşarı ile birlikte basılı olup olmadığını belirtir.

Klavye ve Fare tuşları için hexadecimal sayıları
WM_KEYDOWN >> wParam için
Sembolik ismi Değeri Açıklaması
VK_LBUTTON 01 Fare sol tuşu
VK_RBUTTON 02 Fare Sağ tuşu
VK_RETURN 0D Enter Tuşu
VK_SPACE 20 Boşluk Tuşu
VK_LEFT 25 Sol Ok Tuşu
VK_UP 26 yukarı Ok Tuşu
VK_RIGHT 27 Sağ ok Tuşu
VK_DOWN 28 Aşağı ok Tuşu
Sayılar    
VK_0 30 0 tuşu
VK_1 31 1 tuşu
VK_2 32 2 tuşu
VK_3 33 3 tuşu
VK_4 34 4 tuşu
VK_5 35 5 tuşu
VK_6 36 6 tuşu
VK_7 37 7 tuşu
VK_8 38 8 tuşu
VK_9 39 9 tuşu
Harfler    
VK_A 41 A harfi
VK_B 42 B harfi
VK_C 43 C harfi
VK_D 44 D harfi
VK_E 45 E harfi
VK_F 46 F harfi
VK_G 47 G harfi
VK_H 48 H harfi
VK_I 49 I harfi
VK_J 4A J harfi
VK_K 4B K harfi
VK_L 4C L harfi
VK_M 4D M harfi
VK_N 4E N harfi
VK_O 4F O harfi
VK_P 50 P harfi
VK_Q 51 Q harfi
VK_R 52 R harfi
VK_S 53 S harfi
VK_T 54 T harfi
VK_U 55 U harfi
VK_V 56 V harfi
VK_W 57 W harfi
VK_X 58 X harfi
VK_Y 59 Y harfi
VK_Z 5A Z harfi
     

Gelen mesajın fare ile ilgili olduğunu varsayalım WM_MOUSEMOVE (Fare Haraket Etti ) bu durumda wParam isimli değişken fare haraket ederken basılı olan tuş varsa onu belirtir. wParam = MK_LBUTTON ise sol tuş basılıdır. ( yukardaki listedeki gibi VK_LBUTTON da olabilir çünkü bunlar sayılara karşılık gelen hazır değişkenlerdir.)

WM_MOUSEMOVE >> wParam
MK_CONTROL CTRL basılı
MK_LBUTTON Sol tuş basılı
MK_MBUTTON Orta tuş basılı
MK_RBUTTON Sağ tuş basılı
MK_SHIFT üst Ok tuşu basılı


WM_MOUSEMOVE için lParam ise farenin konumunu belirtir. Ana pencerenin sol tarafı yatay eksende sıfır ve Pencerenin tepesi de Düşey eksende sıfır değerini alır.
xKonumu = LOWORD(lParam);
yKonumu = HIWORD(lParam);
Gördüğünüz gibi bazı durumlarda da lParam yada wParam isimli değişken iki parçaya ayrılabiliyor.

Fare ile ilgili bir uygulamayı aşağıda görmektesiniz. Pencere üzerinde fare tuşunu basılı tutarak sürüklerseniz basit bir çizim yapabilirsiniz.

 

 
#include const char Classismi[] = "pencere"; // gelen mesajları işleyen kısım LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { POINT fare; HDC hdc; switch(msg) { case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; case WM_MOUSEMOVE: if(wParam==VK_LBUTTON) { fare.x = LOWORD(lParam); fare.y = HIWORD(lParam); hdc = GetDC(hwnd); SetPixel(hdc,fare.x,fare.y, RGB(255,25,20)); ReleaseDC(hwnd, hdc); } if(wParam==VK_RBUTTON) { fare.x = LOWORD(lParam); fare.y = HIWORD(lParam); hdc = GetDC(hwnd); SetPixel(hdc,fare.x,fare.y, RGB(255,255,0)); ReleaseDC(hwnd, hdc); } break; default: return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc; HWND hwnd; MSG Msg; //birinci adım: Pencere özelliklerini belirten bir sınıf değişkeni tanımlanıyor wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = (HBRUSH)(COLOR_WINDOW); wc.lpszMenuName = NULL; wc.lpszClassName = Classismi; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if(!RegisterClassEx(&wc)) { MessageBox(NULL, "Pencere tanımlama hatası!", "Hata!", MB_ICONEXCLAMATION | MB_OK); return 0; } // ikinci adım pencere oluşturma hwnd = CreateWindow(Classismi,"Pencere başlığı",WS_OVERLAPPEDWINDOW, 200, 200, 300, 200,NULL, NULL, hInstance, NULL); ShowWindow(hwnd, SW_SHOW); UpdateWindow(hwnd); // üçüncü adım: mesajların alınması ve ayrılması while(GetMessage(&Msg, NULL, 0, 0) > 0) { TranslateMessage(&Msg); DispatchMessage(&Msg); } return Msg.wParam; }

Burada yaptığımız proje ilk derste öğrendiğimiz boş pencereye aşağıdaki kodu eklemekten ibaretti. Bunu aşağıda parça parça inceleyelim.

case WM_MOUSEMOVE:
if(wParam==VK_LBUTTON) //Fare Sol tuş basılınca
{
fare.x = LOWORD(lParam);
fare.y = HIWORD(lParam);
hdc = GetDC(hwnd);
SetPixel(hdc,fare.x,fare.y, RGB(255,25,20));
ReleaseDC(hwnd, hdc);
}

if(wParam==VK_RBUTTON) //Fare Sağ tuş basılınca
{
fare.x = LOWORD(lParam);
fare.y = HIWORD(lParam);
hdc = GetDC(hwnd);
SetPixel(hdc,fare.x,fare.y, RGB(255,255,0));
ReleaseDC(hwnd, hdc);
}
break;

ilk baştaki WM_MOUSEMOVE mesajını yukarda uzunca anlatmıştım. bu mesaj geldiğinde fare sürükleniyor demektir. bu sırada sol tuşun basılı olup olmadığını kontrol etmek için wParam değişkenini kontrol ediyoruz. (mavi ile yazılmış olan if komutu ile... dikkat: c++ da if komutu ile çift eşittir kullanılır)

case WM_MOUSEMOVE:
   if(wParam == VK_LBUTTON)
   {
       //bu kısımdaki kodu aşağıda inceleyeceğiz.
   }
break;

Şimdi de çizim kısmını inceleyelim öncelikle fonksiyonun başında POINT fare; isimli bir tanımlama yapıyoruz. point değişkeni point.X ve point.Y olarak iki parçadan oluşur. bunu kullanmak yerine int fareXkonumu; ve int fareYkonumu; isimli iki değişken tanımlayarak bunları kullanabilirdik. sadece görmeniz için bunu kullandım.

ilk kısımda lParam değişkeni ikiye parçalanarak farenin X ve Y değerleri alınıyor.
fare.x = LOWORD(lParam);
fare.y = HIWORD(lParam);

Daha sonra alınan bu iki noktayı kullanarak ana pencereye bir nokta atılıyor. burdaki esas komut SetPixel isimli komut. ama bunu kullanabilmek için önce hdc isimli bir tanımlama yapmamız gerekiyor. (HDC handle of display device context (DC) = çizim aracı için kulp diyebiliriz)
 hdc = GetDC(hwnd);
  SetPixel( hdc,fare.x,fare.y, RGB(255,25,20));
 ReleaseDC(hwnd, hdc);

Handle Display Device Context (HDC)

hdc ile istediğimiz herhangi bir pencere yada pencere bileşeni izerine çizim veya resim yapmamız mümkün. Biz oyun yapmaya yoğunlaştığımız için sadece ana pencere üzerinde çizim yapacağız. çizim araçlarını kullanırken hdc isimli bir değişkeni bilmeye ihtiyacımız var. bunu bulmak için ana pencerenin handle(tutamaç,kulp) değerini bilmemiz yeterli. bunu da zaten en başta tanımladığımız için (hwnd) programın herhangi biryerinden çağırabiliriz.

hdc=GetDC(hwnd);

Bu komutu yazdığımızda hdc isimli değişken ana pencerenin çizim alanını temsil ediyor olacak. (bunu da program başında HDC hdc diye tanılmıştık, dikkat: C++ kullanırken tüm değişkenleri kullanmadan önce tanımlamalısınız) Bu fonksiyon yerine BeginPaint(hwnd,PaintStruct) fonksiyonu ile de çizime başlayabiliriz.

hdc isimli çizim değişkenini elde ettikten sonra bunun üzerinde istediğimiz çizimleri yapabilir yada üzerine resim yapıştırabiliriz. işimiz bittikten sonra da ReleaseDC(hwnd, hdc); diyerek bunu tekrar ait olduğu pencereye göndermeliyiz. Eğer BeginPaint fonksiyonunu kullanmışsak EndPaint(hwnd,PaintStruct) fonksiyonu ile çizimi bitirmeliyiz.

Şimdi bazı çizim fonksiyonlarına bakalım:

Ellipse( hdc,solkenar,üstkenar,sağkenar,altkenar); //pencereye daire ve elips çizer
Rectangle(hdc, solkenar,üstkenar,sağkenar,altkenar ); //kare veya dikdörtgen çizer
Pie(hdc, solkenar,üstkenar,sağkenar,altkenar,ilkKesmeX,ilkKesmeY, ikinciKesmeX,ikinciKesmeY); //pasta dilimi çizer
Polygon(hdc,NoktaYapısı,noktaSayısı); //çokgen çizer
RoundRect(hdc, solkenar,üstkenar,sağkenar,altkenar,daireEni,daireBoyu); //Köşeleri yuvarlak dikdörtgen çizer
DrawText(hdc, metinDeğişkeni,metinboyu,KareŞekliPointer, hizalama DT_CENTER);

hdc değişkenini bildikten sonra birkaç sayı kullanarak çeşitli şekiller çizebiliyoruz. kullanımlarına örnek verelim. bu örnekleri WM_PAINT mesajı içine yazabilirsiniz. Aşağıda mavi ile yazılı olan kodu hazırladığınız ana pencerede uygun yere taşımanız yeterli olacaktır.

 

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
RECT kare;

  switch (message)
  {
   case WM_CLOSE:
     DestroyWindow(hwnd);
   break;

  case WM_DESTROY:
     PostQuitMessage(0);
  break;

  case WM_PAINT:
     hdc = BeginPaint(hwnd, &ps);
    GetClientRect(hwnd, &kare);
    DrawText(hdc, "www.tr3d.com", strlen("www.tr3d.com"), &kare, DT_CENTER); //ortaya yazı
    Ellipse(hdc,10,10,100,100); //daire çizimi
    Rectangle(hdc,120,30,200,80); //dikdörtgen çizimi
    EndPaint(hWnd, &ps);
  break;

default:
return DefWindowProc(hWnd, message, wParam, lParam);
  }
return 0;
}

pencere üzerinde çizim yapmayı gördük, sonraki derste pencere üzerindeki resimler, resimlerin haraketlendirilmesi ve bunların çarpışması gibi işlemleri inceleyeceğiz.

Konuyu anladık mı ?
Uygulama sorusu: Yukardaki ilk örneği geliştirin. Klavyeden S tuşuna basınca sarı çizim yapılsın, M tuşuna basılınca mavi çizim yapılsın, K tuşuna basınca kırmızı çizim yapılsın.

Ekleyen: drekon

DMCA.com