You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SDL2 C++开发中WASD按键无法移动Texture的问题

2D平台游戏WASD按键无法移动玩家的问题修复

问题核心原因

  1. 输入处理逻辑错误:将实时按键状态检测SDL_GetKeyboardState放在了SDL_PollEvent事件循环内部,且每个按键判断后添加break,导致每次仅处理一次按键检测就退出循环,无法持续响应按住按键的状态。
  2. 重复渲染玩家:在遍历平台的循环中每次都渲染玩家,导致玩家被多次绘制,可能掩盖位置更新效果。
  3. 帧率延迟计算错误:SDL_Delay参数使用100而非1000,导致延迟时间计算偏差,影响游戏运行节奏。
  4. 渲染与更新逻辑混杂:将渲染代码放在固定时间步的更新循环内,可能导致同一帧多次渲染,逻辑混乱。

修复方案

修改后的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.04 00:01:28