C++ 碰撞不是';不一致
我目前正在为一个项目开发一个使用SDL的Mario Bros副本,我刚刚实现了碰撞,尽管我遇到了一些奇怪的情况,每次加载游戏时,碰撞有时会起作用,有时不会。这些gif基本上解释了我的意思: 正如你所看到的,碰撞有时会起作用,但每次我重新加载游戏时,结果都会改变,我实际上不知道为什么。还有其他一些奇怪的事情发生在每个实体周围,比如你可以看到红色边框,这是它们的碰撞框,但有时正如你在gif中看到的那样,尽管有碰撞,一些块却没有显示碰撞框。我过去也有过块,有时甚至不渲染,尽管这已经有一段时间没有发生了 我是如何从一个txt文件加载地图的,该文件如下所示: 然后使用我的LevelMap类加载:C++ 碰撞不是';不一致,c++,sdl,collision-detection,collision,entitymanager,C++,Sdl,Collision Detection,Collision,Entitymanager,我目前正在为一个项目开发一个使用SDL的Mario Bros副本,我刚刚实现了碰撞,尽管我遇到了一些奇怪的情况,每次加载游戏时,碰撞有时会起作用,有时不会。这些gif基本上解释了我的意思: 正如你所看到的,碰撞有时会起作用,但每次我重新加载游戏时,结果都会改变,我实际上不知道为什么。还有其他一些奇怪的事情发生在每个实体周围,比如你可以看到红色边框,这是它们的碰撞框,但有时正如你在gif中看到的那样,尽管有碰撞,一些块却没有显示碰撞框。我过去也有过块,有时甚至不渲染,尽管这已经有一段时间没有
bool LevelMap::CreateMap(std::string path)
{
std::vector<std::string> lines = std::vector<std::string>();
std::fstream file;
file.open(path, std::fstream::in);
char text[256];
std::string currentLine;
while (!file.eof())
{
file.getline(text, 256);
currentLine = text;
currentLine.erase(std::remove_if(currentLine.begin(), currentLine.end(),
std::isspace), currentLine.end()); //Removes Spaces from String
//Checks if String is at correct Width
if (currentLine.size() != mapWidth)
{
std::cout << "Map Has Incorrect Width!" << std::endl;
return false;
}
lines.push_back(currentLine);
}
// Loop over every tile position,
for (int y = 0; y < mapHeight; y++)
{
for (int x = 0; x < mapWidth; x++)
{
char tileType = lines.at(y)[x]; //Gets Each Tile Value
Entity* entity = LoadEntity(tileType, x, y);
if (entity != nullptr)
{
entityManager->AddEntity(entity);
}
}
}
return true;
}
Entity* LevelMap::LoadEntity(char tileType, int x, int y)
{
x *= (SCREEN_WIDTH / mapWidth);
y *= (SCREEN_WIDTH / mapWidth);
switch (tileType)
{
//Creates Block
case '1':
return CreateBlock(Vector2D(x, y));
break;
//Creates Pipe facing Left
case '2':
return CreatePipe(Vector2D(x, y), FACING::FACING_RIGHT);
break;
//Creates Pipe facing Right
case '3':
return CreatePipe(Vector2D(x, y), FACING::FACING_LEFT);
break;
//Creates Player
case 'P':
return CreatePlayer(Vector2D(x, y));
break;
default:
return nullptr;
break;
}
}
Entity* LevelMap::CreateBlock(Vector2D position)
{
Block* block = new Block(renderer, position, this);
return block;
}
Entity* LevelMap::CreatePipe(Vector2D position, FACING direction)
{
Pipe* pipe = new Pipe(renderer, position, direction, this);
return pipe;
}
Entity* LevelMap::CreatePlayer(Vector2D position)
{
Player* player = new Player(renderer, position, this);
return player;
}
实体的更新和渲染由我提到的实体管理器中的更新和渲染函数调用:
void EntityManager::Update(float deltaTime, SDL_Event e)
{
if(!entities.empty())
{
//Runs the Update function of all entities and adds Entites that need to be deleted to a list
for(const auto entity : entities)
{
if(entity.second->ShouldDestroy())
{
toDeleteEntities.push_back(entity.second);
}
//std::cout << entity.second->GetTag() << std::endl;
entity.second->Update(deltaTime, e);
}
//Removes entities that need to be deleted
for(int i = 0; i < toDeleteEntities.size(); i++)
{
RemoveEntity(toDeleteEntities[i], i);
}
}
}
void EntityManager::Render()
{
if(!entities.empty())
{
for(const auto entity : entities)
{
entity.second->Render();
}
}
}
void EntityManager::Update(float deltaTime、SDL_事件e)
{
如果(!entities.empty())
{
//运行所有实体的更新功能,并将需要删除的实体添加到列表中
用于(常量自动实体:实体)
{
if(entity.second->ShouldDestroy())
{
todeletenties.向后推(entity.second);
}
//std::cout GetTag()更新(deltaTime);
}
//删除需要删除的实体
for(int i=0;iRender();
}
}
}
最后,实体管理器的更新和渲染函数由LevelMap调用
对不起,这段文字太长了。我希望这是足够的细节,有人可以找出什么是错的,为什么会发生这种情况,我非常感谢你的帮助。如果你需要更多的细节,请直接询问
编辑
CollisionUpdate()在实体的更新函数中调用,如前所述,该函数由EntityManager调用:
void Entity::Update(float deltaTime, SDL_Event e)
{
//Screen Warps
if (position.X <= 0 - GetTexture()->GetWidth())
{
position.X = SCREEN_WIDTH - GetTexture()->GetWidth();
}
else if (position.X >= SCREEN_WIDTH)
{
position.X = 0 + GetTexture()->GetWidth();
}
if (collsion != nullptr)
{
CollisionUpdate();
}
}
void Entity::Update(浮点deltaTime,SDL_事件e)
{
//筛网翘曲
if(position.X GetWidth())
{
position.X=SCREEN_WIDTH-GetTexture()->GetWidth();
}
else if(位置X>=屏幕宽度)
{
position.X=0+GetTexture()->GetWidth();
}
if(collsion!=nullptr)
{
碰撞更新();
}
}
同时,在玩家和敌人更新函数中调用Intersects函数:
void Player::CollisionUpdate()
{
Entity::CollisionUpdate();
std::vector<Entity*> entities = map->GetEntityManager()->GetEntities("");
for (int i = 0; i < entities.size(); i++)
{
if (entities[i]->GetCollsion() != nullptr)
{
//What Player Collides With
if(collsion->Intersects(entities[i]))
{
if (entities[i]->GetTag() == "Block")
{
SetGravity(false);
}
else
{
SetGravity(true);
}
}
}
}
}
void播放器::碰撞更新()
{
实体::碰撞更新();
std::vector entities=map->GetEntityManager()->GetEntities(“”);
对于(int i=0;iGetCollsion()!=nullptr)
{
//哪位选手撞上了
如果(冲突->相交(实体[i]))
{
if(实体[i]->GetTag()=“块”)
{
设置重力(假);
}
其他的
{
设置重力(真);
}
}
}
}
}
GetEntities函数是EntityManager类的一部分,它将获得具有传入标记的所有实体的向量,因此Block将具有“Block”标记,如果将其传递到函数中,则它将仅返回具有块的函数。
这是您希望看到的GetEntities函数:
std::vector<Entity*> EntityManager::GetEntities(std::string tag)
{
std::vector<Entity*> entityList;
//If Tag is not empty, find certain entities with tag
if (tag != "")
{
for (const auto entity : entities)
{
if (entity.second->GetTag() == tag)
{
entityList.push_back(entity.second);
}
}
}
else if (tag == "") //Else find all entities
{
for (const auto entity : entities)
{
entityList.push_back(entity.second);
}
}
return entityList;
}
std::vector EntityManager::GetEntities(std::string标记)
{
std::向量实体列表;
//如果标记不为空,请查找带有标记的某些实体
如果(标记!=“”)
{
用于(常量自动实体:实体)
{
if(entity.second->GetTag()==标记)
{
entityList.push_back(entity.second);
}
}
}
else if(tag==“”)//else查找所有实体
{
用于(常量自动实体:实体)
{
entityList.push_back(entity.second);
}
}
返回实体列表;
}
尝试在冲突函数中切换返回语句。当它们发生碰撞时,您似乎返回false,而不是返回true if(boundingBox.X+boundingBox.widthif(boundingBox.X + boundingBox.width < entityBoundingBox.X ||
entityBoundingBox.X + entityBoundingBox.width < boundingBox.X ||
boundingBox.Y + boundingBox.height < entityBoundingBox.Y ||
entityBoundingBox.Y + entityBoundingBox.height < boundingBox.Y)
// X Y W H
let boundingBox = {10,10,10,10}
let entityBoundingBox = {10,20,10,10}
10 + 10 < 10 == false
10 + 10 < 10 == false
10 + 10 < 20 == false
20 + 10 < 10 == false
entityBoundingBox.X+entityBoundingBox.width这在您的逻辑中返回true,表示冲突。它们不会碰撞。非常确定您的冲突逻辑不正确。我发现了问题所在。正是我检查实体碰撞的方式导致了问题。我所拥有的是一个for循环,它将循环通过每个实体,并检查实体是否与它们发生碰撞,如果发生碰撞,它将禁用重力 问题是for循环将立即转到下一个实体,并检查与该实体的冲突。因此它会得到实体与块碰撞并停止重力,但它会进入列表中的下一个实体,看我们没有与它碰撞,然后启用重力,尽管仍然与同一块碰撞 因此,不只是检查单个实体(如Mario下的块)的碰撞: 相反,它检查了与所有这些的冲突:
由于我们目前没有与所有其他块碰撞,它再次启用了重力。您应该只发布相关代码。例如,你在哪里调用
CollisionUpdate
或Intersects
?你的代码中有内存泄漏,小心我相信冲突代码和EntityManager代码是相关的,我也对我的帖子做了更改
std::vector<Entity*> EntityManager::GetEntities(std::string tag)
{
std::vector<Entity*> entityList;
//If Tag is not empty, find certain entities with tag
if (tag != "")
{
for (const auto entity : entities)
{
if (entity.second->GetTag() == tag)
{
entityList.push_back(entity.second);
}
}
}
else if (tag == "") //Else find all entities
{
for (const auto entity : entities)
{
entityList.push_back(entity.second);
}
}
return entityList;
}
if(boundingBox.X + boundingBox.width < entityBoundingBox.X ||
entityBoundingBox.X + entityBoundingBox.width < boundingBox.X ||
boundingBox.Y + boundingBox.height < entityBoundingBox.Y ||
entityBoundingBox.Y + entityBoundingBox.height < boundingBox.Y)
// X Y W H
let boundingBox = {10,10,10,10}
let entityBoundingBox = {10,20,10,10}
10 + 10 < 10 == false
10 + 10 < 10 == false
10 + 10 < 20 == false
20 + 10 < 10 == false