当主循环事件在c++中调用w、a、s或d时,SDL2纹理不会移动

jxct1oxe  于 2023-01-22  发布在  其他
关注(0)|答案(1)|浏览(221)

因此,我一直在为我的2D Platformer开发一个游戏系统/引擎,当我按下w、a、s或d键时,它在主循环事件中调用时不会移动。
这里是我所有的项目文件和我写的一切: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(accumulator >= timeStep)
        {
            // Get out controls and events
            while(SDL_PollEvent(&event))
            {
                if (event.type == SDL_QUIT)
                {
                    gameRunning = false;
                    break;

                    // window.freeTexture(grassTexture);
                    // window.freeTexture(playerTexture);
                }
                
                // Add code to move the player texture
                const Uint8* currentKeyStates = SDL_GetKeyboardState(NULL);
                Vector2f& playerPos = player.getPos();
                if(currentKeyStates[SDL_SCANCODE_W]) {
                    playerPos.y -= 1;
                    break;
                }
                if(currentKeyStates[SDL_SCANCODE_S]) {
                    playerPos.y += 1;
                    break;
                }
                if(currentKeyStates[SDL_SCANCODE_A]) {
                    playerPos.x -= 1;
                    break;
                }
                if(currentKeyStates[SDL_SCANCODE_D]) {
                    playerPos.x += 1;
                    break;
                }
            }

            window.clear();

            for (Entity& e : platforms)
            {
                window.render(e);
                window.render(player);
            }
            window.display();

            // // Add code to move the player texture
            // 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;
            // }

            //playerPos.print();

            accumulator -= timeStep;
            // std::cout << accumulator << std::endl;
        }

        // const float alpha = accumulator / timeStep; // 50%?

        // window.freeTexture(grassTexture);
        // window.freeTexture(playerTexture);

        int frameTicks = SDL_GetTicks() - startTicks;

        if (frameTicks < 1000 / window.getRefreshRate())
            SDL_Delay(100 / window.getRefreshRate() - frameTicks);
    }

    window.cleanUp();
    SDL_Quit();

    return 0;
}

renderwindow.hpp:

#pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

#include "Entity.hpp"

class RenderWindow
{
public:
    RenderWindow(const char* p_title, int p_w, int p_h);
    SDL_Texture* loadTexture(const char* p_filePath);

    int getRefreshRate();

    void cleanUp();
    void clear();
    void render(Entity& p_entity);
    //void freeTexture(SDL_Texture* p_tex);
    void display();
private:
    SDL_Window* window;
    SDL_Renderer* renderer;
};

renderwindow.cpp:

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>
#include <iostream>

#include "RenderWindow.hpp"
#include "Entity.hpp"

RenderWindow::RenderWindow(const char* p_title, int p_w, int p_h)
    :window(NULL), renderer(NULL)
{
    window = SDL_CreateWindow(p_title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, p_w, p_h, SDL_WINDOW_SHOWN);

    if (window == NULL)
    {
        std::cout << "ERROR: Window has failed to init! SDL_Error: " << SDL_GetError() << std::endl;
    }

    renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED);

}

SDL_Texture* RenderWindow::loadTexture(const char* p_filePath)
{
    SDL_Texture* texture = NULL;
    texture = IMG_LoadTexture(renderer, p_filePath);

    if (texture == NULL)
        std::cout << "ERROR: Failed to load texture! SDL_Error: " << SDL_GetError() << std::endl;

    return texture;
}

int RenderWindow::getRefreshRate()
{
    int displayIndex = SDL_GetWindowDisplayIndex(window);

    SDL_DisplayMode mode;

    SDL_GetDisplayMode(displayIndex, 0, &mode);

    return mode.refresh_rate;
}

void RenderWindow::cleanUp()
{
    SDL_DestroyWindow(window);
}

void RenderWindow::clear()
{
    SDL_RenderClear(renderer);
}

void RenderWindow::render(Entity& p_entity)
{
    SDL_Rect src;
    src.x = p_entity.getCurrentFrame().x;
    src.y = p_entity.getCurrentFrame().y;
    src.w = p_entity.getCurrentFrame().w;
    src.h = p_entity.getCurrentFrame().h;

    SDL_Rect dst;
    dst.x = p_entity.getPos().x * 4;
    dst.y = p_entity.getPos().y * 4;
    dst.w = p_entity.getCurrentFrame().w * 4;
    dst.h = p_entity.getCurrentFrame().h * 4;

    SDL_RenderCopy(renderer, p_entity.getTex(), &src, &dst);
}

// void RenderWindow::freeTexture(SDL_Texture* p_tex) {

//     SDL_DestroyTexture(p_tex);
// }

void RenderWindow::display()
{
    SDL_RenderPresent(renderer);
}

Entity.hpp:

#pragma once
#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

#include "Math.hpp"

class Entity
{
public:
    Entity(Vector2f p_pos, SDL_Texture* p_tex);
    Vector2f& getPos()
    {
        return pos;
    }
    void setPos(Vector2f p_pos)
    {
        pos = p_pos;
    }
    SDL_Texture* getTex();
    SDL_Rect getCurrentFrame();
private:
    Vector2f pos;
    SDL_Rect currentFrame;
    SDL_Texture* tex;
};

entity.cpp:

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

#include "Entity.hpp"
#include "Math.hpp"

Entity::Entity(Vector2f p_pos, SDL_Texture* p_tex)
:pos(p_pos), tex(p_tex)
{
    currentFrame.x = 0;
    currentFrame.y = 0;
    currentFrame.w = 32;
    currentFrame.h = 32;
}

SDL_Texture* Entity::getTex()
{
    return tex;
}

SDL_Rect Entity::getCurrentFrame()
{
    return currentFrame;
}

math.hpp:

#pragma once

#include <iostream>

struct Vector2f
{
    Vector2f()
    :x(0.0f), y(0.0f) 
    {}

    Vector2f(float p_x, float p_y)
    :x(p_x), y(p_y)
    {}

    void print()
    {
        std::cout << x << ", " << y << std::endl;
    }

    float x, y;
};

Utils.hpp:

#pragma once
#include <SDL2/SDL.h>

namespace utils
{
    inline float hireTimeInSeconds()
    {
        float t = SDL_GetTicks();
        t *= 0.001f;

        return t;
    }
}

谢谢!

qkf9rpyu

qkf9rpyu1#

这是我的代码的更新版本,我已经弄明白了。
结果发现问题是:

if (frameTicks < 1000 / window.getRefreshRate())
            SDL_Delay(100 / window.getRefreshRate() - frameTicks);

实际上是推迟了100年而不是1000年

相关问题