修复 LightGame Windows 输入问题并完善手动亮度控制
- 重构 PlayerController 输入:移除 IButtonInput 依赖,纯使用 IKeyboardState 与 IPointerInput;触摸屏改为上半屏跳跃、左右 1/3 分区分左右移动 - GameStateManager 增加 ESC 键暂停/恢复支持 - 将键盘亮度控制从 SdlPhotoSensor 平台层上提到 LightGameApp 游戏层(W/S 键),并引入 has_manual_override_ 标志防止 photo sensor 默认值覆盖手动调整 - SDLDisplay 初始化时调用 SDL_StopTextInput(),缓解 Windows 中文输入法在按字母键后拦截方向键/空格的问题 - IKeyboardState.h 补充 KEY_S、KEY_ESC、KEY_RETURN 常量
This commit is contained in:
parent
fda8b120d3
commit
acf162d1b9
|
|
@ -2,6 +2,7 @@
|
|||
#include "DrawContext.h"
|
||||
#include "BitmapFont.h"
|
||||
#include "ButtonInput.h"
|
||||
#include "IKeyboardState.h"
|
||||
#include <cstdio>
|
||||
|
||||
namespace LightGame
|
||||
|
|
@ -10,14 +11,19 @@ namespace LightGame
|
|||
: state_(GameState::Title),
|
||||
hud_(),
|
||||
title_blink_ms_(0),
|
||||
title_show_prompt_(true)
|
||||
title_show_prompt_(true),
|
||||
esc_was_down_(false)
|
||||
{
|
||||
}
|
||||
|
||||
void GameStateManager::update(GameState current_state, const Platform::IButtonInput* button, uint32_t dt_ms)
|
||||
void GameStateManager::update(GameState current_state, const Platform::IButtonInput* button, const Platform::IKeyboardState* keyboard, uint32_t dt_ms)
|
||||
{
|
||||
state_ = current_state;
|
||||
|
||||
const bool esc_down = keyboard && keyboard->is_key_down(Platform::KEY_ESC);
|
||||
const bool esc_pressed = esc_down && !esc_was_down_;
|
||||
esc_was_down_ = esc_down;
|
||||
|
||||
switch (state_)
|
||||
{
|
||||
case GameState::Title:
|
||||
|
|
@ -30,14 +36,14 @@ namespace LightGame
|
|||
break;
|
||||
|
||||
case GameState::Playing:
|
||||
if (button && button->was_pressed())
|
||||
if (esc_pressed || (button && button->was_pressed()))
|
||||
{
|
||||
state_ = GameState::Paused;
|
||||
}
|
||||
break;
|
||||
|
||||
case GameState::Paused:
|
||||
if (button && button->was_pressed())
|
||||
if (esc_pressed || (button && button->was_pressed()))
|
||||
{
|
||||
state_ = GameState::Playing;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -15,6 +15,7 @@ namespace RenderData
|
|||
namespace Platform
|
||||
{
|
||||
class IButtonInput;
|
||||
class IKeyboardState;
|
||||
}
|
||||
|
||||
namespace LightGame
|
||||
|
|
@ -53,11 +54,12 @@ namespace LightGame
|
|||
HudData hud_;
|
||||
uint32_t title_blink_ms_;
|
||||
bool title_show_prompt_;
|
||||
bool esc_was_down_;
|
||||
|
||||
public:
|
||||
GameStateManager();
|
||||
|
||||
void update(GameState current_state, const Platform::IButtonInput* button, uint32_t dt_ms);
|
||||
void update(GameState current_state, const Platform::IButtonInput* button, const Platform::IKeyboardState* keyboard, uint32_t dt_ms);
|
||||
void draw(Core::DrawContext& ctx, const RenderData::BitmapFont& font, int32_t screen_w, int32_t screen_h);
|
||||
|
||||
void set_state(GameState state) { state_ = state; }
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
#include "Level1Data.h"
|
||||
#include "Level2Data.h"
|
||||
#include "Level3Data.h"
|
||||
#include "sprite_atlas.h"
|
||||
|
||||
namespace LightGame
|
||||
{
|
||||
|
|
@ -44,21 +45,58 @@ namespace LightGame
|
|||
renderer_(),
|
||||
current_level_index_(0),
|
||||
player_id_(0),
|
||||
manual_light_level_(2048),
|
||||
light_step_(256),
|
||||
has_manual_override_(false),
|
||||
debug_mode_(false)
|
||||
{
|
||||
camera_.configure(screen_width, screen_height);
|
||||
camera_.set_dead_zone(60, 40);
|
||||
|
||||
static const RenderData::Sprite player_idle[] = {
|
||||
sprite_atlas::spr_player_idle_0,
|
||||
sprite_atlas::spr_player_idle_1
|
||||
};
|
||||
static const RenderData::Sprite player_run[] = {
|
||||
sprite_atlas::spr_player_run_0,
|
||||
sprite_atlas::spr_player_run_1,
|
||||
sprite_atlas::spr_player_run_2,
|
||||
sprite_atlas::spr_player_run_3
|
||||
};
|
||||
player_controller_.set_sprites(
|
||||
player_idle, 2,
|
||||
player_run, 4,
|
||||
&sprite_atlas::spr_player_jump,
|
||||
&sprite_atlas::spr_player_fall);
|
||||
}
|
||||
|
||||
void LightGameApp::update(uint32_t dt_ms)
|
||||
{
|
||||
if (photo_sensor_ && photo_sensor_->is_open())
|
||||
if (keyboard_input_)
|
||||
{
|
||||
if (keyboard_input_->is_key_down(Platform::KEY_W))
|
||||
{
|
||||
const uint32_t next = static_cast<uint32_t>(manual_light_level_) + light_step_;
|
||||
manual_light_level_ = static_cast<uint16_t>(next > 4095 ? 4095 : next);
|
||||
has_manual_override_ = true;
|
||||
}
|
||||
if (keyboard_input_->is_key_down(Platform::KEY_S))
|
||||
{
|
||||
manual_light_level_ = manual_light_level_ >= light_step_
|
||||
? manual_light_level_ - light_step_
|
||||
: 0;
|
||||
has_manual_override_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (photo_sensor_ && photo_sensor_->is_open() && !has_manual_override_)
|
||||
{
|
||||
photo_sensor_->update();
|
||||
manual_light_level_ = photo_sensor_->read_level();
|
||||
}
|
||||
|
||||
const GameState prev_state = state_manager_.get_state();
|
||||
state_manager_.update(prev_state, button_input_, dt_ms);
|
||||
state_manager_.update(prev_state, button_input_, keyboard_input_, dt_ms);
|
||||
|
||||
switch (state_manager_.get_state())
|
||||
{
|
||||
|
|
@ -86,7 +124,7 @@ namespace LightGame
|
|||
if (state_manager_.get_state() == GameState::Playing ||
|
||||
state_manager_.get_state() == GameState::Paused)
|
||||
{
|
||||
const uint16_t light = photo_sensor_ ? photo_sensor_->read_level() : 2048;
|
||||
const uint16_t light = manual_light_level_;
|
||||
renderer_.draw(ctx, level_, camera_, light_system_, light);
|
||||
|
||||
if (debug_mode_)
|
||||
|
|
@ -99,7 +137,7 @@ namespace LightGame
|
|||
|
||||
if (debug_mode_ && state_manager_.get_state() == GameState::Playing)
|
||||
{
|
||||
const uint16_t light = photo_sensor_ ? photo_sensor_->read_level() : 2048;
|
||||
const uint16_t light = manual_light_level_;
|
||||
char buf[32];
|
||||
snprintf(buf, sizeof(buf), "L:%d", light);
|
||||
ctx.draw_text(font, screen_width_ - 64, screen_height_ - 16,
|
||||
|
|
@ -130,10 +168,15 @@ namespace LightGame
|
|||
state_manager_.get_hud().current_level = level_index + 1;
|
||||
}
|
||||
|
||||
bool LightGameApp::is_action_pressed()
|
||||
{
|
||||
return button_input_ && button_input_->was_pressed();
|
||||
}
|
||||
|
||||
void LightGameApp::update_title(uint32_t dt_ms)
|
||||
{
|
||||
(void)dt_ms;
|
||||
if (button_input_ && button_input_->was_pressed())
|
||||
if (is_action_pressed())
|
||||
{
|
||||
load_level(0);
|
||||
state_manager_.set_state(GameState::Playing);
|
||||
|
|
@ -142,14 +185,14 @@ namespace LightGame
|
|||
|
||||
void LightGameApp::update_playing(uint32_t dt_ms)
|
||||
{
|
||||
const uint16_t light = photo_sensor_ ? photo_sensor_->read_level() : 2048;
|
||||
const uint16_t light = manual_light_level_;
|
||||
light_system_.update(level_.get_all_objects(), light);
|
||||
state_manager_.get_hud().light_level = light;
|
||||
|
||||
GameObject* player = level_.get_object(player_id_);
|
||||
if (player)
|
||||
{
|
||||
player_controller_.update(*player, level_, physics_, button_input_, keyboard_input_, pointer_input_, dt_ms);
|
||||
player_controller_.update(*player, level_, physics_, keyboard_input_, pointer_input_, screen_width_, screen_height_, dt_ms);
|
||||
camera_.follow(player->position);
|
||||
|
||||
if (player_controller_.is_dead())
|
||||
|
|
@ -168,7 +211,7 @@ namespace LightGame
|
|||
void LightGameApp::update_game_over(uint32_t dt_ms)
|
||||
{
|
||||
(void)dt_ms;
|
||||
if (button_input_ && button_input_->was_pressed())
|
||||
if (is_action_pressed())
|
||||
{
|
||||
state_manager_.get_hud().lives = 3;
|
||||
state_manager_.get_hud().collectibles = 0;
|
||||
|
|
@ -180,7 +223,7 @@ namespace LightGame
|
|||
void LightGameApp::update_level_complete(uint32_t dt_ms)
|
||||
{
|
||||
(void)dt_ms;
|
||||
if (button_input_ && button_input_->was_pressed())
|
||||
if (is_action_pressed())
|
||||
{
|
||||
const int32_t next = current_level_index_ + 1;
|
||||
if (next < kLevelCount)
|
||||
|
|
|
|||
|
|
@ -52,6 +52,10 @@ namespace LightGame
|
|||
int32_t current_level_index_;
|
||||
uint32_t player_id_;
|
||||
|
||||
uint16_t manual_light_level_;
|
||||
uint16_t light_step_;
|
||||
|
||||
bool has_manual_override_;
|
||||
bool debug_mode_;
|
||||
|
||||
public:
|
||||
|
|
@ -76,5 +80,6 @@ namespace LightGame
|
|||
void update_game_over(uint32_t dt_ms);
|
||||
void update_level_complete(uint32_t dt_ms);
|
||||
void check_triggers();
|
||||
bool is_action_pressed();
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include "PlayerController.h"
|
||||
#include "ButtonInput.h"
|
||||
#include "IKeyboardState.h"
|
||||
#include "PointerInput.h"
|
||||
#include <algorithm>
|
||||
|
|
@ -44,9 +43,9 @@ namespace LightGame
|
|||
}
|
||||
|
||||
void PlayerController::update(GameObject& obj, Level& level, Physics2D& physics,
|
||||
const Platform::IButtonInput* button,
|
||||
const Platform::IKeyboardState* keyboard,
|
||||
const Platform::IPointerInput* pointer,
|
||||
int32_t screen_width, int32_t screen_height,
|
||||
uint32_t dt_ms)
|
||||
{
|
||||
if (state_ == PlayerState::Dead)
|
||||
|
|
@ -59,7 +58,7 @@ namespace LightGame
|
|||
return;
|
||||
}
|
||||
|
||||
update_input(button, keyboard, pointer);
|
||||
update_input(keyboard, pointer, screen_width, screen_height);
|
||||
update_movement(obj, dt_ms);
|
||||
|
||||
physics.apply_gravity(obj, dt_ms);
|
||||
|
|
@ -111,48 +110,45 @@ namespace LightGame
|
|||
check_death(obj, level);
|
||||
}
|
||||
|
||||
void PlayerController::update_input(const Platform::IButtonInput* button,
|
||||
const Platform::IKeyboardState* keyboard,
|
||||
const Platform::IPointerInput* pointer)
|
||||
void PlayerController::update_input(const Platform::IKeyboardState* keyboard,
|
||||
const Platform::IPointerInput* pointer,
|
||||
int32_t screen_width, int32_t screen_height)
|
||||
{
|
||||
move_dir_ = 0;
|
||||
jump_held_ = false;
|
||||
|
||||
if (button)
|
||||
{
|
||||
if (button->is_down())
|
||||
{
|
||||
jump_held_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (pointer)
|
||||
{
|
||||
if (pointer->is_down())
|
||||
{
|
||||
const int32_t px = pointer->get_x();
|
||||
if (px < 400)
|
||||
const int32_t py = pointer->get_y();
|
||||
|
||||
// Top half of screen = jump (works across the full width)
|
||||
if (py < screen_height / 2)
|
||||
{
|
||||
jump_held_ = true;
|
||||
}
|
||||
|
||||
// Left 1/3 = move left, right 1/3 = move right
|
||||
if (px < screen_width / 3)
|
||||
{
|
||||
move_dir_ = -1;
|
||||
}
|
||||
else if (px > 600)
|
||||
else if (px > screen_width * 2 / 3)
|
||||
{
|
||||
move_dir_ = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
jump_held_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (keyboard)
|
||||
{
|
||||
if (keyboard->is_key_down(Platform::KEY_LEFT) || keyboard->is_key_down(Platform::KEY_A))
|
||||
if (keyboard->is_key_down(Platform::KEY_LEFT))
|
||||
move_dir_ = -1;
|
||||
if (keyboard->is_key_down(Platform::KEY_RIGHT) || keyboard->is_key_down(Platform::KEY_D))
|
||||
if (keyboard->is_key_down(Platform::KEY_RIGHT))
|
||||
move_dir_ = 1;
|
||||
if (keyboard->is_key_down(Platform::KEY_SPACE) || keyboard->is_key_down(Platform::KEY_UP) || keyboard->is_key_down(Platform::KEY_W))
|
||||
if (keyboard->is_key_down(Platform::KEY_UP))
|
||||
jump_held_ = true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
namespace Platform
|
||||
{
|
||||
class IButtonInput;
|
||||
class IKeyboardState;
|
||||
class IPointerInput;
|
||||
}
|
||||
|
|
@ -72,16 +71,16 @@ namespace LightGame
|
|||
const RenderData::Sprite* fall);
|
||||
|
||||
void update(GameObject& obj, Level& level, Physics2D& physics,
|
||||
const Platform::IButtonInput* button,
|
||||
const Platform::IKeyboardState* keyboard,
|
||||
const Platform::IPointerInput* pointer,
|
||||
int32_t screen_width, int32_t screen_height,
|
||||
uint32_t dt_ms);
|
||||
|
||||
PlayerState get_state() const { return state_; }
|
||||
bool is_dead() const { return state_ == PlayerState::Dead; }
|
||||
|
||||
private:
|
||||
void update_input(const Platform::IButtonInput* button, const Platform::IKeyboardState* keyboard, const Platform::IPointerInput* pointer);
|
||||
void update_input(const Platform::IKeyboardState* keyboard, const Platform::IPointerInput* pointer, int32_t screen_width, int32_t screen_height);
|
||||
void update_movement(GameObject& obj, uint32_t dt_ms);
|
||||
void update_animation(GameObject& obj, uint32_t dt_ms);
|
||||
void check_death(GameObject& obj, Level& level);
|
||||
|
|
|
|||
|
|
@ -7,11 +7,14 @@ namespace Platform
|
|||
constexpr int KEY_A = 4;
|
||||
constexpr int KEY_D = 7;
|
||||
constexpr int KEY_W = 26;
|
||||
constexpr int KEY_S = 22;
|
||||
constexpr int KEY_SPACE = 44;
|
||||
constexpr int KEY_LEFT = 80;
|
||||
constexpr int KEY_RIGHT = 79;
|
||||
constexpr int KEY_UP = 82;
|
||||
constexpr int KEY_DOWN = 81;
|
||||
constexpr int KEY_ESC = 41;
|
||||
constexpr int KEY_RETURN = 40;
|
||||
|
||||
class IKeyboardState
|
||||
{
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ namespace Platform
|
|||
return false;
|
||||
}
|
||||
|
||||
SDL_StopTextInput();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -50,45 +50,9 @@ namespace Platform
|
|||
|
||||
void SdlPhotoSensor::update()
|
||||
{
|
||||
if (!opened_)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
SDL_PumpEvents();
|
||||
const Uint8* keyboard_state = SDL_GetKeyboardState(nullptr);
|
||||
if (!keyboard_state)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (keyboard_state[SDL_SCANCODE_UP])
|
||||
{
|
||||
uint32_t next = static_cast<uint32_t>(level_) + step_;
|
||||
level_ = static_cast<uint16_t>(std::min(next, static_cast<uint32_t>(max_level_)));
|
||||
}
|
||||
|
||||
if (keyboard_state[SDL_SCANCODE_DOWN])
|
||||
{
|
||||
if (level_ >= step_)
|
||||
{
|
||||
level_ -= step_;
|
||||
}
|
||||
else
|
||||
{
|
||||
level_ = min_level_;
|
||||
}
|
||||
}
|
||||
|
||||
if (keyboard_state[SDL_SCANCODE_HOME])
|
||||
{
|
||||
level_ = max_level_;
|
||||
}
|
||||
|
||||
if (keyboard_state[SDL_SCANCODE_END])
|
||||
{
|
||||
level_ = min_level_;
|
||||
}
|
||||
// No-op: keyboard-based brightness control is handled in the game layer
|
||||
// (LightGameApp) through IKeyboardState, not at the platform level.
|
||||
(void)opened_;
|
||||
}
|
||||
|
||||
void SdlPhotoSensor::shutdown()
|
||||
|
|
|
|||
Loading…
Reference in New Issue