查看: 2941|回复: 17

[原创发布] [MV插件]地图箭头MapArrows v1.3 UI 指向目标位置事件 指引导标记

[复制链接]
梦石
0
星屑
7801
在线时间
683 小时
注册时间
2012-7-29
回帖
172
发表于 2023-11-13 00:40:04 | 显示全部楼层 |阅读模式

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

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

×
本帖最后由 开关关 于 2025-7-13 15:51 编辑

【RMMV插件】地图箭头MapArrows 指向目标位置/事件

箭头

箭头
【GitHub】

【v1.1读档会报错“x is not a function”,请v1.1用户尽快更新版本】

示意图

示意图


应用场景
  当你画了一幅宏伟震撼的地图,玩家在其中迷路,叫苦不迭;
  当你的NPC随机移动,玩家想找他对话却找不到当前位置,无所适从;
  当你要给玩家一点奖励,想让玩家发现路边的宝箱,宝箱却不好意思主动蹦出来;
  当你的剧情被好久没玩的玩家暂时遗忘,玩家久违进入游戏却不知道下一步应该往哪个方向走;
  当你的主角被危难几乎摧毁了心智,斗志处于最低谷的时刻,你想要给予他来自上苍的 神圣的指引 ......
  你,可以解除他们的疑惑和苦闷;
  你,可以指引他们在喜悦中知晓前进的方向;
  你,可以成为你笔下主角走出迷茫后永远忘不掉的那一抹圣光!
  只要使用这个插件,施予你的 箭头 !

功能
  本插件为 RPG Maker MV 游戏项目的地图场景边缘显示一个或多个箭头作为GUI,箭头在预先设定好的边框上移动,指向地图上指定的事件或位置。
  本插件提供添加、移除、按样式清除箭头的插件指令。插件指令的风格仿照了Drill_up系列插件,学习成本低。
  每种样式的箭头可以自定图像;可自定边框位置,有矩形和椭圆可选。可叠加显示多个不同箭头。
  请在插件面板中预先设置好样式,然后在游戏过程中添加箭头。
  参数较多,建议下载demo参考。


下载
  帖子附件是新建工程的增量包,覆盖到新建工程上即可得到本插件的demo。
  增量包用法:新建工程,将下载的压缩包内的文件复制到工程中进行替换。替换时,对文件夹选“合并”而不是“替换”。
  论坛无法上传demo完整工程,因为附件大小限制(其实完整工程也不到10M大小)。
  要下载解压即用的完整工程,您可以进入本插件的 【GitHub发布页】 。

↓成为神圣的指引者↓
Kgg_MapArrows_Demo_v1.3.zip (587.5 KB, 下载次数: 5, 售价: 1 星屑)
↑成为神圣的指引者↑
(之所以设置售价,是因为无售价的附件不会记录下载人。售价最低只能设1星屑,每日签到就能获得5星屑。如果实在没有条件,可以到 【GitHub发布页】 下载。)

注意事项
  1.箭头图像文件请放置在img/system/文件夹
  2.箭头图像中箭头朝右
  3.支持使用 Drill_up 的插件最大值编辑器(DrillLengthEditor)修改箭头样式数量的最大值。获取链接:drill插件集合

使用许可
 · Kgg_MapArrows.js
  可免费商用,可修改,无需报告。
  以上未提及的事项,参考MIT License。
 · Kgg_Arrow2.png
  原创素材,可免费商用,可修改,无需报告。

感谢
  此插件是拜读Drill_up的插件教程写出来的,感谢Drill_up大佬!
  感谢honmarei指出问题。

效果截图

demo-野外

demo-野外

demo-旅馆

demo-旅馆

地图箭头插件5插件参数设置截图

地图箭头插件5插件参数设置截图


代码
  代码可以直接复制去用,但还是建议下载demo参考,因为我写的描述不清晰。_(:з」∠)_

[fold=此处有折叠的代码]
[pre lang="javascript" line="1"]//=====================================================================================
// Kgg_MapArrows.js
//=====================================================================================
/*:
* @plugindesc v1.3 地图箭头 MapArrows
* @author 开关关
*
* @Drill_LE_param "箭头-%d"
* @Drill_LE_parentKey "---箭头样式组%d至%d---"
* @Drill_LE_var "Kgg_MapArrows.arrowStyleList.length"
*
* @help
* ==========================================================
* 简介
* ==========================================================
* 功能:
* 本插件为 RPG Maker MV 游戏项目的地图场景显示多个箭头,箭头在
* 预先设定好的边框上移动,指向指定事件或坐标。
* 本插件提供添加、移除、按样式清除箭头的插件指令。
* 请在插件面板中预先设置好样式,然后在游戏过程中添加。
* 参数较多,建议下载demo参考。
*
* 注意事项:
* 1.箭头图像文件请放置在img/system/文件夹
* 2.箭头图像中箭头朝右
* 3.支持使用 Drill_up 的插件最大值编辑器(DrillLengthEditor)
* 修改箭头样式数量的最大值。
* 获取链接:https://rpg.blue/thread-409713-1-1.html
*
* 使用许可:
* 可免费商用,可修改,无需报告。
* 以上未提及的事项,参考MIT License。
*
* 感谢:
* 此插件是拜读Drill_up的插件教程写出来的,感谢Drill_up大佬!
* 感谢honmarei指出问题。
*
* 发布链接:
* https://rpg.blue/thread-494806-1-1.html
* https://github.com/KggFromChina/Kgg_MapArrows_Demo/
* ==========================================================
* 插件指令
* ==========================================================
* 功能:快捷添加默认样式的箭头,指向事件或位置
* 插件指令:
* >地图箭头 : 快捷添加 : 事件[15]
* >地图箭头 : 快捷添加 : 位置[15,16]
* >地图箭头 : 快捷添加 : 事件[15] : 地图[2]
* >地图箭头 : 快捷添加 : 位置[15,16] : 地图[2]
* 说明:
* 这是添加箭头指令的简化版,省略了名称和样式名,尽量简化参数,方便
* 快速上手。
* ----------------------------------------------------------
* 功能:清除所有快捷添加的箭头
* 插件指令:
* >地图箭头 : 清除快捷箭头
* ----------------------------------------------------------
* 功能:在本地图添加箭头,指向事件或位置,可以用常量或变量指定
* 插件指令:
* >地图箭头 : 添加箭头 : 名称 : 样式名 : 事件[15]
* >地图箭头 : 添加箭头 : 名称 : 样式名 : 事件变量[15]
* >地图箭头 : 添加箭头 : 名称 : 样式名 : 位置[15,16]
* >地图箭头 : 添加箭头 : 名称 : 样式名 : 位置变量[15,16]
* 说明:
* 1.名称是自定义的。为箭头设置名称作用是区分不同箭头,移除箭头时用。
* 2.样式名可在插件管理器自定。
* 3.事件变量[15]代表箭头目标是“编号为第15号变量的值的事件”。
* 4.位置[15,16]代表地图中x为15,y为16的格子。
* 5.添加的箭头仅在当前地图生效,重新进入地图仍然生效。
* 6.变量[15]取的是当前的变量值,后续不会跟随变量变化。
* 举例:
* 添加一个箭头,名叫“张三”,样式是“默认样式”,指向本地图15号事件。
* >地图箭头 : 添加箭头 : 张三 : 默认样式 : 事件[15]
* ----------------------------------------------------------
* 功能:在指定地图添加箭头,指向事件
* 插件指令:
* >地图箭头 : 添加箭头 : 名称 : 样式名 : 事件[15] : 地图[1]
* >地图箭头 : 添加箭头 : 名称 : 样式名 : 事件[15] : 地图变量[1]
* 说明:
* 在上一种指令基础上,可以指定生效的地图编号。
* 举例:
* 添加一个箭头,名叫“张三”,样式是“默认样式”,它的目标是2号地图的
* 某个事件。至于是哪个事件,要看5号变量当前值是什么。
* >地图箭头 : 添加箭头 : 张三 : 默认样式 : 事件变量[5] : 地图[2]
* ----------------------------------------------------------
* 功能:按名称移除箭头
* 插件指令:
* >地图箭头 : 移除箭头 : 名称
* 说明:
* 移除指定名称的箭头。
* 举例:
* 移除名叫“张三”的箭头。
* >地图箭头 : 移除箭头 : 张三
* ----------------------------------------------------------
* 功能:按样式清除箭头
* 插件指令:
* >地图箭头 : 按样式清除箭头 : 样式名
* 说明:
* 在所有箭头中找出每个指定样式的箭头,进行移除。
* ----------------------------------------------------------
* 功能:按关键词清除箭头
* 插件指令:
* >地图箭头 : 按关键词清除箭头 : 关键词
* 说明:
* 在所有箭头中找出每个名称包含指定关键词的箭头,进行移除。
* ----------------------------------------------------------
* 功能:清除全部箭头
* 插件指令:
* >地图箭头 : 清除全部箭头
* 说明:
* 清除所有箭头,一个也不剩。
* ==========================================================
* 脚本
* ==========================================================
* 功能:快捷添加箭头,指向事件
* 脚本:
* Kgg_MapArrows.addArrowToEventFast(eventId, mapId)
* 参数:
* {Number} eventId 箭头指向的地图X坐标
* {Number} mapId 生效的地图ID 若不填则默认当前地图
* ----------------------------------------------------------
* 功能:快捷添加箭头,指向位置
* 脚本:
* Kgg_MapArrows.addArrowToLocationFast(mapX, mapY, mapId)
* 参数:
* {Number} mapX 箭头指向的地图X坐标
* {Number} mapY 箭头指向的地图Y坐标
* {Number} mapId 生效的地图ID 若不填则默认当前地图
* ----------------------------------------------------------
* 功能:清除所有快捷添加的箭头
* 脚本:
* Kgg_MapArrows.clearFastArrows();
* ----------------------------------------------------------
* 功能:添加指向指定事件的箭头
* 描述:
* 使用设置好的样式,添加指向特定ID的事件的箭头,仅生效于一张地图。
* 请在开始游戏后调用,勿在主菜单调用。
* 脚本:
* Kgg_MapArrows.addArrowToEvent(name, arrowStyleName, eventId, mapId)
* 参数:
* {String} name 新建箭头名称 用于移除箭头
* {String} arrowStyleName 箭头样式名称
* {Number} eventId 箭头指向的事件ID
* {Number} mapId 生效的地图ID 若不填则默认当前地图
* ----------------------------------------------------------
* 功能:添加指向指定位置的箭头
* 描述:
* 使用设置好的样式,添加指向特定位置的箭头,仅生效于一张地图。
* 请在开始游戏后调用,勿在主菜单调用。
* 脚本:
* Kgg_MapArrows.addArrowToLocation(name, arrowStyleName, mapX, mapY, mapId)
* 参数:
* {String} name 新建箭头名称 用于移除箭头
* {String} arrowStyleName 箭头样式名称
* {Number} mapX 箭头指向的地图X坐标
* {Number} mapY 箭头指向的地图Y坐标
* {Number} mapId 生效的地图ID 若不填则默认当前地图
* ----------------------------------------------------------
* 功能:根据箭头名称移除箭头
* 脚本:
* Kgg_MapArrows.removeArrow(name)
* ----------------------------------------------------------
* 功能:根据样式名称清除箭头
* 描述:一次性移除所有指定样式的箭头。
* 脚本:
* Kgg_MapArrows.clearArrowsByArrowStyle(arrowStyleName)
* ----------------------------------------------------------
* 功能:根据关键词清除箭头
* 描述:一次性移除所有名称含有关键词的箭头。
* 脚本:
* Kgg_MapArrows.clearArrowsByKeyword(keyword)
* ----------------------------------------------------------
* 功能:清除全部箭头
* 描述:一次性移除所有箭头。
* 脚本:
* Kgg_MapArrows.clearAllArrows()
* ==========================================================
* 其他信息
* ==========================================================
* 兼容性:
* 仅在RMMV1.6.3版本进行过测试。
* 更新记录:
* 2023.11.12 v1.0 完成demo,做成可以发布的版本。
* 2023.11.21 v1.1 增加快捷添加功能;将起点设置移到样式内;完善
* 清除箭头的方法;修复已知bug。
* 2024.3.10  v1.2 修复读档时报错x is not a function的问题。
* 2025.7.13  v1.3 增加对插件最大值编辑器(DrillLengthEditor)的
* 支持;修复箭头是否可旋转(canRotate)无法设置为false的问题。
*
* 插件影响范围:
* 重写了几个RM原版的函数,它们属于以下3个类:
* Scene_Map Game_System Game_Interpreter
* 本插件影响存档文件,因为有给$gameSystem添加成员。所有本插件
* 给$gameSystem添加的成员变量名称都有前缀“_kgg_MapArrows”。
* ==========================================================
*
* @param 调试设置
* @default
*
* @param 显示边界线
* @parent 调试设置
* @type boolean
* @on 显示
* @off 关闭
* @desc 添加箭头时,同时显示箭头样式的边界线。建议仅调试时开启。
* @default false
*
* @param 快捷添加设置
* @default
*
* @param 快捷添加默认样式
* @parent 快捷添加设置
* @desc 选择某个样式作为快捷添加的默认样式。填写样式编号(整数)。
* @default 1
*
* @param ---箭头样式组 1至20---
* @desc
*
* @param 箭头-1
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default
*
* @param 箭头-2
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default false
*
* @param 箭头-3
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default
*
* @param 箭头-4
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default 1
*
* @param 箭头-5
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default
*
* @param 箭头-6
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default false
*
* @param 箭头-7
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default
*
* @param 箭头-8
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default 1
*
* @param 箭头-9
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default
*
* @param 箭头-10
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default false
*
* @param 箭头-11
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default
*
* @param 箭头-12
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default 1
*
* @param 箭头-13
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default
*
* @param 箭头-14
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default false
*
* @param 箭头-15
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default
*
* @param 箭头-16
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default
*
* @param 箭头-17
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default
*
* @param 箭头-18
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default
*
* @param 箭头-19
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default
*
* @param 箭头-20
* @parent ---箭头样式组 1至20---
* @type struct<MenuArrowStyle>
* @desc 设置箭头的样式。
* @default
*
*/
/*~struct~MenuArrowStyle:
*
* @param 名称
* @desc 作为该箭头样式的唯一标识,用于添加箭头时选择样式。不可包含空格。
* @default 未命名
*
*
* @param 图像设置
* @default
*
* @param 箭头图像
* @parent 图像设置
* @desc 箭头的图片资源。
* @default Shadow2
* @require 1
* @dir img/system/
* @type file
*
* @param 是否可旋转
* @parent 图像设置
* @type boolean
* @on 可旋转
* @off 不可旋转
* @desc 箭头图像是否跟随指向进行旋转。
* @default true
*
* @param 锚点原点类型(AnchorOriginType)
* @parent 图像设置
* @type select
* @option 图像中心(image_center)
* @value image_center
* @option 左上角(top_left)
* @value top_left
* @desc 选择箭头图像的锚点从图像内的哪个点开始偏移。
* @default top_left
*
* @param 锚点X
* @parent 图像设置
* @desc 箭头图像锚点在X方向上相对锚点原点偏移的距离。若在0~1之间则为图像宽度比例,若大于1则为像素数。
* @default 0.8
*
* @param 锚点Y
* @parent 图像设置
* @desc 箭头图像锚点在Y方向上相对锚点原点偏移的距离。若在0~1之间则为图像高度比例,若大于1则为像素数。
* @default 0.5
*
* @param 混合模式
* @parent 图像设置
* @type select
* @option 0-普通
* @value 0
* @option 1-叠加
* @value 1
* @option 2-实色混合(正片叠底、相乘)
* @value 2
* @option 3-浅色
* @value 3
* @desc 图像渲染混合模式,PIXI的blendMode。
* @default 0
*
*
* @param 起点设置
* @default
*
* @param 起点类型(StartingPointType)
* @parent 起点设置
* @type select
* @option 边框中心(border_center)
* @value border_center
* @option 画面中心(screen_center)
* @value screen_center
* @option 玩家位置(player_screen_position)
* @value player_screen_position
* @option 左上角(top_left)
* @value top_left
* @desc 选择箭头方向的起点的位置。
* @default screen_center
*
* @param 起点X
* @parent 起点设置
* @desc 起点与起点原点的X方向额外偏移的距离。若-1~1之间为屏幕宽度比例,绝对值大于1则为像素数。
* @default 0
*
* @param 起点Y
* @parent 起点设置
* @desc 起点与起点原点的Y方向额外偏移的距离。若-1~1之间为屏幕高度比例,绝对值大于1则为像素数。
* @default 0
*
*
* @param 边框设置
* @default
*
* @param 边框类型(BorderType)
* @parent 边框设置
* @type select
* @option 矩形(rectangle)
* @value rectangle
* @option 椭圆(ellipse)
* @value ellipse
* @desc 箭头指向的目标在框外时,箭头在边框上移动。椭圆为对应矩形的内切椭圆。
* @default rectangle
*
* @param 边框原点类型(BorderOrigin)
* @parent 边框设置
* @type select
* @option 屏幕四边(screen_edges)
* @value screen_edges
* @option 屏幕中心(screen_center)
* @value screen_center
* @option 左上角(top_left)
* @value top_left
* @desc 选择边框线从哪个位置开始偏移。屏幕四边:边线从四周向内坍缩;屏幕中心:边线从中心向外膨胀。
* @default screen_edges
*
* @param 上界(topBound)
* @parent 边框设置
* @desc 矩形边框上边与原点的距离。若在0~1之间则为屏幕高度比例,若大于1则为像素数。
* @default 30
*
* @param 下界(bottomBound)
* @parent 边框设置
* @desc 矩形边框下边与原点的距离。若在0~1之间则为屏幕高度比例,若大于1则为像素数。
* @default 30
*
* @param 左界(leftBound)
* @parent 边框设置
* @desc 矩形边框左边与原点的距离。若在0~1之间则为屏幕宽度比例,若大于1则为像素数。
* @default 30
*
* @param 右界(rightBound)
* @parent 边框设置
* @desc 矩形边框右边与原点的距离。若在0~1之间则为屏幕宽度比例,若大于1则为像素数。
* @default 30
*
*
* @param 渐变与距离设置
* @default
*
* @param 渐变最远距离
* @parent 渐变与距离设置
* @desc 当屏幕中心与指定事件接近到一定程度,箭头图片就会开始变透明。填距离的像素数。
* @default 300
*
* @param 渐变最近距离
* @parent 渐变与距离设置
* @desc 当接近到更近时,箭头会彻底透明。填距离的像素数。
* @default 150
*
* @param 箭头与事件最近距离
* @parent 渐变与距离设置
* @desc 箭头会被目标事件(或目标位置)挤开一定距离。填写像素数。
* @default 30
*
*/

/**
* Kgg_MapArrows
* 地图箭头 命名空间
*/
var Kgg_MapArrows = Kgg_MapArrows || {};

// 加载插件设置
var Imported = Imported || {};
Imported.Kgg_MapArrows = true;
Kgg_MapArrows.parameters = PluginManager.parameters('Kgg_MapArrows');


// =================================================================
// 定义相关
// =================================================================

// 锚点原点类型的枚举
Kgg_MapArrows.AnchorOriginType = {
    IMAGE_CENTER: "image_center",   // 图像中心
    TOP_LEFT: "top_left"            // 左上角
};

// 边框类型的枚举
Kgg_MapArrows.BorderType = {
    RECTANGLE: "rectangle",         // 矩形
    ELLIPSE: "ellipse"              // 椭圆
};

// 边框原点的枚举
Kgg_MapArrows.BorderOrigin = {
    SCREEN_EDGES: "screen_edges",   // 屏幕四边
    SCREEN_CENTER: "screen_center", // 屏幕中心
    TOP_LEFT: "top_left"            // 左上角
};

// 起点类型的枚举
Kgg_MapArrows.StartingPointType = {
    BORDER_CENTER: "border_center", // 边框中心
    SCREEN_CENTER: "screen_center", // 屏幕中心
    PLAYER_SCREEN_POSITION: "player_screen_position", // 玩家位置
    TOP_LEFT: "top_left"            // 左上角
};

// 目标类型的枚举
Kgg_MapArrows.TargetType = {
    EVENT_ID: "event_id", // 边框中心
    MAP_POINT: "map_point", // 屏幕中心
    SCREEN_POINT: "screen_point" // 屏幕位置
};

/**
* 箭头样式类
*/
Kgg_MapArrows.ArrowStyle = function (name, imagePath, canRotate,
    anchorOrigin, anchorX, anchorY,
    startingPointType, startingPointX, startingPointY,
    gradientMaxDistance, gradientMinDistance,
    borderType, borderOrigin, topBound, bottomBound, leftBound, rightBound,
    arrowEventDistance, blendMode) {
    this.name = name;                                           // name 名称

    this.imagePath = imagePath;                                 // imagePath 图像(文件路径的string)
    this.canRotate = canRotate;                                 // canRotate 是否可旋转
    this.anchorOrigin = anchorOrigin;                           // anchorOrigin 锚点原点类型(二选一:图像中心、左上角) AnchorOriginType
    this.anchor = { "x": anchorX, "y": anchorY };               // anchorX anchorY 锚点(XY坐标偏移量)

    this.startingPointType = startingPointType;                 // startingPointType 起点类型
    this.startingPoint = { "x": startingPointX, "y": startingPointY }; // startingPointX startingPointX 起点(XY坐标偏移量)

    this.gradientMaxDistance = gradientMaxDistance;             // gradientMaxDistance 渐变最远距离(number)
    this.gradientMinDistance = gradientMinDistance;             // gradientMinDistance 渐变最近距离(number)

    this.borderType = borderType;                               // borderType 边框类型(二选一:矩形、椭圆形) BorderType
    this.borderOrigin = borderOrigin;                           // borderOrigin 边框原点类型(三选一:屏幕四边、屏幕中心、左上角) BorderOrigin
    this.topBound = topBound;                                   // topBound 上界(number)
    this.bottomBound = bottomBound;                             // bottomBound 下界(number)
    this.leftBound = leftBound;                                 // leftBound 左界(number)
    this.rightBound = rightBound;                               // rightBound 右界(number)

    this.arrowEventDistance = arrowEventDistance;               // arrowEventDistance 箭头与事件最近距离(number)
    this.blendMode = blendMode;                                 // blendMode 混合模式(0 1 2 3)

    this.border = null;                                         // border 初始化后存储矩形或椭圆对象
};

/**
* 箭头指向的目标
*/
Kgg_MapArrows.Target = function () {
    this.type = "";
    this.mapId = 0;
    this.eventId = 0;
    this._mapX = 0;
    this._mapY = 0;
    this._screenX = 0;
    this._screenY = 0;
};
Kgg_MapArrows.Target.prototype.initBySavedTarget = function (target) {
    this.type = target.type;
    this.mapId = target.mapId;
    this.eventId = target.eventId;
    this._mapX = target._mapX;
    this._mapY = target._mapY;
    this._screenX = target._screenX;
    this._screenY = target._screenY;
};
// 当前屏幕坐标x
Kgg_MapArrows.Target.prototype.x = function () {
    switch (this.type) {
        case Kgg_MapArrows.TargetType.EVENT_ID:
            return $gameMap.event(this.eventId).screenX();
        case Kgg_MapArrows.TargetType.MAP_POINT: // 照抄Game_CharacterBase.prototype.screenX
            var tw = $gameMap.tileWidth();
            var scrolledX = $gameMap.adjustX(this._mapX);
            return Math.round(scrolledX * tw + tw / 2);
        case Kgg_MapArrows.TargetType.SCREEN_POINT:
            return this._screenX;
        default:
            return;
    }
};
// 当前屏幕坐标y
Kgg_MapArrows.Target.prototype.y = function () {
    switch (this.type) {
        case Kgg_MapArrows.TargetType.EVENT_ID:
            return Kgg_MapArrows.Screen.correctedTargetY($gameMap.event(this.eventId).screenY());
        case Kgg_MapArrows.TargetType.MAP_POINT:
            var th = $gameMap.tileHeight();
            var scrolledY = $gameMap.adjustY(this._mapY);
            return Math.round(scrolledY * th + th / 2);
        case Kgg_MapArrows.TargetType.SCREEN_POINT:
            return this._screenY;
        default:
            return;
    }
};
// 初始化:指定ID的事件
Kgg_MapArrows.Target.prototype.initEventId = function (mapId, eventId) {
    this.type = Kgg_MapArrows.TargetType.EVENT_ID;
    this.mapId = mapId;
    this.eventId = eventId;
};
// 初始化:地图固定位置
Kgg_MapArrows.Target.prototype.initMapPoint = function (mapId, x, y) {
    this.type = Kgg_MapArrows.TargetType.MAP_POINT;
    this.mapId = mapId;
    this._mapX = x;
    this._mapY = y;
};
// 初始化:屏幕固定位置
Kgg_MapArrows.Target.prototype.initScreenPoint = function (mapId, x, y) {
    this.type = Kgg_MapArrows.TargetType.SCREEN_POINT;
    this.mapId = mapId;
    this._screenX = x;
    this._screenY = y;
};
/**
* 取目标点当前在屏幕上的坐标
* @param {Kgg_MapArrows.Target} target 已初始化的目标点
* @returns 坐标XY {x: x, y: y}
*/
Kgg_MapArrows.Target.getXY = function (target) {
    return { x: target.x(), y: target.y() };
};


/**
* 活动的箭头
*/
Kgg_MapArrows.ActiveArrow = function () {
    this.arrowStyle = null;
    this.target = null;
    this.sprite = null;
};
// 依据SavedArrow初始化ActiveArrow
Kgg_MapArrows.ActiveArrow.prototype.initialize = function (savedArrow) {
    this.arrowStyle = Kgg_MapArrows.arrowStyle(savedArrow.arrowStyleName);
    this.target = new Kgg_MapArrows.Target();
    this.target.initBySavedTarget(savedArrow.target);
};
// 为活动箭头设置Sprite
Kgg_MapArrows.ActiveArrow.prototype.setSprite = function (sprite) {
    this.sprite = sprite;
};

/**
* 保存的箭头
* 用于写入存档,需保证成员可序列化且足够简单。
*/
Kgg_MapArrows.SavedArrow = function () {
    this.arrowStyleName = "";   // 箭头样式名称
    this.target = null;         // 目标 {Kgg_MapArrows.Target}
};
// 初始化保存的箭头
Kgg_MapArrows.SavedArrow.prototype.initialize = function (arrowStyleName, target) {
    this.arrowStyleName = arrowStyleName;
    this.target = target;
};

// =================================================================
// 接口相关
// 其他插件如果需要与Kgg_MapArrows交互,建议使用以下这些函数。
// =================================================================

// $gameTemp._kgg_MapArrows_activeArrowMap 存放活动的箭头
// $gameSystem._kgg_MapArrows_arrowMap 存放需写入存档的箭头 不直接使用

/**
* 添加箭头,目标为事件
* 添加指向特定ID的事件的箭头,仅生效于一张地图。
* @param {String} name 新建箭头名称 用于移除箭头
* @param {String} arrowStyleName 箭头样式名称
* @param {Number} eventId 箭头指向的事件ID
* @param {Number} mapId 生效的地图ID 若不填则默认当前地图
*/
Kgg_MapArrows.addArrowToEvent = function (name, arrowStyleName, eventId, mapId) {
    mapId = mapId || $gameMap.mapId();
    // 创建箭头目标
    var target = new Kgg_MapArrows.Target();
    target.initEventId(mapId, eventId);
    return Kgg_MapArrows.addArrow(name, arrowStyleName, target);
};

/**
* 快捷添加箭头,目标为事件
* 添加指向特定事件的箭头,仅生效于一张地图。
* @param {Number} eventId 箭头指向的地图X坐标
* @param {Number} mapId 生效的地图ID 若不填则默认当前地图
*/
Kgg_MapArrows.addArrowToEventFast = function (eventId, mapId) {
    mapId = mapId || $gameMap.mapId(); // 默认取当前地图编号
    // 自动生成名称
    var name = Kgg_MapArrows.FastAdd.FAST_ADD_NAME_PREFIX;
    var ordinal = 0;
    while (Kgg_MapArrows.arrowExist(name + ordinal.toString())) {
        ordinal += 1;
    }
    name = name + ordinal.toString();
    // 选择默认箭头
    var arrowStyle = Kgg_MapArrows.arrowStyleList[Kgg_MapArrows.FastAdd.defaultStyleOrdinal - 1];
    return Kgg_MapArrows.addArrowToEvent(name, arrowStyle.name, eventId, mapId);
};

/**
* 添加箭头,目标为位置
* 添加指向特定地图坐标的箭头,仅生效于一张地图。
* @param {String} name 新建箭头名称 用于移除箭头
* @param {String} arrowStyleName 箭头样式名称
* @param {Number} mapX 箭头指向的地图X坐标
* @param {Number} mapY 箭头指向的地图Y坐标
* @param {Number} mapId 生效的地图ID 若不填则默认当前地图
*/
Kgg_MapArrows.addArrowToLocation = function (name, arrowStyleName, mapX, mapY, mapId) {
    mapId = mapId || $gameMap.mapId();
    // 创建箭头目标
    var target = new Kgg_MapArrows.Target();
    target.initMapPoint(mapId, mapX, mapY);
    return Kgg_MapArrows.addArrow(name, arrowStyleName, target);
};

/**
* 快捷添加箭头,目标为位置
* 添加指向特定地图坐标的箭头,仅生效于一张地图。
* @param {Number} mapX 箭头指向的地图X坐标
* @param {Number} mapY 箭头指向的地图Y坐标
* @param {Number} mapId 生效的地图ID 若不填则默认当前地图
*/
Kgg_MapArrows.addArrowToLocationFast = function (mapX, mapY, mapId) {
    mapId = mapId || $gameMap.mapId(); // 默认取当前地图编号
    // 自动生成名称
    var name = Kgg_MapArrows.FastAdd.FAST_ADD_NAME_PREFIX;
    var ordinal = 0;
    while (Kgg_MapArrows.arrowExist(name + ordinal.toString())) {
        ordinal += 1; // 如果名称冲突,就继续累加,直到找到不冲突的名称。
    }
    name = name + ordinal.toString();
    // 选择默认箭头
    var arrowStyle = Kgg_MapArrows.arrowStyleList[Kgg_MapArrows.FastAdd.defaultStyleOrdinal - 1];
    return Kgg_MapArrows.addArrowToLocation(name, arrowStyle.name, mapX, mapY, mapId);
};

/**
* 添加箭头
* 使用设置好的样式,添加指向目标的箭头,仅生效于一张地图。
* @param {String} name 新建箭头名称 用于移除箭头
* @param {String} arrowStyleName 箭头样式名称
* @param {Kgg_MapArrows.Target} target 箭头指向的目标
*/
Kgg_MapArrows.addArrow = function (name, arrowStyleName, target) {
    $gameSystem._kgg_MapArrows_arrowMap = $gameSystem._kgg_MapArrows_arrowMap || {};
    if (!!$gameSystem._kgg_MapArrows_arrowMap[name]) { // name已占用,中止。
        console.warn(`Kgg_MapArrows: 箭头名称 ${name} 已被占用。`);
        return false;
    }
    if (!Kgg_MapArrows.arrowStyle(arrowStyleName)) { // 样式不存在,中止。
        console.warn(`Kgg_MapArrows: 样式名称 ${arrowStyleName} 不存在。`);
        return false;
    }
    // 创建保存的箭头
    var savedArrow = new Kgg_MapArrows.SavedArrow();
    savedArrow.initialize(arrowStyleName, target);
    // 创建活动箭头
    var activeArrow = new Kgg_MapArrows.ActiveArrow();
    activeArrow.initialize(savedArrow);
    // 初始化图像
    Kgg_MapArrows.Image.initImage(activeArrow);
    // 添加到显示layer
    if (SceneManager._scene instanceof Scene_Map) {
        Kgg_MapArrows.Screen.addToLayer(activeArrow);
        Kgg_MapArrows.Screen.updateVisibility(activeArrow);
    }
    // 添加到存档和不存档临时位置
    $gameSystem._kgg_MapArrows_arrowMap[name] = savedArrow;
    $gameTemp._kgg_MapArrows_activeArrowMap[name] = activeArrow;
    return true;
};

/**
* 指定名称的箭头是否存在
* @param {String} name 箭头名称
* @returns 是否存在
*/
Kgg_MapArrows.arrowExist = function (name) {
    if (!!$gameSystem._kgg_MapArrows_arrowMap && !!$gameSystem._kgg_MapArrows_arrowMap[name]) return true;
    return false;
};

/**
* 移除指定名称的箭头
* @param {String} name 箭头名称
* @returns 此箭头是否存在并被清除
*/
Kgg_MapArrows.removeArrow = function (name) {
    if (!this.arrowExist(name)) { // 若name不存在,中止。
        return false;
    }
    // 移出layer
    var activeArrow = $gameTemp._kgg_MapArrows_activeArrowMap[name];
    Kgg_MapArrows.Screen.removeFromLayer(activeArrow);
    delete $gameTemp._kgg_MapArrows_activeArrowMap[name];
    delete $gameSystem._kgg_MapArrows_arrowMap[name];
    return true;
};

/**
* 清除指定样式的箭头
* @param {String} arrowStyleName 样式名称
*/
Kgg_MapArrows.clearArrowsByArrowStyle = function (arrowStyleName) {
    if (!$gameSystem._kgg_MapArrows_arrowMap) return;   // 检查保存的箭头所在容器是否存在
    var removingArrowNames = [];
    Object.keys($gameSystem._kgg_MapArrows_arrowMap).forEach(name => {
        if ($gameSystem._kgg_MapArrows_arrowMap[name].arrowStyleName == arrowStyleName) {
            removingArrowNames.push(name);
        }
    });
    removingArrowNames.forEach(name => {
        Kgg_MapArrows.removeArrow(name);
    });
};

/**
* 清除名称含有指定关键词的箭头
* @param {String} keyword 关键词
*/
Kgg_MapArrows.clearArrowsByKeyword = function (keyword) {
    if (!$gameSystem._kgg_MapArrows_arrowMap) return;   // 检查保存的箭头所在容器是否存在
    var removingArrowNames = [];
    Object.keys($gameSystem._kgg_MapArrows_arrowMap).forEach(name => {
        if (name.indexOf(keyword) != -1) {
            removingArrowNames.push(name);
        }
    });
    removingArrowNames.forEach(name => {
        Kgg_MapArrows.removeArrow(name);
    });
};

/**
* 清除所有快捷添加的箭头
*/
Kgg_MapArrows.clearFastArrows = function () {
    return Kgg_MapArrows.clearArrowsByKeyword(Kgg_MapArrows.FastAdd.FAST_ADD_NAME_PREFIX);
};

/**
* 清除所有箭头
*/
Kgg_MapArrows.clearAllArrows = function () {
    if (!$gameSystem._kgg_MapArrows_arrowMap) return;   // 检查保存的箭头所在容器是否存在
    var removingArrowNames = [];
    Object.keys($gameSystem._kgg_MapArrows_arrowMap).forEach(name => {
        removingArrowNames.push(name);
    });
    removingArrowNames.forEach(name => {
        Kgg_MapArrows.removeArrow(name);
    });
};

// =================================================================
// 起点相关处理
// =================================================================

Kgg_MapArrows.StartingPoint = {};
// Kgg:20231119 取消全局的起点设置,改为每个arrowStyle有自己的起点设置。
// 起点类型
// 起点一般是屏幕画面中心,也可能是玩家所在位置
// Kgg_MapArrows.StartingPoint.type = Kgg_MapArrows.StartingPointType.SCREEN_CENTER;
// 起点与屏幕左上角的距离。若在0-1之间则为比例,若大于1则视为像素数。只有起点类型选择“左上角”时才会生效。
// Kgg_MapArrows.StartingPoint.x = 0.5;
// Kgg_MapArrows.StartingPoint.y = 0.5;

/**
* 获取起点在屏幕上的位置
* @param {Kgg_MapArrows.ArrowStyle} arrowStyle 箭头样式
* @returns 起点在屏幕上的位置
*/
Kgg_MapArrows.StartingPoint.screenPoint = function (arrowStyle) {
    // 分类讨论
    var screenPoint = { x: 0, y: 0 };
    switch (arrowStyle.startingPointType) {
        case Kgg_MapArrows.StartingPointType.BORDER_CENTER: // 边界中心
            if (arrowStyle.borderType == Kgg_MapArrows.BorderType.ELLIPSE) {
                screenPoint = {    // 椭圆中心
                    x: arrowStyle.border.centerX,
                    y: arrowStyle.border.centerY
                };
            } else {
                screenPoint = {    // 矩形中心
                    x: arrowStyle.border.x + arrowStyle.border.width / 2,
                    y: arrowStyle.border.y + arrowStyle.border.height / 2
                };
            }
            break;
        case Kgg_MapArrows.StartingPointType.SCREEN_CENTER: // 画面中心
            screenPoint=  { x: Graphics.width / 2, y: Graphics.height / 2 };
            break;
        case Kgg_MapArrows.StartingPointType.PLAYER_SCREEN_POSITION: // 玩家位置
            if (!!$gamePlayer) {
                screenPoint = {
                    x: $gamePlayer.screenX(),
                    y: Kgg_MapArrows.Screen.correctedTargetY($gamePlayer.screenY())
                };
                break;
            }
        // 注意,这里不break。如果$gamePlayer不存在,就继续往下运行,取左上角像素位置。
        case Kgg_MapArrows.StartingPointType.TOP_LEFT:
            break;
        default:
            break;
    }
    // 额外偏移量
    var x = arrowStyle.startingPoint.x, y = arrowStyle.startingPoint.y;
    screenPoint.x += (x > -1 && x < 1) ? Graphics.width * x : x;
    screenPoint.y += (y > -1 && y < 1) ? Graphics.height * y : y;
    return screenPoint;
};

// =================================================================
// 箭头样式相关处理
// =================================================================

Kgg_MapArrows.arrowStyleList = [];          // 箭头样式列表
Kgg_MapArrows.arrowStyleList.length = 20;
Kgg_MapArrows.arrowStyle = function (name) {
    return Kgg_MapArrows.arrowStyleList.find((style) => {
        return style.name == name;
    });
};

// 初始化全部样式的边框
Kgg_MapArrows.initAllBorder = function () {
    for (var i = 0; i < Kgg_MapArrows.arrowStyleList.length; i++) {
        Kgg_MapArrows.initBorder(Kgg_MapArrows.arrowStyleList);
    }
};

// 根据边框类型初始化边框对象
Kgg_MapArrows.initBorder = function (arrowStyle) {
    if (!arrowStyle) return;
    var x1 = arrowStyle.leftBound, x2 = arrowStyle.rightBound, y1 = arrowStyle.topBound, y2 = arrowStyle.bottomBound;
    switch (arrowStyle.borderOrigin) {
        case Kgg_MapArrows.BorderOrigin.SCREEN_EDGES: // 屏幕四边
            x1 = (x1 < 1 && x1 > 0) ? Graphics.width * x1 : x1;         // 转换为左上角参考系的像素数
            x2 = (x2 < 1 && x2 > 0) ? Graphics.width * (1 - x2) : Graphics.width - x2;
            y1 = (y1 < 1 && y1 > 0) ? Graphics.height * y1 : y1;
            y2 = (y2 < 1 && y2 > 0) ? Graphics.height * (1 - y2) : Graphics.height - y2;
            break;
        case Kgg_MapArrows.BorderOrigin.SCREEN_CENTER: // 屏幕中心
            x1 = Graphics.width / 2 - ((x1 < 1 && x1 > 0) ? Graphics.width * x1 : x1); // 转换为左上角参考系的像素数
            x2 = Graphics.width / 2 + ((x2 < 1 && x2 > 0) ? Graphics.width * x2 : x2);
            y1 = Graphics.height / 2 - ((y1 < 1 && y1 > 0) ? Graphics.height * y1 : y1);
            y2 = Graphics.height / 2 + ((y2 < 1 && y2 > 0) ? Graphics.height * y2 : y2);
            break;
        default: // 左上角
            x1 = (x1 < 1 && x1 > 0) ? Graphics.width * x1 : x1;
            x2 = (x2 < 1 && x2 > 0) ? Graphics.width * x2 : x2;
            y1 = (y1 < 1 && y1 > 0) ? Graphics.height * y1 : y1;
            y2 = (y2 < 1 && y2 > 0) ? Graphics.height * y2 : y2;
            break;
    }
    var border = Kgg_MapArrows.Caculation.getRectangle(x1, x2, y1, y2);
    if (arrowStyle.borderType == Kgg_MapArrows.BorderType.ELLIPSE) {
        border = Kgg_MapArrows.Caculation.getInscribedEllipse(border);
    }
    arrowStyle.border = border;
};

// =================================================================
// 图像相关
// =================================================================
Kgg_MapArrows.Image = {};

// 初始化图像
Kgg_MapArrows.Image.initImage = function (activeArrow) {
    // 读取图像
    var filename = activeArrow.arrowStyle.imagePath;
    var img = ImageManager.loadBitmap('img/system/', filename);
    // 不确定路径是否这样设置,要看ArrowStyle是怎么设置的。
    var sprite = new Sprite(img);
    // Kgg:20231101 若要载入多张图片,就在这里写个循环。
    // Kgg:20231115 不做一个箭头样式多张图片的功能了,有需要的可以叠加显示多个箭头。
    // 将图片交给活动箭头
    activeArrow.setSprite(sprite);
    // 根据样式设置锚点
    Kgg_MapArrows.Image.initAnchorFromStyle(activeArrow);
};

// 根据箭头样式初始化活动箭头的sprite的锚点
Kgg_MapArrows.Image.initAnchorFromStyle = function (activeArrow) {
    if (!activeArrow || !activeArrow.sprite) return;
    var arrowStyle = activeArrow.arrowStyle;
    var anchor = arrowStyle.anchor;
    // PIXI的anchor默认是基于比例的,而不是像素数。因此这里要把大于1的转换为比例。
    var anchorX = anchor.x > 1 ? anchor.x / activeArrow.sprite.width : anchor.x;
    var anchorY = anchor.y > 1 ? anchor.y / activeArrow.sprite.height : anchor.y;
    // 若选择锚点的原点是图片中心,则给锚点位置的比例值再加上0.5。
    switch (arrowStyle.anchorOrigin) {
        case Kgg_MapArrows.AnchorOriginType.IMAGE_CENTER:
            anchorX += 0.5;
            anchorY += 0.5;
            break;
        case Kgg_MapArrows.AnchorOriginType.TOP_LEFT:
            break;
        default:
            break;
    }
    activeArrow.sprite.anchor.set(anchorX, anchorY);
};

// 旋转图像
Kgg_MapArrows.Image.setRotationByTwoPoints = function (activeArrow, x1, y1, x2, y2) {
    if (!activeArrow) return;
    var rotation = Kgg_MapArrows.Caculation.getAngle(x1, y1, x2, y2);
    activeArrow.sprite.rotation = rotation;
};

// =================================================================
// 地图相关
// 负责与Scene_Map交互
// =================================================================
Kgg_MapArrows.Map = {};

// 地图场景创建显示层时,加入箭头显示层。
Kgg_MapArrows.Map.createDisplayObjects = Scene_Map.prototype.createDisplayObjects;
Scene_Map.prototype.createDisplayObjects = function () {
    Kgg_MapArrows.Map.createDisplayObjects.apply(this, arguments);
    Kgg_MapArrows.Screen.addLayer(this);
};

// 切换地图时,显示设为在当前地图显示的箭头。
Kgg_MapArrows.Map.start = Scene_Map.prototype.start;
Scene_Map.prototype.start = function () {
    Kgg_MapArrows.Map.start.apply(this, arguments);
    if (!Kgg_MapArrows.arrowStyleBorderReady) {
        Kgg_MapArrows.initAllBorder(); // 初始化ArrowStyle的border
        // 之所以选择在进入地图的时候初始化边框,是因为初始化太早会导致取不到Graphics的属性。
        Kgg_MapArrows.arrowStyleBorderReady = true; // 避免重复计算
    }
    Kgg_MapArrows.Map.needFirstUpdate = true;
};

// 地图场景刷新时,地图箭头也刷新。
Kgg_MapArrows.Map.update = Scene_Map.prototype.update;
Scene_Map.prototype.update = function () {
    Kgg_MapArrows.Map.update.apply(this, arguments);
    Kgg_MapArrows.Map.firstUpdate();
    Kgg_MapArrows.Screen.updateAllArrow();
};

// 进入地图首次刷新时,加载箭头。
Kgg_MapArrows.Map.firstUpdate = function () {
    if (Kgg_MapArrows.Map.needFirstUpdate) {
        Kgg_MapArrows.Map.needFirstUpdate = false;
        // 加载所有箭头
        // $gameSystem._kgg_MapArrows_arrowMap = $gameSystem._kgg_MapArrows_arrowMap || {}; // 取存档中的gameSystem中的savedArrow
        $gameTemp._kgg_MapArrows_activeArrowMap = $gameTemp._kgg_MapArrows_activeArrowMap || {}; // 读取临时数据中的activeArrowMap
        var arrowMap = $gameTemp._kgg_MapArrows_activeArrowMap; // 读取临时数据中的每个activeArrow
        Object.keys(arrowMap).forEach(name => {
            var activeArrow = arrowMap[name];
            // 将$gameTemp._kgg_MapArrows_activeArrowMap中的每一个箭头按条件加入显示层。
            if (activeArrow.target.mapId == $gameMap.mapId()) {
                // 初始化图像
                Kgg_MapArrows.Image.initImage(activeArrow);
                // 添加到显示layer
                Kgg_MapArrows.Screen.addToLayer(activeArrow);
                // Kgg_MapArrows.Screen.updateVisibility(activeArrow);
            }
            // Kgg_MapArrows.addArrow(name, activeArrow.arrowStyle.name, activeArrow.target);
            Kgg_MapArrows.Screen.addToLayer($gameTemp._kgg_MapArrows_activeArrowMap[name]); // 加入Layer
        });
        Kgg_MapArrows.Screen.updateAllVisibility(); // 刷新可见性,依据地图ID是否等于生效的mapId条件。
    }
};

// =================================================================
// 存读档相关
// 负责与Game_System交互
// =================================================================
/*
* 添加箭头或读取存档时,会向$gameSystem._kgg_MapArrows_arrowMap加入箭头
* 数据,并复制一份放在$gameTemp._kgg_MapArrows_activeArrowMap。
* $gameTemp同时会存放Sprite对象。
* 后续的处理使用$gameTemp中的数据。
* 容易与之混淆的是$gameTemp._kgg_MapArrows_arrowLayer,这个是全部
* 箭头所在的层。
*/
Kgg_MapArrows.SaveLoad = {};

// 存进$gameSystem的数据会自动保存进存档,存档时无需额外处理

// 读取存档后处理,加入地图箭头的处理
Kgg_MapArrows.SaveLoad.onAfterLoad = Game_System.prototype.onAfterLoad;
Game_System.prototype.onAfterLoad = function () {
    Kgg_MapArrows.SaveLoad.onAfterLoad.call(this);
    Kgg_MapArrows.onLoadData();
};

// 读取存档后地图箭头的处理
Kgg_MapArrows.onLoadData = function () {
    var savedArrows = $gameSystem._kgg_MapArrows_arrowMap || {}; // 取存档中的gameSystem中的savedArrow
    $gameTemp._kgg_MapArrows_activeArrowMap = {};
    Object.keys(savedArrows).forEach(name => { // 在$gameTemp中创建$gameSystem中的每一个箭头
        var savedArrow = savedArrows[name];
        // 创建活动箭头
        var activeArrow = new Kgg_MapArrows.ActiveArrow();
        activeArrow.initialize(savedArrow);
        // 添加到不存档临时位置
        $gameTemp._kgg_MapArrows_activeArrowMap[name] = activeArrow;
    });
};

// =================================================================
// 屏幕相关
// =================================================================
Kgg_MapArrows.Screen = {};

Kgg_MapArrows.Screen.displayBorder = false; // 是否显示边框线,默认为否。

// 坐标y轴固定偏移18像素
Kgg_MapArrows.Screen.correctedTargetY = function (targetY) {
    return targetY - 18;
};

// 添加箭头显示层
Kgg_MapArrows.Screen.addLayer = function (scene) {
    $gameTemp._kgg_MapArrows_arrowLayer = new Sprite();
    $gameTemp._kgg_MapArrows_arrowLayer.__note__ = "显示箭头的层";
    if (!!scene) {
        scene.addChild($gameTemp._kgg_MapArrows_arrowLayer);
    } else {
        SceneManager._scene.addChild($gameTemp._kgg_MapArrows_arrowLayer);
    }
};

// 刷新整个箭头层级的透明度,依据是是否正在对话
Kgg_MapArrows.Screen.updateArrowLayerOpacity = function () {
    if (!$gameTemp._kgg_MapArrows_arrowLayer) return;
    $gameTemp._kgg_MapArrows_arrowLayer.opacity += !$gameMessage.isBusy() ? 12 : -12;
};

// 将箭头加入显示层级
Kgg_MapArrows.Screen.addToLayer = function (activeArrow) {
    if (!activeArrow || !activeArrow.sprite) {
        console.warn("Kgg_MapArrows.Screen.addToLayer: 参数错误");
        return;
    }
    if (!!$gameTemp._kgg_MapArrows_arrowLayer) {
        $gameTemp._kgg_MapArrows_arrowLayer.addChild(activeArrow.sprite);
    }
    if (this.displayBorder) {
        this.addTestLine(activeArrow.arrowStyle);
    }
};

// 将箭头移出显示层级
Kgg_MapArrows.Screen.removeFromLayer = function (activeArrow) {
    if (!activeArrow || !activeArrow.sprite) return;
    if (!!$gameTemp._kgg_MapArrows_arrowLayer) {
        $gameTemp._kgg_MapArrows_arrowLayer.removeChild(activeArrow.sprite);
    }
};

// 刷新某个箭头可见性
Kgg_MapArrows.Screen.updateVisibility = function (activeArrow) {
    if (!activeArrow || !activeArrow.sprite) return;
    activeArrow.sprite.visible = activeArrow.target.mapId == $gameMap.mapId();
};

// 刷新所有箭头的可见性
Kgg_MapArrows.Screen.updateAllVisibility = function () {
    for (var key in $gameTemp._kgg_MapArrows_activeArrowMap) {
        var o = $gameTemp._kgg_MapArrows_activeArrowMap[key];
        Kgg_MapArrows.Screen.updateVisibility(o);
    }
};

// 刷新某个箭头位置
Kgg_MapArrows.Screen.updatePosition = function (activeArrow) {
    // 计算与边框交点
    // A是起点(屏幕中心点),B是目标点,C是直线AB与边框border的交点(交点有两个取距离B近的),F是最终确定的箭头位置。
    // activeArrow.sprite.x = 0;
    // activeArrow.sprite.y = 0;
    var arrowEventDistance = activeArrow.arrowStyle.arrowEventDistance;
    var borderType = activeArrow.arrowStyle.borderType;
    var border = activeArrow.arrowStyle.border;
    var pointA = Kgg_MapArrows.StartingPoint.screenPoint(activeArrow.arrowStyle);
    var pointB = Kgg_MapArrows.Target.getXY(activeArrow.target);
    var pointC = { x: 0, y: 0 };
    var pointF = { x: -7777, y: -7777 };
    var pointBInsideBorder;

    // 判断B是否在border内
    if (borderType == Kgg_MapArrows.BorderType.RECTANGLE) {
        pointBInsideBorder = Kgg_MapArrows.Caculation.isPointInRectangle(border, pointB);
    } else if (borderType == Kgg_MapArrows.BorderType.ELLIPSE) {
        pointBInsideBorder = Kgg_MapArrows.Caculation.isPointInEllipse(border, pointB);
    }

    if (pointBInsideBorder) {
        // 若B在border内,则取射线BA上符合BC距离的点。
        pointF = Kgg_MapArrows.Caculation.getPointOnRay(pointB, pointA, arrowEventDistance);
    } else {
        // 若B在border外,且C距离B 大于 BC最近距离,则取交点C
        // 若B在border外,且C距离B 小于 BC最近距离,则取射线BA上符合BC距离的点。
        if (borderType == Kgg_MapArrows.BorderType.RECTANGLE) {
            pointC = Kgg_MapArrows.Caculation.getIntersectionPoint(border, pointA, pointB);
        } else if (borderType == Kgg_MapArrows.BorderType.ELLIPSE) {
            pointC = Kgg_MapArrows.Caculation.getEllipseIntersectionPoint(border, pointA, pointB);
        }
        if ((pointC.x - pointB.x) * (pointC.x - pointB.x) + (pointC.y - pointB.y) * (pointC.y - pointB.y) >= arrowEventDistance * arrowEventDistance) {
            // 当C距离B 大于 BC最近距离
            pointF = pointC;
        } else {
            // 当C距离B 小于 BC最近距离
            pointF = Kgg_MapArrows.Caculation.getPointOnRay(pointB, pointA, arrowEventDistance);
        }
    }
    // 设置箭头Sprite的位置
    activeArrow.sprite.position.set(pointF.x, pointF.y);
};

// 刷新某个箭头旋转
Kgg_MapArrows.Screen.updateRotation = function (activeArrow) {
    if (activeArrow.arrowStyle.canRotate == false) return;
    var startingPoint = Kgg_MapArrows.StartingPoint.screenPoint(activeArrow.arrowStyle);
    var targetPoint = Kgg_MapArrows.Target.getXY(activeArrow.target);
    Kgg_MapArrows.Image.setRotationByTwoPoints(activeArrow, startingPoint.x, startingPoint.y, targetPoint.x, targetPoint.y);
};

// 刷新某个箭头渐变透明度,依据画面中心坐标是否足够接近目标
Kgg_MapArrows.Screen.updateAlpha = function (activeArrow) {
    var minDistance = activeArrow.arrowStyle.gradientMinDistance; // 渐变开始距离(完全透明)
    var maxDistance = activeArrow.arrowStyle.gradientMaxDistance; // 渐变结束距离(完全不透明)
    var startingPoint = Kgg_MapArrows.StartingPoint.screenPoint(activeArrow.arrowStyle);  // 起点
    var targetPoint = Kgg_MapArrows.Target.getXY(activeArrow.target); // 目标点
    // 求当前距离在渐变数轴的哪个位置
    var gradientDistance = maxDistance - minDistance;
    var targetDistance = Math.sqrt((startingPoint.x - targetPoint.x) ** 2 + (startingPoint.y - targetPoint.y) ** 2) - minDistance;
    var ratio = Math.min(Math.max(targetDistance / gradientDistance, 0), 1);
    activeArrow.sprite.alpha = ratio;
};

// 刷新所有箭头(位置、旋转、透明度)
Kgg_MapArrows.Screen.updateAllArrow = function () {
    this.updateArrowLayerOpacity();
    for (var key in $gameTemp._kgg_MapArrows_activeArrowMap) {
        var o = $gameTemp._kgg_MapArrows_activeArrowMap[key];
        if (!!o.sprite && o.sprite.visible) {
            // Kgg_MapArrows.Screen.updateVisibility(o);
            // if (o.target.mapId != $gameMap.mapId()) continue; // 校验地图是否正确
            Kgg_MapArrows.Screen.updatePosition(o);
            Kgg_MapArrows.Screen.updateRotation(o);
            Kgg_MapArrows.Screen.updateAlpha(o);
        }
    }
};

// 显示边界线 仅调试用
// 注意,没有提供清除这些边界线的方法。
Kgg_MapArrows.Screen.addTestLine = function (arrowStyle) {
    var stage = SceneManager._scene;
    // 随机颜色
    var color = Math.random() * 0xffffff;
    if (arrowStyle.borderType == Kgg_MapArrows.BorderType.ELLIPSE) {
        var x = arrowStyle.border.centerX;
        var radiusX = arrowStyle.border.radiusX;
        var y = arrowStyle.border.centerY;
        var radiusY = arrowStyle.border.radiusY;
        // 绘制边框线
        var borderTestLine = new PIXI.Graphics();
        borderTestLine.lineStyle(5, color);
        borderTestLine.drawEllipse(x, y, radiusX, radiusY);
        stage.addChild(borderTestLine);
    } else {
        var x = arrowStyle.border.x;
        var width = arrowStyle.border.width;
        var y = arrowStyle.border.y;
        var height = arrowStyle.border.height;
        // 绘制边框线
        var borderTestLine = new PIXI.Graphics();
        borderTestLine.lineStyle(5, color);
        borderTestLine.drawRect(x, y, width, height);
        stage.addChild(borderTestLine);
    }
};

// =================================================================
// 计算相关
// =================================================================
Kgg_MapArrows.Caculation = {};

// 定义一个矩形,由两条垂直线(x1和x2)和两条水平线(y1和y2)组成
Kgg_MapArrows.Caculation.getRectangle = function (x1, x2, y1, y2) {
    var width = Math.abs(x2 - x1);    // 宽
    var height = Math.abs(y2 - y1);   // 高
    var x = Math.min(x1, x2);         // 左上点x
    var y = Math.min(y1, y2);         // 左上点y
    return { x, y, width, height };
};
// 定义一个椭圆,是根据矩形得到的内切椭圆
Kgg_MapArrows.Caculation.getInscribedEllipse = function (rectangle) {
    var centerX = rectangle.x + rectangle.width / 2;  // 中点x
    var centerY = rectangle.y + rectangle.height / 2; // 中点y
    var radiusX = rectangle.width / 2;                // 水平半径
    var radiusY = rectangle.height / 2;               // 垂直半径
    return { centerX, centerY, radiusX, radiusY };
};
// 根据两点得到一条直线(后来没用上这个函数)
Kgg_MapArrows.Caculation.getLine = function (point1, point2) {
    var slope = (point2.y - point1.y) / (point2.x - point1.x);
    var yIntercept = point1.y - slope * point1.x;
    return { slope, yIntercept }; // 直线方程: y = slope * x + yIntercept
};
// 根据矩形、点A与点B的坐标,输出点A向点B发射的射线与矩形的交点
Kgg_MapArrows.Caculation.getIntersectionPoint = function (rectangle, pointA, pointB) {
    var { x: rectX, y: rectY, width: rectWidth, height: rectHeight } = rectangle;
    var { x: pointAX, y: pointAY } = pointA;
    var { x: pointBX, y: pointBY } = pointB;

    // 计算射线斜率
    var slope = (pointBX - pointAX) === 0 ? null : (pointBY - pointAY) / (pointBX - pointAX);

    // 计算射线与矩形四条边的交点
    var topIntersection = slope === null ? { x: pointAX, y: rectY } : slope === 0 ? null : { x: pointAX + (rectY - pointAY) / slope, y: rectY };
    var bottomIntersection = slope === null ? { x: pointAX, y: rectY + rectHeight } : slope === 0 ?
        null : { x: pointAX + (rectY + rectHeight - pointAY) / slope, y: rectY + rectHeight };
    var leftIntersection = slope === null ? null : { x: rectX, y: pointAY + (rectX - pointAX) * slope };
    var rightIntersection = slope === null ? null : { x: rectX + rectWidth, y: pointAY + (rectX + rectWidth - pointAX) * slope };

    // 判断交点是否在矩形内部
    var intersections = [topIntersection, bottomIntersection, leftIntersection, rightIntersection].filter(intersection => intersection !== null);
    var validIntersections = intersections.filter(intersection => {
        return intersection.x >= rectX && intersection.x <= rectX + rectWidth && intersection.y >= rectY && intersection.y <= rectY + rectHeight;
    });

    // 返回最近的交点
    if (validIntersections.length === 0) {
        return { x: -8888, y: -8888 };
    } else {
        var minDistance = Infinity;
        var closestIntersection = null;
        validIntersections.forEach(intersection => {
            var distance = Math.sqrt((intersection.x - pointBX) ** 2 + (intersection.y - pointBY) ** 2);
            if (distance < minDistance) {
                minDistance = distance;
                closestIntersection = intersection;
            }
        });
        return closestIntersection;
    }
};

// 点B是否在矩形内
Kgg_MapArrows.Caculation.isPointInRectangle = function (rectangle, pointB) {
    return pointB.x >= rectangle.x && pointB.x <= rectangle.x + rectangle.width &&
        pointB.y >= rectangle.y && pointB.y <= rectangle.y + rectangle.height;
};
// 点B是否在椭圆内
Kgg_MapArrows.Caculation.isPointInEllipse = function (ellipse, pointB) {
    var { centerX, centerY, radiusX, radiusY } = ellipse;
    var dx = pointB.x - centerX;
    var dy = pointB.y - centerY;
    return (dx * dx) / (radiusX * radiusX) + (dy * dy) / (radiusY * radiusY) <= 1;
};

// 输入点A、B坐标,输入点C与点B的距离,得到在射线BA上的点C的坐标。
Kgg_MapArrows.Caculation.getPointOnRay = function (pointA, pointB, distanceCB) {
    // 计算向量AB
    var vectorAB = { x: pointB.x - pointA.x, y: pointB.y - pointA.y };
    // 计算向量AB的长度
    var lengthAB = Math.sqrt(vectorAB.x * vectorAB.x + vectorAB.y * vectorAB.y);
    // 计算单位向量AB
    var unitVectorAB = { x: vectorAB.x / lengthAB, y: vectorAB.y / lengthAB };
    // 计算向量AC
    var vectorAC = { x: unitVectorAB.x * distanceCB, y: unitVectorAB.y * distanceCB };
    // 计算点C的坐标
    var pointC = { x: pointA.x + vectorAC.x, y: pointA.y + vectorAC.y };
    return pointC;
};

// 根据椭圆、点A与点B的坐标,输出点A向点B发射的射线与椭圆的交点
/*
* 2023.10.27
* 椭圆可以做,只是我高中数学都忘了。
* 1 把坐标系变换到椭圆中心
* 2 得到直线方程和椭圆方程
* 3 联立直线方程和椭圆方程,得到一元二次方程
* 4 用判别式b^2-4ac知道是否有交点
* 5 求出两个交点,看方向。
*
* 如果第2步算y=kx+b的时候得不到k,说明直线是竖直的,直接代入x看有没有交点,若有就取交点看方向。
*/
// __times__ = 0;
Kgg_MapArrows.Caculation.getEllipseIntersectionPoint = function (ellipse, pointA, pointB) {
    // __times__++;
    var { centerX, centerY, radiusX, radiusY } = ellipse; // 获取椭圆属性
    var { x: x1, y: y1 } = pointA;                        // 获取点A(屏幕中心)
    var { x: x2, y: y2 } = pointB;                        // 获取点B(目标点)

    // 将直线的坐标系变换到椭圆中心
    var x1_ = x1 - centerX;
    var y1_ = y1 - centerY;
    var x2_ = x2 - centerX;
    var y2_ = y2 - centerY;

    // 计算直线AB的斜率
    var k = (y2_ - y1_) / (x2_ - x1_);
    // 直线斜率不存在的情况
    if (k === Infinity || k === -Infinity) {
        if (Math.abs(x1_) < radiusX) { // 有交点
            var x_ = x1_;
            var y_ = radiusY * Math.sqrt(radiusX ** 2 - x_ ** 2) / radiusX;
            if (y2_ < 0) y_ = -y_; // 区分在上还是在下
            var x = x_ + centerX;
            var y = y_ + centerY;
            return { x, y };
        }
        return { x: 9999, y: 9999 };
    }

    // 计算直线AB的截距
    var c = y1_ - k * x1_;

    // 计算判别式
    // A、B、C是一元二次方程中的项系数,一元二次标准方程Ax^2+Bx+C=0
    var A = radiusY ** 2 + radiusX ** 2 * k ** 2;
    var B = 2 * radiusX ** 2 * k * c;
    var C = radiusX ** 2 * c ** 2 - radiusX ** 2 * radiusY ** 2;
    var delta = B ** 2 - 4 * A * C;

    // 分类讨论交点个数
    if (delta < 0) { // 没有交点
        return { x: 9999, y: 9999 };
    } else if (delta === 0) { // 有一个交点
        var x_ = -B / (2 * A);
        var y_ = k * x_ + c;
        // 转回屏幕坐标
        var x = x_ + centerX;
        var y = y_ + centerY;
        return { x, y };
    } else { // 有两个交点
        // 用求根公式
        var x_3 = (-B + Math.sqrt(delta)) / (2 * A); // 第一个根
        var y_3 = k * x_3 + c;
        var x_4 = (-B - Math.sqrt(delta)) / (2 * A); // 第二个根
        var y_4 = k * x_4 + c;
        var distance3_square = (x_3 - x2_) * (x_3 - x2_) + (y_3 - y2_) * (y_3 - y2_);
        var distance4_square = (x_4 - x2_) * (x_4 - x2_) + (y_4 - y2_) * (y_4 - y2_);
        // if (__times__ % 2) { // 让两个都显示出来用于测试
        if (distance3_square < distance4_square) { // 判断哪个点离目标点近
            var x = x_3 + centerX; // 转回屏幕坐标
            var y = y_3 + centerY;
            return { x, y };
        } else {
            var x = x_4 + centerX; // 转回屏幕坐标
            var y = y_4 + centerY;
            return { x, y };
        }
    }
};

Kgg_MapArrows.Caculation.getAngle = function (x1, y1, x2, y2) {
    var dx = x2 - x1;
    var dy = y2 - y1;
    return Math.atan2(dy, dx);
};

// =================================================================
// 快捷添加相关
// =================================================================
Kgg_MapArrows.FastAdd = {};
Kgg_MapArrows.FastAdd.defaultStyleOrdinal = 1;
/**
* 快捷添加箭头名称前缀
* 插件指令的空格是参数分隔符,插件指令添加的箭头名称不可能有空格。
* 快捷箭头名称的前缀中包含空格,可以保证区别于用户用插件指令添加的箭头。
*/
Kgg_MapArrows.FastAdd.FAST_ADD_NAME_PREFIX = "fast_arrow: ";

// =================================================================
// 插件指令相关
// 负责与Game_Interpreter交互
// =================================================================
/*
* 插件指令格式:
* ----------------------------------------------------------
* 功能:快捷添加默认样式的箭头,指向事件或位置
* 插件指令:
* >地图箭头 : 快捷添加 : 事件[15]
* >地图箭头 : 快捷添加 : 位置[15,16]
* >地图箭头 : 快捷添加 : 事件[15] : 地图[2]
* >地图箭头 : 快捷添加 : 位置[15,16] : 地图[2]
* 说明:
* 这是添加箭头指令的简化版,省略了名称和样式名,尽量简化参数,方便
* 快速上手。
* ----------------------------------------------------------
* 功能:清除所有快捷添加的箭头
* 插件指令:
* >地图箭头 : 清除快捷箭头
* ----------------------------------------------------------
* 功能:在本地图添加箭头,指向事件或位置,可以用常量或变量指定
* 插件指令:
* >地图箭头 : 添加箭头 : 名称 : 样式名 : 事件[15]
* >地图箭头 : 添加箭头 : 名称 : 样式名 : 事件变量[15]
* >地图箭头 : 添加箭头 : 名称 : 样式名 : 位置[15,16]
* >地图箭头 : 添加箭头 : 名称 : 样式名 : 位置变量[15,16]
* 说明:
* 1.名称是自定义的。为箭头设置名称作用是区分不同箭头,移除箭头时用。
* 2.样式名可在插件管理器自定。
* 3.事件变量[15]代表箭头目标是“编号为第15号变量的值的事件”。
* 4.位置[15,16]代表地图中x为15,y为16的格子。
* 5.添加的箭头仅在当前地图生效,重新进入地图仍然生效。
* 6.变量[15]取的是当前的变量值,后续不会跟随变量变化。
* 举例:
* 添加一个箭头,名叫“张三”,样式是“默认样式”,指向本地图15号事件。
* >地图箭头 : 添加箭头 : 张三 : 默认样式 : 事件[15]
* ----------------------------------------------------------
* 功能:在指定地图添加箭头,指向事件
* 插件指令:
* >地图箭头 : 添加箭头 : 名称 : 样式名 : 事件[15] : 地图[1]
* >地图箭头 : 添加箭头 : 名称 : 样式名 : 事件[15] : 地图变量[1]
* 说明:
* 在上一种指令基础上,可以指定生效的地图编号。
* 举例:
* 添加一个箭头,名叫“张三”,样式是“默认样式”,它的目标是2号地图的
* 某个事件。至于是哪个事件,要看5号变量当前值是什么。
* >地图箭头 : 添加箭头 : 张三 : 默认样式 : 事件变量[5] : 地图[2]
* ----------------------------------------------------------
* 功能:按名称移除箭头
* 插件指令:
* >地图箭头 : 移除箭头 : 名称
* 说明:
* 移除指定名称的箭头。
* ----------------------------------------------------------
* 功能:按样式清除箭头
* 插件指令:
* >地图箭头 : 按样式清除箭头 : 样式名
* 说明:
* 在所有箭头中找出每个指定样式的箭头,进行移除。
* ----------------------------------------------------------
* 功能:按关键词清除箭头
* 插件指令:
* >地图箭头 : 按关键词清除箭头 : 关键词
* 说明:
* 在所有箭头中找出每个名称包含指定关键词的箭头,进行移除。
* ----------------------------------------------------------
* 功能:清除全部箭头
* 插件指令:
* >地图箭头 : 清除全部箭头
* 说明:
* 清除所有箭头,一个也不剩。
* =================================================================
*/
Kgg_MapArrows.Interpreter = {};

/**
* 指定目标类型 参数的处理
* @param {String} unit 指定目标的参数
* @returns 目标类型
*/
Kgg_MapArrows.Interpreter.targetType = function (unit) {
    if (unit.indexOf("事件") != -1) {
        return Kgg_MapArrows.TargetType.EVENT_ID;
    } else if (unit.indexOf("位置") != -1) {
        return Kgg_MapArrows.TargetType.MAP_POINT;
    } else if (unit.indexOf("屏幕") != -1) {
        return Kgg_MapArrows.TargetType.SCREEN_POINT;
    }
    return;
};

/**
* 指定目标事件 参数的处理
* @param {String} unit 指定目标事件的参数
* @returns 事件ID
*/
Kgg_MapArrows.Interpreter.targetEventId = function (unit) {
    var e_id;
    if (unit.indexOf("事件[") != -1) {
        unit = unit.replace("事件[", "");
        unit = unit.replace("]", "");
        e_id = Number(unit);
    }
    if (unit.indexOf("事件变量[") != -1) {
        unit = unit.replace("事件变量[", "");
        unit = unit.replace("]", "");
        e_id = $gameVariables.value(Number(unit));
    }
    return e_id;
};

/**
* 指定目标位置 参数的处理
* @param {String} unit 指定目标位置的参数
* @returns 目标在地图上的坐标
*/
Kgg_MapArrows.Interpreter.targetPoint = function (unit) {
    unit = String(unit);
    var targetPoint = { x: 0, y: 0 };
    if (unit.indexOf("位置[") != -1) {
        unit = unit.replace("位置[", "");
        unit = unit.replace("]", "");
        var pos = unit.split(/[,,]/);
        if (pos.length >= 2) {
            targetPoint.x = Number(pos[0]);
            targetPoint.y = Number(pos[1]);
        }
    } else if (unit.indexOf("位置变量[") != -1) {
        unit = unit.replace("位置变量[", "");
        unit = unit.replace("]", "");
        var pos = unit.split(/[,,]/);
        if (pos.length >= 2) {
            targetPoint.x = $gameVariables.value(Number(pos[0]));
            targetPoint.y = $gameVariables.value(Number(pos[1]));
        }
    } else {
        targetPoint = undefined;
    }
    return targetPoint;
};

// 指定地图的参数的处理,返回地图id
Kgg_MapArrows.Interpreter.mapId = function (mapIdUnit) {
    var mapId = $gameMap.mapId();
    if (!!mapIdUnit) {
        if (mapIdUnit.indexOf("地图[") != -1) {
            mapId = Number(mapIdUnit.replace("地图[", "").replace("]", ""));
        } else if (mapIdUnit.indexOf("地图变量[") != -1) {
            mapId = $gameVariables.value(Number(mapIdUnit.replace("地图变量[", "").replace("]", "")));
        }
    }
    return mapId;
};


// 重写pluginCommand
Kgg_MapArrows.Interpreter.pluginCommand = Game_Interpreter.prototype.pluginCommand;
Game_Interpreter.prototype.pluginCommand = function (command, args) {
    Kgg_MapArrows.Interpreter.pluginCommand.call(this, command, args);

    if (command == ">地图箭头") {
        // 双数位置是冒号“:”,例如args[0],args[2]等。
        if (args.length == 2) {
            var type = String(args[1]);
            if (type == "清除快捷箭头") {
                Kgg_MapArrows.clearFastArrows();
            }
            if (type == "清除全部箭头") {
                Kgg_MapArrows.clearAllArrows();
            }
        }
        if (args.length == 4 || args.length == 6) {
            var type = String(args[1]);
            var name = String(args[3]);
            if (type == "移除箭头") {
                Kgg_MapArrows.removeArrow(name);
            }
            if (type == "按样式清除箭头") {
                Kgg_MapArrows.clearArrowsByArrowStyle(name);
            }
            if (type == "按关键词清除箭头") {
                Kgg_MapArrows.clearArrowsByKeyword(name);
            }
            // 目标事件或位置处理
            var unit = String(args[3]);
            // 地图编号处理
            var mapId = $gameMap.mapId();
            if (args.length == 6) {
                mapId = Kgg_MapArrows.Interpreter.mapId(args[5]);
            }
            if (type == "快捷添加") {
                switch (Kgg_MapArrows.Interpreter.targetType(unit)) {
                    case Kgg_MapArrows.TargetType.EVENT_ID:
                        var e_id = Kgg_MapArrows.Interpreter.targetEventId(unit);
                        Kgg_MapArrows.addArrowToEventFast(e_id, mapId);
                        break;
                    case Kgg_MapArrows.TargetType.MAP_POINT:
                        var location = Kgg_MapArrows.Interpreter.targetPoint(unit);
                        Kgg_MapArrows.addArrowToLocationFast(location.x, location.y, mapId);
                        break;
                    default:
                        console.warn(`Kgg_MapArrows: ${unit} 不是有效的目标。`);
                        break;
                }
            }
        }
        if (args.length == 8 || args.length == 10) {
            var type = String(args[1]);
            var name = String(args[3]);
            var style = String(args[5]);
            var unit = String(args[7]);
            // 地图编号处理
            var mapId = $gameMap.mapId();
            if (args.length == 10) {
                mapId = Kgg_MapArrows.Interpreter.mapId(args[9]);
            }
            // 判断指令类型
            if (type == "添加箭头") {
                switch (Kgg_MapArrows.Interpreter.targetType(unit)) {
                    case Kgg_MapArrows.TargetType.EVENT_ID:
                        var e_id = Kgg_MapArrows.Interpreter.targetEventId(unit);
                        Kgg_MapArrows.addArrowToEvent(name, style, e_id, mapId);
                        break;
                    case Kgg_MapArrows.TargetType.MAP_POINT:
                        var location = Kgg_MapArrows.Interpreter.targetPoint(unit);
                        Kgg_MapArrows.addArrowToLocation(name, style, location.x, location.y, mapId);
                        break;
                    default:
                        console.warn(`Kgg_MapArrows: ${unit} 不是有效的目标。`);
                        break;
                }
            }
        }
    }
};

// =================================================================
// 进入游戏时立即处理
// =================================================================
// 读取插件设置的ArrowStyle,写入键值对。

// 调试设置
Kgg_MapArrows.Screen.displayBorder = Boolean(Kgg_MapArrows.parameters["显示边界线"] == "true");

// 快捷添加设置
Kgg_MapArrows.FastAdd.defaultStyleOrdinal = Number(Kgg_MapArrows.parameters["快捷添加默认样式"] || 1);

// 起点设置
// Kgg_MapArrows.StartingPoint.type = String(Kgg_MapArrows.parameters["起点类型"] || "screen_center");
// Kgg_MapArrows.StartingPoint.x = Number(Kgg_MapArrows.parameters["起点X"] || 0.5);
// Kgg_MapArrows.StartingPoint.y = Number(Kgg_MapArrows.parameters["起点Y"] || 0.5);
// Kgg:20231119 起点设置包含在每个arrowStyle当中,不再单独设置一个全局的起点。

// ---箭头样式组 1至20---
for (var i = 0; i < Kgg_MapArrows.arrowStyleList.length; i++) {
    if (Kgg_MapArrows.parameters["箭头-" + String(i + 1)] != undefined &&
        Kgg_MapArrows.parameters["箭头-" + String(i + 1)] != "") {
        var arrowStyleData = JSON.parse(Kgg_MapArrows.parameters["箭头-" + String(i + 1)]);
        // constructor(name, imagePath, anchorOrigin, anchorX, anchorY, gradientMaxDistance, gradientMinDistance, borderType,
        // borderOrigin, topBound, bottomBound, leftBound, rightBound, arrowEventDistance, blendMode) {
        var arrowStyle = new Kgg_MapArrows.ArrowStyle(
            String(arrowStyleData["名称"] || "未命名"),                 // name 名称
            String(arrowStyleData["箭头图像"] || "Shadow1"),            // imagePath 图像(文件路径的string)
            Boolean(arrowStyleData["是否可旋转"] == "true"),            // canRotate 是否可旋转
            String(arrowStyleData["锚点原点类型(AnchorOriginType)"]
                || Kgg_MapArrows.AnchorOriginType.TOP_LEFT),            // anchorOrigin 锚点原点类型(二选一:图像中心、左上角) AnchorOriginType
            Number(arrowStyleData["锚点X"] || 0.5),                     // anchorX 锚点(XY坐标偏移量)
            Number(arrowStyleData["锚点Y"] || 0.5),                     // anchorY

            String(arrowStyleData["起点类型(StartingPointType)"]
                || Kgg_MapArrows.StartingPointType.SCREEN_CENTER),      // startingPointType 起点类型
            Number(arrowStyleData["起点X"] || 0),                       // startingPointX 起点(XY坐标偏移量)
            Number(arrowStyleData["起点Y"] || 0),                       // startingPointY

            Number(arrowStyleData["渐变最远距离"] || 300),              // gradientMaxDistance 渐变最远距离(number)
            Number(arrowStyleData["渐变最近距离"] || 150),              // gradientMinDistance 渐变最近距离(number)

            String(arrowStyleData["边框类型(BorderType)"]
                || Kgg_MapArrows.BorderType.RECTANGLE),                 // borderType 边框类型(二选一:矩形、椭圆形) BorderType
            String(arrowStyleData["边框原点类型(BorderOrigin)"]
                || Kgg_MapArrows.BorderOrigin.SCREEN_EDGES),            // borderOrigin 边框原点类型(三选一:屏幕四边、屏幕中心、左上角) BorderOrigin
            Number(arrowStyleData["上界(topBound)"] || 0),              // topBound 上界(number)相对原点的偏移量
            Number(arrowStyleData["下界(bottomBound)"] || 0),           // bottomBound 下界(number)相对原点的偏移量
            Number(arrowStyleData["左界(leftBound)"] || 0),             // leftBound 左界(number)相对原点的偏移量
            Number(arrowStyleData["右界(rightBound)"] || 0),            // rightBound 右界(number)相对原点的偏移量

            Number(arrowStyleData["箭头与事件最近距离"] || 30),         // arrowEventDistance 箭头与事件最近距离(number)
            Number(arrowStyleData["混合模式"] || 0)                    // blendMode 混合模式(0 1 2 3)
        );
        Kgg_MapArrows.arrowStyleList = arrowStyle;
    }
};
[/pre]
[/fold]

[fold=此处有弃用但删不掉的帖子附件]
旧版本:请勿使用1.1版本,因为1.1版本有bug。
Kgg_MapArrows_Demo.zip (35.63 KB, 下载次数: 15)
Kgg_MapArrows_Demo_v1.1.zip (38.48 KB, 下载次数: 23, 售价: 1 星屑)
Kgg_MapArrows_Demo_v1.2.zip (38.42 KB, 下载次数: 59, 售价: 1 星屑)
弃用截图:

插件管理器

插件管理器

[/fold]

评分

参与人数 3赞 +3 收起 理由
马铃薯条 + 1
honmarei + 1 塞糖
shantianzu + 1 塞糖

查看全部评分

梦石
0
星屑
883
在线时间
123 小时
注册时间
2018-8-25
回帖
93
发表于 2023-11-13 03:36:22 | 显示全部楼层
这跟钻头的指向标有什么不同吗,能多个目标指示?

点评

(接上句)主要作用是玩家主动用鼠标移动时,显示寻路目的地;而本帖的插件指向位置或事件,最主要的作用是给玩家提供方向指引。  发表于 2023-11-13 09:53
我在Drill_up的小插件集合(https://rpg.blue/thread-411063-1-1.html)查找指向标,找到Drill_MouseDestination和Drill_MouseGridPointer。这俩插件是指示寻路目标的,  发表于 2023-11-13 09:48
请问钻头的指向标插件名称是什么?我在大佬的插件合集里找了好久找不到这个功能,才决定自己写的。(゚Д゚)ノ  发表于 2023-11-13 09:26
回复

使用道具 举报

梦石
0
星屑
883
在线时间
123 小时
注册时间
2018-8-25
回帖
93
发表于 2023-11-14 16:32:49 | 显示全部楼层
哦,钻头那个是原本MOG的指南针,可以指向一个目标。你这个好像能显示多个目标

点评

嗯嗯!你说得对,本插件的优势是能显示多个箭头。我应该在功能介绍中补充这点。  发表于 2023-11-14 18:51
回复

使用道具 举报

梦石
0
星屑
49
在线时间
10 小时
注册时间
2023-11-13
回帖
1
发表于 2023-11-14 21:08:07 | 显示全部楼层
正需要这个功能就看到这个插件了,感谢楼主。刚发现clearArrowsByArrowStyle没有检查$gameSystem._kgg_MapArrows_arrowMap是否为null,这样在没有箭头的时候用会报错。另外魔改了个目标在border之内时箭头不再跟踪旋转,而是保持悬浮在目标点上方的版本,个人比较喜欢这种效果,不过自己写的代码太差就不发上来了。

点评

你好!地图箭头v1.1有读档报错的bug,如果还在使用这个插件,强烈建议升级到目前最新的v1.2版本。  发表于 2024-3-10 17:31
谢谢你的认可!没有检查$gameSystem._kgg_MapArrows_arrowMap是否存在的问题这边记下来了,下个版本修复!  发表于 2023-11-14 22:07
回复

使用道具 举报

梦石
0
星屑
7801
在线时间
683 小时
注册时间
2012-7-29
回帖
172
 楼主| 发表于 2023-11-21 05:20:04 | 显示全部楼层
更新了v1.1。
v1.1 相比 v1.0 的变化:
增加快捷添加功能;将起点设置移到样式内;完善清除箭头的方法,修复已知bug。
回复

使用道具 举报

梦石
0
星屑
7801
在线时间
683 小时
注册时间
2012-7-29
回帖
172
 楼主| 发表于 2024-3-10 16:57:39 | 显示全部楼层
地图箭头插件的用户,您好!
v1.1版本,当有箭头时,存档再读档会报错“x is not a function”,很抱歉现在才发现。如果您仍然在使用此插件,强烈建议您更新到目前最新的v1.2版本。经测试,更新不会产生副作用。




v1.2 相比 v1.1 的变化:
有箭头时读档不再报错“x is not a function”。

更新方法:
下载并解压新版本,进入新版本的文件夹/js/plugins,将Kgg_MapArrows.js复制到您的工程文件夹的/js/plugins文件夹内,替换之前的Kgg_MapArrows.js文件。


[fold=收件人]
@蓝与火 @tanurog2 @zhouhua2022 @huangjianxq @2199414169 @南方大汉 @shashojieshuo @ycf-k @xhll @萌新的派大星 @hzhz69989495 @mnbv7890
[/fold]

点评

责任心max的大大  发表于 2024-3-10 22:50
谢谢大佬更新改善,经测试原版的确会报错  发表于 2024-3-10 22:11
回复 1 0

使用道具 举报

梦石
0
星屑
682
在线时间
55 小时
注册时间
2024-5-3
回帖
38
发表于 2024-5-24 12:59:40 | 显示全部楼层
是我想要的,感谢楼主分享哦

点评

我的插件能对你有用,真是太好了!  发表于 2024-5-27 00:27
回复

使用道具 举报

梦石
0
星屑
937
在线时间
71 小时
注册时间
2022-11-3
回帖
158
发表于 2025-4-18 06:46:10 | 显示全部楼层
感谢大佬分享
回复

使用道具 举报

梦石
0
星屑
7801
在线时间
683 小时
注册时间
2012-7-29
回帖
172
 楼主| 发表于 2025-7-13 15:58:27 | 显示全部楼层
本帖最后由 开关关 于 2025-7-13 16:00 编辑

v1.3更新

v1.3 相比 v1.2 的变化

  • 增加对插件最大值编辑器(DrillLengthEditor)的支持;
  • 修复箭头是否可旋转(canRotate)无法设置为false的问题。

更新方法

  下载并解压新版本,进入新版本的文件夹/js/plugins,将Kgg_MapArrows.js复制到您的工程文件夹的/js/plugins文件夹内,替换之前的Kgg_MapArrows.js文件。
回复

使用道具 举报

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

本版积分规则

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

在本版发帖返回顶部