查看: 5118|回复: 8

[有事请教] 关于自动寻路的问题

[复制链接]
梦石
0
星屑
220
在线时间
45 小时
注册时间
2019-10-1
回帖
25
发表于 2019-10-4 13:28:27 | 显示全部楼层 |阅读模式

加入我们,或者,欢迎回来。

您需要 登录 才可以下载或查看,没有账号?注册会员

×
让事件接近主角使用的应该是类似于鼠标点击的自动寻路,但是会卡住,像下图这样

按照论坛大佬的说法,把Game_Character.prototype.searchLimi的限制数12放大就可以了,但是放大到30以后仍然会卡住

于是找到了17年的帖子,一个大佬写的脚本
[pre lang="javascript"]/*:
* @plugindesc Character. v1.0.0
* @author Kong Jing
*
* @help
* 修复了自带的接近玩家(不会被障碍物卡主不动)
*
* 在自定义路线中写脚本
* this.moveTowardCharacterEx(index);
* 向着事件Id为index的坐标走去。
*
* this.moveTowardDestination(x, y);
* 向地图指定位置走去。
*
* this.moveTowardDestinationEx(Id1, Id2);
* 向变量Id1为x坐标, 变量Id2为y坐标的位置走去。
*
*/

//原版本的一个细节问题2333.
Game_Character.prototype.findDirectionTo = function(goalX, goalY) {
    var searchLimit = this.searchLimit();
    var mapWidth = $gameMap.width();
    var nodeList = [];
    var openList = [];
    var closedList = [];
    var start = {};
    var best = null;//此处应该为null,原版本为start

    if (this.x === goalX && this.y === goalY) {
        return 0;
    }

    start.parent = null;
    start.x = this.x;
    start.y = this.y;
    start.g = 0;
    start.f = $gameMap.distance(start.x, start.y, goalX, goalY);
    nodeList.push(start);
    openList.push(start.y * mapWidth + start.x);
       
        if(start.f == 1){
                var deltaX1 = $gameMap.deltaX(goalX, start.x);
                var deltaY1 = $gameMap.deltaY(goalY, start.y);
                if (deltaY1 > 0 && this.isMapPassable(start.x, start.y, 2)) {
                        return 2;
                } else if (deltaX1 < 0 && this.isMapPassable(start.x, start.y, 4)) {
                        return 4;
                } else if (deltaX1 > 0 && this.isMapPassable(start.x, start.y, 6)) {
                        return 6;
                } else if (deltaY1 < 0 && this.isMapPassable(start.x, start.y, 8)) {
                        return 8;
                }
        }
    while (nodeList.length > 0) {
        var bestIndex = 0;
        for (var i = 0; i < nodeList.length; i++) {
            if (nodeList.f < nodeList[bestIndex].f) {
                bestIndex = i;
            }
        }

        var current = nodeList[bestIndex];
        var x1 = current.x;
        var y1 = current.y;
        var pos1 = y1 * mapWidth + x1;
        var g1 = current.g;

        nodeList.splice(bestIndex, 1);
        openList.splice(openList.indexOf(pos1), 1);
        closedList.push(pos1);

        if (current.x === goalX && current.y === goalY) {
            best = current;
            goaled = true;
            break;
        }

        if (g1 >= searchLimit) {
            continue;
        }

        for (var j = 0; j < 4; j++) {
            var direction = 2 + j * 2;
            var x2 = $gameMap.roundXWithDirection(x1, direction);
            var y2 = $gameMap.roundYWithDirection(y1, direction);
            var pos2 = y2 * mapWidth + x2;

            if (closedList.contains(pos2)) {
                continue;
            }
            if (!this.canPass(x1, y1, direction)) {
                continue;
            }

            var g2 = g1 + 1;
            var index2 = openList.indexOf(pos2);

            if (index2 < 0 || g2 < nodeList[index2].g) {
                var neighbor;
                if (index2 >= 0) {
                    neighbor = nodeList[index2];
                } else {
                    neighbor = {};
                    nodeList.push(neighbor);
                    openList.push(pos2);
                }
                neighbor.parent = current;
                neighbor.x = x2;
                neighbor.y = y2;
                neighbor.g = g2;
                neighbor.f = g2 + $gameMap.distance(x2, y2, goalX, goalY);
                if (!best || neighbor.f - neighbor.g < best.f - best.g) {
                    best = neighbor;
                }
            }
        }
    }

    var node = best;
    while (node.parent && node.parent !== start) {
        node = node.parent;
    }

    var deltaX1 = $gameMap.deltaX(node.x, start.x);
    var deltaY1 = $gameMap.deltaY(node.y, start.y);
    if (deltaY1 > 0) {
        return 2;
    } else if (deltaX1 < 0) {
        return 4;
    } else if (deltaX1 > 0) {
        return 6;
    } else if (deltaY1 < 0) {
        return 8;
    }

    var deltaX2 = this.deltaXFrom(goalX);
    var deltaY2 = this.deltaYFrom(goalY);
    if (Math.abs(deltaX2) > Math.abs(deltaY2)) {
        return deltaX2 > 0 ? 4 : 6;
    } else if (deltaY2 !== 0) {
        return deltaY2 > 0 ? 8 : 2;
    }

    return 0;
};
//优化接近玩家
Game_Character.prototype.moveTowardCharacter = function(character) {
        var x = character.x;
        var y = character.y;
        var direction = this.findDirectionTo(x, y);
        if (direction > 0) {
                this.moveStraight(direction);
        }
};

//向事件寻路
Game_Character.prototype.moveTowardCharacterEx = function(index) {
        var character = $gameMap._events[index];
        var x = character.x;
        var y = character.y;
        var direction = this.findDirectionTo(x, y);
        if (direction > 0) {
                this.moveStraight(direction);
        }
};

//向指定坐标寻路
Game_Character.prototype.moveTowardDestination = function(x, y) {
        var direction = this.findDirectionTo(x, y);
        if (direction > 0) {
                this.moveStraight(direction);
        }
};

//向变量所指位置走去
Game_Character.prototype.moveTowardDestinationEx = function(Id1, Id2) {
        var x = $gameVariables.value(Id1);
        var y = $gameVariables.value(Id2);
        var direction = this.findDirectionTo(x, y);
        if (direction > 0) {
                this.moveStraight(direction);
        }
};[/pre]
使用后确实让“接近主角”不会卡主了,但是偶尔会报错,提示:cannot read property "parent" of null ,应该是这个脚本引起的问题,不是进入游戏触发寻路后立刻报错,而是走着走着不知什么时候会报错

想请问如何解决,或者有没有其他寻路脚本,谢谢各位大佬,国庆快乐
hfc.jpg
梦石
2
星屑
34497
在线时间
614 小时
注册时间
2014-7-18
回帖
647

MZ评测员开拓者

发表于 2019-10-4 15:09:45 | 显示全部楼层
我试了一下上面的脚本,使用上面的插件后只会让人物在无法搜到到达NPC所在路径的情况下反复在两个格乱晃,但是试了很多情况都没有报错,建议楼主把出错的地图截个图。
另外,我个人认为珂能是楼主的工程MV版本比较高,导致与脚本不兼容(因为MV版本不断升级导致自带脚本变化了很多,我的测试工程是MV1.2版本的,不排除是因为1.6版本更换了脚本导致出错)
回复

使用道具 举报

梦石
0
星屑
16261
在线时间
4014 小时
注册时间
2015-9-14
回帖
1322

开拓者

发表于 2019-10-4 15:26:37 | 显示全部楼层
本帖最后由 wabcmcc 于 2019-10-4 20:05 编辑

RM官方論壇智能尋路簡單好用.
作者:Shaz

事件頁,第三頁,插件命令.

插件命令:
  SmartPath eventId1 eventId2  //使事件1找到事件2的路徑  
     例子: SmartPath 1 2
  SmartPath eventId x y            //使事件找到位置x,y的路徑
  SmartPath eventId cancel       //取消尋找事件的路徑
.....................................
event = number for specific event    //事件= 特定事件的號碼.
event = 0 for "this" event               //事件= 0當前事件的號碼.
event = $gameVariables.value(x) to get the event id from variable x
//事件 = 從變量x中獲取事件ID
x, y = coordinates or $gameVariables.value(#) to use a variable coordinate
//x,y =坐標或以使用變量坐標


  1. //=============================================================================
  2. // Smart Pathfinding
  3. // by Shaz
  4. // Last Updated: 2015.10.21
  5. //=============================================================================

  6. /*:
  7. * @plugindesc Allows events or players to do smart Pathfinding
  8. * @author Shaz
  9. *
  10. * @help
  11. *
  12. * Plugin Command:
  13. *  SmartPath eventId1 eventId2      # Makes event 1 find path to event 2
  14. *  SmartPath eventId x y            # Makes event find a path to location x, y
  15. *  SmartPath eventId cancel         # Cancel Pathfinding for event
  16. *
  17. *  event = number for specific event
  18. *  event = 0 for "this" event
  19. *  event = -1 for player
  20. *  event = $gameVariables.value(x) to get the event id from variable x
  21. *
  22. *  x, y = coordinates or $gameVariables.value(#) to use a variable coordinate
  23. *
  24. */

  25. (function() {
  26.   var _Game_Interpreter_pluginCommand = Game_Interpreter.prototype.pluginCommand;
  27.   Game_Interpreter.prototype.pluginCommand = function(command, args) {
  28.     _Game_Interpreter_pluginCommand.call(this, command, args);

  29.     if (command.toUpperCase() === 'SMARTPATH') {
  30.       subject = this.character(eval(args[0]));
  31.       if (args[1].toUpperCase() === 'CANCEL') {
  32.         subject.clearTarget();
  33.       } else if (args.length > 2) {
  34.         subject.setTarget(null, eval(args[1]), eval(args[2]));
  35.       } else {
  36.         subject.setTarget(this.character(eval(args[1])));
  37.       }
  38.     }
  39.   };

  40.   var _Game_CharacterBase_initMembers = Game_CharacterBase.prototype.initMembers;
  41.   Game_CharacterBase.prototype.initMembers = function() {
  42.     _Game_CharacterBase_initMembers.call(this);
  43.     this._target = null;
  44.     this._targetX = null;
  45.     this._targetY = null;
  46.   };

  47.   Game_CharacterBase.prototype.setTarget = function(target, targetX, targetY) {
  48.     this._target = target;
  49.     if (this._target) {
  50.       this._targetX = this._target.x;
  51.       this._targetY = this._target.y;
  52.     } else {
  53.       this._targetX = targetX;
  54.       this._targetY = targetY;
  55.     }
  56.   };

  57.   Game_CharacterBase.prototype.clearTarget = function() {
  58.     this._target = null;
  59.     this._targetX = null;
  60.     this._targetY = null;
  61.   };

  62.   var _Game_CharacterBase_updateStop = Game_CharacterBase.prototype.updateStop;
  63.   Game_CharacterBase.prototype.updateStop = function() {
  64.     _Game_CharacterBase_updateStop.call(this);

  65.     if (this._target) {
  66.       this._targetX = this._target.x;
  67.       this._targetY = this._target.y;
  68.     }

  69.     if (this._targetX != null) {
  70.       direction = this.findDirectionTo(this._targetX, this._targetY);
  71.       if (direction > 0)
  72.       {
  73.         this.moveStraight(direction);
  74.       }
  75.     }
  76.   };
  77. })();
复制代码
https://rpg.blue/data/attachment/album/202003/28/021323lltgrsvfytfwuya5.gif
回复 1 0

使用道具 举报

梦石
0
星屑
220
在线时间
45 小时
注册时间
2019-10-1
回帖
25
 楼主| 发表于 2019-10-4 17:45:29 | 显示全部楼层
wabcmcc 发表于 2019-10-4 15:26
RM官方論壇智能尋路簡單好用.
作者:Shaz

抱歉大佬我没有看懂,使用的时候让本事件移动到事件7处,是在移动路线里写脚本SmartPath event0 event7吗

点评

加上說明  发表于 2019-10-4 20:06
回复

使用道具 举报

梦石
0
星屑
220
在线时间
45 小时
注册时间
2019-10-1
回帖
25
 楼主| 发表于 2019-10-4 17:55:06 | 显示全部楼层
xjzsq 发表于 2019-10-4 15:09
我试了一下上面的脚本,使用上面的插件后只会让人物在无法搜到到达NPC所在路径的情况下反复在两个格乱晃, ...

谢谢大佬,一张17*13的小地图全部可通行没有障碍,但是有很多NPC,每次随机让一个NPC在随机移动N步后停下,循环这个过程。用了很多并行事件和随机数,不知道是不是这个原因产生了BUG。我用的MV跟着steam更新到1.6.2,
回复

使用道具 举报

梦石
0
星屑
3922
在线时间
1198 小时
注册时间
2016-8-9
回帖
2355

开拓者

发表于 2019-10-5 18:22:32 | 显示全部楼层
yep_moveRouteCore插件 可以指定走到某个坐标或者事件或者角色 跳到某个坐标事件或者角色

JUMP TO: x, y
JUMP TO: EVENT x
JUMP TO: PLAYER

MOVE TO: x, y
MOVE TO: EVENT x
MOVE TO: PLAYER

Example: Move To: 20, 30
         Move To: Event 5
         Move To: Player
         Avoid Move To: 30, 40
         Crash Move To: 40, 50


除此之外还有其他功能,寻路已经试验了,穿梭于各种npc事件中毫无压力
酸酸甜甜就④哇噢
回复

使用道具 举报

梦石
0
星屑
220
在线时间
45 小时
注册时间
2019-10-1
回帖
25
 楼主| 发表于 2019-10-5 20:00:05 | 显示全部楼层
白嫩白嫩的 发表于 2019-10-5 18:22
yep_moveRouteCore插件 可以指定走到某个坐标或者事件或者角色 跳到某个坐标事件或者角色

JUMP TO: x, y

感谢大佬,这个yep之前试验过,关于一楼那个插件,我发现用事件替代玩家就不会报错了,虽然有点蠢但问题还是顺利解决了
回复

使用道具 举报

梦石
0
星屑
12161
在线时间
4435 小时
注册时间
2014-4-11
回帖
5616

开拓者

发表于 2019-10-6 20:14:14 | 显示全部楼层
本帖最后由 yang1zhi 于 2019-10-6 20:15 编辑

30不够就再加大。
距离越大,路线就越多的。
他要一个个路线试过来。
这东西,很耗资源的。

另外
这个寻路不是(接近主角)
接近主角,就是最短距离直接过来
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

Powered by Discuz! X5.0 © 2001-2026 Discuz! Team.

在本版发帖返回顶部