设为首页收藏本站|繁體中文

Project1

 找回密码
 注册会员
搜索
查看: 167|回复: 0
打印 上一主题 下一主题

[综合信息] NPC的听力范围(圆形)和视力范围(扇形或三角形)

[复制链接]

Lv2.观梦者

梦石
0
星屑
923
在线时间
100 小时
注册时间
2025-2-15
帖子
52
跳转到指定楼层
1
发表于 2025-10-12 02:41:12 | 只看该作者 |只看大图 回帖奖励 |倒序浏览 |阅读模式

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

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

x
以MZ版为例,MV版应该也是一样的,由于MV版的脚本框没有下拉框,或许需要把太多行数的脚本复制给AI,让它把行数减少一点,因为MV版的脚本框可以横向放入好多的代码,用;符号把几行并成一行就可以了吧。
另外,下面这些脚本有被简单测试过,但是不确定有没有错误。(让一个或几个NPC跟随自己绕着这个NPC绕圈圈和忽远忽近)
我也写不了插件那种系统性的东西,也不会从新架构一套东西,都是对原始代码的一些修修改改而已,我认为简单的、常见的、基础性的代码没有多少的独创性,不构成原创性保护,我自己对这样的代码也是需要用到了就直接抄走的,所以谁需要用到的话,也是直接抄就好了。
如果是高手的话,或许是可以基于像素点、圆形和三角形的数学公式和各种数学公式来制作高性能插件的,还可以会把战争迷雾和障碍物、视线阻碍之类的都考虑进去。所以这个帖子只是只是菜鸟之间的分享和交流而已。

在rmmz_objects.js找到下面这段代码,好像给NPC设置了接近玩家,距离20步才会被触发。
Game_Event.prototype.isNearThePlayer = function() {
    const sx = Math.abs(this.deltaXFrom($gamePlayer.x));
    const sy = Math.abs(this.deltaYFrom($gamePlayer.y));
    return sx + sy < 20;
};

于是就想着能不能让NPC发现NPC,并且不是距离多少步,而是圆形范围和扇形范围之类的。
首先就是把isNearThePlayer改成isNearTheEventZ5,
(Player改成Event,半径Radius太长了就用Z代替吧,5格范围为听力范围,10到20格为视力范围好像是挺好的)
另外,需要分支条件来判断是不是符合条件,Game_Event这个东西需要改成$gameMap.event(this.eventId())才能指定本事件。



//虽然半径是Radius,而不是XYZ轴的Z,但是Z用着顺手啊。
//这个是正常可用的,这个是耳朵的听力范围
Game_Event.prototype.isNearTheEventZ5 = function() {
for(i=$gameVariables.value(2);i<=10;i++){
    const sx = Math.abs(this.deltaXFrom($gameMap.event(i).x));
    const sy = Math.abs(this.deltaYFrom($gameMap.event(i).y));
    sz = Math.sqrt(sx*sx + sy*sy)
   
//$gameMap.event(i).isMoving() 这个是 指定ID事件目前是否正在移动中 好像也可以,下面这个是 指定ID事件目前是否正在停止中(非移动中与非跳跃中) 要灵敏一点。
if(!$gameMap.event(i).isStopping() && sz <= 5){
return sz  <= 5;
}
}
}

$gameMap.event(this.eventId()).isNearTheEventZ5()

特意把脚本框和分支条件的代码粘贴上了,方便大家复制。



接着就是视力范围了,如果改成下面这样的话,好像也可以,但是东西南北分开来写好像太累赘了,可能还会影响性能。
◆变量操作:#0001 = 29
◆变量操作:#0002 = 29
◆独立开关操作:A = 开启

(这里是东南西北四个的脚本和分支条件)

◆变量操作:#0002 += 1
◆如果:#0002 ≥ 134
  ◆跳过
    ◆独立开关操作:A = 关闭
    ◆
  :结束
  ◆变量操作:#0002 = 29
  ◆
:结束分支
因为下面的测试是29到34号事件页,所以这里的初始设置的29,134是随便写的。

◆注释:隔开
:  :
:  :
:  :
:  :下面是本事件朝向下方时,特定NPC在本事件南方的扇形范围之内,
:  :也就是在本事件的视野范围之内触发。
◆注释:就是以本事件所在地图格子为原点,是一个格子。
:  :向着两边延申,接着是三个格子、五个格子,以此类推。
:  :最终的覆盖范围好像是三角形,但应该是一个扇形。
:  :
:  :好像是根据小于等于的那个数字(就拿Z来代替吧),以本事件正前方数到那里,然后以这条直线为半径,向两边覆盖。
:  :因为是圆形、扇形,Z*48这个直线就是这个半径,但是斜线的话,一个格子的对折线是√(48 × 48 + 48 × 48)=67.8822509939。。。所以,正是因为距离相同,延申的地图格子反而不同。

◆脚本://虽然半径是Radius,而不是XYZ轴的Z,但是Z用着顺手啊。
:  ://这个是正常可用的,这个是眼睛的视力范围
:  :Game_Event.prototype.isNearTheEventZ20nan = function() {
:  :for(i=$gameVariables.value(2);i<=34;i++){
:  :    const sx = Math.abs(this.deltaXFrom($gameMap.event(i).x));
:  :    const sy = Math.abs(this.deltaYFrom($gameMap.event(i).y));
:  :    sz = Math.sqrt(sx*sx + sy*sy)
:  ://本事件的朝向是2————该事件相对于本事件的绝对值的横轴小于等于纵轴————在纵轴对比上,本事件在该事件的北方
:  :if($gameMap.event(this.eventId())._direction === 2 && sx <= sy && $gameMap.event(this.eventId()).y < $gameMap.event(i).y ) {
:  :
:  :
:  :return sz  <= 20;
:  :}
:  :
:  :}
:  :}
◆如果:脚本:$gameMap.event(this.eventId()).isNearTheEventZ20nan()
  ◆变量操作:#0002 = i
  ◆文本:无, 无, 暗淡, 中间
  :  :         \v[2] 你在我南方,我看到你了 \.  \^
  ◆
:结束分支



◆脚本:Game_Event.prototype.isNearTheEventZ20bei = function() {
:  :for(i=$gameVariables.value(2);i<=34;i++){
:  :    const sx = Math.abs(this.deltaXFrom($gameMap.event(i).x));
:  :    const sy = Math.abs(this.deltaYFrom($gameMap.event(i).y));
:  :    sz = Math.sqrt(sx*sx + sy*sy)
:  :
:  :if($gameMap.event(this.eventId())._direction === 8 && sx <= sy && $gameMap.event(this.eventId()).y > $gameMap.event(i).y ) {
:  :return sz  <= 20;
:  :}
:  :
:  :}
:  :}
◆如果:脚本:$gameMap.event(this.eventId()).isNearTheEventZ20bei()
  ◆变量操作:#0002 = i
  ◆文本:无, 无, 透明, 中间
  :  :         \v[2] 你在我北方,我看到你了 \.  \^
  ◆
:结束分支



◆脚本:Game_Event.prototype.isNearTheEventZ20xi = function() {
:  :for(i=$gameVariables.value(2);i<=34;i++){
:  :    const sx = Math.abs(this.deltaXFrom($gameMap.event(i).x));
:  :    const sy = Math.abs(this.deltaYFrom($gameMap.event(i).y));
:  :    sz = Math.sqrt(sx*sx + sy*sy)
:  :
:  :if($gameMap.event(this.eventId())._direction === 4 && sy <= sx &&$gameMap.event(this.eventId()).x > $gameMap.event(i).x ) {
:  :return sz  <= 20;
:  :}
:  :
:  :}
:  :}
◆如果:脚本:$gameMap.event(this.eventId()).isNearTheEventZ20xi()
  ◆变量操作:#0002 = i
  ◆文本:无, 无, 暗淡, 中间
  :  :         \v[2] 你在我西边,我看到你了 \.  \^
  ◆
:结束分支



◆脚本:Game_Event.prototype.isNearTheEventZ20dong = function() {
:  :for(i=$gameVariables.value(2);i<=34;i++){
:  :    const sx = Math.abs(this.deltaXFrom($gameMap.event(i).x));
:  :    const sy = Math.abs(this.deltaYFrom($gameMap.event(i).y));
:  :    sz = Math.sqrt(sx*sx + sy*sy)
:  :
:  :if($gameMap.event(this.eventId())._direction === 6 && sy <= sx &&$gameMap.event(this.eventId()).x < $gameMap.event(i).x ) {
:  :return sz  <= 20;
:  :}
:  :
:  :}
:  :}
◆如果:脚本:$gameMap.event(this.eventId()).isNearTheEventZ20dong()
  ◆变量操作:#0002 = i
  ◆文本:无, 无, 暗淡, 中间
  :  :         \v[2] 你在我东边,我看到你了 \.  \^
  ◆
:结束分支




后来想一想,好像是可以通过嚯嚯嚯||  ||  || 来一次性搞定啊。脚本框和分支条件就是下面这样。
//虽然半径是Radius,而不是XYZ轴的Z,但是Z用着顺手啊。
//这个是正常可用的,这个是眼睛的视力范围
Game_Event.prototype.isNearTheEventZ20 = function() {
for(i=$gameVariables.value(2);i<=7;i++){
    const sx = Math.abs(this.deltaXFrom($gameMap.event(i).x));
    const sy = Math.abs(this.deltaYFrom($gameMap.event(i).y));
    sz = Math.sqrt(sx*sx + sy*sy)

//本事件的朝向是2————该事件相对于本事件的绝对值的横轴小于等于纵轴————在纵轴对比上,本事件在该事件的北方
if(($gameMap.event(this.eventId())._direction === 2 && sx <= sy && $gameMap.event(this.eventId()).y < $gameMap.event(i).y ) || ($gameMap.event(this.eventId())._direction === 8 && sx <= sy && $gameMap.event(this.eventId()).y > $gameMap.event(i).y ) || ($gameMap.event(this.eventId())._direction === 6 && sy <= sx &&$gameMap.event(this.eventId()).x > $gameMap.event(i).x ) || ($gameMap.event(this.eventId())._direction === 4 && sy <= sx &&$gameMap.event(this.eventId()).x < $gameMap.event(i).x)) {
return sz  <= 20;
}
}
}



$gameMap.event(this.eventId()).isNearTheEventZ20()



◆变量操作:#0001 = 1
◆变量操作:#0002 = 1
◆独立开关操作:A = 开启

◆脚本://虽然半径是Radius,而不是XYZ轴的Z,但是Z用着顺手啊。
:  ://这个是正常可用的,这个是眼睛的视力范围
:  :Game_Event.prototype.isNearTheEventZ20 = function() {
:  :for(i=$gameVariables.value(2);i<=7;i++){
:  :    const sx = Math.abs(this.deltaXFrom($gameMap.event(i).x));
:  :    const sy = Math.abs(this.deltaYFrom($gameMap.event(i).y));
:  :    sz = Math.sqrt(sx*sx + sy*sy)
:  :
:  ://本事件的朝向是2————该事件相对于本事件的绝对值的横轴小于等于纵轴————在纵轴对比上,本事件在该事件的北方
:  :if(($gameMap.event(this.eventId())._direction === 2 && sx <= sy && $gameMap.event(this.eventId()).y < $gameMap.event(i).y ) || ($gameMap.event(this.eventId())._direction === 8 && sx <= sy && $gameMap.event(this.eventId()).y > $gameMap.event(i).y ) || ($gameMap.event(this.eventId())._direction === 6 && sy <= sx &&$gameMap.event(this.eventId()).x > $gameMap.event(i).x ) || ($gameMap.event(this.eventId())._direction === 4 && sy <= sx &&$gameMap.event(this.eventId()).x < $gameMap.event(i).x)) {
:  :return sz  <= 20;
:  :}
:  :}
:  :}
◆如果:脚本:$gameMap.event(this.eventId()).isNearTheEventZ20()
  ◆变量操作:#0002 = i
  ◆文本:无, 无, 暗淡, 中间
  :  :         \v[2] 你在我正前方20格扇形范围以内,我看到你了 \.  \^
  ◆设置移动路线:本事件 (等待)
  :      :◇随机转向
  ◆独立开关操作:A = 关闭
  ◆
:结束分支
◆变量操作:#0002 += 1
◆如果:#0002 ≥ 134
  ◆跳过
    ◆独立开关操作:A = 关闭
    ◆
  :结束
  ◆变量操作:#0002 = 1
  ◆
:结束分支
您需要登录后才可以回帖 登录 | 注册会员

本版积分规则

拿上你的纸笔,建造一个属于你的梦想世界,加入吧。
 注册会员
找回密码

站长信箱:[email protected]|手机版|小黑屋|无图版|Project1游戏制作

GMT+8, 2025-11-3 10:36

Powered by Discuz! X3.1

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表