将枚举分配给其他枚举值

时间:2012-03-01 04:38:51

标签: d

我正在使用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()

2 个答案:

答案 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()中使用的关键上/下状态等。存储事件对象并稍后查看它们以检查是否按下了键是没有意义的,因为在最坏的情况下,您必须按顺序存储至少十二个事件对象,然后去通过它们只是为了弄清楚一个键是上升还是下降。事件对象不描述事物的“大状态”,它们只描述单一更改。看起来你只是检查最新的变化。这不适用于多个键/事件。

关于枚举赋值:看起来是正确的。

(祝你好运!)