Java 检测与线条的碰撞并限制移动
我正在用Java制作一个libGDX游戏。我正在做碰撞检测。正如你在图片中看到的,我有一条线,这是一堵墙和一个具有指定半径的玩家。所需位置是玩家试图进入的下一个位置。但是因为有一堵墙,他被放置在实际的位置,在速度向量上,但更接近上一个位置。我在想我怎样才能发现那个更近的位置? 我的尝试:Java 检测与线条的碰撞并限制移动,java,libgdx,2d,collision-detection,Java,Libgdx,2d,Collision Detection,我正在用Java制作一个libGDX游戏。我正在做碰撞检测。正如你在图片中看到的,我有一条线,这是一堵墙和一个具有指定半径的玩家。所需位置是玩家试图进入的下一个位置。但是因为有一堵墙,他被放置在实际的位置,在速度向量上,但更接近上一个位置。我在想我怎样才能发现那个更近的位置? 我的尝试: private void move(float deltaTime) { float step; beginMovementAltitude(); if (playerComponen
private void move(float deltaTime) {
float step;
beginMovementAltitude();
if (playerComponent.isWalking())
step = handleAcceleration(playerComponent.getSpeed() + playerComponent.getAcceleration());
else step = handleDeacceleration(playerComponent.getSpeed(), playerComponent.getAcceleration());
playerComponent.setSpeed(step);
if (step == 0) return;
takeStep(deltaTime, step, 0);
}
private void takeStep(float deltaTime, float step, int rotate) {
Vector3 position = playerComponent.getCamera().position;
float x = position.x;
float y = position.y;
int radius = playerComponent.getRadius();
auxEnvelope.init(x, x + radius, y, y + radius);
List<Line> nearbyLines = lines.query(auxEnvelope);
float theta;
int numberOfIntersections = 0;
float angleToMove = 0;
Gdx.app.log(step + "", "");
for (Line line : nearbyLines) {
VertexElement src = line.getSrc();
VertexElement dst = line.getDst();
auxVector3.set(playerComponent.getCamera().direction);
auxVector3.rotate(Vector3.Z, rotate);
float nextX = x + (step * deltaTime) * (auxVector3.x);
float nextY = y + (step * deltaTime) * playerComponent.getCamera().direction.y;
float dis = Intersector.distanceLinePoint(src.getX(), src.getY(), dst.getX(), dst.getY(), nextX, nextY);
boolean bodyIntersection = dis <= 0.5f;
auxVector21.set(src.getX(), src.getY());
auxVector22.set(dst.getX(), dst.getY());
auxVector23.set(nextX, nextY);
if (bodyIntersection) {
numberOfIntersections++;
if (numberOfIntersections > 1) {
return;
}
theta = auxVector22.sub(auxVector21).nor().angle();
float angle = (float) (180.0 / MathUtils.PI * MathUtils.atan2(auxVector23.y - position.y, auxVector23.x - position.x));
if (angle < 0) angle += 360;
float diff = (theta > angle) ? theta - angle : angle - theta;
if (step < 0) step *=-1;
angleToMove = (diff > 90) ? theta + 180 : theta;
}
}
if (numberOfIntersections == 0) {
moveCameraByWalking(deltaTime, step, rotate);
} else {
moveCameraInDirection(deltaTime, step, angleToMove);
}
}
private void移动(浮动deltaTime){
浮动台阶;
开始移动高度();
if(playerComponent.isWalking())
步骤=手动加速(playerComponent.getSpeed()+playerComponent.getAcceleration());
else step=handleDeacceleration(playerComponent.getSpeed(),playerComponent.getAcceleration());
playerComponent.设定速度(步长);
如果(步骤==0)返回;
takeStep(deltaTime,step,0);
}
私有void takeStep(浮动增量时间、浮动步长、整数旋转){
Vector3位置=playerComponent.getCamera().position;
浮动x=位置x;
浮动y=位置y;
int radius=playerComponent.getRadius();
初始(x,x+半径,y,y+半径);
List nearbyLines=lines.query(auxEnvelope);
浮动θ;
int numberofcrossions=0;
浮动角度移动=0;
Gdx.app.log(步骤+“”,“”);
用于(行:近署名){
VertexElement src=line.getSrc();
VertexElement dst=line.getDst();
auxVector3.set(playerComponent.getCamera().direction);
auxVector3.rotate(Vector3.Z,rotate);
浮点nextX=x+(步长*增量)*(auxVector3.x);
float nextY=y+(步长*deltaTime)*playerComponent.getCamera().direction.y;
float dis=Intersector.distanceLinePoint(src.getX(),src.getY(),dst.getX(),dst.getY(),nextX,nextY);
布尔体相交=dis 1){
返回;
}
θ=auxVector22.sub(auxVector21.nor().angle();
浮动角度=(浮动)(180.0/MathUtils.PI*MathUtils.atan2(auxVector23.y-position.y,auxVector23.x-position.x));
如果(角度<0)角度+=360;
浮动差=(θ>角度)?θ-角度:角度-θ;
如果(步骤<0)步骤*=-1;
角度移动=(差值>90)?θ+180:θ;
}
}
if(numberofcrossions==0){
移动摄像机穿越(deltaTime、step、rotate);
}否则{
移动方向(deltaTime、step、angleToMove);
}
}
这个想法是找到物体中心的路径和由圆半径移动的线的交点,请参见该图
首先,你需要找到一条线。怎么做,取决于直线是如何定义的,如果它是由两点定义的,那么公式是
nx = ay - by
ny = bx - ax
如果这条线是由正则方程定义的,那么x和y的系数定义了法线,如果我没记错的话
当找到法线时,我们需要对其进行规格化——将坐标除以向量长度,将长度设置为1。就这样吧
然后,我们将在线上的起点、期望点和随机选择点投影到n,将它们视为
向量a到向量b的投影为
但由于b是n,长度等于1,我们将不应用除法,而且我们只想求结果的长度,我们不乘以b。所以我们只计算上述三个点中的每一个,得到三个数字,让我们作为起点的结果,d为期望点,l为线上的选择点
然后我们应该用圆的半径来修改l:
if (s < d) l -= r;
else if (s > d) l += r;
if(sd)l+=r;
如果s=d,则对象沿直线平行移动,因此直线不会阻碍其移动。这是极不可能的情况,但应该处理
另外,这一点很重要,如果l最初在s和d之间,但修改后不再在s和d之间,这是一种特殊情况,您可能需要处理(例如限制对象移动)
因此,应该计算(d-s)/(l-s)
如果结果大于或等于1,则对象将无法到达直线。如果结果介于0和1之间,则线会阻碍移动,并且结果指示对象将完成的部分路径。0.5表示对象将中途停止。
如果结果为负值,则表示线位于对象后面,不会阻碍移动
请注意,当使用浮点数时,结果不会非常精确,这就是我们处理这种特殊情况的原因。如果你想阻止这种情况发生,组织循环并尝试近似,直到达到所需的精度。你尝试了什么,你的错误是什么?在你给出的链接中,我没有看到将播放器置于“固定”位置的相关部分。我一开始试着检查下一个位置离墙的距离是否小于半径。如果是真的,我不会让玩家移动到那里。如果游戏者的速度是固定的,这种行为是正常的。但是在我的游戏中,速度是根据输入来加速和减速的——因此,如果速度高,玩家不会移动,但当速度低时,玩家会移动(在靠近墙的地方减速时会产生一些“慢跑”运动效果),你能提供你在问题中描述的这种尝试的代码吗?是的,在第一种方法中,似乎有很多行重复,这是实际代码吗?我想不会,因为这不会编译(重复变量名)。第二种方法也是如此
if (s < d) l -= r;
else if (s > d) l += r;