Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/131.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 碰撞不是';不一致_C++_Sdl_Collision Detection_Collision_Entitymanager - Fatal编程技术网

C++ 碰撞不是';不一致

C++ 碰撞不是';不一致,c++,sdl,collision-detection,collision,entitymanager,C++,Sdl,Collision Detection,Collision,Entitymanager,我目前正在为一个项目开发一个使用SDL的Mario Bros副本,我刚刚实现了碰撞,尽管我遇到了一些奇怪的情况,每次加载游戏时,碰撞有时会起作用,有时不会。这些gif基本上解释了我的意思: 正如你所看到的,碰撞有时会起作用,但每次我重新加载游戏时,结果都会改变,我实际上不知道为什么。还有其他一些奇怪的事情发生在每个实体周围,比如你可以看到红色边框,这是它们的碰撞框,但有时正如你在gif中看到的那样,尽管有碰撞,一些块却没有显示碰撞框。我过去也有过块,有时甚至不渲染,尽管这已经有一段时间没有

我目前正在为一个项目开发一个使用SDL的Mario Bros副本,我刚刚实现了碰撞,尽管我遇到了一些奇怪的情况,每次加载游戏时,碰撞有时会起作用,有时不会。这些gif基本上解释了我的意思:

正如你所看到的,碰撞有时会起作用,但每次我重新加载游戏时,结果都会改变,我实际上不知道为什么。还有其他一些奇怪的事情发生在每个实体周围,比如你可以看到红色边框,这是它们的碰撞框,但有时正如你在gif中看到的那样,尽管有碰撞,一些块却没有显示碰撞框。我过去也有过块,有时甚至不渲染,尽管这已经有一段时间没有发生了

我是如何从一个txt文件加载地图的,该文件如下所示:

然后使用我的LevelMap类加载:

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