我目前正在开发一些需要物体围绕另一个物体运行的东西。虽然,我很有限。我无法使用Radians来实现这一目标。我可以获得罪和cos,以及学位。但我不能使用弧度(它打破了一切)。请注意,这是在Minecraft中,并且那里的值不能保持浮点数或双精度数。因此,0.017
之类的答案将是17
。出于这个原因,我不能使用弧度。
计算sin和cos的函数限制在-180到180之间。这意味着我不能简单地将0.787
弧度变为787
弧度,因为它超出了极限,并且回答的答案是完全错误的。
现在代码就像这样:
var distance = 100; // from the centre of orbit
var degrees = 45; // around a 360 degree orbit
var radians = degrees * (Math.PI / 180);
var x = Math.cos(radians) * distance;
var y = Math.sin(radians) * distance;

但该代码完全依赖于将度数转换为弧度。我不能这样做,因为Minecraft的整数限制,以及函数如何计算sin和cos。这根本不可能。
所以主要问题是: 如何只用度,sin和cos找到物体的未来位置? (也许根据答案就好像学位是45)
答案 0 :(得分:2)
为什么不在固定点上制作自己的 LUT ?在C ++中是这样的:
const int fp=1000; // fixed point precision
const int mycos[360]={ 1000, 999, 999, 998, 997, 996, 994, 992, 990, ... }
float x,y,x0=0,y0=0,r=50,ang=45;
x = x0 + ( (r*mycos[ ang %360]) / fp );
y = y0 + ( (r*mycos[(ang+90)%360]) / fp );
您也可以编写一个脚本,为您创建 LUT 。 LUT 中的每个值都计算如下:
LUT[i] = fp*cos(i*M_PI/180); // i = 0,1,2,...359
现在在使用前将角度标准化:
ang %= 360;
if (ang<0) ang+=360;
还有一些方法可以计算只有整数变量的sin,cos
表。我们在Z80的8位时代asm中使用它来处理我们的东西以及后来的x86演示......因此可以编写代码直接在Minecraft脚本中创建它而无需其他编译器使用。
您甚至可以将角度单位更改为2而不是360的幂,这样您就可以摆脱模数并将fp设置为2 -1的割草机,这样您甚至不需要分割。在我的源代码档案中进行了一些挖掘之后,我找到了使用这种技术的古老的 TASM MS-DOS 演示。将其移植到 C ++ 并在此处调整常量 C ++ 结果:
int mysinLUT[256];
void mysin_init100() // <-100,+100>
{
int bx,si=620,cx=0,dx; // si ~amplitude
for (bx=0;bx<256;bx++)
{
mysinLUT[bx]=(cx>>8);
cx+=si;
dx=41*cx;
if (dx<0) dx=-((-dx)>>16); else dx>>=16;
si-=dx;
}
}
void mysin_init127() // <-127,+127>
{
int bx,si=793,cx=0,dx; // si ~amplitude
for (bx=0;bx<256;bx++)
{
mysinLUT[bx]=(cx>>8)+1;
cx+=si;
dx=41*cx;
if (dx<0) dx=-((-dx)>>16); else dx>>=16;
si-=dx;
}
}
int mysin(int a){ return mysinLUT[(a )&255]; }
int mycos(int a){ return mysinLUT[(a+64)&255]; }
设置常数,使sin[256]
保持范围<-100,+100>
或<-127,+127>
(取决于您调用的init)的粗略近似值,角度周期为256
而不是360
。您需要先调用mysin_init???();
一次以启动 LUT ,之后您可以使用mysin,mycos
,不要忘记将最终结果除以/100
或{{ 1}}。
当我使用 VCL :
渲染真实和近似圆圈的叠加层时>>7
结果如下:
红色是实际圆圈,黑色是使用void draw()
{
// select range
// #define range100
#define range127
// init sin LUT just once
static bool _init=true;
if (_init)
{
_init=false;
#ifdef range100
mysin_init100();
#endif
#ifdef range127
mysin_init127();
#endif
}
int a,x,y,x0,y0,r;
// clear screen
bmp->Canvas->Brush->Color=clWhite;
bmp->Canvas->FillRect(TRect(0,0,xs,ys));
// compute circle size from window resolution xs,ys
x0=xs>>1;
y0=ys>>1;
r=x0; if (r>y0) r=y0; r=(r*7)/10;
// render real circle
bmp->Canvas->Pen->Color=clRed;
bmp->Canvas->Ellipse(x0-r,y0-r,x0+r,y0+r);
// render approximated circle
bmp->Canvas->Pen->Color=clBlack;
for (a=0;a<=256;a++)
{
#ifdef range100
x=x0+((r*mycos(a))/100);
y=y0-((r*mysin(a))/100);
#endif
#ifdef range127
// if >> is signed (copying MSB)
x=x0+((r*mycos(a))>>7);
y=y0-((r*mysin(a))>>7);
// if >> is unsigned (inserting 0) and all circle points are non negative
// x=( (x0<<7)+(r*mycos(a)) )>>7;
// y=( (y0<<7)-(r*mysin(a)) )>>7;
// this should work no matter what
// x=r*mycos(a); if (x<0) x=-((-x)>>7); else x>>=7; x=x0+x;
// y=r*mysin(a); if (y<0) y=-((-y)>>7); else y>>=7; y=y0-y;
// this work no matter what but use signed division
// x=x0+((r*mycos(a))/127);
// y=y0-((r*mysin(a))/127);
#endif
if (!a) bmp->Canvas->MoveTo(x,y);
else bmp->Canvas->LineTo(x,y);
}
Form1->Canvas->Draw(0,0,bmp);
//bmp->SaveToFile("out.bmp");
}
的圆圈。如您所见,由于近似精度存在小的偏差,但此处不使用浮点运算。奇怪的是,3个不同数量的bithift rsults方法(它必须是我的编译器的一些优化),常量被调整为第一种方法。