Üdvözlöm a sorozat első leckéjének kedves olvasóját! :)
Ebben a néhány tutorialban szeretném bemutatni teljesen az alapoktól, egészen a 3D-s megjelenítésig a DirectX-et, c++ nyelven programozva.
Néhány apróság a kezdés előtt:
- fel kell telepítenünk először is valamilyen programozói környezetet (én visual studio 2008at használok, ebből is van ingyenes változat, az express)
- szintén telepíteni kell a DirectX SDK-t, amit szintén ingyenesen letölthetünk a netről (én konkrétan a 2008 novemberit használom)
- ha frissen telepítettük mindkét rendszert, akkor a Visual Studio-ban be kell állítanunk a DirectX SDK megfelelő mappáit (ha az nem tette volna meg): Tools -> Options -> Projects and Solutions -> VC++ Directories -> itt az Include és Library fájlok beállítása szükséges, ami nálam:
C:\Program Files\Microsoft DirectX SDK (November 2008)\Include
és
C:\Program Files\Microsoft DirectX SDK (November 2008)\Lib\x86
- egy alap c++ tudás azért szükséges, de bevallom őszintén, én sem igazán ismerem, viszont egyelőre stabilan használom az alap dolgokat, amelyek most elegek is lesznek nekünk :)
A rövidke bevezető után kezdjünk is bele az első leckébe.
Az alapok
A projekt létrehozása
Mint írtam fentebb, Visual Studio 2008-at használok, így abban írom le, hogy hogyan kreáljuk a projektet.
Mellesleg rettentően bonyolult: File -> New -> Project. :)
A C++ tab alatt (ha csak azt raktad fel, akkor nincs is másik), General tab, és ott van egy olyan, hogy Empty Project. Nekünk erre lesz szükségünk.
Adunk neki egy helyet, hogy hova tegye, nevet szintén, majd készen is vagyunk. Én ki szoktam szedni a pipát a "Create directory for solution"-nél, mert kicsit máshogy szervezem: ha lekreáltam a projektet, akkor bezárom a solution-t, és Total Commanderben, amit a projekt mappájába rakott sln-t, áthelyezem az eggyel fölötte lévő mappába.
Tehát ha én Scream néven kreáltam a projektet, akkor nekem a könyvtár-fa a következő képen néz ki:
Scream\ (folder)
Scream.sln
Scream.ncb
Ez csak egy apróság, nekem így kényelmes (kinek hogy). Ha viszont így teszünk, akkor amikor megnyitjuk a solution-t, egy hibát kapunk. A projektet újra be kell tölteni / újra hozzá kell adni, és minden rendben is lesz.
Ez a projekt lesz az Engine-ünk dll-je, ezért máris át kell állítani: A Solution Explorerben a Projekten jobbgomb -> Properties. Bal fent a Configuration-t átállítjuk All Configurations-re (hiszen Debug és Release módban is dll fog kelleni), majd a Configuration Type-ot Dynamic Library (.dll)-re állítjuk. Ezzel meg is vagyunk, mehet az OK. :)
A dll-t valamilyen programnak használnia kell, így szükségünk van egy másik projektre is, ami maga a "játék".
A Solution Explorerben a Solution nevére jobbgombbal kattintunk, majd Add -> New Project. Ez is szintén Empty Project legyen, adjunk neki egy nevet, majd mehet az OK.
Valahogy használni is kellene a dll-t: létezik rá több megoldás is, én a következőt használom:
A játék projektre (mostantól nevezzük Testernek) jobbgomb -> Properties, ott bal oldalt Common Properties. Itt lehet az adott projekthez "hozzáfűzni" más projekteket (nahát, nekünk pontosan erre van szükségünk! :)). "Add New Reference...", és a listában semmi más nem jelenik meg, csak a másik projektünk. OK, majd OK, és ezzel is megvagyunk.
Mivel ez nem egy dll, így szüksége van a programnak egy ún. Entry Point-ra (azaz belépési pontra), amely a mi esetünkben nem WinMain lesz, hanem egy sima int main függvény.
A Testeren jobbgomb, Add -> New Item -> C++ file (.cpp), a név pedig legyen "main", majd mehet az Add. Ezt érdemes követni, hiszen ide tényleg csak ez fog kerülni.
A kód szörnyen bonyolult, egyelőre csak egy üres, int típusú main függvény
int main()
{
return 0;
}
Még egy kis apróság: a Testeren jobbgomb, majd Set as StartUp Project. Ez azért kell, hogy ha nyomunk egy F5-öt (Futtatás), akkor ebben a projektben keresi az előbb definiált Entry Pointot.
Ha minden igaz most lefordul, és el is tudjuk indítani, de csak felvillan egy konzol, majd el is tűnik. Ez teljesen normális, az ablakot csak most fogjuk létrehozni :)
A Windows ablak létrehozása
Az ilyen dolgok természetesen a dll-be fognak kerülni, hiszen ez elég fix, minden játék esetén. :)
A kódot namespace-kbe (névterekbe) rendeztem, a későbbi könnyebb áttekinthetőség érdekében. Az alap namespace nálam a Scream (az engine neve), a most következő Application osztály pedig azon belül a Base namespace-be tartozik.
Jobbgomb a Dll-en (így fogom nevezni a dll-be forduló projektet) -> Add -> New Item -> Header file (.h), a név pedig nálam sApplication.h. Arra figyeljünk, hogy ha a Visual Studioban mappának látszó filtert teszünk be, az még fizikálisan nem különíti el a fájlokat!
Az összes headerünk ezzel a kóddal indul:
#pragma once
ami azt a célt szolgálja, hogy ne definiáljuk többször a header-ünket (többszöri include esetén nyilván)
Szükségünk van még további két includera
#include <string>
#include <Windows.h>
A string az ablak címsorába kerülő szöveg miatt szükséges, de mivel később úgyis kelleni fog nekünk, így nem is gond, hogy itt van. :)
Majd jön az adott névtérben lévő osztály:
namespace Scream
{
namespace Base
{
class __declspec(dllexport) Application
{
};
}
}
a class után álló "__declspec(dllexport)" a dll miatt szükséges. Ezeket az osztályokat fogja csak "kiírni" a dll-be.
Jöhetnek a privát tagok:
//members
std::string m_Title;
int m_X;
int m_Y;
int m_Width;
int m_Height;
bool m_Fullscreen;
bool m_Run;
DWORD m_WindowStyle;
HWND m_Hwnd;
WNDCLASSEXA m_Wnd;
//methods
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
Nézzük őket sorban, bár elég beszédesek:
- m_Title: a kicsivel fentebb említett ablak címsorába kerülő szöveg
- m_X, m_Y: az ablak kezdőpozíciójának x és y koordinátái.
- m_Width, m_Height: ez pedig a szélesség és a magasság, szintén pixelben.
- m_Fullscreen: teljesképernyős-e az ablak?
- m_Run: ez kicsit később fog kelleni, majd látjuk, hogy mire :)
- m_WindowStyle: ezt is látni fogjuk, az ablak stílusát határozza meg
- m_Hwnd: a létrehozott ablakra egy azonosító
- m_Wnd: ez az ablak létrehozásához szükséges adatokat tartalmazza
- WndProc: ez lesz a mi üzenetkezelőnk, hamarosan látni fogjuk a működését.
A private (privát) tagok után következzenek a public (publikus) tagok. Többek között igen fontos a konstruktor, és a destruktor, más c++ cikkekben olvashatunk róluk, ha szeretnénk.
Application(const std::string& p_Title);
~Application();
//members
static bool m_Active;
//methods
void SetParameters(const int& p_Width, const int& p_Height, const bool& p_Fullscreen);
bool Start();
void Show();
void Stop();
void Restart();
bool IsRuning();
- Az első kettő az előbb említett konstruktor és destruktor.
- az alatta lévő statikus bool változó megmutatja, hogy éppen a mi ablakunk az aktív ablak, vagy sem.
- a többi metódust pedig mindjárt tárgyaljuk, bár szerintem a nevük elég beszédes :)
Már csak egy dolog hiányzik ebből a headerből, a "getterek". Ilyet akkor használunk, ha más osztály számára láthatóvá, de nem módosíthatóvá szeretnénk tenni egy-egy privát tagját. Írok egy példát, a többi már adja magát... :)
inline const std::string& GetTitle() const
{
return m_Title;
}
Ez a fajta függvényhívás szinte ugyan olyan gyors (javítsatok ki, ha tévedek), mintha csak simán a változót "kérnénk el".
Ajánlott bejegyzések:
A bejegyzés trackback címe:
Kommentek:
A hozzászólások a vonatkozó jogszabályok értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a Felhasználási feltételekben és az adatvédelmi tájékoztatóban.