Extra2D/docs/API_Tutorial/05_Input_Handling.md

321 lines
7.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 05. 输入处理
Extra2D 提供了统一的输入处理系统,支持手柄、键盘等多种输入设备。
## 输入管理器
通过 `Application::instance().input()` 访问输入管理器:
```cpp
auto& input = Application::instance().input();
```
## 按键检测
### 检测方法
```cpp
// 按键是否按下(持续触发)
if (input.isButtonDown(GamepadButton::A)) {
// 每帧都会触发,只要按键保持按下
}
// 按键是否刚按下(单次触发)
if (input.isButtonPressed(GamepadButton::A)) {
// 只在按下瞬间触发一次
}
// 按键是否刚释放
if (input.isButtonReleased(GamepadButton::A)) {
// 只在释放瞬间触发一次
}
```
### 常用按键
| 按键 | 说明 | Xbox 对应 | Switch 对应 |
|------|------|-----------|-------------|
| `GamepadButton::A` | A 键 | A 键 | A 键 |
| `GamepadButton::B` | B 键 | B 键 | B 键 |
| `GamepadButton::X` | X 键 | X 键 | X 键 |
| `GamepadButton::Y` | Y 键 | Y 键 | Y 键 |
| `GamepadButton::Start` | 开始键 | Menu 键 | + 键 |
| `GamepadButton::Back` | 返回键 | View 键 | - 键 |
| `GamepadButton::Guide` | 导航键 | Xbox 键 | Home 键 |
| `GamepadButton::DPadUp` | 方向上 | 方向键上 | 方向键上 |
| `GamepadButton::DPadDown` | 方向下 | 方向键下 | 方向键下 |
| `GamepadButton::DPadLeft` | 方向左 | 方向键左 | 方向键左 |
| `GamepadButton::DPadRight` | 方向右 | 方向键右 | 方向键右 |
| `GamepadButton::LeftStick` | 左摇杆按下 | L3 | L3 |
| `GamepadButton::RightStick` | 右摇杆按下 | R3 | R3 |
| `GamepadButton::LeftShoulder` | 左肩键 | LB | L |
| `GamepadButton::RightShoulder` | 右肩键 | RB | R |
| `GamepadButton::LeftTrigger` | 左扳机键 | LT | ZL |
| `GamepadButton::RightTrigger` | 右扳机键 | RT | ZR |
## 摇杆输入
### 获取摇杆值
```cpp
// 获取左摇杆位置(范围 -1.0 到 1.0
Vec2 leftStick = input.getLeftStick();
// 获取右摇杆位置
Vec2 rightStick = input.getRightStick();
// 应用摇杆输入
float speed = 200.0f;
player->setPosition(player->getPosition() + leftStick * speed * dt);
```
### 摇杆死区
```cpp
// 设置摇杆死区(默认 0.15
input.setStickDeadZone(0.2f);
```
## 鼠标输入
### 鼠标按钮检测
```cpp
auto& input = Application::instance().input();
// 检测鼠标按钮按下(单次触发)
if (input.isMousePressed(MouseButton::Left)) {
// 左键刚按下
}
if (input.isMousePressed(MouseButton::Right)) {
// 右键刚按下
}
// 检测鼠标按钮状态(持续触发)
if (input.isMouseDown(MouseButton::Left)) {
// 左键保持按下
}
// 检测鼠标按钮释放
if (input.isMouseReleased(MouseButton::Left)) {
// 左键刚释放
}
```
### 鼠标位置
```cpp
// 获取鼠标位置(屏幕坐标)
Vec2 mousePos = input.getMousePosition();
// 获取鼠标在游戏视口中的位置(考虑视口适配)
// 参考 examples/flappy_bird 的 BaseScene 实现
```
### 鼠标按钮枚举
| 枚举值 | 说明 |
|--------|------|
| `MouseButton::Left` | 左键 |
| `MouseButton::Right` | 右键 |
| `MouseButton::Middle` | 中键 |
### 完整示例Flappy Bird 输入处理
参考 `examples/flappy_bird/GameScene.cpp`
```cpp
void GameScene::onUpdate(float dt) {
if (!gameOver_) {
auto &input = extra2d::Application::instance().input();
// 同时支持手柄 A 键和鼠标左键
if (input.isButtonPressed(extra2d::GamepadButton::A) ||
input.isMousePressed(extra2d::MouseButton::Left)) {
if (!started_) {
started_ = true;
startGame();
}
bird_->jump();
}
// 游戏逻辑更新...
}
BaseScene::onUpdate(dt);
}
```
### 完整示例Game Over 界面输入
参考 `examples/flappy_bird/GameOverLayer.cpp`
```cpp
void GameOverLayer::onUpdate(float dt) {
Node::onUpdate(dt);
// 动画完成后才响应输入
if (!animationDone_)
return;
auto &input = extra2d::Application::instance().input();
// A 键重新开始游戏
if (input.isButtonPressed(extra2d::GamepadButton::A)) {
ResLoader::playMusic(MusicType::Click);
auto &app = extra2d::Application::instance();
app.scenes().replaceScene(extra2d::shared<GameScene>(),
extra2d::TransitionType::Fade, 0.5f);
}
// B 键返回主菜单
if (input.isButtonPressed(extra2d::GamepadButton::B)) {
ResLoader::playMusic(MusicType::Click);
auto &app = extra2d::Application::instance();
app.scenes().replaceScene(extra2d::shared<StartScene>(),
extra2d::TransitionType::Fade, 0.5f);
}
}
```
## 完整示例
### 菜单导航
参考 `examples/flappy_bird/StartScene.cpp`
```cpp
void StartScene::onUpdate(float dt) {
Scene::onUpdate(dt);
auto& input = Application::instance().input();
// A 键开始游戏
if (input.isButtonPressed(GamepadButton::A)) {
ResLoader::playMusic(MusicType::Click);
startGame();
}
// BACK 键退出游戏
if (input.isButtonPressed(GamepadButton::Back)) {
ResLoader::playMusic(MusicType::Click);
auto &app = Application::instance();
app.quit();
}
}
```
### Game Over 界面手柄控制
参考 `examples/flappy_bird/GameOverLayer.cpp`
```cpp
void GameOverLayer::onUpdate(float dt) {
Node::onUpdate(dt);
// 检测手柄按键
auto &input = extra2d::Application::instance().input();
// A 键重新开始游戏
if (input.isButtonPressed(extra2d::GamepadButton::A)) {
ResLoader::playMusic(MusicType::Click);
auto &app = extra2d::Application::instance();
app.scenes().replaceScene(extra2d::shared<GameScene>(),
extra2d::TransitionType::Fade, 0.5f);
}
// B 键返回主菜单
if (input.isButtonPressed(extra2d::GamepadButton::B)) {
ResLoader::playMusic(MusicType::Click);
auto &app = extra2d::Application::instance();
app.scenes().replaceScene(extra2d::shared<StartScene>(),
extra2d::TransitionType::Fade, 0.5f);
}
}
```
### 玩家移动
```cpp
void Player::update(float dt) {
auto& input = Application::instance().input();
Vec2 moveDir;
// 方向键移动
if (input.isButtonDown(GamepadButton::DPadLeft)) {
moveDir.x -= 1;
}
if (input.isButtonDown(GamepadButton::DPadRight)) {
moveDir.x += 1;
}
if (input.isButtonDown(GamepadButton::DPadUp)) {
moveDir.y -= 1;
}
if (input.isButtonDown(GamepadButton::DPadDown)) {
moveDir.y += 1;
}
// 摇杆移动
Vec2 stick = input.getLeftStick();
if (stick.length() > 0.1f) {
moveDir = stick;
}
// 应用移动
if (moveDir.length() > 0) {
moveDir.normalize();
setPosition(getPosition() + moveDir * speed_ * dt);
}
// 跳跃
if (input.isButtonPressed(GamepadButton::A)) {
jump();
}
}
```
## 输入映射
### 自定义按键映射
```cpp
// 定义动作
enum class Action {
Jump,
Attack,
Pause
};
// 映射按键到动作
std::unordered_map<Action, GamepadButton> actionMap = {
{Action::Jump, GamepadButton::A},
{Action::Attack, GamepadButton::B},
{Action::Pause, GamepadButton::Start}
};
// 检查动作
bool isActionPressed(Action action) {
auto& input = Application::instance().input();
return input.isButtonPressed(actionMap[action]);
}
```
## 最佳实践
1. **使用 isButtonPressed 进行菜单操作** - 避免持续触发
2. **使用 isButtonDown 进行移动控制** - 实现流畅移动
3. **支持多种输入方式** - 同时支持方向键和摇杆
4. **添加输入缓冲** - 提升操作手感
5. **为常用操作分配标准按键**
- **A 键**:确认、跳跃、主要动作
- **B 键**:取消、返回、次要动作
- **Start 键**:暂停菜单
- **Back 键**:返回上一级/退出
## 下一步
- [06. 碰撞检测](./06_Collision_Detection.md) - 学习碰撞检测系统
- [07. UI 系统](./07_UI_System.md) - 学习 UI 控件使用