No RecastNavigation, como posso tornar um agente ocioso depois de chegar ao seu destino?

8

Esta pergunta é especificamente sobre como lidar com a biblioteca Recast Navigation.

Eu adicionei um agente addAgente defini seu destino com requestMoveTarget. Quando o agente atinge seu destino, ele para, mas ao ser empurrado para fora do caminho (por outro agente), ele tenta retornar ao seu destino. Em vez disso, queira que ele pare e fique ocioso, para que, quando outro agente estiver andando, empurre-o para o lado e ele não retorne.

Tentei ligar resetMoveTargetpara agent.nposestar perto de agent.targetPos(como se o agente tivesse atingido seu destino), mas isso parece quebrar a lógica interna da simulação de multidão - o agente continuaria andando na direção antiga, sem parar.

Como instruo corretamente um agente para parar e ficar inativo (ainda que empurrável) no RecastNavigation?

Kromster
fonte

Respostas:

2

Foi feita uma correção upstream relacionada à sua solução que redefine a velocidade desejada resetMoveTarget.

bool dtCrowd::resetMoveTarget(const int idx)
 {
    if (idx < 0 || idx >= m_maxAgents)
        return false;

    dtCrowdAgent* ag = &m_agents[idx];

    // Initialize request.
    ag->targetRef = 0;
    dtVset(ag->targetPos, 0,0,0);
    dtVset(ag->dvel, 0,0,0); // <<-- This line added
    ag->targetPathqRef = DT_PATHQ_INVALID;
    ag->targetReplan = false;
    ag->targetState = DT_CROWDAGENT_TARGET_NONE;

    return true;
 }
Leif Gruenwoldt
fonte
Tanto quanto me lembro, esta é uma resposta incompleta. Estou confuso. Esta é uma resposta ou um comentário para a minha resposta abaixo? Porque você também precisa redefinir o corredor dos agentes, para que os agentes se tornem realmente ociosos (empurráveis).
Kromster
OK, eu tinha esquecido o seu problema com o agente se tornando imperdoável. Vou tentar reproduzir.
Leif Gruenwoldt
@KromStern Hmm, estou tendo problemas para reproduzir isso. Sem a redefinição do corredor, meus agentes podem ser empurrados por outros agentes. Isso é necessário?
Leif Gruenwoldt
Tentei adicionar isso resetMoveTargetlocalmente, mas não observo diferença. ag->corridor.reset(ag->corridor.getFirstPoly(), agent->npos);
Leif Gruenwoldt
11
Por alguma estranha razão, também não posso reproduzi-lo agora. Parece que algo mais mudou desde então. De qualquer forma, obrigado pela sua participação! :)
Kromster
0

Não tenho certeza, mas meu palpite seria chamar "requestMoveVelocity" com vetor zero também nesse agente. De uma chance.

Rokannon
fonte
0

Nota: Esta solução parece supérflua, mas deixo-a caso o problema apareça novamente.

Após muita decodificação, tentativa e erro, tomei dtCrowd.resetMoveTargetcomo base e encontrei uma maneira de modificá-lo:

procedure TKMTerrainNavigation.AgentTargetClear(aIdx: Integer);
var
  ag: PdtCrowdAgent;
begin
  ag := fRecastCrowd.getAgent(aIdx);

  ag.targetRef := 0;
  dtVset(@ag.targetPos[0], 0, 0, 0);
  ag.targetPathqRef := DT_PATHQ_INVALID;
  ag.targetReplan := False;
  ag.targetState := DT_CROWDAGENT_TARGET_NONE;

  // Reset desired velocity
  dtVset(@ag.dvel[0], 0, 0, 0); 

  // Reset agents corridor so that agent won't try to walk back to his last corner
  ag.ncorners := 0;
end;

O código PS Above está no Delphi, mas deve funcionar tão bem no C ++.

O autor da Recast Navigation comentou:

Em vez de redefinir os cantos, você deve redefinir o corredor para a posição atual do agente e o primeiro polígono.

Geralmente, é preferível definir a posição de destino para a posição atual do agente, do que defini-la como 0,0,0. Mas você está redefinindo todo o resto também, acho que está bem.

Kromster
fonte