07 febrero 2026

Creación de paquetes para Unity

Portada

La reutilización es clave en el desarrollo de software. Unity no es la excepción. Cuando lleves ya tiempo desarrollando juegos, antes o después te encontrarás con problemas que ya resolviste previamente y querrás aprovechar implementaciones anteriores. También puede ser que un compañero tuyo necesite un componente que hubieras desarrollado y que le permitiría resolver un problema de implementación. En ambos casos te verás en la necesidad de exportar una serie de assets de un proyecto anterior de manera que luego sea fácil importarlo en otro. En este artículo veremos algunas manera de hacerlo.

La copia directa

La manera más evidente de compartir componentes es copiarlos a un pincho USB, o a un paquete ZIP, y luego copiarlos en el arbol de carpetas del proyecto de destino. 

Este enfoque tiene la ventaja de la sencillez. Es inmediato hacerlo. Pero tiene la desventaja de que te obliga a hacer una importación manual de cada componente, copiándolos en las carpetas correctas. Si los componentes importados tienen dependencias entre sí, es fácil que estas dependencias se rompan si importas los componentes en carpetas diferentes a las de origen.

Además, debes tener en cuenta qué quieres copiar. Muchas veces no basta con los ficheros originales. Cuando incluyes un fichero en un proyecto de Unity, el editor genera otro de extensión .meta en el que se guardan los parámetros usados en el proceso. Incluir los ficheros .meta en la copia es muy importante si quieres estar seguro de que otros desarrolladores utilizan los assets exportados de la misma manera que tú.

Teniendo en cuenta lo anterior, el método de la copia directa sólo es aconsejable para copias personales. Cosas que usaste en otros proyectos, que conoces bien y sabes cómo funcionan, y que por tanto sabes cómo "trasplantar" a otro proyecto. De no ser esa la situación te aconsejo cualquiera de los otros métodos de este artículo. Serán más limpios y menos propensos a errores.

El Unity Package

El editor de Unity permite la creación de un paquete contenedor con los assets que decidamos y sus dependencias. Podemos pasarle este paquete a otro compañero para que este lo importe desde su editor.

Supongamos que queremos exportar una serie de scripts que utilizamos para las pruebas automatizadas.

Los scripts que queremos exportar
Los scripts que queremos exportar

Para crear el paquete no tenemos más que pulsar con el botón derecho del ratón en cualquier carpeta de la pestaña Project del editor y elegiremos la opción "Export as Asset Package...". 

Nos saldrá una ventana emergente en la que aparecerá seleccionado todo el árbol de carpetas de nuestro proyecto. En esa ventana tendremos que desmarcarlo todo, salvo lo que queramos incluir dentro del paquete exportado.

Ventana de exportación
Ventana de exportación


Hecho eso, pulsaremos en el botón Export y elegiremos el nombre del paquete generado (yo lo he llamado TestsCommonTools) y dónde queremos guardarlo. El fichero generado será el que pasaremos a aquellos con los que queramos compartir nuestros componentes.

Unity package generado
Unity package generado



Ahora vamos a ponernos en el lugar de una persona que quisiera importar nuestros componentes. Esa persona sólo tiene que arrastrar el paquete a la pestaña project de su editor, para que se abra la ventana de importación. Esa ventana le permitirá elegir qué componentes importar, en el caso de que no quisiera importarlos todos.

Ventana de importación
Ventana de importación


Al importar, debemos tener en cuenta que se nos creará la estructura de carpetas del paquete dentro de un nuestra carpeta Assets. Eso puede no ser un problema, si compartimos el mismo estándar de carpetas con el que exportó el paquete, o puede serlo si no nos gusta su estructura de carpeta o si ya tenemos otras con ese nombre, pero no queremos "contaminarlas" con el contenido del paquete.

Estructura de carpetas antes de la importación
Estructura de carpetas antes de la importación

Estructura de carpetas tras la importación
Estructura de carpetas tras la importación

Lo bueno del Unity Package es que el editor se ocupa de incluir los ficheros meta y dependencias varias que pudieran ser necesarias para cargar los assets al importar. Lo malo, como ya hemos visto, es que nuestra estructura de carpetas se "contamina" con el estándar utilizado por el creador del paquete. Por tanto, este recurso sólo es recomendable de manera muy puntual o en caso de compartir assets con miembros de nuestro equipo que compartan nuestro estándar de carpetas.

El paquete UPM

La evolución de los Unity Packages son los paquetes para el Unity Package Manager (UPM). Se trata del sistema moderno y recomendado por Unity para gestionar paquetes, librerías, herramientas, shaders, samples y funcionalidades en tus proyectos.

Tiene múltiples ventajas respecto al sistema anterior:

  • Los paquetes se pueden instalar y desinstalar desde el Package Manager, lo que simplifica muchísimo el proceso y asegura que al desinstalar no queden trazas del paquete. 
  • La instalación se produce fuera de la carpeta Assets, lo que mantiene la limpieza del proyecto.
  • El Package Manager permite gestionar versiones, facilitando que se actualicen los paquetes cuando haga falta.
  • Si un paquete depende de otros, el Package Manager se encarga de instalarlos también.
  • Permite usar repositorios oficiales, como el de Unity; de terceros, como OpenUPM; o personales, como GitHub.
Para crear un paquete UPM, tienes que abrir el Package Manager pinchando en Window > Package Management > Package Manager. En la ventana emergente, tienes que pulsar en el símbolo "+" de la esquina superior izquierda y elegir la opción "Create package".

Creación de un paquete UPM mediante el Package Manager
Creación de un paquete UPM mediante el Package Manager

Al hacerlo te aparecerá una pequeña ventana emergente, en la esquina superior izquierda de la pestaña, donde tendrás que poner el nombre que le quieres dar el paquete. Ehn el caso de mi ejemplo, le he dado el nombre de CommonTestTools.

Hecho eso, nuestro paquete aparecerá en el listado de los paquetes del proyecto.

Apariencia provisional de nuestro paquete
Apariencia provisional de nuestro paquete

Sin embargo, todo lo que muestra el paquete en este punto es provisional. Ahora hay que configurarlo y darle contenido.

Si pulsas el botón Locate, de la descripción del paquete en el Package Manager, verás que la pestaña Project del editor se situará en la carpeta recién creada para el paquete, dentro de la carpeta Packages.

Estructura de carpetas para nuestro paquete
Estructura de carpetas para nuestro paquete

Como puedes ver en la captura anterior, el Package Manager ya se ha encargado de crear una estructura de carpetas para nuestro paquete. Cada una de esas carpetas tiene un propósito específico, pero dependiendo del de nuestro paquete, es posible que no necesites algunas. Paso a explicarte la función de cada una:

  • Documentation: Aquí tienes que colocar la documentación de ayuda de tu paquete, en formato MarkDown o HTML.
  • Editor: Aquí van los scripts con las extensiones del editor, si es que tu paquete incluye alguna.
  • Runtime: Esta contienen los scripts destinados a ser utilizados por el juego, al ser ejecutado.
  • Samples: Ejemplos de uso del paquete.
  • Tests: Esta carpeta debería contener todos los tests (tanto pruebas unitarias, como de integración) para verificar el correcto funcionamiento de tu paquete. Esta carpeta contiene a su vez dos subcarpetas: una de Editor y otra de Runtime. La de Editor se usa para utilidades de testing que usen la API del Editor. Salvando ese caso, lo normal es que uses la de Tests/Runtime.

De todas las carpetas anteriores, el contenido de la de Runtime es el único que puede acabar en el juego final, si se le referencia desde el código compilado. El resto sólo tienen sentido para ser usadas desde el editor, por lo que no contaminan el juego final.

El caso de mi ejemplo es un poco particular, ya que son herramientas para ser utilizadas en los test unitarios de un juego, a priori no tiene sentido que vayan ni a la carpeta Runtime, ni a la de Editor, de la carpeta raíz. Sin embargo, he visto que no consigo visibilidad de las clases de la herramienta, desde mis PlayTests, a no ser que las coloque en la carpeta Runtime. Así que eso es lo que he hecho finalmente. 

Es muy importante que copiemos los ficheros con la pestaña Project del editor de Unity. De esta manera, el editor se ocupará de copiar no sólo sus ficheros sino también sus correspondientes ficheros .meta, indispensables para que el paquete se ejecute correctamente.

Ficheros de mi ejemplo, situados en el paquete
Ficheros de mi ejemplo, situados en el paquete

Dotado de contenido el paquete, ahora toca definir sus metadatos. Eso se hace editando el fichero package.json, situado en la carpeta raíz del paquete. El contenido por defecto del paquete, tal y como lo crea el Package Manager, es algo como lo siguiente:

Contenido por defecto del fichero package.json
Contenido por defecto del fichero package.json

El propósito de los campos es muy intuitivo:

  • name: Es el nombre completo del paquete. Usa el formato de dominio inverso para evitar coincidencias de nombre con otro paquetes. En realidad, da igual el dominio que pongas siempre que el nombre completo no acabe siendo el mismo que el de otro paquete.
  • displayName: Es el nombre corto que se mostrará en el Package Manager y por el que el resto de la gente conocerá tu paquete.
  • version: La versión de tu paquete. Conviene que lo vayas cambiando, conforme saques nuevas versiones del paquete, para que el Package Manager detecte el cambio y aconseje la actualización al usuario.
  • unity: Versión utilizada para generar el paquete. Sirve como señal de la versión mínima compatible con el paquete.
  • unityRelease: La minor-version de la etiqueta anterior. Sólo necesaria si, por lo que quiera que sea, nuestro paquete sólo funcionase a partir de un determinado parche.
  • description: La descripción de lo que hace nuestro paquete.
  • dependencies: Todos los paquetes de los que depende el nuestro para funcionar. El Package Manager instalará todos esos paquetes antes que el nuestro.
  • author: Nuestros datos como autor del paquete.
  • changelogUrl: La URL de nuestro registro de cambios. Lo normal es que lo hagamos apuntar al changelog de nuestro repositorio.
  • documentationUrl: URL a la documentación del paquete. Es buena idea que apunte al readme o a la wiki del repositorio del  paquete.
  • licensesUrl: Si alojas tu paquete en GitHub y has seguido sus buenas prácticas, lo normal es que hayas creado un fichero license en tu repositorio. Esta URL debería apuntar a él.

No tienes que usar todos los campos. En realidad hay muchos más. Estos son los que introduce por defecto el Package Manager al crear el paquete. Pero puedes usar muchos menos. Por ejemplo, un paquete que creé para contar con una regla de medir en el editor tiene el siguiente package.json:

Contenido del package.json de mi paquete unity-measuring-tape
Contenido del package.json de mi paquete unity-measuring-tape

En el caso del paquete que nos ocupa en nuestro ejemplo, podría bastar por el momento con lo siguiente:

package.json para nuestro ejemplo
package.json para nuestro ejemplo

Si luego colgamos el código fuente de nuestro paquete en GitHub, siempre podremos actualizar el package.json introduciendo los correspondientes campos que apunten al repositorio.

Lo más cómodo es utilizar el IDE para editar el fichero package.json, pero Unity también te deja configurarlo desde el editor. Si en el Package Manager localizas el paquete, verás que te ofrece traes botones: Locate, Export y Manage. Ya hemos usado el botón Export. Ahora toca pulsar el botón Manage, lo que abrirá un combo en el que tienes que elegir la opción "Edit Manifest". Esto abrirá una ventana como esta en el inspector:

Edición del package.json desde el inspector
Edición del package.json desde el inspector

Una vez hechos los cambios, es probable que tengas que reiniciar el editor para que se reflejen en el Package Manager.

Ya casi lo tenemos listo. Falta prestarle algo de atención a los ficheros .asmdef. El Package Manager los crea en los directorios donde puede haber código y los enlaza entre sí. En teoría, no deberías necesitar tocarlos porque la configuración que traen por defecto suele bastar para casos sencillos. El problema es que el Package Manager le pone el nombre del ID de nuestro usuario en Unity, y suele ser bastante feo. Por mucho que luego le hayamos cambiado el nombre al paquete en el package.json, el editor de Unity no regenera los ficheros .asmdef. Así que hay que ir buscando esos ficheros por las distintas carpetas para cambiarles el nombre, tanto a nivel de fichero de la pestaña Project, como a nivel del campo Name del inspector del dichero .asmdef. Lo que ocurrirá al hacerlo es que se romperán los enlaces que apuntasen al fichero renombrado desde otros ficheros .asmdef. Por eso, una vez que hayas renombrado todos los ficheros .asmdef te tocará hacer una segunda vuelta rehaciendo los enlaces en el inspector de cada fichero. No tiene mayor complejidad. Verás el enlace roto porque el inspector lo sombrea, así que no tienes más que añadir un nuevo elemento a la lista de enlaces, elegir el fichero con su nuevo nombre y eliminar el elemento del enlace roto. Por ejemplo, el fichero .asmdef de la carpeta donde he dejado las clases de mi paquete ha quedado de la siguiente manera:

El fichero .asmdef de mi paquete
El fichero .asmdef de mi paquete

Con carácter general, que el campo "Auto Referenced" esté marcado puede ayudar para que no haya que enlazar manualmente el asmdef desde los asmdef de código que quiera usar las clases de la herramienta. Sin embargo, puede haber casos en los que con todo y con eso no te quede otra que enlazar el asmdef del paquete para usarlo desde tu código.

Otra cosa importante a tener en cuenta es que el parámetro "Root Namespace" del asmdef debe coincidir con el namespace que usen las clases de nuestro paquete. De otra manera puedes encontrarte con que el usuario del paquete no vea sus clases desde su código.

Teniendo en cuenta lo anterior, el código del proyecto donde hayamos creado el paquete ya podrá ver sus clases importando por el namespace que hayamos definido en el asmdef.

Importación de las clases de nuestro paquete

Compartir un paquete UPM

Con lo anterior, ya tendremos un paquete funcional, pero sólo podrá ser usado en el proyecto desde el que lo hayamos creado. Lo lógico es que queremos exportarlo para poder usarlo en otros proyectos.

La manera más inmediata de exporter un paquete UPM es en formato tgz. Nos basta con pulsar con el botón derecho la carpeta del paquete, dentro de Packages y elegir la opción "Export as UPM package...". Con eso crearemos un fichero .tgz que incluirá nuestro paquete. Aquel al que le pasemos el fichero no tendrá más que importarlo desde el Package Manager, pulsando el icono "+" de la esquina superior izquierda y eligiendo la opción "Install package from tarball...", lo que le permitirá elegir el fichero tgz para cargarlo.

El problema de la opción anterior es que nos obligaría a enviarle nuevos ficheros tgz a nuestros usuarios con cada nueva versión. Una alternativa más versátil es subir el código de nuestro paquete a GitHub. Basta con que la raíz del repositorio esté al nivel del fichero package.json. Haciéndolo así, nuestros usuarios podrán instalarse el paquete usando la opción "Install package from git URL..." y facilitando la URL del repositorio. La ventaja de este enfoque es que si vamos cambiando la versión recogida en el package.json, el Package Manager detectará el cambio y avisará al usuariod e que puede actualizar.

Por último, también puedes compartir tu paquete subiéndolo a un repositorio público como OpenUPM, para maximizar su visibilidad. Sin embargo, OpenUPM se usa al margen del Package Manager por lo que bien puede dar para otro artículo.

Conclusión

En este artículo hemos repasado todas las maneras de reutilizar tus assets de Unity, bien entre tus propios proyectos, o bien compartiéndolos con otros desarrolladores. Esto debería evitar que te vieses obligado a "reinventar" la rueda reimplementando componentes ya presentes en otros proyectos o copiando su código, componentes y dependencias de manera manual entre proyectos.

22 enero 2026

Asignación de costes a la navegación 2D por tilemaps en Unity

Portada del artículo

Hace poco vimos cómo se podía hacer en Godot para asignarle costes a los tiles de un tilemap, de manera que se pudiera usar esos costes en los algoritmos de navegación. Unity tiene su manera particular de hacerlo, pero, como en el caso de Godot, dependerá de si queremos utilizar esos costes con un algoritmo personalizado de navegación o con la navegación con navmesh del engine. Vamos a ver cómo se hace en ambos casos.

En este artículo asumiré que has leído mi artículo anterior sobre cómo asignar datos a los tiles en Unity. En este aprovecharemos algunas cosas lo que conté allí.

Costes para algoritmos personalizados de navegación

Cuando usemos algoritmos personalizados, como nuestras propias implementaciones de Dijkstra o A*, querremos acceder al coste de tránsito de una celda determinada. Podríamos optar por asignarle un game object al tile, tal y como vimos en el artículo mencionado antes, y que ese game object tuviese un script con el dato del coste. Pero eso sería excesivamente complejo, ya que tendríamos que asignarle un collider a ese game object para poder detectarlo con un sensor de volumen, al aplicar el sensor a la posición de la celda. No, definitivamente es mucho mejor en este caso la otra aproximación que veíamos en ese artículo: la de crear una clase que herede de Tile, hacer que incluya un campo de coste y utilizarla para dibujar las celdas que tengan un coste de tránsito más elevado. Sería una clase como la siguiente:

Implementación de nuestro tile personalizado
Implementación de nuestro tile personalizado

La clase se limita a tener un campo para poder meter el coste del tile a través del inspector (línea 13).

Para poder consultar desde nuestro código el coste del tile, en la línea 18 hay una propiedad de sólo lectura.

En el fondo, un Tile es una especie de Scriptable Object, por lo que se extiende de una manera muy parecida a como se hacía con estos. Como con los Scriptable Object, podemos decorarlos con el atributo [CreateAssetMenu] (línea 6) para que el editor muestre una entrada de menú desde las que crear instancias de este tile. En este caso lo he creado para que me lo muestre en la ruta "Scriptable Objects > CoutyardTile".

La creación de un tile de este tipo sería similar a la de un Scriptable Object. Pulsaríamos con el botón derecho en la carpeta donde quisiéramos guardar el tile y elegiríamos la opción configurada en el párrafo anterior.

Creación de una instancia del tile personalizado
Creación de una instancia del tile personalizado

Creada la instancia del tile, podremos darle la apariencia que queramos y asignarle un valor al campo del coste. Mi ejemplo es visualmente muy sencillo. A un tile de agua le he dado un coste de 80.

Configuración de un tile de agua
Configuración de un tile de agua

En mi ejemplo he creado cuatro tipos de tiles transitables:

  • Ground: Gris. Es el que no tiene dificultades de tránsito, por lo que su coste es 1.
  • Grass: Verde. Tiene un coste de 2.
  • Sand: Naranja. Coste 4.
  • Water: Azul. Coste 80.

Acuérdate también de asignarle un sprite. De otra manera, por mucho que le asignes un valor al color, el tile no se verá. Yo me he limitado a usar un sprite de color blanco, para que se aplique sobre él el color.

Creados los tiles personalizados, te bastará con poner en modo edición la pestaña del Tile Palette y arrastrar sobre ella los tiles, desde su carpeta.

Mi tile palette
Mi tile palette

Con eso, ya podemos dibujar las zonas "lentas" del escenario. El mío está bordeado de muros infranqueables y tiene muros internos de color negro.

El escenario de mi ejemplo
El escenario de mi ejemplo


Una vez que los costes están asociados a sus tiles, ¿cómo los recuperaríamos? Nos bastaría con un método como el de la siguiente captura.

Método para recuperar el coste asociado a cada tile
Método para recuperar el coste asociado a cada tile

El método supone que existe una variable global walkableTilemap con una referencia al tilemap donde se encuentren dibujados todos los tiles transitables del escenario. Con esa referencia, usamos su método WorldToCell() (línea 319) para convertir la posición global del escenario que queremos analizar a la coordinada del tilemap que se corresponde con dicha posición. Luego, usamos el método GetTile() (línea 320) para recuperar el tile asociado a esas coordenadas. Una vez que tengamos el tile, podemos acceder a su propiedad Cost para devolver su valor (línea 321).

Mesh navigation con zonas lentas

El método anterior es útil si queremos que nuestros agentes se muevan por el tilemap usando nuestro propio algoritmos de navegación. Sin embargo, puede ser que por rendimiento, o sencillez, prefiramos utilizar el sistema de mesh navigation que ya viene con el engine. El problema en Unity es que su sistema de mesh navigation está pensado para 3D y no sirve tal cual para escenarios 2D como los del ejemplo. Afortunadamente, hay un módulo libre llamado NavMeshPlus que solventa este problema para el 2D y se usa prácticamente igual que el mesh navigation nativo de Unity para 3D. Expliqué su instalación y uso en un artículo anterior en el que cubrí la navegación 2D en Unity. A partir de lo dicho en ese articulo, en este explicaremos cómo implementar zonas lentas que sean tenidas en cuenta por el algoritmo de búsqueda de caminos.

Por tanto, partiendo de que te has leído ese artículo, y que has seguido sus indicaciones para generar un un NavMesh, ahora hay que crear un tipo de área transitable por cada tipo de baldosa que tengamos. Para ello, ve a Window > AI > Navigation. La ventana que se abre tiene dos pestañas: Agents y Areas. Como te imaginarás, la que nos interesa es Areas. Allí ya están definidas las áreas por defecto del sistema de navegación de Unity:  Walkable, Not Walkable y Jump. Fíjate que en la columna de la derecha se definen el coste de tránsito de cada una de las áreas. Es aquí donde definiremos los tipos de áreas que vimos en la sección anterior, con sus correspondientes costes.

Configuración de las áreas transitables y sus costes


Definidas las áreas, hay que asociar cada tile al tipo de área al que pertenecen. Si seguiste el artículo de navegación 2D en Unity, habrás incluido un componente NavigationModifier en el mismo GameObject del tilemap donde tuvieras los tiles transitables. Desmárcale el campo Override Area. 

Acto seguido añade un componente NavigationModifierTilemap. En él hay una lista llamada Tile Modifiers. Añade a esa lista un elemento por cada tipo de tile transitable que queras definir. Luego arrastra a cada uno de los elementos el recurso de su respectivo tile, desde su carpeta. De esta manera podrás definir a qué area pertenece cada tile. 

En mi caso, la configuración queda de la siguiente manera:

Asignación de tiles a cada una de las áreas
Asignación de tiles a cada una de las áreas

Ahora hay que regenerar el NavMesh para que incluya los costes de tránsito que acabamos de definir para cada una de las áreas. 

Sin embargo, antes de pulsar Bake en el componente NavigationSurface tienes que asegurarte de cambiar el parámetro Render Meshes. Si lo tienes configurado tal y como lo dejamos en el artículo de navegación 2D en Unity, este parámetro tendrá el valor Physics Colliders, por lo que sólo tendrá en cuenta los objetos con colliders físicos asociados para "recortar" la zona transitable del NavMesh. Tenemos que cambiarlo a Render Meshes. De esta manera usará como referencia los tiles que hemos definido como transitables (que son componentes visuales, renderizables) para dar forma al NavMesh. Una vez cambiado podremos pulsar Bake.

Configuración de mi NavMesh
Configuración de mi NavMesh

Si haces que el editor te muestre el NavMesh, verás que este tiene varios colores para señalar las distintas áreas que ha detectado.

NavMesh generado con diferentes áreas

Ya tienes tu NavMesh, pero si ejecutas el escenario en este punto es probable que tu agente se quede quieto. Para que se mueva tienes que asegurarte de que esté configurado para usar las áreas transitables. Eso se hace configurando el parámetro AreaMask del NavMeshAgent, de manera que contenga todas las zonas por las que se podrá andar.

Configuración de NavMeshAgent
Configuración de NavMeshAgent

En la captura anterior, puedes ver que he configurado el AreaMask para que incluya las áreas Ground, Grass, Water y Sand.

Ahora sí, si ejecutas el juego, tu agente debería ser capaz de moverse por las zonas transitables, eligiendo siempre el camino con menor coste.

Probablemente te des cuenta de que, aunque el agente elija la ruta de menor coste, no disminuirá la velocidad si se ve obligado a atravesar una zona lenta. Para que eso ocurra, tendrás que llamar al método estático en NavMesh.SamplePosition() desde el Update() del agente, para analizar en todo momento la posición donde se encuentre. Ese método devuelve como parámetro de salida un objeto de tipo AI.NavMeshHit que tiene una propiedad mask con el área a la que está asociada ese punto. Lo normal es que un punto sólo esté asociado a una área, pero a pesar de eso la propiedad mask es (como su nombre indica) una máscara de 32 bits. Un bit por cada una de las áreas de navegación que Unity permite que se definan. Te basta averiguar el índice del bit que está marcado a 1 para saber el área de navegación del punto analizado. Con es índice puedes llamar a otro método estático, NavMesh.GetAreaCost() para obtener el coste del área sobre la que estemos y actuar en consecuencia (habitualmente dividiendo la velocidad del agente entre el coste del área).

Conclusión

Con esto, ya hemos revisado las dos opciones que tenemos en Unity para navegar por un escenario construido con un tilemap.

  1. Usar datos de coste asociados a los tiles para hacer una búsqueda de caminos clásica con nuestra implementación de Dijkstra o con la de A* que integra Godot.
  2. Usar mesh navigation con zonas lentas.

Si tus escenarios tienen un tamaño moderado, puedes permitirte la opción 2, si por la razón que fueses prefirieses modelar el escenario con un grafo. 

Sin embargo, en cuanto tu escenario crezca de tamaño preferirás la opción 3. Es la que mejor rendimiento ofrece y la más sencilla de configurar.