Minecraft数据包用Sin/Cos生成圆形失败及精度优化咨询
一、图形混乱的核心原因
第三方Sin/Cos数据包精度缺陷
大部分Minecraft数学数据包采用泰勒展开近似计算Sin/Cos,若展开项数不足或角度转弧度的缩放精度差,会导致计算值与实际值偏差显著。你使用的yosho27数据包仅将结果乘100保留两位小数,本身的近似误差加上整数运算的截断效应,会让每个顶点的坐标偏移被放大,累积后形成螺旋状或间隙。比如你提到的1号点,MC计算值与Scratch精确值的差异,就是Sin/Cos近似误差直接导致的。整数运算的截断误差
Minecraft计分板仅支持整数运算,计算坐标时,(中心坐标*100 + 半径*Sinθ)的结果直接除以100会截断小数部分,而非四舍五入,进一步加剧坐标偏差。这种截断会让每个点的位置都偏离理论值,多个点累积后就会出现明显的图形变形。修改数据包的逻辑错误
你将除法改为乘10的操作完全破坏了原数据包的精度缩放逻辑:原数据包是把Sin/Cos的浮点结果乘100转为整数以保留两位小数,修改后相当于把精度降到一位,反而放大了误差;同时你没有同步调整角度转弧度的缩放比例,导致数值完全偏离预期,出现无规律偏移。
二、提升精度的可行方案
1. 替换高精度Sin/Cos数据包
优先选择采用查表法的数学数据包:这类数据包预计算好0-360度的Sin/Cos值并存储在计分板或存储中,调用时直接读取对应角度的预计算值,精度远高于实时泰勒展开。如果找不到现成的,也可以自制查表模板:预计算每1度的Sin/Cos值,乘1000保留三位小数,存在计分板的虚拟玩家中,调用时直接读取对应角度的数值。
2. 优化整数运算逻辑
- 用四舍五入代替截断:计算坐标时,先将所有值放大100倍(或1000倍)进行整数运算,最后加50(或500)再除以100(或1000),实现四舍五入。示例MC函数:
# 计算x坐标:中心x*100 + 半径*Cosθ,结果四舍五入到整数坐标 execute store result score temp_x math run scoreboard players operation temp_x = center_x math execute store result score temp_x math run scoreboard players multiply temp_x 100 execute store result score temp_cos math run scoreboard players get @e[tag=calc] math_out execute store result score temp_cos math run scoreboard players multiply temp_cos radius math execute store result score temp_x math run scoreboard players add temp_x temp_cos execute store result score temp_x math run scoreboard players add temp_x 50 execute store result score temp_x math run scoreboard players divide temp_x 100 # 将temp_x转为实体坐标 execute store result entity @e[tag=new_stand] Pos[0] double run scoreboard players get temp_x math - 提升精度缩放倍数:将Sin/Cos的结果乘1000而非100,保留三位小数,缩小整数运算的误差量级。注意要确保所有相关计算(如半径、中心坐标)都同步放大1000倍,避免缩放比例不一致。
3. 精确控制角度增量
确保每个顶点的角度增量均匀且总角度刚好为360度。比如生成20个点时,每次角度加18度(360/20),用计分板记录当前角度,每次累加固定值,避免累积误差导致的螺旋状偏移。
4. 替代方案:无需Sin/Cos的动态半径圆形生成
如果不想依赖Sin/Cos计算,可采用旋转中心实体+动态相对坐标的方法,实现无需修改数据包即可调整半径的需求:
# 初始化:设置半径到计分板(可随时修改数值) scoreboard players set radius math 5 # 生成20个盔甲架组成圆形 execute as @e[tag=center] run summon armor_stand ~ ~ ~ {NoGravity:1,Invisible:1} tag @s add circle_stand execute as @e[tag=center] run scoreboard players set angle math 0 repeat 19 execute as @e[tag=center] run scoreboard players add angle math 18 execute as @e[tag=center] run tp @s ~ ~ ~ rotated ~18 ~ execute as @e[tag=center] run summon armor_stand ~ ~ ~ {NoGravity:1,Invisible:1} tag @s add circle_stand # 将新召唤的盔甲架移动到指定半径位置 execute as @e[tag=center] at @s run execute as @e[tag=circle_stand,limit=1,sort=last] run tp @s ^[radius] ^ ^ end # 重置中心实体角度 execute as @e[tag=center] run tp @s ~ ~ ~ rotated ~0 ~
这个方法完全避免了Sin/Cos的计算误差,半径仅需修改计分板的radius值即可调整。
内容的提问来源于stack exchange,提问作者Accorwolf

