使用 SDL 和 C 为我的爱好游戏引擎处理事件
Event handling using SDL and C for my hobby game engine
我正在构建一个 hobby/minimalist/general 二维游戏引擎,使用 SDL 和 C 作为我的编程语言。还跟随 Lazy Foo Production 教程。我用C语言是为了学习。
我想实现一个通用的事件处理函数,它能够 运行 一个用户编写的函数来处理给定的事件。目前我还在起步阶段。
处理程序头文件:
#ifndef HANDLER_H
#define HANDLER_H
#include <SDL2/SDL.h>
#include <stdarg.h>
int handle(SDL_Event e, void (*handler)(int args,...));
#endif
客户代码:
int quit = FALSE;
SDL_Event e;
while (quit == FALSE) {
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) {
quit = TRUE;
}
//call to handle goes here
}
render_image(&dp,&i_p);
update_display(&dp);
}
我们将函数指针作为 handle()
的参数就足够了吗?还是有更好的方法来实现通用事件处理程序。
我在事件处理方面对引擎的核心目标是能够让 handler
处理游戏循环中轮询的事件,方法是使用最终用户编写的函数而不是在函数中进行硬编码以处理每种类型的可能事件。
如果您希望最终用户编写处理事件的函数,我建议依靠 回调。这个想法是最终用户将指示 什么 事件处理程序为每种事件类型调用,而游戏引擎将指示 何时 调用相应的事件处理程序。
为用户提供了回调结构,以便用户代码可以定义自定义事件处理程序并配置这些回调以引用这些自定义函数。然后,游戏引擎的事件处理循环通过用户设置的回调调用这些函数。
例子
您可以为不同的事件定义不同的函数类型:
typedef void (*quit_handler_t)(void);
typedef void (*keydown_handler_t)(SDL_Keycode);
typedef void (*keyup_handler_t)(SDL_Keycode);
也就是说,用于退出的处理程序不带任何参数,而那些用于按键上升和下降的处理程序采用表示相应键的参数。
然后,您向客户端提供一个结构 event_handlers
,其中包含指向事件处理程序的指针,最终用户应该填充:
struct {
quit_handler_t quit;
keydown_handler_t keydown;
keyup_handler_t keyup;
} event_handlers;
最后,游戏引擎处理事件的循环通过用户设置的回调调用这些函数:
SDL_Event e;
while (!quit && SDL_PollEvent(&e)) {
switch(e.type) {
case SDL_QUIT:
event_handlers.quit();
break;
case SDL_KEYDOWN:
event_handlers.keydown(e.key.keysym.sym);
break;
case SDL_KEYUP:
event_handlers.keyup(e.key.keysum.sym);
break;
}
}
请注意,游戏引擎还可以使用 default 事件处理程序初始化 event_handler
结构。最终用户可以通过修改 event_handler
.
的成员来 覆盖 该默认行为
我正在构建一个 hobby/minimalist/general 二维游戏引擎,使用 SDL 和 C 作为我的编程语言。还跟随 Lazy Foo Production 教程。我用C语言是为了学习。
我想实现一个通用的事件处理函数,它能够 运行 一个用户编写的函数来处理给定的事件。目前我还在起步阶段。
处理程序头文件:
#ifndef HANDLER_H
#define HANDLER_H
#include <SDL2/SDL.h>
#include <stdarg.h>
int handle(SDL_Event e, void (*handler)(int args,...));
#endif
客户代码:
int quit = FALSE;
SDL_Event e;
while (quit == FALSE) {
while (SDL_PollEvent(&e) != 0) {
if (e.type == SDL_QUIT) {
quit = TRUE;
}
//call to handle goes here
}
render_image(&dp,&i_p);
update_display(&dp);
}
我们将函数指针作为 handle()
的参数就足够了吗?还是有更好的方法来实现通用事件处理程序。
我在事件处理方面对引擎的核心目标是能够让 handler
处理游戏循环中轮询的事件,方法是使用最终用户编写的函数而不是在函数中进行硬编码以处理每种类型的可能事件。
如果您希望最终用户编写处理事件的函数,我建议依靠 回调。这个想法是最终用户将指示 什么 事件处理程序为每种事件类型调用,而游戏引擎将指示 何时 调用相应的事件处理程序。
为用户提供了回调结构,以便用户代码可以定义自定义事件处理程序并配置这些回调以引用这些自定义函数。然后,游戏引擎的事件处理循环通过用户设置的回调调用这些函数。
例子
您可以为不同的事件定义不同的函数类型:
typedef void (*quit_handler_t)(void);
typedef void (*keydown_handler_t)(SDL_Keycode);
typedef void (*keyup_handler_t)(SDL_Keycode);
也就是说,用于退出的处理程序不带任何参数,而那些用于按键上升和下降的处理程序采用表示相应键的参数。
然后,您向客户端提供一个结构 event_handlers
,其中包含指向事件处理程序的指针,最终用户应该填充:
struct {
quit_handler_t quit;
keydown_handler_t keydown;
keyup_handler_t keyup;
} event_handlers;
最后,游戏引擎处理事件的循环通过用户设置的回调调用这些函数:
SDL_Event e;
while (!quit && SDL_PollEvent(&e)) {
switch(e.type) {
case SDL_QUIT:
event_handlers.quit();
break;
case SDL_KEYDOWN:
event_handlers.keydown(e.key.keysym.sym);
break;
case SDL_KEYUP:
event_handlers.keyup(e.key.keysum.sym);
break;
}
}
请注意,游戏引擎还可以使用 default 事件处理程序初始化 event_handler
结构。最终用户可以通过修改 event_handler
.