Advertisement
MkNish

[RMMV Plugin] Pathfinding

Dec 14th, 2015
526
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //=============================================================================
  2. // μ'ki's Pathfinding v1.00
  3. // MK_Pathfinding.js
  4. //=============================================================================
  5.  
  6. var Imported = Imported || {};
  7. Imported.MK_Pathfinding = true;
  8. var Maki = Maki || {};
  9. Maki.PF = Maki.PF || {};
  10.  
  11. //=============================================================================
  12. /*:
  13.  * @plugindesc v1.00 Pathfinding Extras
  14.  * @author μ'ki
  15.  *
  16.  * @param Pathfinding Limit
  17.  * @desc Pathfinding search depth limit (0 = unlimited).
  18.  * @default 12
  19.  *
  20.  * @param Pathfinding Algorithm
  21.  * @desc Pathfinding algorithm (0: A*, 1: Jump-point Search, 2: Dijkstra, 3: Greedy Best-first Search).
  22.  * @default 1
  23.  *
  24.  * @param 8-directional Mode
  25.  * @desc 8-directional mode for the pathfinding algorithm (true/false).
  26.  * @default false
  27.  *
  28.  * @param Remember Path
  29.  * @desc Keeps the found path until reaching the destination, can be obstructed by moving characters (true/false).
  30.  * @default false
  31.  *
  32.  * @param Path Trace
  33.  * @desc Display visualization of the path and explored tiles (true/false). Warning, at cost of the performance!
  34.  * @default false
  35.  *
  36.  * @help
  37.  * ============================================================================
  38.  * Introduction
  39.  * ============================================================================
  40.  * Unlike in RPG Maker VX Ace and former, RPG Maker MV's default game system
  41.  * allows the player to click on a game map tile as destination. The player
  42.  * character will find a shortest path to it using A* pathfinding algorithm, as
  43.  * implemented in method Game_Character.findDirectionTo.
  44.  *
  45.  * In this plugin, such that method is overriden and extended to allow you to
  46.  * select one of pathfinding algorithms: A*, Jump-point Search, Dijkstra and
  47.  * Greedy Best-first Search. Additionally, you can also enable the characters
  48.  * to move diagonally by setting the parameter '8-directional Mode'.
  49.  *
  50.  * Contact me for support/bug report:
  51.  * listra92[at]gmail.com
  52.  *
  53.  * ============================================================================
  54.  * Features and Usages
  55.  * ============================================================================
  56.  *  - Option to select other pathfinding algorithms to experiment: Jump-point
  57.  *    Search, Dijkstra and Greedy Best-first Search.
  58.  *  - Option whether to keep the found path until the character reach the
  59.  *    destination; thus the pathfinding algorithm is only executed once when
  60.  *    being ordered to move to the destination. However, the path can be
  61.  *    obstructed by some moving objects (other characters), as the character
  62.  *    won't move avoiding them.
  63.  *  - Option whether to draw diagnostic traces as magenta and blue squares
  64.  *    that represent path and explored tiles.
  65.  *
  66.  * ============================================================================
  67.  * Notes
  68.  * ============================================================================
  69.  *  - If you have MK_AdvancedMove plugin installed, put this plugin under it.
  70.  *  - Jump-point search is the fastest algorithm since it searches fewer tiles
  71.  *    than A* does, but still produces shortest path.
  72.  *  - Greedy best-first search often performs badly; it tends to produce much
  73.  *    longer path. Also unless the 'Remember Path' option is enabled, the
  74.  *    character's movement can somewhat get stalled.
  75.  *
  76.  * ============================================================================
  77.  * Coming in the Next Version
  78.  * ============================================================================
  79.  *  - Some optimizations, probably.
  80.  *
  81.  * ============================================================================
  82.  * Known issues
  83.  * ============================================================================
  84.  *  - The current implemented jump-point search somewhat fails on dealing with
  85.  *    some certain tiles, like in sample map 'School Hall'.
  86.  *
  87.  */
  88. //=============================================================================
  89.  
  90. //=============================================================================
  91. // Parameter Variables
  92. //=============================================================================
  93.  
  94. Maki.PF.Parameters = PluginManager.parameters('MK_Pathfinding');
  95.  
  96. Maki.PF.DepthLimit = Number(Maki.PF.Parameters['Pathfinding Limit']);
  97. Maki.PF.Algo = Number(Maki.PF.Parameters['Pathfinding Algorithm']);
  98. Maki.PF.Dir8 = !!eval(String(Maki.PF.Parameters['8-directional Mode']));
  99. Maki.PF.PathTrace = !!eval(String(Maki.PF.Parameters['Path Trace']));
  100. Maki.PF.MemPath = !!eval(String(Maki.PF.Parameters['Remember Path']));
  101. Maki.PF.SQRT2 = Math.sqrt(2);
  102.  
  103. Game_Map.prototype.distance = function(x1, y1, x2, y2) {
  104.     var deltaX = Math.abs(this.deltaX(x1, x2));
  105.     var deltaY = Math.abs(this.deltaY(y1, y2));
  106.     if (Maki.PF.Dir8) {
  107.         return Math.min(deltaX, deltaY) * Maki.PF.SQRT2 + Math.abs(deltaX - deltaY);
  108.     } else {
  109.         return deltaX + deltaY;
  110.     }
  111. };
  112.  
  113. Maki.PF.GameCharacterBaseInitMembers = Game_CharacterBase.prototype.initMembers;
  114. Game_CharacterBase.prototype.initMembers = function() {
  115.     Maki.PF.GameCharacterBaseInitMembers.call(this);
  116.     this._path = [];
  117.     this._explored = [];
  118.     this._pathl = 0;
  119.     this._exploredl = 0;
  120. };
  121.  
  122. //-----------------------------------------------------------------------------
  123. // Sprite_Trace
  124. //-----------------------------------------------------------------------------
  125.  
  126. function Sprite_Trace() {
  127.     this.initialize.apply(this, arguments);
  128. }
  129.  
  130. Sprite_Trace.prototype = Object.create(Sprite.prototype);
  131. Sprite_Trace.prototype.constructor = Sprite_Trace;
  132.  
  133. Sprite_Trace.prototype.initialize = function() {
  134.     Sprite.prototype.initialize.call(this);
  135.     this.createBitmap();
  136.     this._frameCount = 0;
  137.     this.ispath = 0;
  138. };
  139.  
  140. Sprite_Trace.prototype.update = function() {
  141.     if ($gameTemp.isDestinationValid() && this.idx < $gamePlayer._exploredl +
  142.         ($gamePlayer._pathl - $gamePlayer._exploredl) * this.ispath){
  143.         this.updatePosition();
  144.         this.updateAnimation();
  145.         this.visible = true;
  146.     } else {
  147.         this._frameCount = 0;
  148.         this.visible = false;
  149.     }
  150. };
  151.  
  152. Sprite_Trace.prototype.createBitmap = function() {
  153.     var tileWidth = $gameMap.tileWidth();
  154.     var tileHeight = $gameMap.tileHeight();
  155.     this.bitmap = new Bitmap(tileWidth, tileHeight);
  156.     this.anchor.x = 0.5;
  157.     this.anchor.y = 0.5;
  158.     this.blendMode = Graphics.BLEND_ADD;
  159. };
  160.  
  161. Sprite_Trace.prototype.updatePosition = function() {
  162.     if ($gameTemp.isDestinationValid() && this.idx < $gamePlayer._exploredl +
  163.         ($gamePlayer._pathl - $gamePlayer._exploredl) * this.ispath){
  164.     var tileWidth = $gameMap.tileWidth();
  165.     var tileHeight = $gameMap.tileHeight();
  166.     if (this.ispath) {
  167.         var x = $gamePlayer._path[this.idx] % $gameMap.width();
  168.         var y = Math.floor($gamePlayer._path[this.idx] / $gameMap.width());
  169.     } else {
  170.         var x = $gamePlayer._explored[this.idx] % $gameMap.width();
  171.         var y = Math.floor($gamePlayer._explored[this.idx] / $gameMap.width());
  172.     }
  173.     this.x = ($gameMap.adjustX(x) + 0.5) * tileWidth;
  174.     this.y = ($gameMap.adjustY(y) + 0.5) * tileHeight;
  175.     }
  176. };
  177.  
  178. Sprite_Trace.prototype.updateAnimation = function() {
  179.     /*this._frameCount++;
  180.     this._frameCount %= 20;
  181.     this.opacity = 120 + (20 - this._frameCount) * 6;
  182.     this.scale.x = 1 + this._frameCount / 20;
  183.     this.scale.y = this.scale.x;*/
  184. };
  185.  
  186. Maki.PF.SpritesetMapCreateDestination = Spriteset_Map.prototype.createDestination;
  187. Spriteset_Map.prototype.createDestination = function() {
  188.     Maki.PF.SpritesetMapCreateDestination.call(this);
  189.     if (Maki.PF.PathTrace){
  190.     this._traceSprite = [];
  191.     this._traceSprite2 = [];
  192.     for (var i = 0; i < 256; i++) {
  193.         this._traceSprite.push(new Sprite_Trace());
  194.         this._traceSprite[i].idx = i;
  195.         this._traceSprite[i].ispath = 1;
  196.         this._traceSprite[i].z = 9;
  197.         this._traceSprite[i].bitmap.fillRect(0, 0,
  198.             $gameMap.tileWidth(), $gameMap.tileHeight(), 'red');
  199.         this._tilemap.addChild(this._traceSprite[i]);
  200.     }
  201.     for (var i = 0; i < 512; i++) {
  202.         this._traceSprite2.push(new Sprite_Trace());
  203.         this._traceSprite2[i].idx = i;
  204.         this._traceSprite2[i].ispath = 0;
  205.         this._traceSprite2[i].z = 9;
  206.         this._traceSprite2[i].bitmap.fillRect(0, 0,
  207.             $gameMap.tileWidth(), $gameMap.tileHeight(), 'blue');
  208.         this._tilemap.addChild(this._traceSprite2[i]);
  209.     }
  210.     }
  211. };
  212.  
  213. if (!Imported.MK_AdvancedMove) {
  214.     Game_Player.prototype.executeMove = function(direction) {
  215.         if (direction % 2 > 0) {
  216.             this.moveDiagonally((direction % 6)+3, Math.floor(direction/6)*6+2);
  217.         } else {
  218.             this.moveStraight(direction);
  219.         }
  220.     };
  221. }
  222.  
  223. if (Maki.PF.MemPath) {
  224. Game_Player.prototype.moveByInput = function() {
  225.     if (!this.isMoving() && this.canMove()) {
  226.         var direction = this.getInputDirection();
  227.         if (direction > 0) {
  228.             $gameTemp.clearDestination();
  229.             this._path = [];
  230.             this._explored = [];
  231.             this._pathl = 0;
  232.             this._exploredl = 0;
  233.         } else if ($gameTemp.isDestinationValid()){
  234.             if (!this._pathl && $gameTemp.isDestinationValid()){
  235.                 var x = $gameTemp.destinationX();
  236.                 var y = $gameTemp.destinationY();
  237.                 direction = this.findDirectionTo(x, y);
  238.             }
  239.             var deltaX1 = $gameMap.deltaX(
  240.             this._path[this._pathl-1] % $gameMap.width(), this.x);
  241.             var deltaY1 = $gameMap.deltaY(
  242.             Math.floor(this._path[this._pathl-1]/$gameMap.width()), this.y);
  243.             if (1 >= Math.abs(deltaX1) && 1 >= Math.abs(deltaY1)) this._pathl--;
  244.             if (this._pathl + 1) {
  245.                 if (deltaX1 !== 0) deltaX1 /= Math.abs(deltaX1);
  246.                 if (deltaY1 !== 0) deltaY1 /= Math.abs(deltaY1);
  247.                 direction = 5 - deltaY1 * 3 + deltaX1;
  248.             }
  249.         }
  250.         if (direction > 0) {
  251.             this.executeMove(direction);
  252.         }
  253.     }
  254. };
  255. }
  256.  
  257. //=============================================================================
  258. // Game_Character
  259. //=============================================================================
  260.  
  261. Game_Character.prototype.searchLimit = function() {
  262.     return Maki.PF.DepthLimit;
  263. };
  264.  
  265. Game_Character.prototype.findDirectionTo = function(goalX, goalY) {
  266.     if (Maki.PF.Algo === 0) {
  267.         return Maki.PF.Pathfinding_AStar(this, goalX, goalY);
  268.     } else if (Maki.PF.Algo === 1) {
  269.         return Maki.PF.Pathfinding_JPS(this, goalX, goalY);
  270.     } else if (Maki.PF.Algo === 2) {
  271.         return Maki.PF.Pathfinding_Dijkstra(this, goalX, goalY);
  272.     } else if (Maki.PF.Algo === 3) {
  273.         return Maki.PF.Pathfinding_GBFS(this, goalX, goalY);
  274.     }
  275. };
  276.  
  277. Maki.PF.Pathfinding_AStar = function(character, goalX, goalY) {
  278.     var searchLimit = character.searchLimit();
  279.     var mapWidth = $gameMap.width();
  280.     var nodeList = [];
  281.     var openList = [];
  282.     var closedList = [];
  283.     var start = {};
  284.     var best = start;
  285.  
  286.     if (character.x === goalX && character.y === goalY) {
  287.         return 0;
  288.     }
  289.  
  290.     start.parent = null;
  291.     start.x = character.x;
  292.     start.y = character.y;
  293.     start.g = 0;
  294.     start.f = $gameMap.distance(start.x, start.y, goalX, goalY);
  295.     nodeList.push(start);
  296.     openList.push(start.y * mapWidth + start.x);
  297.  
  298.     if (Maki.PF.PathTrace || Maki.PF.MemPath) {
  299.         character._pathl = 0;
  300.         character._path = [];
  301.         character._exploredl = 0;
  302.         character._explored = [];
  303.     }
  304.     while (nodeList.length > 0) {
  305.         var bestIndex = 0;
  306.         var l = nodeList.length;
  307.         for (var i = 0; i < l; i++) {
  308.             if (nodeList[i].f < nodeList[bestIndex].f) {
  309.                 bestIndex = i;
  310.             }
  311.         }
  312.  
  313.         var current = nodeList[bestIndex];
  314.         var x1 = current.x;
  315.         var y1 = current.y;
  316.         var pos1 = y1 * mapWidth + x1;
  317.         var g1 = current.g;
  318.  
  319.         nodeList.splice(bestIndex, 1);
  320.         openList.splice(openList.indexOf(pos1), 1);
  321.         closedList.push(pos1);
  322.         if (Maki.PF.PathTrace && character._exploredl < 512) {
  323.             character._explored.push(pos1);
  324.             character._exploredl++;
  325.         }
  326.  
  327.         if (current.x === goalX && current.y === goalY) {
  328.             best = current;
  329.             goaled = true;
  330.             break;
  331.         }
  332.  
  333.         if (g1 >= searchLimit && searchLimit > 0) {
  334.             continue;
  335.         }
  336.  
  337.         for (var j = 1; j <= 9; j++) {
  338.             var direction = j;
  339.             if (direction === 5) continue;
  340.             if (direction % 2 > 0 && !Maki.PF.Dir8) continue;
  341.             var x2 = $gameMap.roundXWithDirection(x1, ((direction-1) % 3)+4);
  342.             var y2 = $gameMap.roundYWithDirection(y1, Math.floor((direction-1)/3)*3+2);
  343.             var pos2 = y2 * mapWidth + x2;
  344.             if (closedList.contains(pos2)) {
  345.                 continue;
  346.             }
  347.             if (direction % 2 > 0 && Maki.PF.Dir8) {
  348.                 if (!character.canPassDiagonally(x1, y1,
  349.                     (direction % 6)+3, Math.floor(direction/6)*6+2) &&
  350.                     $gameMap.distance(x1, y1, goalX, goalY) > 1.5) {
  351.                     continue;
  352.                 }
  353.             } else {
  354.                 if (!character.canPass(x1, y1, direction) &&
  355.                     $gameMap.distance(x1, y1, goalX, goalY) > 1) {
  356.                     continue;
  357.                 }
  358.             }
  359.  
  360.             var g2 = g1;
  361.             if (direction % 2 > 0) {
  362.                 g2 += Maki.PF.SQRT2;
  363.             } else {
  364.                 g2 += 1;
  365.             }
  366.             var index2 = openList.indexOf(pos2);
  367.  
  368.             if (index2 < 0 || g2 < nodeList[index2].g) {
  369.                 var neighbor;
  370.                 if (index2 >= 0) {
  371.                     neighbor = nodeList[index2];
  372.                 } else {
  373.                     neighbor = {};
  374.                     nodeList.push(neighbor);
  375.                     openList.push(pos2);
  376.                 }
  377.                 neighbor.parent = current;
  378.                 neighbor.x = x2;
  379.                 neighbor.y = y2;
  380.                 neighbor.g = g2;
  381.                 neighbor.f = g2 + $gameMap.distance(x2, y2, goalX, goalY);
  382.                 if (!best || neighbor.f - neighbor.g < best.f - best.g) {
  383.                     best = neighbor;
  384.                 }
  385.             }
  386.         }
  387.     }
  388.  
  389.     var node = best;
  390.     while (node.parent && node.parent !== start) {
  391.         if ((Maki.PF.PathTrace || Maki.PF.MemPath) && character._pathl < 256 &&
  392.             character.isDestinationValid()) {
  393.             character._path.push(node.y * mapWidth + node.x);
  394.             character._pathl++;
  395.         }
  396.         node = node.parent;
  397.     }
  398.     if ((Maki.PF.PathTrace || Maki.PF.MemPath) && character._pathl < 256) {
  399.         character._path.push(node.y * mapWidth + node.x);
  400.         character._pathl++;
  401.     }
  402.  
  403.     var deltaX1 = $gameMap.deltaX(node.x, start.x);
  404.     var deltaY1 = $gameMap.deltaY(node.y, start.y);
  405.     if (deltaX1 !== 0) deltaX1 /= Math.abs(deltaX1);
  406.     if (deltaY1 !== 0) deltaY1 /= Math.abs(deltaY1);
  407.     if (deltaX1 === 0 && deltaY1 === 0) return 0;
  408.     return 5 - deltaY1 * 3 + deltaX1;
  409. };
  410.  
  411. Maki.PF.Pathfinding_JPS_scanh = function(character, current, goalX, goalY, hdir, recur) {
  412.     var nodeList = [];
  413.     var snodeList = [];
  414.     var x0 = current.x;
  415.     var y0 = current.y;
  416.     var x1 = x0;
  417.     var y1 = y0;
  418.     while (true) {
  419.         if (!character.canPass(x0, y0, 5+hdir) &&
  420.             $gameMap.distance(x0, y0, goalX, goalY) > 1.3) {
  421.             return [];
  422.         }
  423.         x1 = x0+hdir;
  424.         var node = {};
  425.         node.x = x1;
  426.         node.y = y1;
  427.         node.dirs = [];
  428.         node.parent = current;
  429.         node.g = node.parent.g+(x1-current.x)*hdir;
  430.         node.f = node.g+$gameMap.distance(x1, y1, goalX, goalY);
  431.         if (x1 === goalX && y1 === goalY) {
  432.             return [node];
  433.         }
  434.         node.dirs = [5+hdir];
  435.         if (Maki.PF.Dir8) {
  436.         if (!character.canPass(x1, y1, 2) &&
  437.             character.canPassDiagonally(x1, y1, 5+hdir, 2) &&
  438.             $gameMap.distance(x1, y1, goalX, goalY) > 1.3) {
  439.             node.dirs.push(2+hdir);
  440.         }
  441.         if (!character.canPass(x1, y1, 8) &&
  442.             character.canPassDiagonally(x1, y1, 5+hdir, 8) &&
  443.             $gameMap.distance(x1, y1, goalX, goalY) > 1.3) {
  444.             node.dirs.push(8+hdir);
  445.         }
  446.         if (!character.canPass(x1, y1, 2) &&
  447.             1.3 > $gameMap.distance(x1, y1, goalX, goalY)) {
  448.             node.dirs.push(2);
  449.         }
  450.         if (!character.canPass(x1, y1, 8) &&
  451.             1.3 > $gameMap.distance(x1, y1, goalX, goalY)) {
  452.             node.dirs.push(8);
  453.         }
  454.         } else {
  455.         if (!character.canPass(x0, y1, 2) &&
  456.             character.canPass(x1, y1, 2) &&
  457.             $gameMap.distance(x0, y1, goalX, goalY) > 1.3) {
  458.             node.dirs.push(2);
  459.         }
  460.         if (!character.canPass(x0, y1, 8) &&
  461.             character.canPass(x1, y1, 8) &&
  462.             $gameMap.distance(x0, y1, goalX, goalY) > 1.3) {
  463.             node.dirs.push(8);
  464.         }
  465.         }
  466.         if (!recur && node.dirs.length > 1) {
  467.             return [node];
  468.         }
  469.         if (recur) {
  470.         nodeList = [node];
  471.         var done1 = 0;
  472.         var done2 = 0;
  473.         if (node.dirs.length === 1 && nodeList.length === 1) {
  474.             done1 = 1;
  475.             snodeList = Maki.PF.Pathfinding_JPS_scanv(character, node, goalX, goalY, 1);
  476.             if (snodeList.length > 0) {
  477.                 nodeList.push(snodeList[0]);
  478.             }
  479.         }
  480.         if (node.dirs.length === 1 && nodeList.length === 1) {
  481.             done2 = 1;
  482.             snodeList = Maki.PF.Pathfinding_JPS_scanv(character, node, goalX, goalY, -1);
  483.             if (snodeList.length > 0) {
  484.                 nodeList.push(snodeList[0]);
  485.             }
  486.         }
  487.         if (node.dirs.length*nodeList.length > 1) {
  488.             if (node.dirs.length === 1 && done1 === 0) {
  489.                 node.dirs.push(2);
  490.             }
  491.             if (node.dirs.length === 1 && done2 === 0) {
  492.                 node.dirs.push(8);
  493.             }
  494.             return nodeList;
  495.         }
  496.         }
  497.         x0 = x1;
  498.     }
  499. };
  500.  
  501. Maki.PF.Pathfinding_JPS_scanv = function(character, current, goalX, goalY, vdir, recur) {
  502.     var nodeList = [];
  503.     var snodeList = [];
  504.     var x0 = current.x;
  505.     var y0 = current.y;
  506.     var x1 = x0;
  507.     var y1 = y0;
  508.     while (true) {
  509.         if (!character.canPass(x0, y0, 5-3*vdir) &&
  510.             $gameMap.distance(x0, y0, goalX, goalY) > 1.3) {
  511.             return [];
  512.         }
  513.         y1 = y0+vdir;
  514.         var node = {};
  515.         node.x = x1;
  516.         node.y = y1;
  517.         node.dirs = [];
  518.         node.parent = current;
  519.         node.g = current.g+(y1-current.y)*vdir;
  520.         node.f = node.g+$gameMap.distance(x1, y1, goalX, goalY);
  521.         if (x1 === goalX && y1 === goalY) {
  522.             return [node];
  523.         }
  524.         node.dirs = [5-3*vdir];
  525.         if (Maki.PF.Dir8) {
  526.         if (!character.canPass(x1, y1, 6) &&
  527.             character.canPassDiagonally(x1, y1, 6, 5-3*vdir) &&
  528.             $gameMap.distance(x1, y1, goalX, goalY) > 1.3) {
  529.             node.dirs.push(6-3*vdir);
  530.         }
  531.         if (!character.canPass(x1, y1, 4) &&
  532.             character.canPassDiagonally(x1, y1, 4, 5-3*vdir) &&
  533.             $gameMap.distance(x1, y1, goalX, goalY) > 1.3) {
  534.             node.dirs.push(4-3*vdir);
  535.         }
  536.         if (!character.canPass(x1, y1, 6) &&
  537.             1.3 > $gameMap.distance(x1, y1, goalX, goalY)) {
  538.             node.dirs.push(6);
  539.         }
  540.         if (!character.canPass(x1, y1, 4) &&
  541.             1.3 > $gameMap.distance(x1, y1, goalX, goalY)) {
  542.             node.dirs.push(4);
  543.         }
  544.         } else {
  545.         if (!character.canPass(x1, y0, 6) &&
  546.             character.canPass(x1, y1, 6) &&
  547.             $gameMap.distance(x1, y0, goalX, goalY) > 1.3) {
  548.             node.dirs.push(6);
  549.         }
  550.         if (!character.canPass(x1, y0, 4) &&
  551.             character.canPass(x1, y1, 4) &&
  552.             $gameMap.distance(x1, y0, goalX, goalY) > 1.3) {
  553.             node.dirs.push(4);
  554.         }
  555.         }
  556.         if (!recur && node.dirs.length > 1) {
  557.             return [node];
  558.         }
  559.         if (recur) {
  560.         nodeList = [node];
  561.         var done1 = 0;
  562.         var done2 = 0;
  563.         if (node.dirs.length === 1 && nodeList.length === 1) {
  564.             done1 = 1;
  565.             snodeList = Maki.PF.Pathfinding_JPS_scanh(character, node, goalX, goalY, 1);
  566.             if (snodeList.length > 0) {
  567.                 nodeList.push(snodeList[0]);
  568.             }
  569.         }
  570.         if (node.dirs.length === 1 && nodeList.length === 1) {
  571.             done2 = 1;
  572.             snodeList = Maki.PF.Pathfinding_JPS_scanh(character, node, goalX, goalY, -1);
  573.             if (snodeList.length > 0) {
  574.                 nodeList.push(snodeList[0]);
  575.             }
  576.         }
  577.         if (node.dirs.length*nodeList.length > 1) {
  578.             if (node.dirs.length === 1 && done1 === 0) {
  579.                 node.dirs.push(6);
  580.             }
  581.             if (node.dirs.length === 1 && done2 === 0) {
  582.                 node.dirs.push(4);
  583.             }
  584.             return nodeList;
  585.         }
  586.         }
  587.         y0 = y1;
  588.     }
  589. };
  590.  
  591. Maki.PF.Pathfinding_JPS_scand = function(character, current, goalX, goalY, hdir, vdir) {
  592.     var nodeList = [];
  593.     var snodeList = [];
  594.     var x0 = current.x;
  595.     var y0 = current.y;
  596.     var x1 = x0;
  597.     var y1 = y0;
  598.     while (true) {
  599.         if (!character.canPassDiagonally(x0, y0, 5+hdir, 5-3*vdir) &&
  600.             $gameMap.distance(x0, y0, goalX, goalY) > 1.3) {
  601.             return [];
  602.         }
  603.         x1 = x0+hdir;
  604.         y1 = y0+vdir;
  605.         var node = {};
  606.         node.x = x1;
  607.         node.y = y1;
  608.         node.dirs = [];
  609.         node.parent = current;
  610.         node.g = current.g+(x1-current.x)*hdir*Maki.PF.SQRT2;
  611.         node.f = node.g+$gameMap.distance(x1, y1, goalX, goalY);
  612.         if (x1 === goalX && y1 === goalY) {
  613.             return [node];
  614.         }
  615.         node.dirs = [5+hdir-3*vdir];
  616.         if (!character.canPass(x1, y1, 5-hdir) &&
  617.             character.canPassDiagonally(x1, y1, 5-hdir, 5-3*vdir) &&
  618.             $gameMap.distance(x1, y1, goalX, goalY) > 1.3) {
  619.             node.dirs.push(5-hdir-3*vdir);
  620.         }
  621.         if (!character.canPass(x1, y1, 5+3*vdir) &&
  622.             character.canPassDiagonally(x1, y1, 5+hdir, 5+3*vdir) &&
  623.             $gameMap.distance(x1, y1, goalX, goalY) > 1.3) {
  624.             node.dirs.push(5+hdir+3*vdir);
  625.         }
  626.         nodeList = [node];
  627.         var hor_done = 0;
  628.         var vert_done = 0;
  629.         if (node.dirs.length === 1 && nodeList.length === 1) {
  630.             hor_done = 1;
  631.             snodeList = Maki.PF.Pathfinding_JPS_scanh(character, node, goalX, goalY, hdir);
  632.             if (snodeList.length > 0) {
  633.                 nodeList.push(snodeList[0]);
  634.             }
  635.         }
  636.         if (node.dirs.length === 1 && nodeList.length === 1) {
  637.             vert_done = 1;
  638.             snodeList = Maki.PF.Pathfinding_JPS_scanv(character, node, goalX, goalY, vdir);
  639.             if (snodeList.length > 0) {
  640.                 nodeList.push(snodeList[0]);
  641.             }
  642.         }
  643.         if (node.dirs.length*nodeList.length > 1) {
  644.             if (hor_done === 0) {
  645.                 node.dirs.push(5+hdir);
  646.             }
  647.             if (vert_done === 0) {
  648.                 node.dirs.push(5-3*vdir);
  649.             }
  650.             return nodeList;
  651.         }
  652.         x0 = x1;
  653.         y0 = y1;
  654.     }
  655. };
  656.  
  657. Maki.PF.Pathfinding_JPS = function(character, goalX, goalY) {
  658.     var searchLimit = character.searchLimit();
  659.     var mapWidth = $gameMap.width();
  660.     var nodeList = [];
  661.     var openList = [];
  662.     var closedList = [];
  663.     var start = {};
  664.     var best = start;
  665.  
  666.     if (character.x === goalX && character.y === goalY) {
  667.         return 0;
  668.     }
  669.  
  670.     start.parent = null;
  671.     start.x = character.x;
  672.     start.y = character.y;
  673.     start.g = 0;
  674.     start.f = $gameMap.distance(start.x, start.y, goalX, goalY);
  675.     if (Maki.PF.Dir8) {
  676.         start.dirs = [1, 2, 3, 4, 6, 7, 8, 9];
  677.     } else {
  678.         start.dirs = [2, 4, 6, 8];
  679.     }
  680.     nodeList.push(start);
  681.     openList.push(start.y * mapWidth + start.x);
  682.  
  683.     if (Maki.PF.PathTrace || Maki.PF.MemPath) {
  684.         character._pathl = 0;
  685.         character._path = [];
  686.         character._exploredl = 0;
  687.         character._explored = [];
  688.     }
  689.     while (nodeList.length > 0) {
  690.         var bestIndex = 0;
  691.         var l = nodeList.length;
  692.         for (var i = 0; i < l; i++) {
  693.             if (nodeList[i].f < nodeList[bestIndex].f) {
  694.                 bestIndex = i;
  695.             }
  696.         }
  697.  
  698.         var current = nodeList[bestIndex];
  699.         var x1 = current.x;
  700.         var y1 = current.y;
  701.         var pos1 = y1 * mapWidth + x1;
  702.         var g1 = current.g;
  703.  
  704.         nodeList.splice(bestIndex, 1);
  705.         openList.splice(openList.indexOf(pos1), 1);
  706.         closedList.push(pos1);
  707.         if (Maki.PF.PathTrace && character._exploredl < 512) {
  708.             character._explored.push(pos1);
  709.             character._exploredl++;
  710.         }
  711.  
  712.         if (current.x === goalX && current.y === goalY) {
  713.             best = current;
  714.             goaled = true;
  715.             break;
  716.         }
  717.  
  718.         if (g1 >= searchLimit && searchLimit > 0) {
  719.             continue;
  720.         }
  721.         var nodes = [];
  722.         var l = current.dirs.length;
  723.         for (var i = 0; i < l; i++) {
  724.             var direction = current.dirs[i];
  725.             if (direction === 5) continue;
  726.             if (direction % 2 > 0 && !Maki.PF.Dir8) continue;
  727.             if (direction % 2 > 0 && Maki.PF.Dir8) {
  728.                 if (!character.canPassDiagonally(x1, y1,
  729.                     (direction % 6)+3, Math.floor(direction/6)*6+2) &&
  730.                     $gameMap.distance(x1, y1, goalX, goalY) > 1.3) {
  731.                     continue;
  732.                 }
  733.                 nodes = Maki.PF.Pathfinding_JPS_scand(character, current, goalX, goalY,
  734.                     ((direction-1) % 3)-1, 1-Math.floor((direction-1)/3));
  735.             } else {
  736.                 if (!character.canPass(x1, y1, direction) &&
  737.                     $gameMap.distance(x1, y1, goalX, goalY) > 1.3) {
  738.                     continue;
  739.                 }
  740.                 if (((direction-1) % 3)-1 === 0) {
  741.                     nodes = Maki.PF.Pathfinding_JPS_scanv(character, current,
  742.                         goalX, goalY, 1-Math.floor((direction-1)/3), !Maki.PF.Dir8);
  743.                 } else {
  744.                     nodes = Maki.PF.Pathfinding_JPS_scanh(character, current,
  745.                         goalX, goalY, ((direction-1) % 3)-1, !Maki.PF.Dir8);
  746.                 }
  747.             }
  748.             var ll = nodes.length;
  749.             for (var j = 0; j < ll; j++) {
  750.                 var pos2 = nodes[j].y * mapWidth + nodes[j].x;
  751.                 if (closedList.contains(pos2)) continue;
  752.                 var index2 = openList.indexOf(pos2);
  753.                 if (index2 < 0 || nodes[j].g < nodeList[index2].g) {
  754.                     if (index2 >= 0) {
  755.                         nodeList[index2] = nodes[j];
  756.                     } else {
  757.                         openList.push(pos2);
  758.                         nodeList.push(nodes[j]);
  759.                     }
  760.                     if (!best || nodes[j].f - nodes[j].g < best.f - best.g) {
  761.                         best = nodes[j];
  762.                     }
  763.                 }
  764.             }
  765.         }
  766.     }
  767.  
  768.     var node = best;
  769.     while (node.parent && node.parent !== start) {
  770.         if ((Maki.PF.PathTrace || Maki.PF.MemPath) && character._pathl < 256) {
  771.             character._path.push(node.y * mapWidth + node.x);
  772.             character._pathl++;
  773.         }
  774.         node = node.parent;
  775.     }
  776.     if ((Maki.PF.PathTrace || Maki.PF.MemPath) && character._pathl < 256) {
  777.         character._path.push(node.y * mapWidth + node.x);
  778.         character._pathl++;
  779.     }
  780.  
  781.     var deltaX1 = $gameMap.deltaX(node.x, start.x);
  782.     var deltaY1 = $gameMap.deltaY(node.y, start.y);
  783.     if (deltaX1 !== 0) deltaX1 /= Math.abs(deltaX1);
  784.     if (deltaY1 !== 0) deltaY1 /= Math.abs(deltaY1);
  785.     if (deltaX1 === 0 && deltaY1 === 0) return 0;
  786.     return 5 - deltaY1 * 3 + deltaX1;
  787. };
  788.  
  789. Maki.PF.Pathfinding_Dijkstra = function(character, goalX, goalY) {
  790.     var searchLimit = character.searchLimit();
  791.     var mapWidth = $gameMap.width();
  792.     var nodeList = [];
  793.     var openList = [];
  794.     var closedList = [];
  795.     var start = {};
  796.     var best = start;
  797.  
  798.     if (character.x === goalX && character.y === goalY) {
  799.         return 0;
  800.     }
  801.  
  802.     start.parent = null;
  803.     start.x = character.x;
  804.     start.y = character.y;
  805.     start.g = 0;
  806.     nodeList.push(start);
  807.     openList.push(start.y * mapWidth + start.x);
  808.  
  809.     if (Maki.PF.PathTrace || Maki.PF.MemPath) {
  810.         character._pathl = 0;
  811.         character._path = [];
  812.         character._exploredl = 0;
  813.         character._explored = [];
  814.     }
  815.     while (nodeList.length > 0) {
  816.         var bestIndex = 0;
  817.         var l = nodeList.length;
  818.         for (var i = 0; i < l; i++) {
  819.             if (nodeList[i].g < nodeList[bestIndex].g) {
  820.                 bestIndex = i;
  821.             }
  822.         }
  823.  
  824.         var current = nodeList[bestIndex];
  825.         var x1 = current.x;
  826.         var y1 = current.y;
  827.         var pos1 = y1 * mapWidth + x1;
  828.         var g1 = current.g;
  829.  
  830.         nodeList.splice(bestIndex, 1);
  831.         openList.splice(openList.indexOf(pos1), 1);
  832.         closedList.push(pos1);
  833.         if (Maki.PF.PathTrace && character._exploredl < 512) {
  834.             character._explored.push(pos1);
  835.             character._exploredl++;
  836.         }
  837.  
  838.         if (current.x === goalX && current.y === goalY) {
  839.             best = current;
  840.             goaled = true;
  841.             break;
  842.         }
  843.  
  844.         if (g1 >= searchLimit && searchLimit > 0) {
  845.             continue;
  846.         }
  847.  
  848.         for (var j = 1; j <= 9; j++) {
  849.             var direction = j;
  850.             if (direction === 5) continue;
  851.             if (direction % 2 > 0 && !Maki.PF.Dir8) continue;
  852.             var x2 = $gameMap.roundXWithDirection(x1, ((direction-1) % 3)+4);
  853.             var y2 = $gameMap.roundYWithDirection(y1, Math.floor((direction-1)/3)*3+2);
  854.             var pos2 = y2 * mapWidth + x2;
  855.             if (closedList.contains(pos2)) {
  856.                 continue;
  857.             }
  858.             if (direction % 2 > 0 && Maki.PF.Dir8) {
  859.                 if (!character.canPassDiagonally(x1, y1,
  860.                     (direction % 6)+3, Math.floor(direction/6)*6+2) &&
  861.                     $gameMap.distance(x1, y1, goalX, goalY) > 1.5) {
  862.                     continue;
  863.                 }
  864.             } else {
  865.                 if (!character.canPass(x1, y1, direction) &&
  866.                     $gameMap.distance(x1, y1, goalX, goalY) > 1) {
  867.                     continue;
  868.                 }
  869.             }
  870.  
  871.             var g2 = g1;
  872.             if (direction % 2 > 0) {
  873.                 g2 += Maki.PF.SQRT2;
  874.             } else {
  875.                 g2 += 1;
  876.             }
  877.             var index2 = openList.indexOf(pos2);
  878.  
  879.             if (index2 < 0 || g2 < nodeList[index2].g) {
  880.                 var neighbor;
  881.                 if (index2 >= 0) {
  882.                     neighbor = nodeList[index2];
  883.                 } else {
  884.                     neighbor = {};
  885.                     nodeList.push(neighbor);
  886.                     openList.push(pos2);
  887.                 }
  888.                 neighbor.parent = current;
  889.                 neighbor.x = x2;
  890.                 neighbor.y = y2;
  891.                 neighbor.g = g2;
  892.             }
  893.         }
  894.     }
  895.  
  896.     var node = best;
  897.     while (node.parent && node.parent !== start) {
  898.         if ((Maki.PF.PathTrace || Maki.PF.MemPath) && character._pathl < 256) {
  899.             character._path.push(node.y * mapWidth + node.x);
  900.             character._pathl++;
  901.         }
  902.         node = node.parent;
  903.     }
  904.     if ((Maki.PF.PathTrace || Maki.PF.MemPath) && character._pathl < 256) {
  905.         character._path.push(node.y * mapWidth + node.x);
  906.         character._pathl++;
  907.     }
  908.  
  909.     var deltaX1 = $gameMap.deltaX(node.x, start.x);
  910.     var deltaY1 = $gameMap.deltaY(node.y, start.y);
  911.     if (deltaX1 !== 0) deltaX1 /= Math.abs(deltaX1);
  912.     if (deltaY1 !== 0) deltaY1 /= Math.abs(deltaY1);
  913.     if (deltaX1 === 0 && deltaY1 === 0) return 0;
  914.     return 5 - deltaY1 * 3 + deltaX1;
  915. };
  916.  
  917. Maki.PF.Pathfinding_GBFS = function(character, goalX, goalY) {
  918.     var searchLimit = character.searchLimit();
  919.     var mapWidth = $gameMap.width();
  920.     var closedList = [];
  921.     var start = {};
  922.     var best;
  923.  
  924.     if (character.x === goalX && character.y === goalY) {
  925.         return 0;
  926.     }
  927.  
  928.     start.parent = null;
  929.     start.x = character.x;
  930.     start.y = character.y;
  931.     start.h = $gameMap.distance(start.x, start.y, goalX, goalY);
  932.     var current = start;
  933.     var g = 0;
  934.  
  935.     if (Maki.PF.PathTrace || Maki.PF.MemPath) {
  936.         $gameTemp._pathl = 0;
  937.         $gameTemp._path = [];
  938.         $gameTemp._exploredl = 0;
  939.         $gameTemp._explored = [];
  940.     }
  941.     while (g < (searchLimit || 2048)) {
  942.         g++;
  943.         var x1 = current.x;
  944.         var y1 = current.y;
  945.         var pos1 = y1 * mapWidth + x1;
  946.  
  947.         closedList.push(pos1);
  948.         if (Maki.PF.PathTrace && character._exploredl < 512) {
  949.             character._explored.push(pos1);
  950.             character._exploredl++;
  951.         }
  952.  
  953.         if (current.x === goalX && current.y === goalY) {
  954.             goaled = true;
  955.             break;
  956.         }
  957.  
  958.         best = 0;
  959.         for (var j = 1; j <= 9; j++) {
  960.             var direction = j;
  961.             if (direction === 5) continue;
  962.             if (direction % 2 > 0 && !Maki.PF.Dir8) continue;
  963.             var x2 = $gameMap.roundXWithDirection(x1, ((direction-1) % 3)+4);
  964.             var y2 = $gameMap.roundYWithDirection(y1, Math.floor((direction-1)/3)*3+2);
  965.             var pos2 = y2 * mapWidth + x2;
  966.             if (closedList.contains(pos2)) {
  967.                 continue;
  968.             }
  969.             if (direction % 2 > 0 && Maki.PF.Dir8) {
  970.                 if (!character.canPassDiagonally(x1, y1,
  971.                     (direction % 6)+3, Math.floor(direction/6)*6+2) &&
  972.                     $gameMap.distance(x1, y1, goalX, goalY) > 1.5) {
  973.                     continue;
  974.                 }
  975.             } else {
  976.                 if (!character.canPass(x1, y1, direction) &&
  977.                     $gameMap.distance(x1, y1, goalX, goalY) > 1) {
  978.                     continue;
  979.                 }
  980.             }
  981.  
  982.                 var neighbor = {};
  983.                 neighbor.parent = current;
  984.                 neighbor.x = x2;
  985.                 neighbor.y = y2;
  986.                 neighbor.h = $gameMap.distance(x2, y2, goalX, goalY);
  987.                 if (!best || neighbor.h < best.h) {
  988.                     best = neighbor;
  989.                 }
  990.         }
  991.         current = best;
  992.     }
  993.  
  994.     var node = best;
  995.     while (node.parent && node.parent !== start) {
  996.         if ((Maki.PF.PathTrace || Maki.PF.MemPath) && character._pathl < 256) {
  997.             character._path.push(node.y * mapWidth + node.x);
  998.             character._pathl++;
  999.         }
  1000.         node = node.parent;
  1001.     }
  1002.     if ((Maki.PF.PathTrace || Maki.PF.MemPath) && character._pathl < 256) {
  1003.         character._path.push(node.y * mapWidth + node.x);
  1004.         character._pathl++;
  1005.     }
  1006.  
  1007.     var deltaX1 = $gameMap.deltaX(node.x, start.x);
  1008.     var deltaY1 = $gameMap.deltaY(node.y, start.y);
  1009.     if (deltaX1 !== 0) deltaX1 /= Math.abs(deltaX1);
  1010.     if (deltaY1 !== 0) deltaY1 /= Math.abs(deltaY1);
  1011.     if (deltaX1 === 0 && deltaY1 === 0) return 0;
  1012.     return 5 - deltaY1 * 3 + deltaX1;
  1013. };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement