使用 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;
}
问题已解决!
基本上我正在尝试使用 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;
}
问题已解决!