Dans RecastNavigation, comment puis-je rendre un agent inactif après avoir atteint sa destination?

8

Cette question concerne spécifiquement la gestion de la bibliothèque de navigation de refonte.

J'ai ajouté un agent avec addAgentet défini son objectif avec requestMoveTarget. Lorsque l'agent atteint sa destination, il s'arrête, mais lorsqu'il est repoussé (par un autre agent), il essaiera de revenir à sa cible. Au lieu de cela, voulez-vous qu'il s'arrête et devienne inactif, de sorte que lorsqu'un autre agent marche en le repoussant et qu'il ne revienne pas.

J'ai essayé d'appeler resetMoveTargeten agent.nposétant proche de agent.targetPos(comme si l'agent avait atteint sa destination), mais cela semble briser la logique interne de la simulation de foule - l'agent continuerait simplement à marcher dans l'ancienne direction, sans jamais s'arrêter.

Comment dire correctement à un agent de s'arrêter et de devenir inactif (mais pouvant être poussé) dans RecastNavigation?

Kromster
la source

Réponses:

2

Un correctif a été fait en amont lié à votre solution qui réinitialise la vitesse souhaitée en 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
la source
Pour autant que je m'en souvienne, cette réponse est incomplète. Je suis confus. Est-ce une réponse ou un commentaire à ma réponse ci-dessous? Parce que vous devez également réinitialiser le couloir des agents, afin que les agents deviennent vraiment inactifs (pouvant être poussés).
Kromster
OK, j'avais oublié votre problème avec l'agent devenant impusible. Je vais essayer de reproduire.
Leif Gruenwoldt
@KromStern Hmm J'ai du mal à reproduire cela. Sans la réinitialisation du cooridor, mes agents peuvent être poussés par d'autres agents. Est-ce nécessaire?
Leif Gruenwoldt
J'ai essayé d'ajouter ceci resetMoveTargetlocalement mais je n'observe aucune différence. ag->corridor.reset(ag->corridor.getFirstPoly(), agent->npos);
Leif Gruenwoldt
1
Pour une raison étrange, je ne peux pas non plus le reproduire maintenant. On dirait que quelque chose d'autre a changé depuis. Quoi qu'il en soit, merci pour votre participation! :)
Kromster
0

Je ne suis pas sûr mais ma conjecture serait d'appeler "requestMoveVelocity" avec zéro-vecteur également sur cet agent. Essaie.

Rokannon
la source
0

Remarque: Cette solution semble être superflue, mais je la laisse au cas où le problème réapparaîtrait.

Après beaucoup de décodage, d'essais et d'erreurs, j'ai pris dtCrowd.resetMoveTargetcomme base et trouvé un moyen de le modifier:

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;

PS Le code ci-dessus est en Delphi, mais il devrait tout aussi bien fonctionner en C ++.

L'auteur de la refonte de la navigation a commenté:

Au lieu de réinitialiser les coins, vous devez réinitialiser le couloir à la position actuelle des agents et au premier polygone.

Il est généralement préférable de définir la position cible sur la position actuelle des agents plutôt que de la définir sur 0,0,0. Mais vous réinitialisez tout le reste aussi, je pense que ça va.

Kromster
la source