How to Draw a Sphere - HeartyYF/fabric-carpet-Wiki-CN GitHub Wiki

如何画球(译者注:大型造方形轮子现场)

Carpet 内置了了绘制基本图形的工具,球体包含在其中,所以要画一个球实际上并不需要用到 scarpet(译者注:好了,此帖终结),但是用 scarpet 试一试也是一个不错的练习。【而且/draw sphere只会扫描绘制球体所必需的那些方块,所以它更加高效,比下文中的任何一个方法都要更快。但是因为同时填充这么多的方块总会让游戏卡顿那么一两秒,所以你也感觉不出来这个效率的提升就是了。】在下面的例子中,我们会画一个球心在 (100, 100, 100),半径为 50 个方块的球。要清空绘制区域,只需要运行这个命令:

/script run scan(100,100,100,50,50,50,set(_,'air'))

使用命令 /draw circle <center> <radius> <block> (replace <replacement>)?

要画一个球,最简单的方法就是用 draw 命令:

/draw sphere 100 100 100 50 glass

或者如果要在已有的地形上绘制而不破坏除空气以外的任何方块,则可以这样:

/draw sphere 100 100 100 50 glass replace air

要想安全地删除这个球而不破坏已有的方块,只需要用空气方块把这个球填充回去:

/draw sphere 100 100 100 50 air replace glass

但是这样没有用到数学方法。要发挥数学的威力,我们就要用到 scarpet 脚本了:

使用 /script fill <origin> <from> <to> <expression> <block> (replace <replacement>)?

注意:如果要在很大的区域内绘制,你需要先用 /carpet fillLimit 进行一番调整,因为 /script fill/script scan 受到 /fill 命令的范围限制,一次最多只能填充 32000 方块。

这个命令用起来和原版 /fill 差不多,在 <expression> 条件为真的位置绘制方块。第一个坐标参数 <origin> 表示 <expression> 中各坐标的参考点,换言之,<expression> 中的 xyz 会以 <origin> 为原点。将 <origin> 设为 (0,0,0) 就相当于用绝对坐标来绘制,但是把原点平移到球心去可以极大地简化我们的 <expression> 表达式。

既然这个球的半径是 50,以 (100, 100, 100) 为球心,那么绘制的范围就是 (50, 50, 50) 到 (150, 150, 150)。

首先来画一个实心球:

/script fill 100 100 100 50 50 50 150 150 150 "x*x + y*y + z*z <= 50*50" glass replace air

对于空心球而言,将 <= 号简单替换成 == 号效果并不好,只有少数的点能匹配上,因此我们要稍微绕个圈子:

/script fill 100 100 100 50 50 50 150 150 150 "round(sqrt(x*x + y*y + z*z)) == 50" glass replace air

注意:因为 <expression> 后面还有其他参数,这里必须加上引号。

使用 /script scan <origin> <from> <to> expr

这个命令要更通用一些,它会扫描一个区域内的所有方块,然后执行命令。这里我们不再依赖 /draw 或者 /fill 来画方块,而是手动使用 set 命令:

/script scan 100 100 100 50 50 50 150 150 150 if( round(sqrt(x*x + y*y + z*z)) == 50, set(_, 'glass'))

如果要避免破坏已有的方块则这样:

/script scan 100 100 100 50 50 50 150 150 150 if( air(_) && round(sqrt(x*x + y*y + z*z)) == 50, set(_, 'glass'))

使用 /script run expr

最后一个例子中我们连 scan 和 fill 提供的坐标系统也不用了,所有的运算都由我们自己来做:

/script run 
c = l(100,100,100); 
r = 50; 
scan(c,r,r,r, 
  if ( air(_), 
    v=pos(_)-c; 
    if( round(sqrt(v:0*v:0+v:1*v:1+v:2*v:2))==r, 
      set(_, 'glass')
    )
  )
);

有点复杂、没看懂?这是因为我们要自己去设置绘画的位置。首先我们设置了球心 c 和半径 r,然后用 scan 函数(译者注:你这不还是用了吗……)在区域内逐个方块迭代。我们希望跳过所有非空气方块(包括 'cave_air''void_air')。然后定义向量 v 表示当前点到圆心 c 的位移,最后检查 v 的长度是不是与定义好的半径 r 相等。这有点多此一举(译者注:你还知道啊?),但是我们成功了。实际上比起把各个坐标列出来,用 reduce 函数可以稍微简化一点点:

/script run 
c = l(100,100,100); 
r = 50; 
scan(c,r,r,r, 
  if ( air(_) && round(sqrt(reduce(pos(_)-c, _a+_*_, 0)))==r, 
    set(_, 'glass')
  )
);

本篇由 @茨月 翻译。

⚠️ **GitHub.com Fallback** ⚠️