输入(Input)类

在游戏引擎中实现一个完整的输入(Input)类涉及到多个方面的功能,包括键盘、鼠标、触摸屏等输入设备的检测和处理。下面是一个简化的输入类的实现示例,使用C++语言和一些常见的游戏引擎库(如SDL)来实现。

1. 包含必要的头文件

#include <SDL.h>
#include <unordered_map>
#include <vector>

2. 定义输入类

class Input {
public:
    Input();
    ~Input();

    bool Initialize();
    void Shutdown();

    void Update();

    bool IsKeyDown(SDL_Keycode key) const;
    bool IsKeyUp(SDL_Keycode key) const;
    bool IsKeyPressed(SDL_Keycode key) const;

    bool IsMouseButtonDown(int button) const;
    bool IsMouseButtonUp(int button) const;
    bool IsMouseButtonPressed(int button) const;

    SDL_Point GetMousePosition() const;

private:
    std::unordered_map<SDL_Keycode, bool> keyStates;
    std::unordered_map<int, bool> mouseButtonStates;
    SDL_Point mousePosition;
};

3. 实现输入类的方法

Input::Input() {
    // 初始化SDL
    if (SDL_Init(SDL_INIT_VIDEO) < 0) {
        SDL_Log("SDL could not initialize! SDL_Error: %s\n", SDL_GetError());
    }
}

Input::~Input() {
    Shutdown();
}

bool Input::Initialize() {
    // 初始化输入系统
    return true;
}

void Input::Shutdown() {
    // 清理输入资源
    SDL_Quit();
}

void Input::Update() {
    SDL_Event event;
    while (SDL_PollEvent(&event)) {
        switch (event.type) {
            case SDL_KEYDOWN:
                keyStates[event.key.keysym.sym] = true;
                break;
            case SDL_KEYUP:
                keyStates[event.key.keysym.sym] = false;
                break;
            case SDL_MOUSEBUTTONDOWN:
                mouseButtonStates[event.button.button] = true;
                break;
            case SDL_MOUSEBUTTONUP:
                mouseButtonStates[event.button.button] = false;
                break;
            case SDL_MOUSEMOTION:
                mousePosition.x = event.motion.x;
                mousePosition.y = event.motion.y;
                break;
        }
    }
}

bool Input::IsKeyDown(SDL_Keycode key) const {
    auto it = keyStates.find(key);
    if (it != keyStates.end()) {
        return it->second;
    }
    return false;
}

bool Input::IsKeyUp(SDL_Keycode key) const {
    return !IsKeyDown(key);
}

bool Input::IsKeyPressed(SDL_Keycode key) const {
    // 这里可以实现按键按下的检测逻辑
    // 例如,通过记录上一帧的状态来判断是否刚刚按下
    return false;
}

bool Input::IsMouseButtonDown(int button) const {
    auto it = mouseButtonStates.find(button);
    if (it != mouseButtonStates.end()) {
        return it->second;
    }
    return false;
}

bool Input::IsMouseButtonUp(int button) const {
    return !IsMouseButtonDown(button);
}

bool Input::IsMouseButtonPressed(int button) const {
    // 这里可以实现鼠标按钮按下的检测逻辑
    // 例如,通过记录上一帧的状态来判断是否刚刚按下
    return false;
}

SDL_Point Input::GetMousePosition() const {
    return mousePosition;
}

4. 使用输入类

int main(int argc, char* argv[]) {
    Input input;
    if (!input.Initialize()) {
        return -1;
    }

    bool running = true;
    while (running) {
        input.Update();

        if (input.IsKeyDown(SDLK_ESCAPE)) {
            running = false;
        }

        SDL_Delay(16); // 大约60 FPS
    }

    input.Shutdown();

    return 0;
}

5. 扩展输入类功能

为了使输入类更加强大和灵活,可以考虑添加以下功能:

5.1 触摸屏输入

对于支持触摸屏的设备,可以添加触摸屏输入的检测和处理。

bool Input::IsTouchDown(int fingerId) const {
    // 实现触摸屏按下的检测逻辑
    return false;
}

bool Input::IsTouchUp(int fingerId) const {
    // 实现触摸屏抬起的检测逻辑
    return false;
}

bool Input::IsTouchPressed(int fingerId) const {
    // 实现触摸屏按下的检测逻辑
    return false;
}

SDL_Point Input::GetTouchPosition(int fingerId) const {
    // 实现获取触摸位置的逻辑
    return {0, 0};
}
5.2 自定义输入映射

允许开发者自定义输入映射,以便更好地适应不同的游戏需求。

class InputMapping {
public:
    void AddMapping(SDL_Keycode key, std::function<void()> action);
    void AddMouseMapping(int button, std::function<void()> action);
    void ProcessInput(const Input& input);

private:
    std::unordered_map<SDL_Keycode, std::function<void()>> keyMappings;
    std::unordered_map<int, std::function<void()>> mouseButtonMappings;
};

void InputMapping::AddMapping(SDL_Keycode key, std::function<void()> action) {
    keyMappings[key] = action;
}

void InputMapping::AddMouseMapping(int button, std::function<void()> action) {
    mouseButtonMappings[button] = action;
}

void InputMapping::ProcessInput(const Input& input) {
    for (const auto& pair : keyMappings) {
        if (input.IsKeyPressed(pair.first)) {
            pair.second();
        }
    }
    for (const auto& pair : mouseButtonMappings) {
        if (input.IsMouseButtonPressed(pair.first)) {
            pair.second();
        }
    }
}

6. 示例:使用扩展功能的输入类

int main(int argc, char* argv[]) {
    Input input;
    if (!input.Initialize()) {
        return -1;
    }

    InputMapping inputMapping;
    inputMapping.AddMapping(SDLK_SPACE, []() {
        std::cout << "Space key pressed!" << std::endl;
    });
    inputMapping.AddMouseMapping(SDL_BUTTON_LEFT, []() {
        std::cout << "Left mouse button pressed!" << std::endl;
    });

    bool running = true;
    while (running) {
        input.Update();
        inputMapping.ProcessInput(input);

        if (input.IsKeyDown(SDLK_ESCAPE)) {
            running = false;
        }

        SDL_Delay(16); // 大约60 FPS
    }

    input.Shutdown();

    return 0;
}

通过这些扩展和优化,输入类可以更好地适应不同的游戏场景和需求,提供更灵活和强大的输入处理功能。在实际的游戏引擎中,输入类可能还会包含更多的功能和优化,以满足高性能和高质量输入的需求。

7. 输入事件系统

为了更好地管理输入事件,可以实现一个输入事件系统,允许其他系统(如游戏逻辑、UI等)订阅和响应输入事件。

7.1 定义输入事件
enum class InputEventType {
    KeyDown,
    KeyUp,
    KeyPressed,
    MouseButtonDown,
    MouseButtonUp,
    MouseButtonPressed,
    MouseMotion,
    // 其他事件类型
};
7.2 定义输入事件回调
using InputEventCallback = std::function<void(InputEventType, int)>;

class Input {
public:
    // ... 其他成员函数 ...

    void SubscribeToEvent(InputEventType eventType, InputEventCallback callback) {
        eventCallbacks[eventType].push_back(callback);
    }

private:
    std::unordered_map<InputEventType, std::vector<InputEventCallback>> eventCallbacks;
};
7.3 触发输入事件
void Input::TriggerEvent(InputEventType eventType, int eventData) {
    if (eventCallbacks.find(eventType) != eventCallbacks.end()) {
        for (auto& callback : eventCallbacks[eventType]) {
            callback(eventType, eventData);
        }
    }
}

8. 示例:使用输入事件系统的输入类

int main(int argc, char* argv[]) {
    Input input;
    if (!input.Initialize()) {
        return -1;
    }

    input.SubscribeToEvent(InputEventType::KeyDown, [](InputEventType eventType, int eventData) {
        std::cout << "Key down event: " << eventData << std::endl;
    });

    input.SubscribeToEvent(InputEventType::MouseButtonDown, [](InputEventType eventType, int eventData) {
        std::cout << "Mouse button down event: " << eventData << std::endl;
    });

    bool running = true;
    while (running) {
        input.Update();

        if (input.IsKeyDown(SDLK_ESCAPE)) {
            running = false;
        }

        SDL_Delay(16); // 大约60 FPS
    }

    input.Shutdown();

    return 0;
}

9. 输入设备管理

为了更好地管理不同的输入设备,可以实现一个输入设备管理器,负责设备的初始化、更新和清理。

9.1 定义输入设备接口
class IInputDevice {
public:
    virtual ~IInputDevice() {}
    virtual void Initialize() = 0;
    virtual void Update() = 0;
    virtual void Shutdown() = 0;
};
9.2 实现键盘设备
class KeyboardDevice : public IInputDevice {
public:
    // ... 实现键盘设备的初始化、更新和清理 ...
};
9.3 实现鼠标设备
class MouseDevice : public IInputDevice {
public:
    // ... 实现鼠标设备的初始化、更新和清理 ...
};
9.4 输入设备管理器
class InputDeviceManager {
public:
    InputDeviceManager() {
        devices.push_back(std::make_unique<KeyboardDevice>());
        devices.push_back(std::make_unique<MouseDevice>());
    }

    void Initialize() {
        for (auto& device : devices) {
            device->Initialize();
        }
    }

    void Update() {
        for (auto& device : devices) {
            device->Update();
        }
    }

    void Shutdown() {
        for (auto& device : devices) {
            device->Shutdown();
        }
    }

private:
    std::vector<std::unique_ptr<IInputDevice>> devices;
};

10. 示例:使用输入设备管理器

int main(int argc, char* argv[]) {
    InputDeviceManager deviceManager;
    deviceManager.Initialize();

    bool running = true;
    while (running) {
        deviceManager.Update();

        // 处理输入事件

        if (/* 检测到退出事件 */) {
            running = false;
        }

        SDL_Delay(16); // 大约60 FPS
    }

    deviceManager.Shutdown();

    return 0;
}

通过这些扩展和优化,输入类可以更好地适应不同的游戏场景和需求,提供更灵活和强大的输入处理功能。在实际的游戏引擎中,输入类可能还会包含更多的功能和优化,以满足高性能和高质量输入的需求。

11. 多线程输入处理

在现代游戏引擎中,多线程处理可以显著提高性能,特别是在处理输入这种频繁更新的任务时。以下是如何为输入类添加多线程支持的示例。

11.1 线程安全的输入更新

确保输入更新操作是线程安全的,以避免多个线程同时访问和修改输入状态时出现竞态条件。

#include <mutex>

class Input {
public:
    // ... 其他成员函数 ...

    void Update() {
        std::lock_guard<std::mutex> lock(inputMutex);
        // 更新输入状态
    }

private:
    std::mutex inputMutex;
};
11.2 异步输入处理

异步处理输入事件可以避免阻塞主线程,提高游戏的响应速度。

#include <future>

class Input {
public:
    // ... 其他成员函数 ...

    std::future<void> UpdateAsync() {
        return std::async(std::launch::async, [this]() {
            Update();
        });
    }
};

12. 示例:使用多线程功能的输入类

int main(int argc, char* argv[]) {
    Input input;
    if (!input.Initialize()) {
        return -1;
    }

    bool running = true;
    while (running) {
        auto future = input.UpdateAsync();

        // 处理其他任务

        future.get(); // 等待输入更新完成

        if (/* 检测到退出事件 */) {
            running = false;
        }

        SDL_Delay(16); // 大约60 FPS
    }

    input.Shutdown();

    return 0;
}

13. 跨平台支持

为了使输入类能够在不同的操作系统和平台上运行,需要考虑跨平台支持。

13.1 抽象输入接口

定义一个抽象的输入接口,然后为每个支持的操作系统和平台实现具体的输入类。

class IInput {
public:
    virtual ~IInput() {}
    virtual void Initialize() = 0;
    virtual void Update() = 0;
    virtual void Shutdown() = 0;
    // 其他公共接口
};

class WindowsInput : public IInput {
    // 实现Windows平台的输入功能
};

class LinuxInput : public IInput {
    // 实现Linux平台的输入功能
};

class MacInput : public IInput {
    // 实现Mac平台的输入功能
};
13.2 工厂模式创建输入实例

使用工厂模式来创建特定平台的输入实例。

class InputFactory {
public:
    static std::unique_ptr<IInput> CreateInput() {
        #ifdef _WIN32
        return std::make_unique<WindowsInput>();
        #elif __linux__
        return std::make_unique<LinuxInput>();
        #elif __APPLE__
        return std::make浮现<pot>
        #else
        #error "Unsupported platform"
        #endif
    }
};

14. 示例:跨平台输入类使用

int main(int argc, char* argv[]) {
    std::unique_ptr<IInput> input = InputFactory::CreateInput();
    if (!input->Initialize()) {
        return -1;
    }

    bool running = true;
    while (running) {
        input->Update();

        // 处理输入事件

        if (/* 检测到退出事件 */) {
            running = false;
        }

        SDL_Delay(16); // 大约60 FPS
    }

    input->Shutdown();

    return 0;
}

通过这些扩展和优化,输入类可以更好地适应不同的游戏场景和需求,提供更灵活和强大的输入处理功能。在实际的游戏引擎中,输入类可能还会包含更多的功能和优化,以满足高性能和高质量输入的需求。

15. 输入数据记录与回放

在某些情况下,开发者可能需要记录玩家的输入数据并在之后进行回放,以进行调试或创建演示视频。

15.1 记录输入数据
class InputRecorder {
public:
    void RecordInput(const Input& input) {
        recordedInputs.push_back(input);
    }

    std::vector<Input> GetRecordedInputs() const {
        return recordedInputs;
    }

private:
    std::vector<Input> recordedInputs;
};
15.2 回放输入数据
class InputReplayer {
public:
    void SetRecordedInputs(const std::vector<Input>& inputs) {
        recordedInputs = inputs;
        currentIndex = 0;
    }

    void ReplayInput(Input& input) {
        if (currentIndex < recordedInputs.size()) {
            input = recordedInputs[currentIndex++];
        }
    }

private:
    std::vector<Input> recordedInputs;
    size_t currentIndex = 0;
};

16. 示例:使用输入数据记录与回放

int main(int argc, char* argv[]) {
    Input input;
    InputRecorder recorder;
    InputReplayer replayer;

    if (!input.Initialize()) {
        return -1;
    }

    bool recording = false;
    bool replaying = false;
    bool running = true;
    while (running) {
        input.Update();

        if (recording) {
            recorder.RecordInput(input);
        }

        if (replaying) {
            replayer.ReplayInput(input);
        }

        // 处理输入事件

        if (/* 检测到退出事件 */) {
            running = false;
        }

        SDL_Delay(16); // 大约60 FPS
    }

    input.Shutdown();

    return 0;
}

17. 输入自定义数据

有时开发者可能需要为输入添加自定义数据,例如玩家ID、游戏状态等。

class Input {
public:
    // ... 其他成员函数 ...

    void SetCustomData(void* data) {
        customData = data;
    }

    void* GetCustomData() const {
        return customData;
    }

private:
    void* customData = nullptr;
};

18. 示例:使用输入自定义数据

int main(int argc, char* argv[]) {
    Input input;
    int playerID = 1;

    if (!input.Initialize()) {
        return -1;
    }

    bool running = true;
    while (running) {
        input.Update();

        input.SetCustomData(&playerID);

        // 处理输入事件

        if (/* 检测到退出事件 */) {
            running = false;
        }

        SDL_Delay(16); // 大约60 FPS
    }

    input.Shutdown();

    return 0;
}

19. 输入性能优化

为了提高输入处理的性能,可以考虑以下优化策略:

19.1 批量处理输入事件

批量处理输入事件可以减少函数调用的开销。

class Input {
public:
    // ... 其他成员函数 ...

    void ProcessEvents(const std::vector<SDL_Event>& events) {
        for (const auto& event : events) {
            // 处理事件
        }
    }
};
19.2 使用输入缓存

输入缓存可以减少重复计算的开销。

class Input {
public:
    // ... 其他成员函数 ...

    bool WasKeyPressedLastFrame(SDL_Keycode key) const {
        return keyStatesLastFrame[key];
    }

private:
    std::unordered_map<SDL_Keycode, bool> keyStates;
    std::unordered_map<SDL_Keycode, bool> keyStatesLastFrame;
};

通过这些扩展和优化,输入类可以更好地适应不同的游戏场景和需求,提供更灵活和强大的输入处理功能。在实际的游戏引擎中,输入类可能还会包含更多的功能和优化,以满足高性能和高质量输入的需求。

20. 输入的触摸屏支持

对于移动设备和触摸屏设备,需要特别处理触摸事件。

20.1 触摸事件处理
class Input {
public:
    // ... 其他成员函数 ...

    bool IsTouchDown(int fingerId) const {
        // 实现触摸屏按下的检测逻辑
        return false;
    }

    bool IsTouchUp(int fingerId) const {
        // 实现触摸屏抬起的检测逻辑
        return false;
    }

    bool IsTouchPressed(int fingerId) const {
        // 实现触摸屏按下的检测逻辑
        return false;
    }

    SDL_Point GetTouchPosition(int fingerId) const {
        // 实现获取触摸位置的逻辑
        return {0, 0};
    }
};

21. 示例:使用触摸屏支持的输入类

int main(int argc, char* argv[]) {
    Input input;
    if (!input.Initialize()) {
        return -1;
    }

    bool running = true;
    while (running) {
        input.Update();

        // 处理触摸事件
        for (int i = 0; i < MAX_FINGERS; ++i) {
            if (input.IsTouchDown(i)) {
                SDL_Point pos = input.GetTouchPosition(i);
                std::cout << "Touch down at: (" << pos.x << ", " << pos.y << ")" << std::endl;
            }
        }

        if (/* 检测到退出事件 */) {
            running = false;
        }

        SDL_Delay(16); // 大约60 FPS
    }

    input.Shutdown();

    return 0;
}

22. 输入的虚拟现实支持

对于虚拟现实设备,需要特别处理头部运动和手柄输入。

22.1 虚拟现实事件处理
class Input {
public:
    // ... 其他成员函数 ...

    bool IsHeadsetMoved() const {
        // 实现头部移动的检测逻辑
        return false;
    }

    SDL_Point GetHeadsetPosition() const {
        // 实现获取头部位置的逻辑
        return {0, 0};
    }

    bool IsControllerButtonPressed(int controllerId, int button) const {
        // 实现手柄按钮按下的检测逻辑
        return false;
    }
};

23. 示例:使用虚拟现实支持的输入类

int main(int argc, char* argv[]) {
    Input input;
    if (!input.Initialize()) {
        return -1;
    }

    bool running = true;
    while (running) {
        input.Update();

        // 处理虚拟现实事件
        if (input.IsHeadsetMoved()) {
            SDL_Point pos = input.GetHeadsetPosition();
            std::cout << "Headset moved to: (" << pos.x << ", " << pos.y << ")" << std::endl;
        }

        for (int i = 0; i < MAX_CONTROLLERS; ++i) {
            if (input.IsControllerButtonPressed(i, BUTTON_A)) {
                std::cout << "Controller "<< i << " button A pressed" << std::endl;
            }
        }

        if (/* 检测到退出事件 */) {
            running = false;
        }

        SDL_Delay(16); // 大约60 FPS
    }

    input.Shault();

    return 0;
}

24. 输入的远程控制支持

对于远程控制设备,需要特别处理遥控器输入。

24.1 远程控制事件处理
class Input {
public:
    // ... 其他成员函数 ...

    bool IsRemoteButtonPressed(int button) const {
        // 实现遥控器按钮按下的检测逻辑
        return false;
    }
};

25. 示例:使用远程控制支持的输入类

int main(int argc, char* argv[]) {
    Input input;
    if (!input.Initialize()) {
        return -1;
    }

    bool running = true;
    while (running) {
        input.Update();

        // 处理远程控制事件
        if (input.IsRemoteButtonPressed(REMOTE_BUTTON_OK)) {
            std::cout << "Remote button OK pressed" << std::endl;
        }

        if (/* 检测到退出事件 */) {
            running = false;
        }

        SDL_Delay(16); // 大约60 FPS
    }

    input.Shutdown();

    return 0;
}

通过这些扩展和优化,输入类可以更好地适应不同的游戏场景和需求,提供更灵活和强大的输入处理功能。在实际的游戏引擎中,输入类可能还会包含更多的功能和优化,以满足高性能和高质量输入的需求。

26. 输入的辅助功能支持

对于辅助功能设备,如语音输入、手势识别等,需要特别处理这些输入方式。

26.1 辅助功能事件处理
class Input {
public:
    // ... 其他成员函数 ...

    bool IsVoiceCommandRecognized(const std::string& command) const {
        // 实现语音命令识别的检测逻辑
        return false;
    }

    bool IsGestureRecognized(const std::string& gesture) const {
        // 实现手势识别的检测逻辑
        return false;
    }
};

27. 示例:使用辅助功能支持的输入类

int main(int argc, char* argv[]) {
    Input input;
    if (!input.Initialize()) {
        return -1;
    }

    bool running = true;
    while (running) {
        input.Update();

        // 处理辅助功能事件
        if (input.IsVoiceCommandRecognized("start")) {
            std::cout << "Voice command 'start' recognized" << std::endl;
        }

        if (input.IsGestureRecognized("swipe_left")) {
            std::cout << "Gesture 'swipe_left' recognized" << std::endl;
        }

        if (/* 检测到退出事件 */) {
            running = false;
        }

        SDL_Delay(16); // 大约60 FPS
    }

    input.Shutdown();

    return 0;
}

28. 输入的多人游戏支持

对于多人游戏,需要处理多个玩家的输入。

28.1 多人游戏输入处理
class Input {
public:
    // ... 其他成员函数 ...

    bool IsPlayerKeyPressed(int playerId, SDL_Keycode key) const {
        // 实现多个玩家按键按下的检测逻辑
        return false;
    }

    bool IsPlayerMouseButtonPressed(int playerId, int button) const {
        // 实现多个玩家鼠标按钮按下的检测 void *data) const {
        return false;
    }
};

29. 示例:使用多人游戏支持的输入类

int main(int argc, char* argv[]) {
    Input input;
    if (!input.Initialize()) {
        return -1;
    }

    bool running = true;
    while (running) {
        input.Update();

        // 处理多个玩家的输入
        for (int i = 0; i < MAX_PLAYERS; ++i) {
            if (input.IsPlayerKeyPressed(i, SDLK_SPACE)) {
                std::cout << "Player "<< i << " pressed space key" << std::endl;
            }

            if (input.IsPlayerMouseButtonPressed(i, SDL_BUTTON_LEFT)) {
                std::cout << "Player "<< i << " pressed left mouse button" << std::endl;
            }
        }

        if (/* 检测到退出事件 */) {
            running = false;
        }

        SDL_Delay(16); // 大约60 FPS
    }

    input.Shutdown();

    return 0;
}

30. 输入的调试和测试工具

为了方便调试和测试输入系统,可以添加一些调试和测试工具。

30.1 输入调试工具
class InputDebugger {
public:
    void LogInputState(const Input& input) {
        // 实现输入状态的日志记录
    }
};

31. 示例:使用输入调试工具

int main(int argc, char* argv[]) {
    Input input;
    InputDebugger debugger;
    if (!input.Initialize()) {
        return -1;
    }

    bool running = true;
    while (running) {
        input.Update();

        debugger.LogInputState(input);

        if (/* 检测到退出事件 */) {
            running = false;
        }

        SDL_Delay(16); // 大约60 FPS
    }

    input.Shutdown();

    return 0;
}

通过这些扩展和优化,输入类可以更好地适应不同的游戏场景和需求,提供更灵活和强大的输入处理功能。在实际的游戏引擎中,输入类可能还会包含更多的功能和优化,以满足高性能和高质量输入的需求。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

你一身傲骨怎能输

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值