SDL2 C++开发中WASD按键无法移动Texture的问题
2D平台游戏WASD按键无法移动玩家的问题修复
问题核心原因
- 输入处理逻辑错误:将实时按键状态检测
SDL_GetKeyboardState放在了SDL_PollEvent事件循环内部,且每个按键判断后添加break,导致每次仅处理一次按键检测就退出循环,无法持续响应按住按键的状态。 - 重复渲染玩家:在遍历平台的循环中每次都渲染玩家,导致玩家被多次绘制,可能掩盖位置更新效果。
- 帧率延迟计算错误:
SDL_Delay参数使用100而非1000,导致延迟时间计算偏差,影响游戏运行节奏。 - 渲染与更新逻辑混杂:将渲染代码放在固定时间步的更新循环内,可能导致同一帧多次渲染,逻辑混乱。
修复方案
修改后的main.cpp代码
#include <SDL2/SDL.h> #include <SDL2/SDL_image.h> #include <iostream> #include <vector> #include "RenderWindow.hpp" #include "Entity.hpp" #include "Utils.hpp" int main(int argc, char const *argv[]) { if (SDL_Init(SDL_INIT_VIDEO) > 0) std::cout << "ERROR: SDL_Init() HAS FAILED: SDL_ERROR => " << SDL_GetError() << std::endl; if (!(IMG_Init(IMG_INIT_PNG))) std::cout << "ERROR: IMG_Init() HAS FAILED: SDL_ERROR => " << SDL_GetError() << std::endl; RenderWindow window("GAME v1.0", 1280, 720); SDL_Texture* grassTexture = window.loadTexture("res/gfx/ground_grass.png"); SDL_Texture* playerTexture = window.loadTexture("res/gfx/ghost.png"); std::vector<Entity> platforms = {Entity(Vector2f(0, 30), grassTexture), Entity(Vector2f(30, 30), grassTexture), Entity(Vector2f(30, 30), grassTexture), Entity(Vector2f(60, 30), grassTexture)}; Entity player(Vector2f(30, 8), playerTexture); bool gameRunning = true; SDL_Event event; const float timeStep = 0.01f; float accumulator = 0.0f; float currentTime = utils::hireTimeInSeconds(); while(gameRunning) { int startTicks = SDL_GetTicks(); float newTime = utils::hireTimeInSeconds(); float frameTime = newTime - currentTime; currentTime = newTime; accumulator += frameTime; // 处理事件 while(SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { gameRunning = false; break; } } // 固定时间步更新逻辑 while(accumulator >= timeStep) { // 处理按键输入 const Uint8* currentKeyStates = SDL_GetKeyboardState(NULL); Vector2f& playerPos = player.getPos(); if(currentKeyStates[SDL_SCANCODE_W]) { playerPos.y -= 1; } if(currentKeyStates[SDL_SCANCODE_S]) { playerPos.y += 1; } if(currentKeyStates[SDL_SCANCODE_A]) { playerPos.x -= 1; } if(currentKeyStates[SDL_SCANCODE_D]) { playerPos.x += 1; } accumulator -= timeStep; } // 渲染逻辑 window.clear(); for (Entity& e : platforms) { window.render(e); } // 单独渲染一次玩家 window.render(player); window.display(); // 帧率控制,修复延迟计算错误 int frameTicks = SDL_GetTicks() - startTicks; int targetFrameTime = 1000 / window.getRefreshRate(); if (frameTicks < targetFrameTime) SDL_Delay(targetFrameTime - frameTicks); } window.cleanUp(); SDL_Quit(); return 0; }
关键修改点
- 将按键输入处理从
SDL_PollEvent循环中移出,放到固定时间步的更新循环内,移除break以支持多按键同时输入。 - 将玩家渲染移到平台遍历循环之外,确保仅渲染一次。
- 修复帧率延迟计算中的
100为1000,保证延迟时间正确。 - 分离事件处理、逻辑更新、渲染三个模块,使代码结构更清晰。
内容的提问来源于stack exchange,提问作者Ralph Turner
相关产品推荐
相关产品推荐

