STDIO
Tìm kiếm gần đây
    • Nội dung
    • QR Code
    • 0
    • 0
    • Sao chép

    Xử Lý Sự Kiện Trong SDL

    Hướng dẫn xử lý sự kiện trong game bằng thư viện SDL.
    13/10/2015
    27/09/2020
    8 phút đọc
    Xử Lý Sự Kiện Trong SDL

    Xử lý sự kiện trong game vô cùng quan trọng, đó có thể là sự kiện chuột, bàn phím, hay touch (đối với những dòng có màn hình cảm ứng). Framework SDL (Simple DirectMedia Layer) hỗ trợ đầy đủ những sự kiện đó để thao tác và xây dựng ứng dụng.

    Sự kiện trong SDL

    Cấu trúc SDL_Event

    SDL có cung cấp một union có tên là SDL_Event để chứa tất cả các thông tin của tất cả các event trong bộ thư viện này, cấu trúc của SDL_Event như sau:

    Uint32 type event type, shared with all events
    SDL_CommonEvent common common event data
    SDL_WindowEvent window window event data
    SDL_KeyboardEvent key keyboard event data
    SDL_TextEditingEvent edit text editing event data
    SDL_TextInputEvent text text input event data
    SDL_MouseMotionEvent motion mouse motion event data
    SDL_MouseButtonEvent button mouse button event data
    SDL_MouseWheelEvent wheel mouse wheel event data
    SDL_JoyAxisEvent jaxis joystick axis event data
    SDL_JoyBallEvent jball joystick ball event data
    SDL_JoyHatEvent jhat joystick hat event data
    SDL_JoyButtonEvent jbutton joystick button event data
    SDL_JoyDeviceEvent jdevice joystick device event data
    SDL_ControllerAxisEvent caxis game controller axis event data
    SDL_ControllerButtonEvent cbutton game controller button event data
    SDL_ControllerDeviceEvent cdevice game controller device event data
    SDL_AudioDeviceEvent adevice audio device event data (>= SDL 2.0.4)
    SDL_QuitEvent quit quit request event data
    SDL_UserEvent user custom event data
    SDL_SysWMEvent syswm system dependent window event data
    SDL_TouchFingerEvent tfinger touch finger event data
    SDL_MultiGestureEvent mgesture multi finger gesture data
    SDL_DollarGestureEvent dgesture multi finger gesture data
    SDL_DropEvent drop drag and drop event data

    Dưới đây là định nghĩa SDL_Event trong bộ thư viện SDL:

    typedef union SDL_Event
    {
        Uint32 type;                    /**< Event type, shared with all events */
        SDL_CommonEvent common;         /**< Common event data */
        SDL_WindowEvent window;         /**< Window event data */
        SDL_KeyboardEvent key;          /**< Keyboard event data */
        SDL_TextEditingEvent edit;      /**< Text editing event data */
        SDL_TextInputEvent text;        /**< Text input event data */
        SDL_MouseMotionEvent motion;    /**< Mouse motion event data */
        SDL_MouseButtonEvent button;    /**< Mouse button event data */
        SDL_MouseWheelEvent wheel;      /**< Mouse wheel event data */
        SDL_JoyAxisEvent jaxis;         /**< Joystick axis event data */
        SDL_JoyBallEvent jball;         /**< Joystick ball event data */
        SDL_JoyHatEvent jhat;           /**< Joystick hat event data */
        SDL_JoyButtonEvent jbutton;     /**< Joystick button event data */
        SDL_JoyDeviceEvent jdevice;     /**< Joystick device change event data */
        SDL_ControllerAxisEvent caxis;      /**< Game Controller axis event data */
        SDL_ControllerButtonEvent cbutton;  /**< Game Controller button event data */
        SDL_ControllerDeviceEvent cdevice;  /**< Game Controller device event data */
        SDL_QuitEvent quit;             /**< Quit request event data */
        SDL_UserEvent user;             /**< Custom event data */
        SDL_SysWMEvent syswm;           /**< System dependent window event data */
        SDL_TouchFingerEvent tfinger;   /**< Touch finger event data */
        SDL_MultiGestureEvent mgesture; /**< Gesture event data */
        SDL_DollarGestureEvent dgesture; /**< Gesture event data */
        SDL_DropEvent drop;             /**< Drag and drop event data */
    
        /* This is necessary for ABI compatibility between Visual C++ and GCC
           Visual C++ will respect the push pack pragma and use 52 bytes for
           this structure, and GCC will use the alignment of the largest datatype
           within the union, which is 8 bytes.
    
           So... we'll add padding to force the size to be 56 bytes for both.
        */
        Uint8 padding[56];
    } SDL_Event;

    Lấy thông tin Event

    Tất cả các event của Windows đều được lưu ở hàng đợi (queue), SDL có định nghĩa một hàm để lấy ra event từ hằng đợi đó, hàm này có prototype như sau:

    int SDL_PollEvent(SDL_Event* event)
    

    Có tham số truyền vào là một con trỏ tới đối tượng SDL_Event. Trả về 1 nếu có event tồn tại trong queue ngược lại trả về 0 nếu queue rỗng. Và có chức năng là lấy thông tin của event ở queue và đổ dữ liệu vào đối tượng SDL_Event sau đó xóa event đó khỏi queue.

    Ví dụ:

    SDL_Event mainEvent;
    SDL_PollEvent(&mainEvent);

    Thao tác với Event trong ứng dụng

    Sử dụng mã nguồn ở bài Khởi Tạo Môi Trường Lập Trình Game Sử Dụng Thư Viện SDL (Simple DirectMedia Layer) để khởi tạo 1 cửa sổ, tiếp tục project với đoạn code như dưới đây:

    #include <stdio.h>
    #include <SDL.h>
    
    #undef main
    int main()
    {
    	//initializes  the subsystems
    	if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
    	{
    		printf("Unable to initialize SDL %s\n", SDL_GetError());
    		return -1;
    	}
    
    	SDL_Window* window = NULL;
    	//Create window
    	window = SDL_CreateWindow("Stdio.vn - SDL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 640, SDL_WINDOW_SHOWN);
    	if (window == NULL)
    	{
    		printf("Could not create window %s", SDL_GetError());
    		return -1;
    	}
    	
    	//Delay 2s
    	SDL_Delay(2000);
    
    	//Destroy a window.
    	SDL_DestroyWindow(window);
    
    	//cleans up all initialized subsystems
    	SDL_Quit();
    	return 0;
    }

    Ở project trước, ứng dụng delay 2s sau đó giải phóng tài nguyên và thoát chương trình, do bản chất của game là cập nhật và render liên lục, nên project bắt buộc phải có một vòng lặp while để duy trì vòng đời của game (main game, main loop), trong vòng lặp đó sẽ lấy ra các sự kiện và xử lý riêng tùy theo yêu cầu của game.

    bool isRunning = true;
    SDL_Event mainEvent;
    
    while (isRunning)
    {
    	while (SDL_PollEvent(&mainEvent))
    	{
    		switch (mainEvent.type)
    		{
    
    		//User - requested quit
    		case SDL_QUIT:
    		{
    			isRunning = false;
                break;
    		}
    
    		//Mouse button pressed
    		case SDL_MOUSEBUTTONDOWN:
    		{
    			//Do Something
    			break;
    		}
    
    		//Mouse button released
    		case SDL_MOUSEBUTTONUP:
    		{
    			//Do Something
    			break;
    		}
    
    		//Mouse moved
    		case SDL_MOUSEMOTION:
    		{
    			//Do Something
    			break;
    		}
    		
    		//Mouse wheel motion
    		case SDL_MOUSEWHEEL:
    		{
    			//Do Something
    			break;
    		}
    		
    		//Key released
    		case SDL_KEYDOWN:
    		{
    			//Do Something
    			break;
    		}
    
    		//Key pressed
    		case SDL_KEYUP:
    		{
    			//Do Something
    			break;
    		}
    		default:
    			break;
    		}
    	}
    }

    Giá trị main.type được so sánh với các giá trị như SDL_KEYDOWN,  SDL_KEYUP để biết rằng đó là loại sự kiện gì.

    Ta có mối quan hệ giữa trường dữ liệu type của đối tượng SDL_Event với các cấu trúc SDL_EventType như sau, dựa vào đó có thể xử lý theo từng event cho phù hợp.

    Event Type Event Structure SDL_Event Field
    SDL_AUDIODEVICEADDED
    SDL_AUDIODEVICEREMOVED
    SDL_AudioDeviceEvent adevice
    SDL_CONTROLLERAXISMOTION SDL_ControllerAxisEvent caxis
    SDL_CONTROLLERBUTTONDOWN
    SDL_CONTROLLERBUTTONUP
    SDL_ControllerButtonEvent cbutton
    SDL_CONTROLLERDEVICEADDED
    SDL_CONTROLLERDEVICEREMOVED
    SDL_CONTROLLERDEVICEREMAPPED
    SDL_ControllerDeviceEvent cdevice
    SDL_DOLLARGESTURE
    SDL_DOLLARRECORD
    SDL_DollarGestureEvent dgesture
    SDL_DROPFILE SDL_DropEvent drop
    SDL_FINGERMOTION
    SDL_FINGERDOWN
    SDL_FINGERUP
    SDL_TouchFingerEvent tfinger
    SDL_KEYDOWN
    SDL_KEYUP
    SDL_KeyboardEvent key
    SDL_JOYAXISMOTION SDL_JoyAxisEvent jaxis
    SDL_JOYBALLMOTION SDL_JoyBallEvent jball
    SDL_JOYHATMOTION SDL_JoyHatEvent jhat
    SDL_JOYBUTTONDOWN
    SDL_JOYBUTTONUP
    SDL_JoyButtonEvent jbutton
    SDL_JOYDEVICEADDED
    SDL_JOYDEVICEREMOVED
    SDL_JoyDeviceEvent jdevice
    SDL_MOUSEMOTION SDL_MouseMotionEvent motion
    SDL_MOUSEBUTTONDOWN
    SDL_MOUSEBUTTONUP
    SDL_MouseButtonEvent button
    SDL_MOUSEWHEEL SDL_MouseWheelEvent wheel
    SDL_MULTIGESTURE SDL_MultiGestureEvent mgesture
    SDL_QUIT SDL_QuitEvent quit
    SDL_SYSWMEVENT SDL_SysWMEvent syswm
    SDL_TEXTEDITING SDL_TextEditingEvent edit
    SDL_TEXTINPUT SDL_TextInputEvent text
    SDL_USEREVENT SDL_UserEvent user
    SDL_WINDOWEVENT SDL_WindowEvent window

    SDL_EventType được định nghĩa trong bộ thư viện SDL như sau:

    typedef enum
    {
        SDL_FIRSTEVENT     = 0,     /**< Unused (do not remove) */
    
        /* Application events */
        SDL_QUIT           = 0x100, /**< User-requested quit */
    
        /* These application events have special meaning on iOS, see README-ios.txt for details */
        SDL_APP_TERMINATING,        /**< The application is being terminated by the OS
                                         Called on iOS in applicationWillTerminate()
                                         Called on Android in onDestroy()
                                    */
        SDL_APP_LOWMEMORY,          /**< The application is low on memory, free memory if possible.
                                         Called on iOS in applicationDidReceiveMemoryWarning()
                                         Called on Android in onLowMemory()
                                    */
        SDL_APP_WILLENTERBACKGROUND, /**< The application is about to enter the background
                                         Called on iOS in applicationWillResignActive()
                                         Called on Android in onPause()
                                    */
        SDL_APP_DIDENTERBACKGROUND, /**< The application did enter the background and may not get CPU for some time
                                         Called on iOS in applicationDidEnterBackground()
                                         Called on Android in onPause()
                                    */
        SDL_APP_WILLENTERFOREGROUND, /**< The application is about to enter the foreground
                                         Called on iOS in applicationWillEnterForeground()
                                         Called on Android in onResume()
                                    */
        SDL_APP_DIDENTERFOREGROUND, /**< The application is now interactive
                                         Called on iOS in applicationDidBecomeActive()
                                         Called on Android in onResume()
                                    */
    
        /* Window events */
        SDL_WINDOWEVENT    = 0x200, /**< Window state change */
        SDL_SYSWMEVENT,             /**< System specific event */
    
        /* Keyboard events */
        SDL_KEYDOWN        = 0x300, /**< Key pressed */
        SDL_KEYUP,                  /**< Key released */
        SDL_TEXTEDITING,            /**< Keyboard text editing (composition) */
        SDL_TEXTINPUT,              /**< Keyboard text input */
    
        /* Mouse events */
        SDL_MOUSEMOTION    = 0x400, /**< Mouse moved */
        SDL_MOUSEBUTTONDOWN,        /**< Mouse button pressed */
        SDL_MOUSEBUTTONUP,          /**< Mouse button released */
        SDL_MOUSEWHEEL,             /**< Mouse wheel motion */
    
        /* Joystick events */
        SDL_JOYAXISMOTION  = 0x600, /**< Joystick axis motion */
        SDL_JOYBALLMOTION,          /**< Joystick trackball motion */
        SDL_JOYHATMOTION,           /**< Joystick hat position change */
        SDL_JOYBUTTONDOWN,          /**< Joystick button pressed */
        SDL_JOYBUTTONUP,            /**< Joystick button released */
        SDL_JOYDEVICEADDED,         /**< A new joystick has been inserted into the system */
        SDL_JOYDEVICEREMOVED,       /**< An opened joystick has been removed */
    
        /* Game controller events */
        SDL_CONTROLLERAXISMOTION  = 0x650, /**< Game controller axis motion */
        SDL_CONTROLLERBUTTONDOWN,          /**< Game controller button pressed */
        SDL_CONTROLLERBUTTONUP,            /**< Game controller button released */
        SDL_CONTROLLERDEVICEADDED,         /**< A new Game controller has been inserted into the system */
        SDL_CONTROLLERDEVICEREMOVED,       /**< An opened Game controller has been removed */
        SDL_CONTROLLERDEVICEREMAPPED,      /**< The controller mapping was updated */
    
        /* Touch events */
        SDL_FINGERDOWN      = 0x700,
        SDL_FINGERUP,
        SDL_FINGERMOTION,
    
        /* Gesture events */
        SDL_DOLLARGESTURE   = 0x800,
        SDL_DOLLARRECORD,
        SDL_MULTIGESTURE,
    
        /* Clipboard events */
        SDL_CLIPBOARDUPDATE = 0x900, /**< The clipboard changed */
    
        /* Drag and drop events */
        SDL_DROPFILE        = 0x1000, /**< The system requests a file open */
    
        /* Render events */
        SDL_RENDER_TARGETS_RESET = 0x2000, /**< The render targets have been reset */
    
        /** Events ::SDL_USEREVENT through ::SDL_LASTEVENT are for your use,
         *  and should be allocated with SDL_RegisterEvents()
         */
        SDL_USEREVENT    = 0x8000,
    
        /**
         *  This last event is only for bounding internal arrays
         */
        SDL_LASTEVENT    = 0xFFFF
    } SDL_EventType;

    Ví dụ demo

    #include <stdio.h>
    #include <SDL.h>
    
    #undef main
    int main()
    {
    	//initializes  the subsystems
    	if (SDL_Init(SDL_INIT_EVERYTHING) < 0)
    	{
    		printf("Unable to initialize SDL %s\n", SDL_GetError());
    		return -1;
    	}
    
    	SDL_Window* window = NULL;
    	bool isRunning = true;
    	SDL_Event mainEvent;
    	//Create window
    	window = SDL_CreateWindow("Stdio.vn - SDL", SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, 800, 640, SDL_WINDOW_SHOWN);
    	if (window == NULL)
    	{
    		printf("Could not create window %s", SDL_GetError());
    		return -1;
    	}
    
    	while (isRunning)
    	{
    		while (SDL_PollEvent(&mainEvent))
    		{
    			switch (mainEvent.type)
    			{
    
    				//User - requested quit
    			case SDL_QUIT:
    			{
    				isRunning = false;
    				break;
    			}
    
    			//Mouse button pressed
    			case SDL_MOUSEBUTTONDOWN:
    			{
    				if (mainEvent.button.button == SDL_BUTTON_LEFT)
    				{
    					printf("Left Mouse Clicked\n");
    				}
    				else if (mainEvent.button.button == SDL_BUTTON_RIGHT)
    				{
    					printf("Right Mouse Clicked\n");
    				}
    				break;
    			}
    
    			//Mouse button released
    			case SDL_MOUSEBUTTONUP:
    			{
    
    				if (mainEvent.button.button == SDL_BUTTON_LEFT)
    				{
    					printf("Left Mouse Released\n");
    				}
    				else if (mainEvent.button.button == SDL_BUTTON_RIGHT)
    				{
    					printf("Right Mouse Released\n");
    				}
    				break;
    			}
    
    			//Mouse moved
    			case SDL_MOUSEMOTION:
    			{
    				printf("Current Position Mouse: (%d, %d)\n", mainEvent.motion.x, mainEvent.motion.y);
    				break;
    			}
    
    			//Mouse wheel motion
    			case SDL_MOUSEWHEEL:
    			{
    				printf("Mouse Wheel Motion\n");
    				break;
    			}
    
    			//Key pressed
    			case SDL_KEYDOWN:
    			{
    				printf("%c released\n", mainEvent.key.keysym.sym);
    				break;
    			}
    
    			//Key released
    			case SDL_KEYUP:
    			{
    				printf("%c pressed\n", mainEvent.key.keysym.sym);
    				break;
    			}
    			default:
    				break;
    			}
    		}
    	}
    
    	//Destroy a window.
    	SDL_DestroyWindow(window);
    
    	//cleans up all initialized subsystems
    	SDL_Quit();
    	return 0;
    }

    Download demo

    Stdio_SDL_Event_VS2013.zip 

    0 Bình luận
    Lập Trình Game

    Lập Trình Game

    Kiến thức, kỹ thuật, kinh nghiệm lập trình game.

    Đề xuất

    Xử Lý Sự Kiện Trong Cocos2d-x 3.x.x
    Bài viết nằm trong loạt bài viết chương trình Tự Học Cocos2d-x 3.x.x. ...
    Hướng Dẫn Viết Game Zero Với Cocos2d-x - Phần 8: Hiện thực GameScene - Xử lý sự kiện trong game
    Hướng dẫn cách nhận các sự kiện từ người chơi và xử lý chúng theo logic ...

    Khám phá

    Xử Lý Sự Kiện Chuột và Phím với Borland Graphics Interface - BGI
    Giới thiệu cách lập trình để xử lý sự kiện chuột cũng như bàn phím thông ...
    Chỉ Thị Tiền Xử Lý trong C/C++
    Chỉ thị tiền xử lý là những chỉ thị cung cấp cho bộ tiền xử lý để xử lý ...
    10/08/2016
    Phép Tích Chập Trong Xử Lý Ảnh (Convolution)
    Convolution là kỹ thuật quan trọng trong Xử Lý Ảnh, được sử dụng chính ...
    Xử Lý Ảnh Với OpenCV: Các Phép Toán Hình Thái Học
    Giới thiệu những thuật toán cơ sở trong xử lý hình thái học, những thuật ...
    Load Texture Trong SDL
    Cách load hình ảnh lên màn hình sử dụng framework SDL (Simple ...
    Xử Lý Chuỗi Trong PHP
    Thao tác xử lý chuỗi và các hàm xử lý chuỗi thông dụng trong ngôn ngữ ...
    28/08/2015
    std::string và Xử Lý Chuỗi trong C++
    Giới thiệu và hướng dẫn sử dụng thư viện std::string trong C++ xử lý ...
    15/08/2015
    Xử Lý Với File PLIST trong Cocos2d-x 3.x.x
    Giới thiệu những đặc điểm, cách xử lý và ứng dụng của file PLIST trong ...
    Khi bạn nhấn vào liên kết sản phẩm do STDIO đề xuất và mua hàng, STDIO có thể nhận được hoa hồng. Điều này hỗ trợ STDIO tạo thêm nhiều nội dung hữu ích. Tìm hiểu thêm.
    STDIO
    Trang chính
    Công ty TNHH STDIO

    30, Trịnh Đình Thảo, Hòa Thạnh, Tân Phú, Hồ Chí Minh
    +84 28.36205514 - +84 942.111912
    developer@stdio.vn

    383/1 Quang Trung, Phường 10, Quận Gò Vấp, Hồ Chí Minh
    Số giấy phép ĐKKD: 0311563559 do sở Kế hoạch và Đầu Tư TPHCM cấp ngày 23/02/2012

    ©STDIO, 2013 - 2020