Supongamos que estamos construyendo un juego de estrategia. El juego tendrá unidades de jugador y enemigos que navegan a través de un mapa completo de obstáculos. Mientras que las unidades jugador serán controlados haciendo clic en el mapa las posiciones, los enemigos van a caminar solo, después de cualquier estrategia de AI.

Usted puede haber notado que, dada una posición de origen y de destino, las unidades deben encontrar un camino que conecta los dos puntos evitando cualquier obstáculo en el camino. Además, es importante que este camino es el más corto posible.

El proceso que acabamos de describir se llama búsqueda de caminos y se usa en muchos juegos, así como otros problemas de IA. En este tutorial voy a mostrar cómo utilizar una biblioteca de búsqueda de caminos para resolver este problema en su juego. Al final, vamos a construir un mapa donde podemos hacer clic a donde queremos que nuestro personaje a medida, y encontraremos el camino más corto desde su posición hasta la posición deseada.

Para leer este tutorial, es importante que usted está familiarizado con los conceptos siguientes:


  • Javascript y conceptos orientados a objetos.
  • conceptos básicos Phaser, tales como: estados, sprites, los grupos y la física de arcade
  • Creación de mapas con baldosa

    No se pierda! extremos de la oferta en

    • Accede a los más de 200 cursos
    • Nuevos cursos añadió mensual
    • Cancelar en cualquier momento
    • Los certificados de terminación

      ACCESO ahora

      Indice

      archivos de código fuente

      Puede descargar los archivos de código fuente tutorial aquí.

      ¿Qué se pathfinding?

      Antes de escribir nuestra Pathfinder, voy a explicar por medio de un ejemplo, ¿cuál es nuestro objetivo, y cómo se puede lograr.

      La siguiente figura muestra un personaje en un mapa azulejo con obstáculos. Supongamos que queremos este personaje para moverse a la posición resaltada. Algunos caminos posibles están resaltadas en el mapa, pero que quieren encontrar la más corta. ¿Cómo podemos hacer eso?

      ejemplo

      Una forma común de resolver este problema es comenzar desde la posición original y para ampliar el rango de búsqueda mediante la comprobación de los azulejos vecinos, evitando los obstáculos, como se muestra en el siguiente ejemplo.

      Sin embargo, hay que elegir una forma eficaz de ampliar el rango de búsqueda para reducir el tiempo que tenemos para gastar en busca de un camino. Simplemente ampliando a todas las direcciones que podemos garantizar un camino más corto, pero en un momento de alta ejecución, ya que estamos ampliando a direcciones que no conduciría a la posición de destino. En esta ocasión alta ejecución no sería notado por un solo camino, pero en un juego donde hay que calcular trayectorias constantemente para varias unidades, este tiempo de ejecución puede convertirse fácilmente en prohibitivamente largo.

      La A * (pronunciado como “una estrella”) algoritmo es una forma eficaz de resolver el problema de búsqueda de caminos. El algoritmo sigue la idea de ampliar el rango de búsqueda, pero utiliza una heurística para guiar eficazmente la búsqueda hacia la posición de destino. La idea es calcular el coste de una baldosa por su distancia a la posición original más una estimación de su distancia a la posición de destino. Entonces, teniendo en cuenta el mosaico de menor costo cuando se expande el rango de búsqueda, podemos guiar de manera eficiente el algoritmo. Este video compara el algoritmo A * con otros algoritmos que no fueron diseñados a obstáculos de manejar, y se puede ver claramente su eficacia.

      La biblioteca EasyStar

      En lugar de escribir nuestro propio código de A *, vamos a utilizar una biblioteca de búsqueda de caminos llamado EasyStar. Esta es una biblioteca de código abierto creado por Bryce Neal y disponible a través de la licencia MIT, lo que permite un uso comercial. También proporciona un repositorio GitHub donde se puede comprobar el código fuente y su uso. En este tutorial, voy a cubrir los métodos básicos que necesitaremos para nuestra búsqueda de caminos de demostración.

      Creación de un mapa de la baldosa

      La siguiente figura muestra el mapa de baldosa que creó para esta demostración. Siéntase libre para crear su propia cuenta o con la mía uso, siempre en el código fuente. Si no está familiarizado con la baldosa, se puede comprobar nuestra serie de tutoriales sobre cómo crear un juego de plataformas utilizando baldosa, que cubren en detalle cómo usarlo. Sólo hay dos cosas que hay que tener cuidado, porque van a ser importantes en nuestro código más tarde. En primer lugar, todos los obstáculos deben estar en una capa llamada colisiones, que debe tener una propiedad de colisión define como verdadera, como se muestra a continuación.

      mapa

      collision_layer object_properties

      Además, en la capa de objetos no debe ser un objeto jugador con sus propiedades definidas a continuación. Este será el personaje en nuestra demo.

      Después de crear el mapa, guardarlo en el formato JSON.

      Phaser estados de nuestra demo

      Los activos, grupos y mapa de nuestra demo se describirán en un archivo JSON, como a continuación. Entonces, nuestro juego tendrá los siguientes estados, responsable de cargar este archivo:


      • BootState:. Carga el archivo JSON antes de llamar LoadingState

      • LoadingState: cargas de todos los activos de juego, incluyendo el archivo de mapa JSON. Después de todos los activos se cargan, se llama WorldState.
      • WorldState:. Crear las capas de mapas, grupos de juego y casas prefabricadas

        El código para BootState y LoadingState se muestran abajo. Tenga en cuenta que la LoadingState utiliza la clave de activos desde el archivo JSON para cargar el activo correcta.
        var PathfindingExample = PathfindingExample || {}; PathfindingExample.BootState = function () { «utilizar estricta»; Phaser.State.call (this);}; PathfindingExample.BootState.prototype = Object.create (Phaser.State.prototype); PathfindingExample.BootState.prototype.constructor = PathfindingExample.BootState; PathfindingExample.BootState.prototype.init = function ( level_file, next_state) { «utilizar estricta»; this.level_file = level_file; this.next_state = next_state;}; PathfindingExample.BootState.prototype.preload = function () { «utilizar estricta»; this.load.text ( «level1», this.level_file);}; PathfindingExample.BootState.prototype.create = function () { «utilizar estricta»; level_text var, level_data; level_text = this.game.cache.getText ( «level1»); level_data = JSON.parse (level_text); this.game.state.start ( «LoadingState», verdadero, falso, level_data, this.next_state);}; 12345678910111213141516171819202122232425262728varPathfindingExample = PathfindingExample || {}; PathfindingExample.BootState = function () { «uso estricto»; Phaser.State. llamar (this);}; PathfindingExample.BootState.prototype = Object.create (Phaser.State.prototype); PathfindingExample.BootState.prototype.constructor = PathfindingExample.BootState; PathfindingExample.BootState.prototype.init = function (level_file, next_state) { «utilizar estricta»; this.level_file = level_file; this.next_state = next_state;}; PathfindingExample.BootState.prototype.preload = function () { «utilizar estricta»; this.load.text ( «level1», this.level_file );}; PathfindingExample.BootState.prototype.create = function () { «utilizar estricta»; varlevel_text, level_data; level_text = this.game.cache.getText ( «level1»); level_data = JSON.parse (level_text); esta .game.state.start ( «LoadingState», verdadero, falso, level_data, this.next_state);}; var PathfindingExample = PathfindingExample || {}; PathfindingExample.LoadingState = function () { «utilizar estricta»; Phaser.State.call (this);}; PathfindingExample.LoadingState.prototype = Object.create (Phaser.State.prototype); PathfindingExample.LoadingState.prototype.constructor = PathfindingExample.LoadingState; PathfindingExample.LoadingState.prototype.init = function ( level_data, next_state) { «utilizar estricta»; this.level_data = level_data; this.next_state = next_state;}; PathfindingExample.LoadingState.prototype.preload = function () { «utilizar estricta»; var activos, asset_loader, asset_key, activo; = activos this.level_data.assets; para (asset_key en activos) {// activos de carga de acuerdo con la clave activo si (assets.hasOwnProperty (asset_key)) {activos = activos [asset_key]; interruptor (asset.type) {case «imagen»: this.load.image (asset_key, asset.source); descanso; caso «spritesheet»: this.load.spritesheet (asset_key, asset.source, asset.frame_width, asset.frame_height, asset.frames, asset.margin, asset.spacing); descanso; caso «tilemap»: this.load.tilemap (asset_key, asset.source, null, Phaser.Tilemap.TILED_JSON); descanso; }}}}; PathfindingExample.LoadingState.prototype.create = function () { «utilizar estricta»; this.game.state.start (this.next_state, verdadero, falso, this.level_data);}; 123456789101112131415161718192021222324252627282930313233343536373839404142varPathfindingExample = PathfindingExample || {}; PathfindingExample.LoadingState = function () { «utilizar estricta»; Phaser.State.call ( este);}; PathfindingExample.LoadingState.prototype = Object.create (Phaser.State.prototype); PathfindingExample.LoadingState.prototype.constructor = PathfindingExample.LoadingState; PathfindingExample.LoadingState.prototype.init = function (level_data, next_state) {» uso estricto «; this.level_data = level_data; this.next_state = next_state;}; PathfindingExample.LoadingState.prototype.preload = function () {» utilizar estricta «; varassets, asset_loader, asset_key, activo; activos = this.level_data.assets ; para (inassets asset_key) {// activos de carga de acuerdo con keyif activo (assets.hasOwnProperty (asset_key)) {activos = activos [asset_key]; conmutador (asset.type) {case «imagen»: this.load.image (asset_key , asset.source); break; caso «spritesheet»: this.load.spritesheet (asset_key, asset.source, asset.fr ame_width, asset.frame_height, asset.frames, asset.margin, asset.spacing); break; caso «tilemap»: this.load.tilemap (asset_key, asset.source, null, Phaser.Tilemap.TILED_JSON); break;} }}}; PathfindingExample.LoadingState.prototype.create = function () { «utilizar estricta»; this.game.state.start (this.next_state, verdadero, falso, this.level_data);};

        El código WorldState es un poco más complejo, y se muestra a continuación. En el método “init” que iniatilizes el motor de física y el mapa. Luego, en el método de “crear” que crea todas las capas del mapa, grupos de juego y casas prefabricadas. Aviso cuando una capa de mapa tiene la propiedad de colisión definido como verdadero, como se mencionó antes, se define como Collidable.
        var PathfindingExample = PathfindingExample || {}; PathfindingExample.WorldState = function () { «utilizar estricta»; Phaser.State.call (this); this.prefab_classes = { «jugador»: PathfindingExample.Player.prototype.constructor};}; PathfindingExample.WorldState.prototype = Object.create (Phaser.State.prototype); PathfindingExample.WorldState.prototype.constructor = PathfindingExample.WorldState; PathfindingExample .WorldState.prototype.init = function (level_data) { «utilizar estricta»; tileset_index var, tile_dimensions; this.level_data = this.level_data || level_data; this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL; this.scale.pageAlignHorizontally = true; this.scale.pageAlignVertically = true; sistema de física this.game.physics.startSystem (Phaser.Physics.ARCADE) // empezar; this.game.physics.arcade.gravity.y = 0; // crear el mapa y establecer conjunto de baldosas this.map = this.game.add.tilemap (this.level_data.map.key); tileset_index = 0; this.map.tilesets.forEach (función (conjunto de baldosas) {this.map.addTilesetImage (tileset.name, this.level_data.map.tilesets [tileset_index]); tileset_index + = 1;}, this);}; PathfindingExample.WorldState .prototype.create = function () { «utilizar estricta»; GROUP_NAME var, object_layer, collision_tiles; // crear capas de mapa this.layers = {}; this.map.layers.forEach (función (capa) {this.layers [layer.name] = this.map.createLayer (layer.name), si (layer.properties.collision) {// collision_tiles capa colisión = [] ; layer.data.forEach (function (data_row) {// encontrar azulejos usados ​​en la capa de data_row.forEach (function (teja) {// Comprobar si se trata de un índice de baldosas válido y no está ya en la lista si (teja. índice> 0 && collision_tiles.indexOf (tile.index) === -1) {collision_tiles.push (tile.index);}}, esto);}, this); this.map.setCollision (collision_tiles, es cierto, capa .name);}}, this); // cambiar el tamaño del mundo para ser el tamaño de las this.layers capa actuales [this.map.layer.name] .resizeWorld (); // crear grupos this.groups = {}; this.level_data.groups.forEach (function (GROUP_NAME) {this.groups [GROUP_NAME] = this.game.add.group ();}, this); this.prefabs = {}; para (object_layer en this.map.objects) {if (this.map.objects.hasOwnProperty (object_layer)) {// crear capa de objetos this.map.objects [object_layer] .forEach (this.create_object, este); }}}; PathfindingExample.WorldState.prototype.create_object = función (objeto) { «utilizar estricta»; var object_y, la posición, prefabricada; // azulejos coordenadas se inicia en la esquina inferior izquierda object_y = (object.gid)? object.y – (this.map.tileHeight / 2): object.y + (object.height / 2); posición = { «x»: object.x + (this.map.tileHeight / 2), «y»: object_y}; // crear el objeto de acuerdo con su tipo si (this.prefab_classes.hasOwnProperty (object.type)) {= prefabricadas nuevas this.prefab_classes [object.type] (esto, object.name, la posición, object.properties); } this.prefabs [object.name] = prefabricada;}; 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788varPathfindingExample = PathfindingExample || {}; PathfindingExample.WorldState = function () { «utilizar estricta»; Phaser.State.call (this); this.prefab_classes = {» jugador «: PathfindingExample.Player.prototype.constructor};}; PathfindingExample.WorldState.prototype = Object.create (Phaser.State.prototype); PathfindingExample.WorldState.prototype.constructor = PathfindingExample.WorldState; PathfindingExample.WorldState.prototype.init = function (level_data) { «utilizar estricta»; vartileset_index, tile_dimensions; this.level_data = this.level_data || level_data; this.scale.scaleMode = Phaser.ScaleManager.SHOW_ALL; this.scale.pageAlignHorizontally = true; this.scale. pageAlignVertically = true; // iniciar la física systemthis.game.physics.startSystem (Phaser.Physics.ARCADE); this.game.physics.arcade.gravity.y = 0; // crear y conjunto del tilesetthis.map = This.game.add.tilemap (this.level_data.map.key); tileset_index = 0; this.map.tilesets.forEach (función (conjunto de baldosas) {this.map.addTilesetImage (tileset.name, this.level_data.map .tilesets [tileset_index]); tileset_index + = 1;}, this);}; PathfindingExample.WorldState.prototype.create = function () { «utilizar estricta»; vargroup_name, object_layer, collision_tiles; // crear layersthis.layers mapa = { }; this.map.layers.forEach (función (capa) {this.layers [layer.name] = this.map.createLayer (layer.name), si (layer.properties.collision) {// layercollision_tiles colisión = [ ]; layer.data.forEach (function (data_row) {// encontrar azulejos utilizados en la layerdata_row.forEach (function (teja) {// Comprobar si se trata de un índice de baldosas válido y no está ya en la listif (tile.index > 0 && collision_tiles.indexOf (tile.index) === -1) {collision_tiles.push (tile.index);}}, esto);}, this); this.map.setCollision (collision_tiles, es cierto, layer.name );}}, this); // cambiar el tamaño del mundo para ser el tamaño de los actuales layerthis.layers [this.map.layer.name] .resizeWorld (); // crear groupsthis.g rupos = {}; this.level_data.groups.forEach (function (GROUP_NAME) {this.groups [GROUP_NAME] = this.game.add.group ();}, this); this.prefabs = {}; for (object_layer inthis.map.objects) {if (this.map.objects.hasOwnProperty (object_layer)) {// crear objectsthis.map.objects capa [object_layer] .forEach (this.create_object, este);}}}; PathfindingExample.WorldState .prototype.create_object = función (objeto) { «utilizar estricta»; varobject_y, la posición, prefabricada; // coordenadas azulejos comienza en el cornerobject_y inferior izquierda = (object.gid) object.y- (this.map.tileHeight / 2? ): object.y + (object.height / 2); posición = { «x»: object.x + (this.map.tileHeight / 2), «y»: object_y}; // crear objeto de acuerdo con su typeif (esto .prefab_classes.hasOwnProperty (object.type)) {prefabricada = newthis.prefab_classes [object.type] (esto, object.name, posición, object.properties);} this.prefabs [object.name] = prefabricada;}; < p> El método “create_object” se utiliza para crear todas las casas prefabricadas de juego. Se identifica la clase prefabricada mediante la asignación del tipo prefabricado (definida en el mapa de baldosa) a su constructor. Esto se hace mediante la propiedad “prefab_classes”, definido en el constructor WorldState. Las propiedades prefabricados se obtienen de las propiedades definidas en el mapa de baldosa. Tenga en cuenta que esto es posible porque todas las casas prefabricadas tienen el mismo constructor, que se muestra en el siguiente código.
        var PathfindingExample = PathfindingExample || {}; PathfindingExample.Prefab = function (game_state, nombre, posición, propiedades) { «utilizar estricta»; Phaser.Sprite.call (esto, game_state.game, position.x, position.y, properties.texture); this.game_state = game_state; this.name = Nombre; this.game_state.groups [properties.group] .add (this); this.frame = + properties.frame; si (properties.scale) {this.scale.setTo (properties.scale.x, properties.scale.y); } This.game_state.prefabs [nombre] = esta;}; PathfindingExample.Prefab.prototype = Object.create (Phaser.Sprite.prototype); PathfindingExample.Prefab.prototype.constructor = PathfindingExample.Prefab; 12345678910111213141516171819202122varPathfindingExample = PathfindingExample || {} ; PathfindingExample.Prefab = function (game_state, nombre, posición, propiedades) { «utilizar estricta»; Phaser.Sprite.call (esto, game_state.game, position.x, position.y, properties.texture); this.game_state = game_state; This.Name = nombre; this.game_state.groups [properties.group] .add (this); this.frame = + properties.frame; si (properties.scale) {this.scale.setTo (properties.scale. x, properties.scale.y);} this.game_state.prefabs [nombre] = esta;}; PathfindingExample.Prefab.prototype = Object.create (Phaser.Sprite.prototype); PathfindingExample.Prefab.prototype.constructor = PathfindingExample. prefabricada;

        Creación de un plugin de Pathfinding

        En Phaser puede crear plugins que pueden ser fácilmente conectados en sus juegos, de manera que pueda volver a utilizarlos. En este tutorial, vamos a escribir el código de búsqueda de caminos en un plugin, por lo que más adelante se puede utilizar en sus propios juegos. Para obtener más información acerca de los módulos, se puede comprobar la documentación Phaser.

        El Pathfinding plugin de código se muestra a continuación. En el método “init” inicializar la red EasyStar, que será utilizado durante A *. EasyStar requiere dos cosas: una rejilla mundo, representando cada baldosa con un identificador y un conjunto de baldosas aceptables, en representación de los azulejos que no son obstáculos. Tenga en cuenta que estamos utilizando el índice de mosaico del mapa de Phaser para crear la red mundial, que se obtiene a partir del mapa de baldosa JSON.
        var PathfindingExample = PathfindingExample || {}; PathfindingExample.Pathfinding = function (juego, los padres) { «use strict»; Phaser.Plugin.call (esto, juego, los padres); this.easy_star = new EasyStar.js ();}; PathfindingExample.Pathfinding.prototype = Object.create (Phaser.Plugin.prototype); PathfindingExample.Pathfinding.prototype.constructor = PathfindingExample.Pathfinding; PathfindingExample.Pathfinding.prototype.init = función (world_grid, acceptable_tiles, tile_dimensions) { «utilizar estricta»; var grid_row, grid_column, grid_indices; this.grid_dimensions = {consecutivas: world_grid.length, columna: world_grid [0] .length}; grid_indices = []; para (grid_row = 0; grid_row this.grid_dimensions.row – 1 || coord.column <0 || coord.column> this.grid_dimensions.column – 1;}; PathfindingExample.Pathfinding.prototype.get_coord_from_point = function (punto) { «utilizar estricta»; fila var, columna; fila = Math.floor (Punto.y / this.tile_dimensions.y); Columna = Math.floor (punto.x / this.tile_dimensions.x); retorno {fila: fila, columna: columna};}; PathfindingExample.Pathfinding.prototype.get_point_from_coord = función (coord) { «utilizar estricta»; var x, y; x = (coord.column * this.tile_dimensions.x) + (this.tile_dimensions.x / 2); y = (coord.row * this.tile_dimensions.y) + (this.tile_dimensions.y / 2); volver nueva Phaser.Point (x, y);}; 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778varPathfindingExample = PathfindingExample || {}; PathfindingExample.Pathfinding = function (juego, los padres) { «use strict»; Phaser.Plugin.call (esto, juego, los padres); this.easy_star = newEasyStar.js ();}; PathfindingExample.Pathfinding.prototype = Object.create (Phaser.Plugin.prototype); PathfindingExample.Pathfinding.prototype.constructor = PathfindingExample.Pathfinding; PathfindingExample.Pathfinding.prototype.init = function (world_grid, acceptable_tiles, tile_dimensions) { «uso estricto»; vargrid_row, grid_column, grid_indices; this.grid_dimensions = {consecutivas: world_grid.length, columna: world_grid [0] .length}; grid_indices = []; for (grid_row = 0 ; grid_row this.grid_dimensions.row-1 || coord.column <0 || coord.column> this.grid_dimensions .Column-1;}; PathfindingExample.Pathfinding.prototype.get_coord_from_point = function (punto) { «utilizar estricta»; varrow, columna; fila = Math.floor (Punto.y / this.tile_dimensions.y); columna = Math. piso (punto.x / this.tile_dimensions.x); retorno {fila: fila, columna: columna};}; PathfindingExample.Pathfinding.prototype.get_point_from_coord = función (coord) { «utilizar estricta»; varX, y; x = (coord.column * this.tile_dimensions.x) + (this.tile_dimensions.x / 2); = y (coord.row * this.tile_dimensions.y) + (this.tile_dimensions.y / 2); returnnewPhaser.Point ( x, y);};

        El método “find_path” es responsable de ejecutar EasyStar para encontrar un camino de “origen” a “objetivo”. Esto se hace llamando EasyStar y métodos “FindPath” “calcular”. Cuando se encuentra la ruta de acceso, se ejecuta el método “call_callback_function”, lo que creará una matriz con todos los puntos en la ruta de acceso y llamar a la función de devolución de llamada apropiado en el contexto correcto.

        Los métodos restantes son útiles para que sea más fácil de usar el plugin. Por ejemplo, los métodos y “get_point_from_coord” “get_coord_from_point” convierten una coord cuadrícula a un punto de coordenadas en el mundo, y viceversa.

        Ahora, tenemos que añadir nuestro plugin en WorldState. Esto se puede hacer en WorldState método “init”, como se muestra a continuación. Tenga en cuenta que pasamos los datos de capa de mapa de colisiones como la red mundial, y los azulejos sólo es aceptable es -1. Este valor se utiliza por Phaser para representar posiciones sin azulejos. En la práctica, esto significa que cualquier posición sin un obstáculo es aceptable.
        // initialize pathfinding tile_dimensions = nuevo Phaser.Point (this.map.tileWidth, this.map.tileHeight); this.pathfinding = this.game.plugins.add (PathfindingExample.Pathfinding, this.map.layers [1] .data, [-1], tile_dimensions); 123 // initialize pathfindingtile_dimensions = newPhaser.Point (this.map.tileWidth , this.map.tileHeight); this.pathfinding = this.game.plugins.add (PathfindingExample.Pathfinding, this.map.layers [1] .data, [- 1], tile_dimensions);

        El jugador prefabricada < / h2>

        Ahora que tenemos nuestro plugin Pathfinding, vamos a crear nuestro prefabricada Player, que se trasladará a un lugar de destino con este plugin.

        El código prefabricada jugador se muestra a continuación. En el constructor, inicializamos el cuerpo físico. Dado que el jugador de sprites es más grande que el tilesed utilizamos (como se habrán dado cuenta al construir el mapa de baldosa), vamos a reducir el tamaño de la misma del cuerpo físico con el método “setSize” del cuerpo. Además, vamos a cambiar su punto de anclaje para el centro de su cuerpo físico, para manejar adecuadamente los movimientos y colisiones.
        var PathfindingExample = PathfindingExample || {}; PathfindingExample.Player = function (game_state, nombre, posición, propiedades) { «utilizar estricta»; PathfindingExample.Prefab.call (esto, game_state, nombre, posición, propiedades); //this.anchor.setTo(0.5); //this.scale.setTo(0.666, 0,5); this.walking_speed = + properties.walking_speed; this.game_state.game.physics.arcade.enable (this); // cambiar el tamaño y la posición de la this.body.setSize caja de colisión (12, 12, 0, 4); this.body.collideWorldBounds = true; // set punto de anclaje para ser el centro de la this.anchor.setTo caja de colisión (0.5, 0.75); this.path = []; this.path_step = -1;}; PathfindingExample.Player.prototype = Object.create (PathfindingExample.Prefab.prototype); PathfindingExample.Player.prototype.constructor = PathfindingExample.Player; PathfindingExample.Player.prototype.update = function () { «utilizar estricta»; next_position var, la velocidad; this.game_state.game.physics.arcade.collide (esto, this.game_state.layers.collision); si (this.path.length> 0) {next_position = this.path [this.path_step]; (! This.reached_target_position (next_position)) {si la velocidad = new Phaser.Point (next_position.x – this.position.x, next_position.y – this.position.y); velocity.normalize (); this.body.velocity.x = velocity.x * this.walking_speed; this.body.velocity.y = velocity.y * this.walking_speed; } Else {this.position.x = next_position.x; this.position.y = next_position.y; si (this.path_step 0) {next_position = this.path [this.path_step]; if (! this.reached_target_position ( next_position)) {velocidad = newPhaser.Point (next_position.x-this.position.x, next_position.y-this.position.y); velocity.normalize (); this.body.velocity.x = velocity.x * este .walking_speed; this.body.velocity.y = velocity.y * this.walking_speed;} else {this.position.x = next_position.x; this.position.y = next_position.y; si (this.path_step el método “move_to” recibirá una posición de destino y llame a nuestro plugin Pathfinding para encontrar el camino desde la posición actual hasta el destino. Cuando se encuentra el camino, el método “move_through_path” se llama, lo que permitirá ahorrar el camino encontrado y restablecer la variable “path_step”. El movimiento real se hace en el método de “actualización”. Se mueve al jugador hacia la posición indicada por la variable “path_step”. Si el jugador ha alcanzado esa posición, incrementa “path_step” hasta que se complete todo el camino. Para comprobar si el jugador ha alcanzado una posición determinada, debemos tener en cuenta un margen de error como se hace en el método “reached_target_position”, ya que el jugador no será exactamente en la posición deseada, pero cerca de ella.

        Por último, hay que añadir en WorldState el código para mover al jugador. Hacemos esto mediante la adición de un evento de entrada en el método de “crear”, como se muestra a continuación. Este evento de entrada llamará al método “move_player” (también se muestra a continuación), que se moverá el jugador a la posición seleccionada por el ratón. Hay una última modificación que hice en el WorldState, que está mostrando el cuerpo físico del jugador en el método “render”. Este método es llamado automáticamente por Phaser después de actualizar todos los objetos, y lo usará para mostrar el cuerpo del jugador. Esto es útil para comprobar si el movimiento y las colisiones están funcionando correctamente.
        // Añadir entrada del usuario para mover jugador this.game.input.onDown.add (this.move_player, este); 12 // entrada del usuario Agregar para mover playerthis.game.input.onDown.add (this.move_player, este); PathfindingExample.WorldState.prototype.move_player = function () { «utilizar estricta»; target_position var; target_position = nuevo Phaser.Point (this.game.input.activePointer.x, this.game.input.activePointer.y); this.prefabs.player.move_to (target_position);}; 1234567PathfindingExample.WorldState.prototype.move_player = function () { «utilizar estricta»; vartarget_position; target_position = newPhaser.Point (this.game.input.activePointer.x, esto. game.input.activePointer.y); this.prefabs.player.move_to (target_position);};

        demo

        Y ahora, nuestra búsqueda de caminos de demostración está completa. Trate de mover al jugador a diferentes posiciones y comprobar si está evitando obstáculos correctamente.

        Mensajes relacionados
        > <img src =

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *