如果减慢你的意思只是重力而不是空气摩擦力kv^2
or kv^3
那么你可以使用 2 遍方法非常简单地计算:
-
定义
为了简单起见,我们假设子弹是p0,v0
球是p1,v1
...意味着位置、速度和全局加速度a
适用于两者......所以牛顿达朗贝尔物理学规定:
v0+=a*dt; p0+=v0*dt;
v1+=a*dt; p1+=v1*dt;
更新时间为dt
...
-
估计子弹速度
简单的直接视线就足够了,所以:
v0=normalize(p1-p0)*v;
其中 v 是子弹的启动速度。
-
计算碰撞时间
简单地通过解决t
in:
(p0+(v0*t)+(0.5*a*t*t)) = (p1+(v1*t)+(0.5*a*t*t));
t = (p1-p0)/(v0-v1);
因为这是每个轴的一个解决方案,请使用 3 个视图中大于零的最小结果get_solution
下面例子中的函数
-
计算两者之间的位置差p0,p1
after t
简单地通过:
dp=(p1-p0)+((v1-v0)*t);
并纠正初始v0
估计之后t
秒差将为零:
v0+=dp/t;
-
实时计算
再次使用:
t = (p1-p0)/(v0-v1);
或者如果您需要考虑两个对象的半径,则:
t = ((r0+r1-p0+p1)/(v0-v1));
但请注意,这种方法将改变|v0|
“稍微”,所以如果有问题,你应该使用球坐标来拟合 v0...
这里是一个小的 C++/VCL 示例(只是改编自我的之前的回答 https://stackoverflow.com/a/71808916/2521214例子)
//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#include "GLSL_math.h"
#pragma hdrstop
#include "win_main.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TMain *Main;
//---------------------------------------------------------------------------
vec3 p0=vec3( 0, 0, 0),v0=vec3( 0, 0,0); // bullet
vec3 p1=vec3(150,100, 0),v1=vec3(-50,-30,0); // ball
vec3 a =vec3(0,-10,0); // global acceleration
//---------------------------------------------------------------------------
float t0=0.0; // time to hit
const float r0= 2.0; // bullet radius
const float r1=15.0; // ball radius
float x0,y0,z0,x1,y1,z1; // walls
//---------------------------------------------------------------------------
float get_solution(vec3 tt)
{
float t=0.0;
// t = min(tt)
if (t<tt.x) t=tt.x;
if (t<tt.y) t=tt.y;
if (t<tt.z) t=tt.z;
return t;
}
//---------------------------------------------------------------------------
void shoot()
{
const float v=250.0; // bullet start speed
int i;
float t;
vec3 dp;
p0=vec3(0.5*(x0+x1),y0+r0,0); // reset shot start position
// solve t for colision:
// (p0+(v0*t)+(0.5*a*t*t)) - (p1+(v1*t)+(0.5*a*t*t)) = r0+r1;
// t = (r0+r1-p0+p1)/(v0-v1);
v0=normalize(p1-p0)*v; // v0 estimate
t=get_solution((p1-p0)/(v0-v1));// time estimate
dp=(p1-p0)+((v1-v0)*t); // diference after time t
v0+=dp/t; // correct v0 estimate
t0=get_solution((r0+r1-p0+p1)/(v0-v1)); // real time to collision
}
//---------------------------------------------------------------------------
void update(double dt)
{
int e=0;
// Newton/d'Lambert simulation
v0+=a*dt; p0+=v0*dt;
v1+=a*dt; p1+=v1*dt;
t0-=dt;
// bullet timeout
if (t0<=0.0) e=1;
// bullet hit the target
if (length(p1-p0)<=r1+r0) e=1;
// bullet colision with wall
if (p0.x<x0+r0) e=1;
if (p0.x>x1-r0) e=1;
if (p0.y<y0+r0) e=1;
if (p0.y>y1-r0) e=1;
if (p0.z<z0+r0) e=1;
if (p0.z>z1-r0) e=1;
// ball colision with wall
if (p1.x<x0+r1){ p1.x=x0+r1; v1.x=-v1.x; }
if (p1.x>x1-r1){ p1.x=x1-r1; v1.x=-v1.x; }
if (p1.y<y0+r1){ p1.y=y0+r1; v1.y=-v1.y; }
if (p1.y>y1-r1){ p1.y=y1-r1; v1.y=-v1.y; }
if (p1.z<z0+r1){ p1.z=z0+r1; v1.z=-v1.z; }
if (p1.z>z1-r1){ p1.z=z1-r1; v1.z=-v1.z; }
// shoot again if needed
if (e) shoot();
}
//---------------------------------------------------------------------------
void TMain::draw()
{
if (!_redraw) return;
float x,y,r;
// clear buffer
bmp->Canvas->Brush->Color=clBlack;
bmp->Canvas->FillRect(TRect(0,0,xs,ys));
// walls
bmp->Canvas->Pen->Color=clWhite;
bmp->Canvas->Brush->Color=clBlack;
bmp->Canvas->Rectangle(x0,ys-y0,x1,ys-y1);
// ball
bmp->Canvas->Pen->Color=clAqua;
bmp->Canvas->Brush->Color=clBlue;
x=p1.x; y=ys-p1.y; r=r1;
bmp->Canvas->Ellipse(x-r,y-r,x+r,y+r);
// bullet
x=p0.x; y=ys-p0.y; r=r0;
bmp->Canvas->Ellipse(x-r,y-r,x+r,y+r);
bmp->Canvas->Brush->Color=clBlack;
bmp->Canvas->Font->Color=clYellow;
bmp->Canvas->TextOutA(0,0,AnsiString().sprintf("time to hit: %.3fs",t0));
// render backbuffer
Main->Canvas->Draw(0,0,bmp);
_redraw=false;
}
//---------------------------------------------------------------------------
__fastcall TMain::TMain(TComponent* Owner) : TForm(Owner)
{
bmp=new Graphics::TBitmap;
bmp->HandleType=bmDIB;
bmp->PixelFormat=pf32bit;
pyx=NULL;
_redraw=true;
}
//---------------------------------------------------------------------------
void __fastcall TMain::FormDestroy(TObject *Sender)
{
if (pyx) delete[] pyx;
delete bmp;
}
//---------------------------------------------------------------------------
void __fastcall TMain::FormResize(TObject *Sender)
{
xs=ClientWidth; xs2=xs>>1;
ys=ClientHeight; ys2=ys>>1;
bmp->Width=xs;
bmp->Height=ys;
if (pyx) delete[] pyx;
pyx=new int*[ys];
for (int y=0;y<ys;y++) pyx[y]=(int*) bmp->ScanLine[y];
_redraw=true;
int w=32;
// boundaries
x0=w; x1=xs-w;
y0=w; y1=ys-w;
z0=-100; z1=+100;
p1=vec3(x1-r1,y1-r1,0);
shoot();
update(0.0);
}
//---------------------------------------------------------------------------
void __fastcall TMain::FormPaint(TObject *Sender)
{
_redraw=true;
}
//---------------------------------------------------------------------------
void __fastcall TMain::tim_redrawTimer(TObject *Sender)
{
update(0.04);
_redraw=true;
draw();
}
//---------------------------------------------------------------------------
并预览:
再次重要的是功能shoot()
瞄准并发射子弹p0,v0
所以它击中了p1,v1
after t0
秒...功能update(dt)
只是模拟时间并处理碰撞......