View Full Version : آموزش: آموزش مقدماتی SDL
H_G_G_I
دوشنبه 27 آذر 1391, 15:09 عصر
به نام خدا
اموزش مقدماتی SDL :لبخند:
اول از همه
1 - باید با زبان سی پلاس پلاس اشنایی داشته باشید ! حداقل در حد متوسط ! اگه بلد نیستی اصلا چرا اینو می خونی !:عصبانی:
2 - من از Windows 7 x64 و Visual Studio 2010 استفاده می کنم ! تمام نمونه ها و مثالا هم همین طوره !
3 - اگه سوتی ای دادم اشتباهی و .. شد به بزرگی خودتون بوخشید . :لبخند:
SDL چیه ؟ :متفکر:
SDL مخفف Simple DirectMedia Layer هست .
یه کتابخونه که به زبان سی نوشته شده . کار باهاش راحته و کراس پلتفرم هم هست !
کراس پلتفرم یعنی اینکه بر روی پلتفرم های مختلفی کار می کنه ! مثل ویندوز و لینوکس و مک
در حال حاضر این پلتفرم ها رو پشتیبانی می کنه !
Linux, Windows, Windows CE, BeOS, MacOS, Mac OS X, FreeBSD, NetBSD, OpenBSD, BSD/OS,
Solaris, IRIX, and QNX. The code contains support for AmigaOS, Dreamcast, Atari, AIX, OSF/Tru64, RISC OS, SymbianOS, and OS/2
به چه درد ما می خوره ؟ :متفکر:
می توانیم با SDL یه سری کارای گرافیکی کنیم . به ماوس و کیبورد و دسته و صدا و ... دستیابی داشته باشیم و راحت از اون ها استفاده کنیم ! درکل از محیط ضایع کنسولی خلاص میشیم !:لبخندساده:
کجا هست این SDL ؟ :متفکر:
به سایتش برید . http://www.libsdl.org
و از قسمت دانلود بسته به کامپایلرتون Development Librarie رو دانلود کنید ! (دیگه این چیزا رو نباید توضیح بدم چون اول کاره می گم !)
بعد که دانلود کردین یه جایی اکسترکتش کنید ! من تو D اکسترکت کردم !
از کجا شروع کنیم ؟ :متفکر:
خب اول از همه ما باید ویژال استدیو رو اجرا کنیم ! (ن پ ن می خواهید تو نت پد کار کنیم )
و یه پروژه C++ خالی ایجاد کنیم !
File/New/Project/Visual C++/General/EmptyProjcet
حالا باید سرفایل های اس دی ال رو برای این پروژه مشخص کنیم !
پس به قسمت تنظیمات پروژه بروید ! (کلیک راست رو پروژه و Properties )
و مثل عکس انجام بدین ! دقت کنید که من sdl رو در درایو D ریختم !
96812
حالا باید دایرکتوری فایل های lib. رو مشخص کنیم !
96811
فقط مانده.lib هایی که باید لینک بشن رو معرفی کنیم .
این کار هم سادست به تنظیمات پروژه بروید و سپس
Linker/Input/Additional Dependencies
فقط کافیه sdl.lib و sdlmain.lib رو بنویسم !
96813
حالا یه فایل به اسم main.cpp ایجاد کنید و این ها رو بنویسید ! (کلیک راست رو پروژه و Add/ New/ و بعد هم C++File )
#include <SDL.h>
int main(int argc, char* argv[])
{
SDL_Init(SDL_INIT_EVERYTHING);
SDL_Surface* l_pScren = SDL_SetVideoMode( 640, 480, 32, SDL_SWSURFACE );
return 0;
}
برنامه را دیباگ کنید ببینید بالا میاد یانه !
اولین خطایی که می ده این هست ! دی این چیه ! :ناراحت:
error LNK1561: entry point must be defined
خب این بخاطر اینه که ما نوع پروژه رو مشخص نکردیم .
برای اینکار به تنظیمات پروژه بروید و سپس
linker/sytem
و subSystem رو کنسول انتخاب کنید !
حالا دو باره کامپایل کنید ایندفعه دیگه باید بشه ! بله میشه اما وقتی برنامه اجرا میشه اینو میده !
96814
این می گه که برنامه نمی تونه اجرا بشه چون به sdl.dll نیاز داره !خب ما از SDL ـی استفاده کردیم که به صورت dll کامپایل شده پس این برنامه ما به SDL.dll نیازمنده !
sdl.dll رو یا بایددر دایرکتوری ویندوز کپی کنید یا کنار فایل اجرایی برنامه تون !
شما D:\SDL-1.2.15\lib\x86\SDL.dll را کپی کنید کنار فایل اجرایی برنامه !
حالا دیگه بدون هیچ خطایی باید برنامه اجرا بشه !
باید یه لحضه پنجره ظاهر شه و بسته شه همین !
+++ ادامه دارد +++
H_G_G_I
دوشنبه 27 آذر 1391, 15:13 عصر
خب حالا بریم کد ها رو بررسی کنیم !
اول از همه که SDL.h رو اینکلود کردیم !
تابع ( **main(int, char هم که برا برنامه ی کنسولیه نوشته شده !
اولین تابعی که استفاده کردیم ! SDL_Init هست !
این تابع برا اماده سازی و مقدار اولیه گرفتن اس دی ال هست و باعث لود شدن اس دی ال می شه که باید قبل از استفاده از هر تابع دیگر SDL صدا زده شود !
این تابع یه پارامتر می گیره از نوع Unit32 که همون unsigned int هست ! مشخص می کنه چه چیز هایی باید اماده سازی بشه !
از ثابت های زیر برا مشخص کردن چیزهایی که می خواهیم اماده سازی بشه استفاده می کنیم !
SDL_INIT_TIMER
SDL_INIT_AUDIO
SDL_INIT_VIDEO
SDL_INIT_CDROM
SDL_INIT_JOYSTICK
SDL_INIT_NOPARACHUTE
SDL_INIT_EVENTTHREAD
SDL_INIT_EVERYTHING
همه با SDL_INIT شروع می شوند ! همون طور که می بینید کاملا مفهوم هستن .
من از SDL_INIT_EVERYTHING استفاده کردم یعنی همه چی اماده سازی بشه ! (صدا - تصویر - کبیورد دسته و... )
این تابع یه مقدار بازگشتی داره که مشخص می کنه چیزهایی که می خواستیم اماده بشن درست اماده شدن یا نه !
اگه صفر برگردونه یعنی همه چی درسته ! اگر 1- بده یعنی به یه خطایی رسیده ! مثلا سیستم ذغالیه یا چه میدونم دسته بازی کار نمی کنه و ...
خب تابع بعدی SDL_SetVideoMode که یکمی هم توضیحش برا من سخته کارش اماده سازی حالت نمایشه !
در واقع یه پنجره درست می کنه که ما داخل اون پنجره چیز هایی که می خواهیم رو رسم می کنیم !
پارامتر هاش رو به ترتیب می گم ! هرچند که دو تا اولش واضحه !
- عرض پنجره
- طول پنجره
- byte per pixel مقدار بیت هر پیکسل !
bpp مشخص می کنه که هر پیکسل چند بیت باشه برا اینکه ما از مد رنگی R8G8B8A8 استفده کنیم باید 32 رو بنویسم !
(8 بیت قرمز + 8 بیت سبز + 8 بیت ابی + 8 بیت الفا یا همون شفافیت) میشه 32 دیگه! هر 8 بیت هم یه بایته تو هر یه بایت هم یه عدد بین 0 تا 255 جا می گیره !
اگه مقدار رو 0 بدین bpp در حال حاضر سیستم رو در نظر می گیره !
خب پس اگه ما عرض رو بدیم 800 و ارتفاع رو 600 و bpp رو 32 به نظر شما چقدر از حافظه رو اشغال می کنه ؟
800 * 600 * 32 == ؟؟؟
-
پارامتر اخر هم یه سری ویژگی ها رو مشخص می کنه که زیاد واردش نمی شم !
من از SDL_SWSURFACE استفاده کردم که حافظه مورد نیازش رو از رم سیستم میگیره !
SDL_HWSURFACE حافظه رو از گرافیک می گیره !
SDL_FULLSCREEN پنجره رو حالت تمام صفحه می کنه !
برای اطلاعات بیشتر داکیومنت SDL رو بخونید !
خب !
مقدار بازگشتی این تابع یه اشاره گر به SDL_Surface هست ! اگه با موفقیت کار نکنه اشاره گر NULL بر می گردونه !
SDL_Surface رو مثل یک ورق کاغذ در نظر بگیرید که طول و عرض داره !
تصاویری که بعدا لود می کنیم هم SDL_Surface هستند !
Surface ها رو میشه روی یک یا چند Surface دیگر انداخت !
الان ما یه Surface داریم که در واقع همون چیزیه که پنجره ما نشون می ده ! می تونیم یه Surface دیگه مثلا یه تصویر که خودمون لود کردیم روی آن بندازیم ! (به زودی )
خط بعد هم return هست !
تو این چند خط ما فقط اس دی ال رو اماده سازی کردیم و یه پنجره رو نمایش دادیم و تمام !
برای اینکه حلقه ای وجود نداشت فقط یه لحظه یه پنجره امد و رفت !
+++ ادمه داره +++
H_G_G_I
دوشنبه 27 آذر 1391, 15:39 عصر
در این قسمت ما می خواهیم یه جور بازی ساده درست کنیم !:تشویق: و با مباحث
- لود کردن تصویر
- رویداد ها
- حلقه بازی
- پاک کردن و رفرش صفحه و ...
کمی اشنا شویم !
یه پروژه جدید ایجاد کنید و SDL رو لینک و ... کنید!
یا پروژه قبلی رو باز کنید و هرچی نوشتید رو پاک کنید !
من دو تا تصویر اماده کردم !:لبخندساده:
96815
-
96816
اینا رو سیو کنید !
در ضمن اینا jpg. هستن . SDL فقط می تونه bmp. لود کنه . باید اینا رو bmp کنید .
هدف اینه که بتونیم اون یارو ماریو رو نمایش دهیم و با کلید های چپ و راست و بالا و پایین حرکتش بدیم !:لبخند:
و در هر فرم تعدادی سکه به طور تصادفی نمایش دهیم !
خب ! اول از همه بگم که ما سه تا تابع اصلی می نویسیم .
void init();
void loop();
void quit();
init برای اماده سازی اس دی ال و لود کردن تصاویر !
loop برای ایجاد حلقه اپدیت بازی !
quit هم برای زمان خروج - برای ازاد کردن تصویری که لود شده و ...
اول از همه که این کارو می کنیم !
#include <SDL.h>
بعد این متغیر ها رو تعریف می کنیم !
SDL_Surface* g_pScreen;
SDL_Surface* g_pMario;
SDL_Surface* g_pCoin;
SDL_Event g_event;
int g_marioX = 200;
int g_marioY = 300;
g_pScreen اشاره گری به سورفیس نمایش هست و مربوط به پنجره ایست که می سازیم !
g_pMario و g_pCoin تصویری هست که ما لود می کنیم ! همون طور که قبلا گفتم تصاویری که لود می کنیم هم SDL_Surface می باشند!
g_event تمامی رویداد ها رو در خودش نگه می داره ! رویداد خروج ار برنامه - فشار دادن کلید و ...
marioX و marioY هم محل نمایش یارو ماریو هست !
حالا تابع init را می نویسیم !
void init()
{
SDL_Init(SDL_INIT_EVERYTHING);
g_pScreen = SDL_SetVideoMode( 640, 480, 32, SDL_SWSURFACE );
//Load Images
g_pMario = SDL_LoadBMP("D:\mario.bmp");
g_pCoin = SDL_LoadBMP("D:\coin.bmp");
}
خط های اولی رو که توضیح دادم قبلا !
فقط می مونه SDL_LoadBMP .
این کارش لود کردن یه تصویر با فرمت .bmp هست ! اس دی ال فقط می تونه .bmp لود کنه ! برای فرمتهای دیگه می تونیم از SDL_Image استفاده کنیم که فعلا بیخیال !
مقدار برگشتی در صورت بروز خطا اشاره گر NULL هست !
خب حالا بریم quit رو بنویسم !
void quit()
{
SDL_FreeSurface(g_pMario);
SDL_FreeSurface(g_pCoin);
SDL_Quit();
}
تابع SDL_FreeSurface باعث ازاد شدن سورفیسی که بهش ارسال می کنیم میشه ! یعنی فضایی که سورفیس از حافظه اشغال کرده ازاد می شه !
تابع quit باعث آزاد شدن اس دی ال میشه ! همون طور که با SDL_Init لودش کردیم با این هم ازادش می کنیم !
در حالت عادی وقتی برنامه ای بسته میشه هر چقدر که فضا گرفته بوده ازاد میشه ! ولی خب شما بهتره این کارو دستی انجام بدین !
این زمانی به کار ادم میاد که مثلا بخواهیم اس دی ال را لود کنیم و یه کاری انجام دهیم و بعد ازاد کنیم و بعد برنامه شروع به کار کنه !
خب حالا مونده تابع loop البته باید قبلش یه تابعی درست کنیم که بتونیم یه سورفیس رو به راحتی نمایش بدیم !
این تابع رو بنویسید !
void apply_surface(SDL_Surface* _surface, short _x, short _y)
{
SDL_Rect l_offset;
l_offset.x = _x;
l_offset.y = _y;
SDL_BlitSurface(_surface, NULL, g_pScreen, &l_offset);
};
آرگومان اول همون سورفیسیه که ما می خواهیم نمایش بدیم . دوتای بعدی هم محل نمایشه !
حالا بریم تو تابع !
SDL_BlitSurface کارش اینه که قسمتی از یه سورفیس رو روی قسمتی از یه سورفیس دیگه میندازه !
آرگومانها به ترتیب ::
- سورفیس منبع (همون که قراره روی دیگری قرار بگیره )
- مشخص کننده قسمتی از سورفیس منبع که باید روی سورفیس مقصد قرار بگیره ! اگر NULL بدیم کل سورفیس در نظر گرفته میشه !
- سورفیس مقصد .
- قسمتی از سورفیس مقصد که سورفیس منبع روی ان قرار می گیره !
من برای اینکه کل سورفیسم (تصویر ماریو و سکه) در نقطه _x و _y قرار بگیره پارامتر دوم رو NULL دادم و
همچنین یه SDL_Rect تعریف کردم و x,y ـش رو برابر x_ و y_ قرار دادم .
حالا تابع loop رو می نویسیم !
void loop()
{
bool l_loop = true;
//Game Loop
while(l_loop)
{
//Read Inputs
while(SDL_PollEvent(&g_event))
{
switch(g_event.type)
{
case SDL_QUIT:
l_loop = false;
break;
case SDL_KEYDOWN:
switch(g_event.key.keysym.sym)
{
case SDLKey::SDLK_ESCAPE :
l_loop = false;
break;
case SDLKey::SDLK_RIGHT :
g_marioX += 8;
break;
case SDLKey::SDLK_LEFT :
g_marioX -= 8;
break;
case SDLKey::SDLK_UP :
g_marioY -= 8;
break;
case SDLKey::SDLK_DOWN :
g_marioY += 8;
break;
}
break;
}
}
//clear screen
SDL_FillRect( g_pScreen, NULL, 0xFFFFFF);
apply_surface(g_pMario, g_marioX, g_marioY);
for(int i = 0; i < 8; i++)
apply_surface(g_pCoin, rand() % 800, rand()% 600);
//Update Screen
SDL_Flip(g_pScreen);
//Pause 100 millisecond
SDL_Delay(60);
}
}
اول از همه یه l_loop داریم که مشخص می کنه حلقه ما همین طور به کارش دامه بده یا نه!
در کل دو تا حلقه داریم ! اولی حلقه بازی هست که تا زمانی l_loop صحیح باشه حی می چرخه !
حلقه دوم که توی حلقه بازی هست مربوط به رویداد هاست ! ما با این حلقه دونه دونه رویداد می گیریم !
رویداد ها مثل فشاردادن کلید و ... همه تو یه صف ذخیره شدن و وقتی ما از SDL_PollEvent استفاده می کنیم ! یک رویداد می گیریم !
وقتی که همه رویداد ها دریافت شد و دیگه رویداد جدیدی نبود مقدار 0 بر می گردونه و حلقه رویداد تموم میشه !
فعلا به داخل حلقه رویداد ها کاری نداریم ! میریم بیرون از اون .
با تابع SDL_FillRect می می تونیم قسمتی از یک سوفیس را با یه رنگی پر کنیم !
من کل سورفیس نمایش رو با رنگ سفید پر کردم !
در واقع این کار هون پاک کردن صفحه هست ! صفحه رو با رنگ سفید پر کردم !
در مورد رنگ هم باید بگم که عوض اینکه بیایم قرمز و سبز ابی الفا رو جدا تو یک بایت ذخیره کنیم می اییم و انها رو در یک int قرار می دهیم !
بعد می تونیم با عملگر های شیفت مقدار قرمز یا سبز یا ... رو بدست اوریم !
من عدد رو در مبنی 16 نوشتم ! در مبنای 16 خوبیش اینه که یکمی مفهوم داره یعنی هر دو رقم یه بایت می شه !
مثلا من می خوام رنگ قرمز باشه می نویسم . FF معادل 255 در مبنای 10 هست !
RRGGBBAA
0xFF111111
.
برای اینکه به کامپیلر بگیم این عددمون در مبنای 16 هست باید عدد رو با 0x شروع کنیم !
تابع بعدی apply_surface هست که خودمون نوشتیم !
با این تابع سورفیس ماریو رو در مختصاتی که دادیم نمایش می دهیم .
-
با 2 خط بعدی 8 تا سکه تو نقاطی تصادفی نمایش می دیم !
تاحلا هرچی بلا سر سورفیس اصلی اواردیم ثبت شده ! حالا برای اینکه نتیجه رو ببینیم باید سورفیسمون رو یه رفرش بکنیم !
اگه این کارو نکنیم هیچ چیزی مشاهده نمی شه !
تابع SDL_Delay باعث ایجاد وقفه میشه ! بر حسب میلی ثانیه هست !
ما 60 وارد کردیم یعنی برنامه 60 میلی ثانیه صبر می کنه بعد به کارش ادامه می ده !
فقط مونده یه توضیح از حلقه رویداد ها !
یه switch(g_event.type داریم !
g_event.type نوع رویداد رو مشخص می کنه !
SDL_QUIT
زمانی اتفاق میفته که فرمان خروج صادر شده باشه یعنی ما روی ضربدر قرمز رنگ پنجره کلیل کنیم !
وقتی این رویداد اتفاق میفته ما l_loop که مشخص می کنه حلقه بازی همین طور ادامه داشته باشه یا نه رو false می کنیم ! تا بازی تموم شه !
SDL_KEYDOWN
زمانی اتفاق میفته که ما کلیدی رو فشار دهیم !
شماره کلیدی که فشرده شده در g_event.key.keysym.sym ذخیره می شود !
رویداد های دیگری مثل
SDL_KEYUP
SDL_MOUSEBUTTONDOWN
و ... هم هستن که دیگه من توضضیح نمی دم !
فقط مانده switch(g_event.key.keysym.sym
همون طور که گفتم کلیدی که فشرده شده درg_event.key.keysym.sym ذخیره شده !
من یه سویچ گذاشتم که بشه با Escape هم برنامه رو بست و با جهت ها ماریو رو تکون داد !
دیگه تنها چیزی که مونده اینه که توابع رو در main صدا بزنیم .
int main(int argc, char* argv[])
{
init();
loop();
quit();
return 1;
}
این هم از نتیجه کار ما ::
96818
-
و این هم کل کد ها :: :کف:
#include <SDL.h>
SDL_Surface* g_pScreen;
SDL_Surface* g_pMario;
SDL_Surface* g_pCoin;
SDL_Event g_event;
int g_marioX = 200;
int g_marioY = 300;
void apply_surface(SDL_Surface* _surface, short _x, short _y)
{
SDL_Rect l_offset;
l_offset.x = _x;
l_offset.y = _y;
SDL_BlitSurface(_surface, NULL, g_pScreen, &l_offset);
};
void init()
{
SDL_Init(SDL_INIT_EVERYTHING);
g_pScreen = SDL_SetVideoMode( 640, 480, 32, SDL_SWSURFACE );
//Load Images
g_pMario = SDL_LoadBMP("D:\mario.bmp");
g_pCoin = SDL_LoadBMP("D:\coin.bmp");
}
void loop()
{
bool l_loop = true;
//Game Loop
while(l_loop)
{
//Events loop
while(SDL_PollEvent(&g_event))
{
switch(g_event.type)
{
case SDL_QUIT:
l_loop = false;
break;
case SDL_KEYDOWN:
switch(g_event.key.keysym.sym)
{
case SDLKey::SDLK_ESCAPE :
l_loop = false;
break;
case SDLKey::SDLK_RIGHT :
g_marioX += 8;
break;
case SDLKey::SDLK_LEFT :
g_marioX -= 8;
break;
case SDLKey::SDLK_UP :
g_marioY -= 8;
break;
case SDLKey::SDLK_DOWN :
g_marioY += 8;
break;
}
break;
}
}
//clear screen
SDL_FillRect( g_pScreen, NULL, 0xFFFFFF);
apply_surface(g_pMario, g_marioX, g_marioY);
for(int i = 0; i < 8; i++)
apply_surface(g_pCoin, rand() % 800, rand()% 600);
//Update Screen
SDL_Flip(g_pScreen);
//Pause 100 millisecond
SDL_Delay(60);
}
}
void quit()
{
SDL_FreeSurface(g_pMario);
SDL_FreeSurface(g_pCoin);
SDL_Quit();
}
int main(int argc, char* argv[])
{
init();
loop();
quit();
return 1;
}
++ادامه داره++
H_G_G_I
دوشنبه 27 آذر 1391, 22:06 عصر
خب حالا سعي می کنیم تا چند تا کلاس کاربردي بنویسم . و یه بازی ساده جمع و جور کنیم .
اگه ارسال های قبلی رو خوب متوجه شده باشيد تو اين قسمت مشکلي پيش نمياد !
اين دفعه يکمي کد ها بيشتر ميشه !:لبخند:
اول از همه این دو تا رو ذخیره کنید ! یادتون باشه که اینا رو bmp. کنید .
96850
-
96851
خب سه تا کلاس اصلي می نویسم که ما عبارت است از
Input
براي دسترسي به کیبرد و موس از اين استفاده مي کنيم !
توابعي مثل keydown , keypress , mousedown , و ... رو پياده سازي مي کنيم !
Object
کلاس ابجکت مختصات و يک اشاره گر به صورفيس رو در خودش نگه مي داره !
هدف ما اينه که سورفيس رو در مختصات ذخيره شده رسم کنيم ! با تابع draw
Game
کلاس گيم برا اماده سازي اس دي ال و رفتن به حلقه بازي هست !
اين کلاس وظيفه بروز رساني Input و نمايش ابچکتها رو داره !
حالا سه تا فايل .h و .cpp با نام اين کلاس ها ايجاد کنيد !
اول از همه Game.h
ابتدا اينا رو در سرفايل گيم بنویسید !
#ifndef __GAME_H__
#define __GAME_H__
#include <SDL.h>
#include "Input.h"
#include "Object.h"
static class Game
{
public:
static SDL_Surface* sp_screen;
static bool sp_quit;
static void init(int _w, int _h);
static void run( void(* _upfateFunc)(void) );
};
#endif //__GAME_H__
توضیح ::
اين کلاس ما که استاتيکه دو تا تابع بيشتر نداره !
init
براي اماده سازي اس دي ال و یه سری چیزای دیگه ! این تابع انداره پنجره اي که مي خواهيم نمايش داده بشه رو مي گيره !
run
اين تابع يه اشاره گر به يه تابعي که نه مقدار برگشتي داره نه ارگومان دريافت مي کنه ! و هر 16 میلی ثانیه اون رو اجرا مي کنه !
sp_screen که سورفيس نمايش ما هست !
sp_quit مشخص مي که از بازي خارج بشيم يا نه ! (از حلقه اپديت)
حالا اين ها رو هم در input.h بنویسید .
#ifndef __INPUT_H__
#define __INPUT_H__
#include "Game.h"
#include <memory>
static class Input
{
private:
static SDL_Event sp_event;
static bool sp_curKeys[322];
static bool sp_preKeys[322];
static bool sp_curMouse[6];
static bool sp_preMouse[6];
static int sp_mouseX;
static int sp_mouseY;
static int sp_mouseVelX;
static int sp_mouseVelY;
public:
static void init();
static void update();
static bool keyDown(SDLKey _key);
static bool keyUp(SDLKey _key);
static bool keyPress(SDLKey _key);
static bool keyRelease(SDLKey _key);
static bool mouseDown(int _btn);
static bool mouseUp( int _btn);
static bool mousePress(int _btn);
static bool mouseRelease( int _btn);
static int mouseX();
static int mouseY();
static int mouseXVel();
static int mouseYVel();
};
#endif //_INPUT_H__
اين کلاس هم کاملا استاتيکه !
اول از همه ميريم سراغ متغير هاش
sp_event
در ارسال قبلي اشنا شديم ! برا ذخيره رويداد ها !
sp_curKeys
sp_preKeys
براي انکه مشخص کنيم چه کليدي پايين هست و چه کليدي بالا يه ارايه 322 تايي از نوع bool در نظر مي گيريم !
برا اينکه از توابع فشار دادن و رها شدن کليد هم استفاده کنيم بايد يک ارايه ديگه هم داشته باشيم و پايبن بودن و نبودن کليد در فريم قبلي رو در آن نگه داريم !
درمورد اینکه چرا 322 تا گذاشتم یاید بگم که خب ما کلا 322 تا کلید که رو کیبورد نداریم !
اگه فایل SDL_keysym.h رو نگاه کنید می بینید که کلا حدود 232 تا کلید تعریف شده ! کلید هایی مثل پاور هم هست ... بعضی کلیدا هم نمی دونم واس چیه !
مقداری که بر این کلید ها گذاشته شده پشت سر هم نیست بیشترین مقدار که 322 هست برای کلید SDLK_UNDO هست که جلوش کامنت داده Atari keyboard has Undo
نمی دونم منظورش از اتاریه چیه ! یادش بخیر اتاری !:قهقهه: :متفکر:
به خاطر همین من 322 تا گذشتم .
sp_curMouse
sp_preMouse
اينم شبیه بالايي ! اما برا کليک چپ و راست و وسط ماوس + چرخوندن قلتک !:متفکر:
sp_mouseX و sp_mouseY
براي ذخيره مکان موس !
sp_mouseVelX و sp_mouseVelY
براي دخيره سرعت حرکت ماوس !
توابع کلاس ::
init براي اماده سازي !
update برا بروز کردن ! ديگه اينا که تابلوست !
keyDown
برای اینه که بفهمیم کلید مورد نظظر ما پایین هست یا نه
بقیه هم واضحه فکر کنم !:متفکر:
حالا اینا رو تو object.h بنویسید.:لبخندساده:
#ifndef __OBJECT_H__
#define __OBJECT_H__
#include "Game.h"
class Object
{
public:
short m_x, m_y;
SDL_Surface* p_pSurface;
Object( SDL_Surface* _PSurface,Uint32 _colorKey, short _x, short _y );
int getDistance(Object * _other);
void Draw();
};
#endif //__OBJECT_H__
توضیح ::
m_x, m_y
محل نمايش ابجکت !
p_pSurface
سورفيسي که بايد نمايش داده شود !
تابع getDistance فاصله اين ابجکت با ابجکت ديگر رو بدست مياره !
تابع Draw اين ابجکت رو رسم مي کنه !
سازنده کلاس ::
- سورفيسي که بايد نمايش داده بشه رو دريافت مي کنه
- يه رنگ ديافت مي کنه که بعدا توضيح مي دم
- و مکان ابجکت !
خب .
حالا مي ريم سراغ game.cpp
#include "Game.h"
SDL_Surface* Game::sp_screen = NULL;
bool Game::sp_quit = false;
void Game::init(int _w, int _h)
{
SDL_Init(SDL_INIT_EVERYTHING);
sp_screen = SDL_SetVideoMode( _w, _h, 32, SDL_SWSURFACE );
}
void Game::run( void(* _upfateFunc)(void) )
{
while(sp_quit == false)
{
SDL_FillRect(sp_screen, NULL, 0); //Clear Screen With Black Color
Input::update(); //Update Inputs
_upfateFunc(); //Update Objects
SDL_Flip(sp_screen); //Update Screen
SDL_Delay(16); //Pause 16 Millisecond
}
}
توضیح ::
ابتدا game.h را اينکلود کرديم و سپس متغيير هاي استاتيک کلاس را پياده سازي کرديم !
در تابع init هم که اس دي ال را امده سازي کرديم و ...!
در تابع run حلقه اي گذاشتيم که تا sp_quit برقرار نيست هر دفعه
1 - سورفيس اسکرين رو با رنگ سياه پر مي کند !
2 - ورودي ها را اپديت مي کند !
3 - تابعي که به ان ارسال شده را صدا مي زند
4 - سورفيس اپديت مي شود !
5 - 16 ميلي ثانيه وقفه ايجاد مي شود !
خب حالا اینا رو در Object.cpp بنویسین !
#include "Object.h"
Object::Object( SDL_Surface* _PSurface,Uint32 _RGBcolorKey, short _x, short _y )
{
p_pSurface = _PSurface;
SDL_SetColorKey(p_pSurface, SDL_SRCCOLORKEY,_RGBcolorKey );
m_x = _x;
m_y = _y;
}
void Object::Draw()
{
SDL_Rect l_rect;
l_rect.x = m_x;
l_rect.y = m_y;
SDL_BlitSurface(p_pSurface, NULL, Game::sp_screen, &l_rect);
}
int Object::getDistance( Object * _other )
{
int l_xx = m_x - _other->m_x;
int l_yy = m_y - _other->m_y;
return (int)sqrtf(l_xx*l_xx + l_yy*l_yy);
}
توضیح ::
اول بريم سراغ سازندش !
بزاريد اول تابع SDL_SetColorKey رو بگم !
وقتي ما يک تصوير رو لود کرديم ! چون .bmp هست الفا نداره و تصوير به طور کامل نمايش داده مي شه !
ما مي تونيم براي سورفيس يه رنگي رو در نظر بگيريم ! و تو هر جاي سورفيس اون رنگي هست نمايش داده نشه !
تو دو تا عکس که من گذاشتم ! رنگ پشت زمينه کاملا سفيده ! ما اون رنگ رو به عنوان ColorKey در نظز مي گيريم !
چيز خاص ديگه هم که نداره !
getDistance
با تابعgetDistance فاصله ي ابجکت تا يه ابجکت ديگه رو بدست مياريم !
فرمولش هم مربوط مي شه به بدست اوردن وتر يه مثلث قايم الزاويه !:لبخند:
تابع Draw هم اين ابجکت را رسم ميکنه!
چيز خاصي نداره ! تو ارسال های قبلي توضيح دادم !
خب حالا بریم سر input.cpp :لبخندساده:
#include "Input.h"
SDL_Event Input::sp_event;
bool Input::sp_curKeys[322];
bool Input::sp_preKeys[322];
bool Input::sp_curMouse[6];
bool Input::sp_preMouse[6];
int Input::sp_mouseVelY;
int Input::sp_mouseVelX;
int Input::sp_mouseY;
int Input::sp_mouseX;
void Input::init()
{
memset(sp_curKeys, 0, sizeof(bool) * 322);
memset(sp_preKeys, 0, sizeof(bool) * 322);
memset(sp_curMouse, 0, sizeof(bool) * 6);
memset(sp_preMouse, 0, sizeof(bool) * 6);
}
void Input::update()
{
memcpy(sp_preKeys, sp_curKeys, sizeof(bool) * 322);
memcpy(sp_preMouse, sp_curMouse, sizeof(bool) * 6);
sp_mouseVelX = 0;
sp_mouseVelY = 0;
while(SDL_PollEvent(&sp_event))
{
switch(sp_event.type)
{
case SDL_QUIT:
Game::sp_quit = true;
break;
case SDL_KEYDOWN:
sp_curKeys[sp_event.key.keysym.sym] = true;
break;
case SDL_KEYUP:
sp_curKeys[sp_event.key.keysym.sym] = false;
break;
case SDL_MOUSEBUTTONDOWN:
sp_curMouse[sp_event.button.button] = true;
break;
case SDL_MOUSEBUTTONUP:
sp_curMouse[sp_event.button.button] = false;
break;
case SDL_MOUSEMOTION:
sp_mouseX = sp_event.motion.x;
sp_mouseY = sp_event.motion.y;
sp_mouseVelX = sp_event.motion.xrel;
sp_mouseVelY = sp_event.motion.yrel;
break;
}
}
}
bool Input::keyDown( SDLKey _key )
{
return sp_curKeys[_key];
}
bool Input::keyUp( SDLKey _key )
{
return (!sp_curKeys[_key]);
}
bool Input::keyPress( SDLKey _key )
{
return (sp_curKeys[_key] == true && sp_preKeys[_key] == false );
}
bool Input::keyRelease( SDLKey _key )
{
return (sp_curKeys[_key] == false && sp_preKeys[_key] == true );
}
bool Input::mouseDown( int _btn )
{
return sp_curMouse[_btn];
}
bool Input::mouseUp( int _btn )
{
return !sp_curMouse[_btn];
}
bool Input::mousePress( int _btn )
{
return (sp_curMouse[_btn] == true && sp_preMouse[_btn] == false);
}
bool Input::mouseRelease( int _btn )
{
return (sp_curMouse[_btn] == false && sp_preMouse[_btn] == true);
}
int Input::mouseX()
{
return sp_mouseX;
}
int Input::mouseY()
{
return sp_mouseY;
}
int Input::mouseXVel()
{
return sp_mouseVelX;
}
int Input::mouseYVel()
{
return sp_mouseVelY;
}
:گیج:
اول از همه متغير هاي استاتيک رو پياده سازي کرديم !
حالا ميريم سراغ توابعش ::
init
در اين تابع ما مقدار همه ارايه ها رو صفر کرديم !
مي تونستيم اين کار رو با for انجام بديم ! ولي از memset استفاده کردم !
memset در سرفايل memory هست و کارش اينه که يه قسمت از حافظه رو با مقداري که مي خواهيم پر مي کنه !
update
در خط اول ابتدا ارايه sp_curKeys را کپي کرديم در sp_preKeys .
اين کار را هم مي توانستيم با for انجام بديم ولي من از memcpy استفاده کردم !
memcpy هم در سرفايل memory قرار داره و کارش اينه که يه قسمتي از حافطه رو کپي مي کنه يه جاي ديگه !
خط بعد هم که همين قضيه رو داره !
در کل ما بايد وضعيت کنوني کليد ها رو بريزيم در ارايه ديگه !
خبSDL_PollEvent رو در ارسال های قبلي توضيح دادم !
ما تک تک رويداد ها رو مي گيريم !
زماني که SDL_QUIT اتفاق ميفته Game::sp_quit = true را true مي کنيم تا حلقه بازي به پايان برسد !
SDL_KEYDOWN وقتي رخ مي دهد که کليدي پايين بره !
وقتي اين اتفاق ميفته ما بايد کليدي که پايين رفته رو ثبت کنيم !
sp_curKeys[sp_event.key.keysym.sym] = true
در SDL_KEYUP برعکس KEYDOWN عمل مي کنيم !
براي SDL_MOUSEBUTTONDOWN و SDL_MOUSEBUTTONUP هم که به همين شکل هست !
SDL_MOUSEMOTION زماني اتفاق مي افتد که موس رو حرکت بديم !
در اين زمان ما مکان و سرعت حرکت ماس رو ذخيره مي کنيم !
تابع keyDown
اين تابع هم با دسترسي به ارايه وضيت کليد ها ، وضعيت کليد مورد نظر رو بر مي گردونه ! (پايين يا نبودنش)
فقط در مورد keyPress و keyRelease توضيح بدم اونم اينکه ::
براي اينکه بدونيم کليد ما فشار داده شده (فشار دادن نه اينکه پايين باشه ) بايد وضعيت جاري کليد پايين و در فريم قبلي بالا باشد !:متفکر:
و براي release هم اين قضيه برعکسه !
براي mousePress و mouseRelease هم همين طوره !
خب حالا بايد از اين کد هامون استفاده کنيم !
اين ها رو در main.cpp بنویسید !
دیگه اینو توضیح نمی دم چون همون فقط کدهای که خودمون نوشتیم رو استفاده کردیم !:قهقهه:
فقط یادتون باشه اون دو تا تصویر رو bmp. کنید و بزارین کنار فایل اجرایی برنامه!
#include "Game.h"
SDL_Surface* surface_player = SDL_LoadBMP("player.bmp");
SDL_Surface* surface_item = SDL_LoadBMP("item.bmp");
Object g_player = Object(surface_player, 0xFFFFFF, 100, 100);
Object* g_items[32];
int g_nItem = 0;
int g_score = 0;
void funcUpdate()
{
if(Input::keyDown(SDLKey::SDLK_RIGHT))
g_player.m_x += 4;
else if(Input::keyDown(SDLKey::SDLK_LEFT))
g_player.m_x -= 4;
if(Input::keyDown(SDLKey::SDLK_UP))
g_player.m_y -= 4;
else if(Input::keyDown(SDLKey::SDLK_DOWN))
g_player.m_y += 4;
if(Input::mousePress(SDL_BUTTON_LEFT))
{
g_items[g_nItem]->m_x = Input::mouseX();
g_items[g_nItem]->m_y = Input::mouseY();
g_nItem++;
g_nItem %= 32;
}
if(Input::mouseDown(SDL_BUTTON_RIGHT))
{
for(int i = 0; i < 32; i++)
{
g_items[i]->m_x += Input::mouseXVel();
g_items[i]->m_y += Input::mouseYVel();
}
}
for(int i = 0; i < 32; i++)
{
if(g_player.getDistance(g_items[i]) < 20)
{
g_items[i]->m_x = -1000;
g_items[i]->m_y = -1000;
g_score++;
char l_caption[64];
sprintf(l_caption, "Score : %d", g_score);
SDL_WM_SetCaption(l_caption, NULL);
}
else
{
g_items[i]->Draw();
}
}
g_player.Draw();
}
int main(int argc, char* argv[])
{
Game::init(800, 600);
for(int i = 0; i < 32; i++)
g_items[i] = new Object(surface_item, 0xFFFFFF, 100 +rand()%600, 100 + rand() % 400);
Game::run(funcUpdate);
return 1;
}
دیگه تموم شد.
الان تا کامپایل بشه بی زحمت تشکر این پست های منو رو بزنید !:لبخند:
H_G_G_I
سه شنبه 28 آذر 1391, 19:19 عصر
دیگه به احتمال 99.9999999999999999 درصد ادامه نداره !:ناراحت:
نظر ،انتقاد ،ناسزا و .. داشتید بگید !:لبخندساده:
mohamad1370
دوشنبه 11 دی 1391, 15:45 عصر
ممنون
خیلی خوب بود امااااااااااااااااااااااا ااااااااااااااااااااااااا ااااااااااااااااااااااااا ااااااااااااااااااااااااا ا بازم مثل بقیه تایپک ها نا تموم موند
لااقل یه چندتا پست دیگه میدادی بعد تمومش می کردی
فش که نمیدیم از دوست هرچه آید خوش آید تا همینجاش دست گلت درد نکنه
programer0611
جمعه 18 اسفند 1391, 07:34 صبح
خیلی ممنون خیلی عالی بود
hossseinG
پنج شنبه 21 شهریور 1392, 15:59 عصر
بابت آموزش ها ممنون . من SDL2 کار می کنم خیلی چیز هاش تغییر کرده(مثلا SDL_SetVideoMode ) . اگه منبع خوبی دارید معرفی میکنید؟ (کتاب , سایت و ...) .
ممنون
amin.khani
چهارشنبه 03 دی 1393, 19:05 عصر
عالی بود جناب. کاش ادامش میدادید.
vBulletin® v4.2.5, Copyright ©2000-1404, Jelsoft Enterprises Ltd.