我正在使用D和SDL来创建一个简单的游戏。我正在尝试创建一个围绕SDL的包装器,以便我不直接使用它。现在我正在尝试创建自己的Input类,尽可能远离SDL的输入。但是,我在为键盘键分配正确的枚举值时遇到了一些麻烦。
到目前为止,我已经尝试过,为键盘按键分配SDL的枚举,因为这看起来最简单,但它似乎没有工作,没有任何东西打印到控制台。
- SDLInput -
import derelict.sdl.sdl;
import SDLApp;
class SDLInput
{
private:
SDLApp sdlapp;
SDL_Event event;
public:
this()
{
event = sdlapp.event;
}
bool KeyPressed(SDLKey key)
{
if(event.type == SDL_KEYDOWN && event.key.keysym.sym == key)
return true;
else
return false;
}
bool KeyReleased(SDLKey key)
{
if(event.type == SDL_KEYUP && event.key.keysym.sym == key)
return true;
else
return false;
}
}
- DPInput -
import SDLInput;
import derelict.sdl.sdl; //Eventually I'd get rid of this, only here for testing
class DPInput
{
private:
SDLInput sdlinput;
public:
enum DPKey
{
DPK_SPACE = SDLK_SPACE
}
this()
{
sdlinput = new SDLInput;
}
bool KeyPressed(DPKey key)
{
return sdlinput.KeyPressed(key);
}
}
- DPApp -
import SDLApp;
import DPInput;
import DPTime;
import std.stdio;
class DPApp
{
//...
void Run()
{
Init();
Loop();
Cleanup();
}
void Loop()
{
dptime.InitNextTime();
while(gameRunning)
{
if(sdlapp.PollQuit())
gameRunning = false;
UpdateGame();
Render();
dptime.DPDelay(dptime.TimeLeft());
dptime.UpdateNextTime();
}
}
void UpdateGame()
{
if(dpinput.KeyPressed(dpinput.DPKey.DPK_SPACE))
writeln("DPAPP: SPACE PRESSED");
}
}
// ..主要在这里调用run()
答案 0 :(得分:1)
不要误会我的意思,我不反对DIY方法,但如果你想让你的项目继续下去,尽量不要在早期重新发明轮子 - 使用已经存在的工具,由数百名开发人员完成(和测试)。
这就是说,我全心全意地建议你使用优秀的废弃物2 - http://www.dsource.org/projects/derelict。它已包含您上面写的所有内容,以及更多(几乎所有核心SDL库)。
答案 1 :(得分:0)
我根本不了解SDL,但我发现此代码可能存在一些问题:
1) event
中的SDLInput
在何处更新?看起来您假设SDL_Event
将始终自动包含最新的“状态”?我有一种感觉它不会。
请注意,SDL_Event
可能是一个结构(?),并且this.event = app.event;
会在该确切的位置复制该事件,现在您在两个不同的位置有两个不同的事件对象并且更新一个赢了' t更新另一个。 (但如果SDL_Event
是一个类,则this.event
将引用与app.event
相同的对象。)
2)虽然很难说,但由于代码不完整,我认为这段代码对事件的运作方式感到困惑。从我所看到的,这种设计意味着你每帧只能处理一个事件,任何其他事件都会被删除。
想象一下,用户同时按下两个按钮。这会产生两个按键事件,可能在一个帧中,但你有一个事件对象,我认为你将覆盖任何传入的事件,然后你读取这个对象。您可能会在此过程中丢弃事件。此外,通过仅查看最后一个事件,无法知道是否按下了特定键。如果按下两个键并且你只看了最后一个事件,你就不可能知道第一个键是否关闭,那么这个信息会永远丢失。
传统方法是让事件调度程序调用某些函数并传递一个事件对象,其中包含有关该事件的一些额外信息,然后保留您自己的输入状态。这将发生在update()
- 函数之外,它可能会在update()
之前发生多次。例如,你可以有类似的东西:
// Pseudo code
bool keys[256];
void keyDown(Event e){
keys[e.keyCode] = true;
}
void keyUp(Event e){
keys[e.keyCode] = false;
}
void update(){
if(keys[KEY_W])
movePlayerForward();
if(keys[KEY_SPACE])
jumpPlayer();
}
void loop(){
while(true){
fireAllQueuedEvents(); // Could call keyUp/Down several times
update();
render();
}
}
fireAllQueuedEvents()
可以触发多个事件,并且它可以正常工作。这里可以同时按下W和空格键,玩家可以跳跃和移动。现在,我不知道如何在SDL中执行此操作或如何处理输入“SDL-way”,所以,除非您知道,否则docs-mobile!我想..
通常,在事件处理中,某处需要有一个事件队列。我怀疑SDL有一个或依赖底层OS:es事件队列。在某些时候,这个队列需要调度等待事件,我怀疑SDL当时有拦截这些事件的功能。这就是你需要挂钩系统的地方,你需要对它们发生的事件做出响应,然后更新你自己的数据结构,以便你以后在update()
中使用的关键上/下状态等。存储事件对象并稍后查看它们以检查是否按下了键是没有意义的,因为在最坏的情况下,您必须按顺序存储至少十二个事件对象,然后去通过它们只是为了弄清楚一个键是上升还是下降。事件对象不描述事物的“大状态”,它们只描述单一更改。看起来你只是检查最新的变化。这不适用于多个键/事件。
关于枚举赋值:看起来是正确的。
(祝你好运!)