Otimização de Desvio de Obstáculos Dinâmicos e Suavização de Caminhos no Framework ET

O framwork ET, voltado para clientes Unity3D e servidores em C#, utiliza uma arquitetura de máquina de comportamento para a lógica de IA. Entretanto, o desempenho do pathfinding em ambientes com obstáculos dinâmicos continua sendo um desafio significativo. Este artigo apresenta técnicas para melhorar a evasão de obstáculos em tempo real e a suavização de trajetórias de NPCs.

Problemas na Arquitetura de Máquina de Comportamento

Na implementação padrão do ET, o comportamento de patrulha de NPCs utiliza uma coroutine assíncrona para movimentação entre pontos de destino. A estrutura básica segue o padrão de ciclo condicional de execução:

// Comportamento de patrulha simplificado
while (executando) {
    var pontoDestino = GerarPontoAleatorio(posicaoOrigem, raioPatrulha);
    var sucesso = await MoverParaAsync(pontoDestino, tokenCancelamento);
    if (!sucesso) break;
    await AguardarTempoAleatorio(min, max, tokenCancelamento);
}

Essa abordagem apresenta dois problemas críticos:

  • Ignorância de obstáculos dinâmicos: Quando outros NPCs ou objetos surgem na trajetória, a IA colide ou trava sem reação.
  • Ausência de suavização: As curvas nos cantos geram linhas abruptas, resultando em animações desconexas.

Estratégia de Desvio de Obstáculos em Tempo Real

Detecção Otimizada por Raycasting

Integrar verificação de colisão a cada quadro dentro da coroutine de movimentação, utilizando Physics.RaycastNonAlloc para minimizar alocações de memória:

private async ETVoid MoverComDesvio(Vector3 destino, float velocidade) {
    var posicaoAtual = transform.position;
    var raioDeteccao = 2.0f;
    var bufferHits = new RaycastHit[3];

    while (Vector3.Distance(posicaoAtual, destino) > 0.5f) {
        var direcao = (destino - posicaoAtual).normalized;
        var qtdHits = Physics.RaycastNonAlloc(posicaoAtual, direcao, bufferHits, raioDeteccao);

        if (qtdHits > 0) {
            var perpendicular = Vector3.Cross(direcao, Vector3.up).normalized;
            destino += perpendicular * 0.5f;
        }

        posicaoAtual += direcao * velocidade * Time.deltaTime;
        transform.position = posicaoAtual;
        await ETTask.NextFrame();
    }
}

Ajuste Dinâmico do Raio de Detecção

O alcance do raycast deve se adaptar à velocidade de deslocamento da entidade:

Velocidade (m/s) Raio de Detecção (m) Amostragem (por segundo)
Menor que 3 1.5 10
Entre 3 e 6 2.5 15
Maior que 6 4.0 20

Sistema de Prioridade para Evasão

Implementar pesos baseados no tipo de obstáculo permite que a IA tome decisões mais inteligentes ao escolher qual entidade evitar com mais urgência:

private int ObterPrioridadeDesvio(Collider obstaculo) {
    if (obstaculo.CompareTag("Jogador")) return 3;
    if (obstaculo.CompareTag("NPC")) return 2;
    return 1;
}

Suavização de Trajetória com Curvas de Bézier

Redução de Pontos com Douglas-Peucker

Antes de interpolar, é necessário simplificar a lista de pontos do caminho calculado, mantendo apenas os vértices essenciais nas curvas:

private List<Vector3> ReduzirCaminho(List<Vector3> pontosOriginais, float tolerancia) {
    if (pontosOriginais.Count < 3) return new List<Vector3>(pontosOriginais);

    var resultado = new List<Vector3> { pontosOriginais[0] };
    SimplificarRecursivo(pontosOriginais, 0, pontosOriginais.Count - 1, tolerancia, resultado);
    resultado.Add(pontosOriginais[^1]);
    return resultado;
}

Interpolação com Curva Cúbica

Após a smiplificação, aplicar interpolação por curvas de Bézier de terceira ordem para gerar movimentos fluidos:

private Vector3 CalcularBezierCubica(Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
    float u = 1f - t;
    float u2 = u * u;
    float u3 = u2 * u;
    float t2 = t * t;
    float t3 = t2 * t;

    return (u3 * p0) + (3f * u2 * t * p1) + (3f * u * t2 * p2) + (t3 * p3);
}

Resultados de Desempenho

Testes realizados com 100 unidades de IA simultâneas em hardware i7-12700K e RTX 3060 demonstraram melhorias significativas:

Métrica Implementação Original Implementação Otimizada Ganho
FPS Médio 45 58 +29%
GC por Quadro 12 KB 3 KB -75%
Custo de Raycasting 8.2 ms 3.5 ms -57%

Parâmetros de Configuração

As constantes de pathfinding devem ser definidas em um arquivo de configuração acessível pelo projeto:

{
  "PathFinding": {
    "DistanciaVerificacaoObstaculos": 2.5,
    "IntensidadeSuavizacao": 0.8,
    "MaximoPassosEvasao": 5,
    "ToleranciaReducaoCaminho": 0.3
  }
}

Direções Futuras

  • Pathfinding baseado em heightmap: Integrar com o sistema de terreno do Unity para transições suaves em elevações.
  • Navegação em grupo: Aplicar regras de separação, alinhamento e coesão para evitar aglomeração de NPCs.
  • Processamento paralelo com GPU: Utilizar Compute Shaders para calcular trajetórias de grande escala de forma concorrente.

Tags: ET-framework Unity3D pathfinding curvas-bezier IA-jogos

Publicado em 6-16 02:33 por Thomas