使用 SDL2 和 C++ 编写游戏引擎,我的精灵和碰撞盒在以一定角度移动时分离

Writing game engine using SDL2 and C++, my sprite and collision box separate when moving at angle

基本上我正在尝试使用 C++ 和 SDL2 实现一个游戏引擎,并且大部分事情进展顺利。

碰撞检测有效(使用分离轴定理)、移动等,但是当我绘制碰撞盒的顶点时,我的精灵以一定角度移动,精灵和碰撞盒彼此远离.

我不确定发生了什么,我有两个不同的角度来表示图像本身的角度和运动角度,我尝试用常量调整它们,调整哪个改变以及如何改变移动等,但它们仍然不一起移动(以一定角度移动时)。

这不是绘图错误,因为当碰撞盒碰到另一个 sprite 的碰撞盒时,它会检测到碰撞。

我会在下面留下我认为相关的代码,但我认为它很多,所以如果有人愿意看的话,我也会在回购中留下 link。 Repo link.

相关类大概是Sprite和Ship,相关函数:Sprite::VectorProjection、Sprite::UpdateVertices、Sprite::MoveSprite、Ship::PlayerInput

代码:

//Sprite.cpp

void Sprite::VectorProjection(double Speed)
{
    Velocity.x = Speed * cos(MoveAngle) + Acceleration.x;
    Velocity.y = Speed * sin(MoveAngle) + Acceleration.y;
    this->Speed = sqrt((Velocity.x * Velocity.x) + (Velocity.y * Velocity.y));
    MoveAngle = atan2(Velocity.y, Velocity.x);
}

void Sprite::UpdateVertices()
{
    std::vector<Vec2D> NewVerts;
    Vec2D vert;
    for (int i = 0; i < vertices.size(); ++i)
    {
        vert.x = ((vertices[i].x - Center.x) * cos(ImageAngle - LastAngle)) - ((vertices[i].y - Center.y) * sin(ImageAngle - LastAngle)) + Center.x;
        vert.y = ((vertices[i].x - Center.x)*sin(ImageAngle - LastAngle)) + ((vertices[i].y - Center.y)*cos(ImageAngle - LastAngle)) + Center.y;
        NewVerts.push_back(vert);
    }
    LastAngle = ImageAngle;
    vertices = NewVerts;
}

void Sprite::MoveSprite()
{
    std::vector<Vec2D> NewVerts;
    Vec2D vert;
    texture.x += Velocity.x;
    texture.y += Velocity.y;
    Position.x += Velocity.x;
    Position.y += Velocity.y;
    Center.x += Velocity.x;
    Center.y += Velocity.y;
    for (int i = 0; i < vertices.size(); ++i)
    {
        vert.x = vertices[i].x + Velocity.x;
        vert.y = vertices[i].y + Velocity.y;
        NewVerts.push_back(vert);
    }
    vertices = NewVerts;
}

--------------------------------------------------
//Ship.cpp

void Ship::PlayerInput(SDL_Event Event, SDL_Renderer* renderer)
{
    double IA;
    double MA;
    if(Event.type == SDL_MOUSEBUTTONDOWN)
    {
        if (Event.button.button == SDL_BUTTON_LEFT)
        {
            Fire();
        }
    }
    if (Event.type == SDL_KEYDOWN)
    {
        if (Event.key.keysym.sym == SDLK_w)
        {
            //MoveAngle = -M_PI/2;
            SetSpeed(2.00);
            MoveSprite();
        }
        SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
        if (Event.key.keysym.sym == SDLK_a)
        {
            IA = ConvertToDegrees(ImageAngle);
            MA = ConvertToDegrees(MoveAngle);
            SetImageAngle(IA - 1);
            SetMoveAngle(MA - 1);
            UpdateVertices();
        }
        if (Event.key.keysym.sym == SDLK_d)
        {
            IA = ConvertToDegrees(ImageAngle);
            MA = ConvertToDegrees(MoveAngle);
            SetImageAngle(IA + 1);
            SetMoveAngle(MA + 1);
            UpdateVertices();
        }
    }
    if (Event.type == SDL_KEYUP)
    {
        SetSpeed(0.00);
    }
}

如有任何帮助,我们将不胜感激。正在发生的事情的图像:The blue dots are the vertices and the image of the sprite should be inside of it. When moving left/right, up/down, it stays inside, but at an angle this happens.

编辑:被要求提供我计算顶点并渲染它们的代码,这是:

//Initial set of vertices:
void Sprite::SetVertices()
{
    Vec2D vert1{(double)texture.x, (double)texture.y};
    Vec2D vert2{(double)texture.x + (double)texture.w, (double)texture.y};
    Vec2D vert3{(double)texture.x, (double)texture.y + (double)texture.h};
    Vec2D vert4{(double)texture.x + (double)texture.w, (double)texture.y + (double)texture.h};
    //Order of insertion of vertices matters
    vertices.push_back(vert1);
    vertices.push_back(vert3);
    vertices.push_back(vert4);
    vertices.push_back(vert2);
}

-------------------------------------------
//Vertices are drawn in the Tick function of the Scene class
void Scene::Tick()
{
    bool bWindowVisible = true;
    SDL_Event Event;
    while (bPlay)
    {
        CurrentTime = std::chrono::system_clock::now();
        DeltaTime = CurrentTime - LastTime;
        if (DeltaTime.count() < RefreshSeconds)
        {
            continue; //only used here to clean up code and help alleviate several layers of nesting
        }
        LastTime = CurrentTime;
        if (!bPaused)
        {
            SDL_PollEvent(&Event);
            EventHandler(Event, OUT bPlay, OUT bPaused);
            SDL_RenderClear(Renderer);
            for (Sprite* s : Sprites)
            {
                s->Update(Renderer);
                SDL_RenderCopyEx(Renderer, s->Image, NULL, &s->texture, s->ConvertToDegrees(s->ImageAngle), NULL, SDL_FLIP_NONE);

                //Draws vertices for debugging
                for (Vec2D vert : s->vertices)
                {
                    SDL_SetRenderDrawColor(Renderer, 0, 0, 255, 255);
                    SDL_RenderDrawPoint(Renderer, vert.x, vert.y);
                }
            }
            SDL_SetRenderDrawColor(Renderer, 0, 0, 0, 255);
            SDL_RenderPresent(Renderer);
        }
        else
        {
            PausedEventHandler(OUT bPlay, OUT bPaused); // this function was also created to help alleviate 
        }
    }
    return;
}

由于 SDL 中的图像是由它在左上角的点定义的,它不会随图像一起旋转(因此如果旋转图像,该点将保持不变)。然而,当以一个角度移动时,图像中的所有其他点将相对于该角度移动,但不会相对于该点移动,这将导致碰撞盒和精灵本身分离。问题出在这个代码块

void Sprite::MoveSprite()
{
    std::vector<Vec2D> NewVerts;
    Vec2D vert;
    texture.x += Velocity.x;
    texture.y += Velocity.y;
    Position.x += Velocity.x;
    Position.y += Velocity.y;
    Center.x += Velocity.x;
    Center.y += Velocity.y;
    for (int i = 0; i < vertices.size(); ++i)
    {
        vert.x = vertices[i].x + Velocity.x;
        vert.y = vertices[i].y + Velocity.y;
        NewVerts.push_back(vert);
    }
    vertices = NewVerts;
}

我假设纹理坐标应该随速度移动。为了解决这个问题,我创建了一个名为 D 的变量并将其定义为纹理坐标和中心之间的距离

D.x = Center.x - texture.x;
D.y = Center.y - texture.y;

这会起作用,因为纹理坐标总是在左上角 然后我们将 movesprite 方法更改为:

void Sprite::MoveSprite()
{
    std::vector<Vec2D> NewVerts;
    Vec2D vert;
    Position.x += Velocity.x;
    Position.y += Velocity.y;
    Center.x += Velocity.x;
    Center.y += Velocity.y;
    texture.x = Center.x - D.x;
    texture.y = Center.y - D.y;
    for (int i = 0; i < vertices.size(); ++i)
    {
        vert.x = vertices[i].x + Velocity.x;
        vert.y = vertices[i].y + Velocity.y;
        NewVerts.push_back(vert);
    }
    vertices = NewVerts;
}

问题已解决!