欢迎光临散文网 会员登陆 & 注册

【MCBE·命令】判断实体视线是否穿越另一实体的碰撞箱

2021-12-12 00:17 作者:Happy2018new  | 我要投稿

前言

  1. 本专栏参考自专栏A“【MC】用命令判断实体碰撞箱被视线穿过”。

  2. 本专栏基本不包含指令,此处需要的是一个会思考的大脑。

  3. 本专栏的所述内容的本质与专栏A的基本一致,但本专栏的可读性更强。

  4. 若要顺利阅读并理解本专栏所述内容,至少需要小学学历。

  5. 由于本专栏的受众面要求,因此本专栏总体上较为拖沓。有能力的读者可以跳读本专栏。

  6. 本文总计4625字,对于只有小学学历基础的读者,完全阅读并详细理解本专栏预计需要23+分钟。

引入

  在制作形似于起床战争的地图时,我们通常无法使用纯指令达到我们想要的一些效果,其中就包括“不允许伤害同队玩家”这一效果。那么我们应当如何解决形似这种问题的这一类问题呢?

如何解决问题?

  让我们仔细思考一下。实际上“引入”提出的问题可以通过解决“判断实体视线是否穿越另一实体的碰撞箱”这一问题来解决。当我们确定同队玩家看向了同队玩家后(且看向的这个玩家距离他最近),就可以赋予其高等级力量效果以达到不能攻击的目的(在高等级力量效果的作用下,被赋予该效果的玩家不能通过非投掷性物品对其他实体造成伤害)。

问题的转化·如何解决“判断实体视线是否穿越另一实体的碰撞箱”?

问题

  假设一个环境A中仅有2个物体,它们分别是实体A和实体B,那么如何判定实体A的视线是否穿过实体B?

  要解决这个问题,我们需要构造“视线”和“碰撞箱”。

视线的构造

  那么我们应当如何构造这个“视线”呢?

 在众多的游戏中,玩家的视线一般是一条射线。我们可以通过描述玩家(也就是物体)的位置及其朝向(也就是物体看向的方向)来描述玩家的视线。尝试想象一下,当你看向正北方且平视的时候,在你的鼻子处(这个“鼻子处”就是上文提到的“位置”)描一个点M,然后让点M向正北方且平视的这个方向(这个“正北方且平视的这个方向”就是上文提到的“朝向”)移动无穷米(也就是∞m),那么这个点M移动的轨迹就是你的视线。

  在小学的时候,我们学到了如何用形似(a,b)的方式来表示同学所坐的座位位置。那么我们是否我们在游戏中构造一个三维的坐标系,然后用3个值(长、宽、高)来表示玩家在游戏(即场景)中的位置呢?答案是——可以!不难发现,MCBE自带有“坐标”的功能,因此我们可以直接使用MCBE内置的“坐标法则”来表示一个实体所在的位置。关于如何使用指令在MCBE中获取实体的坐标,详见“[MCBE]CB:关于二分法,你了解多少”或“【minecraft命令】运用二分法计算两点的垂直视角(单击该链接后自动跳转到1:55处)”。

  对于MCBE中的一般情况,我们用两个轴的值来描述朝向,它们分别是RX和RY,分别对应垂直方向的旋转角和水平方向的旋转角。设想一下,当你左右旋转你的头的时候,改变的是你的RY轴值,而当你上下旋转旋转你的头的时候,改变的便是你的RX轴值。但在解决本专栏所述的问题的时候,我们为了简便就采取了另一个方法来描述物体的朝向——向量。

  向量不仅存在长度,还存在方向(如下图“图1”)。在MCBE中,运用Tp(或Teleport)的Facing(朝向)功能就可以让目标传送到指定位置A并朝向指定位置B(A和B可以相同)。在这一过程中,你先被传送到了指定位置A,然后看向了指定位置B,那么AB就可以称为一个向量,它从A点指向B点,有长度且有方向[AB的长度就是AB的模(数学上表示为|AB|,指的是线段AB的长度);AB的方向可以通过一个过程来表现,而这个过程就是“先用直尺连接A点和B点,然后把一个笔的笔尖放在A点处并让笔尖顺着刚刚连接的这个线滑动到B点”的过程]。在这里,A点可以用坐标表示其位置,B点也可以用坐标表示其位置,那么我们用2组坐标并按照一定顺序摆放这两组坐标来表示一个方向(见下图“图2”)。

图1

图2


  在MCBE中,玩家的位置就可以看成“图1”中的A点的坐标。我们可以很简单的得到玩家的坐标,但我们如何得到另一个点B的坐标呢?

  这很简单。我们可以使用MCBE内置的“局部坐标系”的法则来表示并使用二分法得到点B的坐标。要详细了解这个法则及该法则的使用,可以前往“命令 - Minecraft Wiki_BWIKI_哔哩哔哩(单击该链接后自动跳转到指定位置)”以详细了解。我们通常用“^ ^ ^1”来表示实体的朝向,因此我们可以使用指令“Execute <玩家> ^ ^ ^1 Summon Minecraft:Armor_Stand”来在B点处生成一个盔甲架,然后该盔甲架的位置可以被表示为一组坐标,于是我们就得到B点的坐标了。

碰撞箱的构造

  在MC中的一般情况下,只要是实体,那么都存在碰撞箱和“相对坐标”*(目前已知的一个特例是MCJE中的“标记”是不存在碰撞箱的)。我们可以把碰撞箱看做一个长方体X,然后这个长方体有一个实体N且这个实体被长方体X完全盖住。一般来说,碰撞箱和“相对坐标”由实体的模型决定(对于末影龙和凋零来说,它们的碰撞箱不适用该法则),关于“模型”的详细信息,可见“模型 - Minecraft Wiki_BWIKI_哔哩哔哩”。

  我们无法在MCBE中直接用指令得到碰撞箱,因此我们可以通过预先设置碰撞箱的方法来构造碰撞箱,本专栏预设的碰撞箱大小为1*1*2(长1、宽1、高2;“*”指的是乘号)。

  什么是“相对坐标”呢?“相对坐标”可以理解为碰撞箱(也就是长方体)的几何中心,我们用直尺连接这个碰撞箱(也就是长方体)的4个对角线,这些对角线的交点就是这个长方体的几何中心。碰撞箱可以用2组坐标表示,例如(x,y,z)和(x',y',z'),那么几何中心的坐标可以表示为下图“图3”中所写的形式。平面中的碰撞箱和几何中心可以用下图“图4”中的例子来表现。

图3

  

图4

  碰撞箱的表示方法跟“Fill”命令中起止点坐标的表示方法一致,它们都用来表示一个长方体区域。简而言之,这种坐标表示方法用到了长方体1组对角线的坐标。你可以尝试理解上图“图4”中的(x,y)和(x',y'),这两组坐标就是长方形的1组对角线的坐标。“Fill”命令的具体用法可见“命令/fill - Minecraft Wiki_BWIKI_哔哩哔哩”,当你了解该命令关于起止点坐标的表示方法后,你就会表示一个长方体区域了。

正式开始解决问题

  让我们重新看到要解决的问题——假设一个环境A中仅有2个物体,它们分别是实体A和实体B,那么如何判定实体A的视线是否穿过实体B?

  我们可以通过章节“视线的构造”和章节“碰撞箱的构造”分别取得实体A的视线和实体B的碰撞箱。此处将实体A的视线表示为(X,Y,Z)(X',Y',Z'),它对应的方向指的是“从(X,Y,Z)指向(X',Y',Z')”。此处将实体B的碰撞箱表示为(q,r,s)(q',r',s'),它表示的是一个长方体区域,也就是从(q,r,s)到(q',r',s')间的区域。

  我们让X''的值等于X'减去X的值,Y''的值等于Y'减去Y的值,Z''的值等于Z'减去Z的值,于是我们可以将得到的X''、Y''和Z''表示为一组坐标,写为(X'',Y'',Z'')。我们以实体A为原点,构建一个三维坐标系,那么该原点指向(X'',Y'',Z'')的方向就是玩家的视线,因此我们可以用(X'',Y'',Z'')来表示玩家的视线,这样更加方便。

  需要注意的是,由于刚刚构造了新的坐标系,因此我们也需要让表示碰撞箱的2组坐标中的每一个轴的值减去对应的原点坐标中的每一个轴的值。本处不再赘述如何得到碰撞箱的2组新坐标,具体的原理与上一段落的处理办法基本一致。

  在“视线的构造”中,我们学习了有关“向量”的知识,因此我们知道玩家的视线是向量,它有长度和方向。因此,我们可以在不改变实体A的视线方向的情况下,只改变实体A视线的长度。我们让X''、Y''和Z''乘上L(L指的是缩放倍数,它可以让视线的长度缩小或放大L倍),得到了(LX'',LY'',LZ''),目前假定L是一个未知数。需要注意的是,L必须是正数或0,因为实体A的视线相对于原点是往前的,不能往后(也就是反方向)。由于原有的“有长度的视线(X'',Y'',Z'')”被缩放了L倍,因此现在得到的视线(LX'',LY'',LZ'')是一个长度未知但是方向已知的视线(你可以把这个视线想象成一个在不断拉伸的细绳,但这个细绳不能拉伸到实体A视线的负方向)。

  为了让问题简单容易解决,我们可以将刚刚构建好的三维坐标系的3个轴(也就是X轴、Y轴和Z轴)拆开来,先一个一个轴来解决,本专栏解决的是X轴。

  我们知道实体B的碰撞箱是从(q,r,s)到(q',r',s'),因此实体B在X轴上的碰撞箱是从q到q'。如果实体A的视线穿越了实体B的碰撞箱,那么实体A在X轴上的视线LX''一定经过从q到q'这个范围(如下图“图5”)。

图5

  也就是说,如果“实体A在X轴上的视线LX''经过从q到q'这个范围”,那么必定存在至少一个L让LX''得到的值在q到q'这个范围内(如下图“图6”)。

图6

  很显然,在上图“图6”中,L取了一个值,让LX''这个点落在了qq'这一线段上。于是,我们得到了不等式:

图7

  进而得到:

图8

  目前,X''、q和q'均已知,仅L是一个未知数,所以我们可以求出L的取值范围。上图“图8”中的不等式指的是L可以取到q÷X''到q'÷X''之间的数。特别的,如果X''为0,那么L可以取遍数轴上的任意数。

  于是,关于X轴的解决过程到此结束。

  我们可以使用同样的方法来解决Y轴和Z轴,因此此处不再赘述关于解决Y轴和Z轴的过程。最终,我们得到了3个不等式:

图9
图10
图11

  然后,我们得到了3个关于L的范围。如果这三个范围中能取到至少一个L同时满足上图“图9”、“图10”和“图11”中的3个不等式,那么就存在一个L可以让实体A的视线(LX'',LY'',LZ'')对应的点[将满足上述3个不等式条件的各个L依次代入坐标(LX'',LY'',LZ'')则可以得到至少一组明确的坐标,而得到的每组明确的坐标将对应一个位于的点]落入实体B的碰撞箱内。

  换言之,如果找得到一个L满足上述3个不等式,那么实体A的视线经过实体B的碰撞箱。

  于是,问题“假设一个环境A中仅有2个物体,它们分别是实体A和实体B,那么如何判定实体A的视线是否穿过实体B?”就得到了解决。

数学语言

  准备:

    以发出射线的实体处建立三维直角坐标系.
  定义:
    1. (x,y,z)是一个单位矢量。将该坐标放大倍数n可得到视线上任何一点,表示为n(x,y,z).
    2. 长方体的范围是(a1,b1,c1)到(a2,b2,c2)且a1≤a2,b1≤b2,c1≤c2.

  初步:

    用集合表示射线上每一点:A={n(x,y,z)|n≥0}.
    用集合表示长方体内每一点:B={(a,b,c)|a1≤a≤a2, b1≤b≤b2, c1≤c≤c2}.

  根据题意可得:
    若视线有一点穿越长方体,则有A∩B≠∅.
    若A∩B≠∅,则存在一个或多个n可以使(x,y,z)被缩放到视线上一点且该点在长方体内,即可得:
    不等式组{a1≤nx≤a2, b1≤ny≤b2, c1≤nz≤c2}的解集≠∅.
    其中,a1、a2、b1、b2、c1、c2、x、y和z均已知,那么可通过上述不等式组得到关于n的解集。如果n在上述不等式组的解集=∅,则视线不穿过长方体。如果n在上述不等式组的解集≠∅,则视线穿过长方体.

结语

  本专栏讲述的解决方法是“向量法”。解决这类问题并不局限于本专栏的方法,更多的,是用“智慧的大脑”寻找解决问题的关键,得到解决问题的方法。

  为了贯彻这一理念,本专栏基本上不会出现指令,而是纯逻辑的讲解。

  该专栏写于仓促之间,难免存在问题,欢迎各位大佬在“勘误”楼中指出本专栏的错误。同时感谢各位读者花费如此长的时间阅读本专栏,临走前还希望各位能点一个免费的“”呢~

注释

  “相对坐标”:此处及下文提到的“相对坐标”指的是实体碰撞箱的几何中心的坐标,而不是坐标中的“~”。

【MCBE·命令】判断实体视线是否穿越另一实体的碰撞箱的评论 (共 条)

分享到微博请遵守国家法律