توضیح

در صورت مواجه شدن با مشکل یا کم توضیح دادن من در جایی یا اشتباه نوشتن من خواشمندم که به من اطاع دهید

درس ۶ : استفاده از Sprite ها

فایلهای استفاده شده :

source code

pic

 

استفاده از Sprite ها  :

Sprite در حقیقت یک فایل عکس است که در ان چندین عکس موجود است مثلا در یک بازی ساده که از 25 عکس استفاده می شود 2 راه وجود دارد یکی این که 25 فایل مجزا داشته باشیم و دیگر این که 1 فایل بزرگ شامل همه این 25 عکس راه حل دوم بهتر است

//The surfaces

SDL_Surface *dots = NULL;

SDL_Surface *screen = NULL;

 

//The event structure

SDL_Event event;

 

//The portions of the sprite map to be blitted

SDL_Rect clip[ 4 ];

 

در اینجا ما چند متغییر global تعریف کردیم سطوح ساختار event و یک ارایه از SDL_Rect که مختصات 4 عکس را در بر دارد

void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination, SDL_Rect* clip = NULL )

{

    //Holds offsets

    SDL_Rect offset;

   

    //Get offsets

    offset.x = x;

    offset.y = y;

   

    //Blit

    SDL_BlitSurface( source, clip, destination, &offset );

}

این تابع apply_surface ما است اما با کمی دستکاری پارامتر جدید clip است از نوع اشاره گر به SDL_Rect که مختصات مر بعی از ان عکس  است که ما می خواهیم  بچسبانیم اگر NULL بفرستیم دیگر فرقی با تابع قبلی نخواهد داشت  و تغییر دوم عوض کردن پارامتر دوم SDL_BlitSurface از NULL به clip است

    //Clip range for the top left

    clip[ 0 ].x = 0;

    clip[ 0 ].y = 0;

    clip[ 0 ].w = 100;

    clip[ 0 ].h = 100;

   

    //Clip range for the top right

    clip[ 1 ].x = 100;

    clip[ 1 ].y = 0;

    clip[ 1 ].w = 100;

    clip[ 1 ].h = 100;

   

    //Clip range for the bottom left

    clip[ 2 ].x = 0;

    clip[ 2 ].y = 100;

    clip[ 2 ].w = 100;

    clip[ 2 ].h = 100;

   

    //Clip range for the bottom right

    clip[ 3 ].x = 100;

    clip[ 3 ].y = 100;

    clip[ 3 ].w = 100;

    clip[ 3 ].h = 100;

در تابع main بعد از اماده شدن و بارگزاری فایلها ما مختصات 4 عکس را تنظیم می کنیم

در ادامه کار

    //Fill the screen white

    SDL_FillRect( screen, &screen->clip_rect, SDL_MapRGB( screen->format, 0xFF, 0xFF, 0xFF ) );

 

ما از تابع SDL_FillRect استفاده می کنیم که یک سطح رامی گیرد و ناحیه مشخص شده از سطح که پارامتر دوم است د باید از جنس SDL_Rect باشد را به رنگ پارامتر سوم در می اورد

    //Apply the images to the screen

    apply_surface( 0, 0, dots, screen, &clip[ 0 ] );

    apply_surface( 540, 0, dots, screen, &clip[ 1 ] );

    apply_surface( 0, 380, dots, screen, &clip[ 2 ] );

    apply_surface( 540, 380, dots, screen, &clip[ 3 ] );

   

    //Update the screen

    if( SDL_Flip( screen ) == -1 )

    {

        return 1;   

    }

حالا کار ما به اتمام رسیده است و نتیجه پایانی به صورت زیر است

درس 5: Color Keying

فایل های استفاده شده :

source code

adamak

‌background

درس 5: Color Keying (حذف کردن رنگهای مشخص در هنگام چسباندن)

 

ساختار SDL_Surface دارای عضوی به نام color key است

Color key رنگ مشخصی است که ما در هنگام چسباندن نمی خواهیم حضور یابد

 فرض کنید می خواهید این ادمک را به

این پس زمینه بچسبانید

ولی شما نمی خواهید اون رنگ ابی کم رنگ مزاحمتان شود

برای اینکار شما می توانید این رنگ ابی را به عنوان color key معرفی کنید

 

یک مقدمه در مورد رنگها :

همه رنگها از سه رنگ اصلی قرمزوسبزو آبی تشکیل شده اند (Red Green Blue)[RGB]  

هر رنگ از یک بایت تشکیل شده است پس جمعا 256*256*256 رنگ با این مدل می توان ساخت

یعنی : 16777216 رنگ می توان با این مدل ساخت.

مثلا رنگ 0 , 0 , 0 معرف رنگ سیاه است یعنی هیچ رنگی از هیچ کدام موجود نیست

یا رنگ 255,0,0 معرف قرمز مطلق

یا رنگ 0,255,0 معرف سبز مطلق

یا رنگ 0,0,255 معرف ابی مطلق

یا رنگ 255,255,255 معرف سفید

و رنگ 0,255,255 معرف همین ابی کم رنگ است

شما در مبنای HEX یعنی مبنی 16 هم می توانید بنویسید اعداد پایه HEX شامل :

1 2 3 4 5 6 7 8 9 A B C D E F

هست (ماشین حساب ویندوز یا لینوکس را ببینبد)

این رنگ ابی 0,0,FF است

 

معمولا color key را در هنگام بارگزاری فایل ست می کنند

SDL_Surface *load_image( std::string filename )

{

    //The image that's loaded

    SDL_Surface* loadedImage = NULL;

   

    //The optimized image that will be used

    SDL_Surface* optimizedImage = NULL;

   

    //Load the image

    loadedImage = IMG_Load( filename.c_str() );

   

    //If the image loaded

    if( loadedImage != NULL )

    {

        //Create an optimized image

        optimizedImage = SDL_DisplayFormat( loadedImage );

       

        //Free the old image

        SDL_FreeSurface( loadedImage );

این همان تابع image_load است که ما می خواهیم تغییر دهیم

        //If the image was optimized just fine

        if( optimizedImage != NULL )

        {

            //Map the color key

            Uint32 colorkey = SDL_MapRGB( optimizedImage->format, 0, 0xFF, 0xFF );

حالا هر می خواهیم color key را مشخص کنیم

تابع SDL_MapRGB 4 پارامتر می گیرد و رنگ مورد نظر را بر می گرداند پارامتر اول فرمت رنگ مثلا 32 bit که ما اینجا از فرمت optimizedImage استفاده می کنیم و سپس سه رنگ را می دهیم

            //Set all pixels of color R 0, G 0xFF, B 0xFF to be transparent

            SDL_SetColorKey( optimizedImage, SDL_RLEACCEL | SDL_SRCCOLORKEY, colorkey );

        }

حالا وقت انجام Color keying  است SDL_SetColorKey سه پارامتر می گیرد سطح مورد نظر . تنظیمات و رنگ

    //Return the optimized image

    return optimizedImage;

}

سر اخر optimizeImage  دستکاری شده را به ما می دهد

    //Apply the surfaces to the screen

    apply_surface( 0, 0, background, screen );

    apply_surface( 240, 190, foo, screen );

   

    //Update the screen

    if( SDL_Flip( screen ) == -1 )

    {

        return 1;   

    }

حال شکل مورد نظر به صورت زیر است

درس 4 : برنامه های مبتنی بر رویداد ( حادثه )

فایلهای استفاده شده :

source code

عکس

 

 

درس 4 : برنامه های مبتنی بر رویداد ( حادثه )

 

یک رویداد اتفاقی است که رخ می دهد مثل فشار دادن دکمه p صفحه کلید تکان دادن Mouse تغییر اندازه پنجره برنامه  کلیک کردن بر روی دکمه X یا ضربدر پنجره و ...

 

در این درس یاد می گیرید که چگونه رخداد یک رزیداد را بررسی کنید و مثال ما همان زدن X است

 

//The headers

#include "SDL/SDL.h"

#include "SDL/SDL_image.h"

#include

 

//Screen attributes

const int SCREEN_WIDTH = 640;

const int SCREEN_HEIGHT = 480;

const int SCREEN_BPP = 32;

 

//The surfaces

SDL_Surface *image = NULL;

SDL_Surface *screen = NULL;

 

در اول کار مثل قبل هدر و ثابت ها و سطوح را تعریف می کنیم

//The event structure that will be used

SDL_Event event;

حال یک چیز جدید ساختار SDL_Event به ما در نگهداری رویداد ها کمک می کند در اصل SDL_Event یک union است به شکل زیر :

 

typedef union{
  Uint8 type;
  SDL_ActiveEvent active;
  SDL_KeyboardEvent key;
  SDL_MouseMotionEvent motion;
  SDL_MouseButtonEvent button;
  SDL_JoyAxisEvent jaxis;
  SDL_JoyBallEvent jball;
  SDL_JoyHatEvent jhat;
  SDL_JoyButtonEvent jbutton;
  SDL_ResizeEvent resize;
  SDL_ExposeEvent expose;
  SDL_QuitEvent quit;
  SDL_UserEvent user;
  SDL_SywWMEvent syswm;
} SDL_Event;
 

 

SDL_Surface *load_image( std::string filename )

{

    //The image that's loaded

    SDL_Surface* loadedImage = NULL;

   

    //The optimized image that will be used

    SDL_Surface* optimizedImage = NULL;

   

    //Load the image

    loadedImage = IMG_Load( filename.c_str() );

   

    //If the image loaded

    if( loadedImage != NULL )

    {

        //Create an optimized image

        optimizedImage = SDL_DisplayFormat( loadedImage );

       

        //Free the old image

        SDL_FreeSurface( loadedImage );

    }

   

    //Return the optimized image

    return optimizedImage;

}

 

void apply_surface( int x, int y, SDL_Surface* source, SDL_Surface* destination )

{

    //Temporary rectangle to hold the offsets

    SDL_Rect offset;

   

    //Get the offsets

    offset.x = x;

    offset.y = y;

   

    //Blit the surface

    SDL_BlitSurface( source, NULL, destination, &offset );

}

این توابع همچنان مثل درس های قبل است و تغییر نکرده اند

bool init()

{

    //Initialize all SDL subsystems

    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )

    {

        return false;   

    }

   

    //Set up the screen

    screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );

   

    //If there was in error in setting up the screen

    if( screen == NULL )

    {

        return false;   

    }

   

    //Set the window caption

    SDL_WM_SetCaption( "Event test", NULL );

   

    //If everything initialized fine

    return true;

}

این تابع هم برای اماده سازی است تغییر تیتر شروع SDL و چک کردن برای Error .

bool load_files()

{

    //Load the image

    image = load_image( "x.png" );

   

    //If there was an error in loading the image

    if( image == NULL )

    {

        return false;   

    }

   

    //If everything loaded fine

    return true;   

}

 

این تابع برای بارگزاری فایل است و چک کردن برای بروز خطا توجه کنید که فایل x.png حتما باید باشد.

void clean_up()

{

    //Free the image

    SDL_FreeSurface( image );

   

    //Quit SDL

    SDL_Quit();   

}

واین تابع اخر هم کار خالی کردن حافظه و خروج از SDL را انجام می دهد

int main( int argc, char* args[] )

{

    //Make sure the program waits for a quit

    bool quit = false;

در تابع main ما یک متغییر تعریف کردیم به نام quit که در صورت TRUE شدن از برنامه خارج شود

//Initialize

if( init() == false )

{

     return 1;   

}

 

 //Load the files

if( load_files() == false )

{

return 1;   

}

 

در اینجا توابع را فراخوانی می کنیم

    //Apply the surface to the screen

    apply_surface( 0, 0, image, screen );

   

    //Update the screen

    if( SDL_Flip( screen ) == -1 )

    {

        return 1;   

    }

سپس عکس را نمایش می دهیم

    //While the user hasn't quit

    while( quit == false )

    {

این حلقه اصلی برنامه است تا وقتی که برنامه مقدار quit را true نکرده باشد ادامه میابد.

        //While there's an event to handle

        while( SDL_PollEvent( &event ) )

        {

 

در SDL همانند Windows وقتی چند رویداد دخ میدهد این رویداد ها درون یک صف قرار می گیرند و هر کی اول تو صف ایستاد اول هم پردازش می شود حال ما چطور می توانیم این ها را از تو صف در اوریم ؟

جواب : استفاده از تابع SDL_PollEvent() است و یک ساختار SDL_Event

 

ما یک ساختار را به صورت ارجاع به SDL_PollEvent  می فرستیم واین تابع هم ان را دستکاری می کند

و تا موقعی که کسی درون صف باشد SDL_PollEvent مقدار غیر صفر بر میگرداند

            //If the user has Xed out the window

            if( event.type == SDL_QUIT )

            {

                //Quit the program

                quit = true;

            }   

        }

    }

وقتی کاربر دکمه X را بزند از حلقه بیرون می اید

 

    //Free the surface and quit SDL

    clean_up();

       

    return 0;   

}

در اینجا هم برنامه پایان میابد

 

بحث تکمیلی :

SDL_Event را می توان بعد از SDL_Surface مهمترین ساختار SDL دانست.

این ها مثال هایی از type هستند

Event type        Event Structure

SDL_ACTIVEEVENT            SDL_ActiveEvent

SDL_KEYDOWN/UP            SDL_KeyboardEvent

SDL_MOUSEMOTION         SDL_MouseMotionEvent

SDL_MOUSEBUTTONDOWN/UP   SDL_MouseButtonEvent

SDL_JOYAXISMOTION       SDL_JoyAxisEvent

SDL_JOYBALLMOTION      SDL_JoyBallEvent

SDL_JOYHATMOTION        SDL_JoyHatEvent

SDL_JOYBUTTONDOWN/UP         SDL_JoyButtonEvent

SDL_QUIT      SDL_QuitEvent

SDL_SYSWMEVENT            SDL_SysWMEvent

SDL_VIDEORESIZE  SDL_ResizeEvent

SDL_VIDEOEXPOSE            SDL_ExposeEvent

SDL_USEREVENT     SDL_UserEvent

 

SDL_Event دو استفاده دارد

1.خواندن رویداد ها از صف (به وسیله SDL_PollEvent)

2.قرار دادن رویدادهای مصنوعی در صف(به وسیله SDL_PushEvent)

مثال :

SDL_Event test_event;
while(SDL_PollEvent(&test_event)) {
  switch(test_event.type) {
    case SDL_MOUSEMOTION:
      printf("We got a motion event.
");
      printf("Current mouse position is: (%d, %d)
", test_event.motion.x, test_event.motion.y);
      break;
    default:
      printf("Unhandled Event!
");
      break;
  }
}
printf("Event queue empty.
");

 

 

در درسهای بعدی در مورد برنامه نویسی Mouse به شما خواهم گفت تا چند درس دیگر.

درس ۳ : نصب کتابخانه های الحاقی برروی SDL

نصب کتابخانه های الحاقی برروی SDL :

 

اولین کار رفتن به این صفحه و دانلود SDL_Image که یکی از کتابخانه های الحاقی هست است

this page

 

فایل ZIP را باز کنید سپس پوشه درون ان را باز کنید در این پوشه دو پوشه وجود دارد فایلهای lib را
به پوشه LibویژالC++خود کپی کنید مثلا در
C:Program FilesMicrosoft Visual StudioVC98Lib
سپس فایل های هدر را به پوشه includesdl ویژوال C خود کپی کنید

سپس فایل های DLL را از پوشه
Lib
به پوشه windows/system32 کپی کنید

 

سپس به setting رفته در برگه linker بعد از SDL.libو SDLmain.lib تایپ کنید

SDL_image.lib

 

حال تابع image_load خود را دستکاری می کنیم و SDL_LoadBMP را به IMG_Load تغییر می دهیم حال شما توانایی بارگزاری فایلهای :

BMP, PNM, XPM, LBM, PCX, GIF, JPEG, TGA, PNG

دارید

 

 

SDL_Surface *load_image( std::string filename )

{

    //The image that's loaded

    SDL_Surface* loadedImage = NULL;

   

    //The optimized image that will be used

    SDL_Surface* optimizedImage = NULL;

   

    //Load the image using SDL_image

    loadedImage = IMG_Load( filename.c_str() );

   

    //If the image loaded

    if( loadedImage != NULL )

    {

        //Create an optimized image

        optimizedImage = SDL_DisplayFormat( loadedImage );

       

        //Free the old image

        SDL_FreeSurface( loadedImage );

    }

   

    //Return the optimized image

    return optimizedImage;

}

 

کار با CD-Rom

به نام خالق نًفًسهام

 

کار با CD-Rom :

 

شما در این درس با ساختارهای :

 

SDL_CDStatus

SDL_CD

SDL_CDtrack

و توابع :

SDL_CDNumDrives

SDL_CDName

SDL_CDOpen

SDL_CDPlay

SDL_CDPlayTracks

SDL_CDPause

SDL_CDResume

SDL_CDStop

اشنا می شوید.

 

SDL حتی توانایی پشتیبانی از سیستم های با 32 درایو CD-Rom را دارد قبل ازفراخوانی باید CD-Rom را به وسیله دستور SDL_Init() برای استفاده اماده کنیم وسپس می توان بوسیله تابع SDL_CDNumDrives() تعداد CD درایو ها را تشخیص دهیم.

 

قبل از ادامه کار ساختارهای SDL_CD و SDL_status را توضیح می دهیم

 

CD_status یک enum هست که اینگونه تعریف می شود

 

typedef enum {

  CD_TRAYEMPTY,

  CD_STOPPED,

  CD_PLAYING,

  CD_PAUSED,

  CD_ERROR = -1

} CDstatus;

که موقعیت CD را می تواند به ما اطلاع بدهد

 

typedef struct {

  int id;

  CDstatus status;

  int numtracks;

  int cur_track;

  int cur_frame;

  SDL_CDtrack track[SDL_MAX_TRACKS+1];

} SDL_CD;

که id مشخص کننده شناسه عددی از CD_Rom است

status هم مشخص کننده وضیعت CD-Rom است

Numtracks تعداد ترک های روی که CD است

cur_track شماره ترک فعلی را نشان می دهد

cur_frame شماره فرم فعلی را مشخص می کند

SDL_CDtrack ساختار ترک از CD را مشخص میکند

 

ساختار SDL_CDtrackساختار نشان دهنده مشخصات ترک است

typedef struct{
  Uint8 id;
  Uint8 type;
  Uint32 length;
  Uint32 offset;
} SDL_CDtrack;

 

id شماره ترک

Type نوع ترک را مشخص میکند داده(SDL_DATA_TRACK) یا صوتی (SDL_AUDIO_TRACK)

 

Length طول ترک را مشخص میکند در فرمت فرم

Offset مبدا ترک در فرمت فرم

 

---------------------------------------------------------

سپس می توان بوسیله تابع

SDL_CD *SDL_CDOpen(int drive);

با دادن شماره درایو هر کدام را به اتخاب اماده کرد.

که این تابع یک ساختار SDL_CD بر میگرداند

 

یک CD از یک ترک یا بیشتر درست شده است و هر ترک تعداد معینی فرم دارد و هر فرم تقریبا kb 2 است ودر سرعت معمولی هر CD-Rom در ثانیه75 فرم را می خواند

SDL با فرم ها کار میکند ولی میتوان به راحتی با ماکروهای FRAMES_TO_MSF و MSF_TO_FRAMES ان را به دقیقه و ثانیه و

فرم تبدیل کرد.

مثال :

فرض کنید متغییرcdrom با SDL_CDOpen تخصیص داده شده باشد //

int min, sec, frame;
int frame_offset;
 
FRAMES_TO_MSF(cdrom->cur_frame, &min, &sec, &frame);
printf(“Current Position: %d minutes, %d seconds, %d frames
”, min, sec, frame);
 
frame_offset=MSF_TO_FRAMES(min, sec, frame);

 

 

 

تابع  SDL_CDName(int number) اسم CD را بر میگرداند

 

const char *SDL_CDName(int drive);

مثال :

·         "/dev/cdrom"

·         "E:"

·         "/dev/disk/ide/1/master"

یک مثال دیگر :

int main(int a, char* b[]){
SDL_CD *cdrom;
int cur_track;
int min, sec, frame;
SDL_Init(SDL_INIT_CDROM);
atexit(SDL_Quit);
 
/* Check for CD drives */
if(!SDL_CDNumDrives()){
  /* None found */
  fprintf(stderr, "No CDROM devices available
");
  exit(-1);
}
 
/* Open the default drive */
cdrom=SDL_CDOpen(0);
 
/* Did if open? Check if cdrom is NULL */
if(!cdrom){
  fprintf(stderr, "Couldn't open drive: %s
", SDL_GetError());
  exit(-1);
}
 
/* Print Volume info */
printf("Name: %s
", SDL_CDName(0));
printf("Tracks: %d
", cdrom->numtracks);
for(cur_track=0;cur_track < cdrom->numtracks; cur_track++){
  FRAMES_TO_MSF(cdrom->track[cur_track].length, &min, &sec, &frame);
  printf("	Track %d: Length %d:%d
", cur_track, min, sec);
}
 
SDL_CDClose(cdrom);
}
تابع SDL_CDPlay :
int SDL_CDPlay(SDL_CD *cdrom, int start, int length);
که cd مورد نظر را از فرم start به مدت length فرم پخش می کند
 
تابع SDL_CDPlayTracks :
int SDL_CDPlayTracks(SDL_CD *cdrom, int start_track, int start_frame, int ntracks, int nframes));
 
start_track شماره ترک برای شروع
start_frame شماره فرم از ترک اول
ntracks تعداد ترک های که باید پخش شود
Nframes شماره فرم از اخرین ترکی که باید پخش شود
 
 
مثال :
/* assuming cdrom is a previously opened device */
/* Play the entire CD */
if(CD_INDRIVE(SDL_CDStatus(cdrom)))
  SDL_CDPlayTracks(cdrom, 0, 0, 0, 0);
 
/* Play the first track */
if(CD_INDRIVE(SDL_CDStatus(cdrom)))
  SDL_CDPlayTracks(cdrom, 0, 0, 1, 0);
 
/* Play first 15 seconds of the 2nd track */
if(CD_INDRIVE(SDL_CDStatus(cdrom)))
  SDL_CDPlayTracks(cdrom, 1, 0, 0, CD_FPS*15);
 

بقیه توابع هم از اسمشان معلوم اند.