椭圆形碰撞检测无法正常工作

发布于 2024-09-01 10:17:57 字数 3015 浏览 7 评论 0原文

所以我试图实现一个测试,其中椭圆形可以与圆形连接,但它不起作用。

edist = (float) Math.sqrt(
    Math.pow((px + ((pwidth/2) )) - (bx + (bsize/2)), 2 ) + 
    Math.pow(-((py + ((pwidth/2)) ) - (bx + (bsize/2))), 2 )
);

这是完整的代码(需要 Slick2D):

import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;

public class ColTest extends BasicGame{


    float px = 50;
    float py = 50;
    float pheight = 50;
    float pwidth = 50;



    float bx = 200;
    float by = 200;
    float bsize = 200;

    float edist;

    float pspeed = 3;
    Input input;

    public ColTest()
    {
        super("ColTest");
    }

    @Override
    public void init(GameContainer gc)
            throws SlickException {

    }

    @Override
    public void update(GameContainer gc, int delta)
            throws SlickException
    {
        input = gc.getInput();

        try{    
            if(input.isKeyDown(Input.KEY_UP))   
                py-=pspeed;

            if(input.isKeyDown(Input.KEY_DOWN)) 
                py+=pspeed;

            if(input.isKeyDown(Input.KEY_LEFT)) 
                px-=pspeed;

            if(input.isKeyDown(Input.KEY_RIGHT))    
                px+=pspeed;
        }

        catch(Exception e){}
    }

    public void render(GameContainer gc, Graphics g)
            throws SlickException
    {   
            g.setColor(new Color(255,255,255));
            g.drawString("col: " + col(), 10, 10);
            g.drawString("edist: " + edist + " dist: " + dist, 10, 100);

            g.fillRect(px, py, pwidth, pheight);
            g.setColor(new Color(255,0,255));
            g.fillOval(px, py, pwidth, pheight);
            g.setColor(new Color(255,255,255));
            g.fillOval(200, 200, 200, 200);

    }

    public boolean col(){

        edist = (float) Math.sqrt(Math.pow((px + ((pwidth/2) )) - (bx + (bsize/2)), 2) + Math.pow(-((py + ((pwidth/2)) ) - (bx + (bsize/2))), 2));

        if(edist <= (bsize/2) + (px + (pwidth/2)))
            return true;

        else
            return false;
    }

    public float rotate(float x, float y, float ox, float oy, float a, boolean b)
    {
         float dst = (float) Math.sqrt(Math.pow(x-ox,2.0)+ Math.pow(y-oy,2.0));

         float oa = (float) Math.atan2(y-oy,x-ox);

         if(b)
            return (float) Math.cos(oa + Math.toRadians(a))*dst+ox;

         else
            return (float) Math.sin(oa + Math.toRadians(a))*dst+oy;

    }

    public static void main(String[] args)
            throws SlickException
    {
         AppGameContainer app =
            new AppGameContainer( new ColTest() );

         app.setShowFPS(false);
         app.setAlwaysRender(true);
         app.setTargetFrameRate(60);
         app.setDisplayMode(800, 600, false);
         app.start();
    }
}

So I'm trying to implement a test where a oval can connect with a circle, but it's not working.

edist = (float) Math.sqrt(
    Math.pow((px + ((pwidth/2) )) - (bx + (bsize/2)), 2 ) + 
    Math.pow(-((py + ((pwidth/2)) ) - (bx + (bsize/2))), 2 )
);

and here is the full code (requires Slick2D):

import org.newdawn.slick.AppGameContainer;
import org.newdawn.slick.BasicGame;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.Input;
import org.newdawn.slick.SlickException;

public class ColTest extends BasicGame{


    float px = 50;
    float py = 50;
    float pheight = 50;
    float pwidth = 50;



    float bx = 200;
    float by = 200;
    float bsize = 200;

    float edist;

    float pspeed = 3;
    Input input;

    public ColTest()
    {
        super("ColTest");
    }

    @Override
    public void init(GameContainer gc)
            throws SlickException {

    }

    @Override
    public void update(GameContainer gc, int delta)
            throws SlickException
    {
        input = gc.getInput();

        try{    
            if(input.isKeyDown(Input.KEY_UP))   
                py-=pspeed;

            if(input.isKeyDown(Input.KEY_DOWN)) 
                py+=pspeed;

            if(input.isKeyDown(Input.KEY_LEFT)) 
                px-=pspeed;

            if(input.isKeyDown(Input.KEY_RIGHT))    
                px+=pspeed;
        }

        catch(Exception e){}
    }

    public void render(GameContainer gc, Graphics g)
            throws SlickException
    {   
            g.setColor(new Color(255,255,255));
            g.drawString("col: " + col(), 10, 10);
            g.drawString("edist: " + edist + " dist: " + dist, 10, 100);

            g.fillRect(px, py, pwidth, pheight);
            g.setColor(new Color(255,0,255));
            g.fillOval(px, py, pwidth, pheight);
            g.setColor(new Color(255,255,255));
            g.fillOval(200, 200, 200, 200);

    }

    public boolean col(){

        edist = (float) Math.sqrt(Math.pow((px + ((pwidth/2) )) - (bx + (bsize/2)), 2) + Math.pow(-((py + ((pwidth/2)) ) - (bx + (bsize/2))), 2));

        if(edist <= (bsize/2) + (px + (pwidth/2)))
            return true;

        else
            return false;
    }

    public float rotate(float x, float y, float ox, float oy, float a, boolean b)
    {
         float dst = (float) Math.sqrt(Math.pow(x-ox,2.0)+ Math.pow(y-oy,2.0));

         float oa = (float) Math.atan2(y-oy,x-ox);

         if(b)
            return (float) Math.cos(oa + Math.toRadians(a))*dst+ox;

         else
            return (float) Math.sin(oa + Math.toRadians(a))*dst+oy;

    }

    public static void main(String[] args)
            throws SlickException
    {
         AppGameContainer app =
            new AppGameContainer( new ColTest() );

         app.setShowFPS(false);
         app.setAlwaysRender(true);
         app.setTargetFrameRate(60);
         app.setDisplayMode(800, 600, false);
         app.start();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

原来是傀儡 2024-09-08 10:17:57

使用椭圆形是绝对要求吗?您可以通过用多个圆圈来表示更奇特的形状之间的碰撞。这样,您就可以在圆圈之间使用非常简单的碰撞检测,并且仍然可以为观看者实现高精度。

collision(c1, c2) {
  dx = c1.x - c2.x;
  dy = c1.y - c2.y;
  dist = c1.radius + c2.radius;

  return (dx * dx + dy * dy <= dist * dist)
}

替代文本
(来源:strd6.com

Is using ovals an absolute requirement? You can approximate collisions between fancier shapes by representing them with multiple circles. That way you can use very a simple collision detection between circles and still achieve a high level of accuracy for the viewer.

collision(c1, c2) {
  dx = c1.x - c2.x;
  dy = c1.y - c2.y;
  dist = c1.radius + c2.radius;

  return (dx * dx + dy * dy <= dist * dist)
}

alt text
(source: strd6.com)

沉默的熊 2024-09-08 10:17:57

找到交叉点比你想象的要难。您的 col() 方法有点偏离,但该方法最多能够告诉您单个点是否在圆内。它无法真正检测到交叉点。

我在谷歌上搜索了一些用于计算实际交叉点的代码。我发现 JavaScript 中的一个非常有趣而且真的很复杂。查看源代码

如果您想要更简单的东西(但不太准确),您可以检查椭圆周围的几个点,看看它们是否在圆内。

private boolean isInCircle(float x, float y) {
    float r = bsize / 2;
    float center_x = bx + r;
    float center_y = by + r;
    float dist = (float) Math.sqrt(Math.pow(x - center_x, 2) + Math.pow(y - center_y, 2));

    return dist < r;
}

public boolean col() {
    return 
        isInCircle(px + pwidth / 2, py              ) || // top
        isInCircle(px + pwidth    , py + pheight / 2) || // right
        isInCircle(px + pwidth / 2, py + pheight    ) || // bottom
        isInCircle(px             , py + pheight / 2);   // left
}

Finding the intersection is harder than you think. Your col() method is a bit off, but that approach will at best be able to tell you if a single point is within the circle. It won't be able to really detect intersections.

I Googled up some code for computing the actual intersections. I found one in JavaScript that's really interesting and really complicated. Take a look at the source.

If you wanted something a bit simpler (but less accurate), you could check a few points around the ellipse to see if they're within the circle.

private boolean isInCircle(float x, float y) {
    float r = bsize / 2;
    float center_x = bx + r;
    float center_y = by + r;
    float dist = (float) Math.sqrt(Math.pow(x - center_x, 2) + Math.pow(y - center_y, 2));

    return dist < r;
}

public boolean col() {
    return 
        isInCircle(px + pwidth / 2, py              ) || // top
        isInCircle(px + pwidth    , py + pheight / 2) || // right
        isInCircle(px + pwidth / 2, py + pheight    ) || // bottom
        isInCircle(px             , py + pheight / 2);   // left
}
紫轩蝶泪 2024-09-08 10:17:57

如果您计划实现更多形状和/或需要形状之间的最小距离,您可以开始使用 GJK :您只需要为每个新形状实现支持函数。如果计算时间也很关键,那么 GJK 绝对是您应该考虑的东西,但它肯定需要您进行更多编程。

If you plan on implementing more shapes and/or need the minimum distance between your shapes, you could start using GJK : you would only need to implement the support functions for each new shape. If computation time is also critical, GJK is definitely something you should look at, but it would surely require some more programming on your side.

七颜 2024-09-08 10:17:57

如果您能找到焦点,则可以使用下面的伪代码检查是否发生碰撞。
警告这仅适用于两个椭圆碰撞(椭圆和圆形碰撞也适用)。

r = length of semi major axis
a_x = x coordinate of foci 1 of the first ellipse
a_y = y coordinate of foci 1 of the first ellipse
b_x = x coordinate of foci 2 of the first ellipse
b_y = y coordinate of foci 2 of the first ellipse

c_x = x coordinate of foci 1 of the second ellipse
c_y = y coordinate of foci 1 of the second ellipse
d_x = x coordinate of foci 2 of the second ellipse
d_y = y coordinate of foci 2 of the second ellipse

p_x = (a_x+b_x+c_x+d_x)/4 // i.e. the average of the foci x values
p_y = (a_y+b_y+c_y+d_y)/4 // i.e. the average of the foci y values

if r >= ( sqrt( (p_x + a_x)^2+(p_y + a_y)^2 ) + sqrt( (p_x + a_x)^2+(p_y + a_y)^2 ) )
then collision

如果您确实想要此推导,请告诉我,我会提供。但它使用的思想是,椭圆的焦点与​​椭圆边缘上的任何点之间的距离之和是相距设定距离(半长轴)的。并求解位于两个椭球体边缘的点,如果存在一个点,则它们是碰撞。

If you can find your foci you can check for collision with the pseudo code below.
WARNING this only works for two ellipse collisions (ellipse and circle collisions work also).

r = length of semi major axis
a_x = x coordinate of foci 1 of the first ellipse
a_y = y coordinate of foci 1 of the first ellipse
b_x = x coordinate of foci 2 of the first ellipse
b_y = y coordinate of foci 2 of the first ellipse

c_x = x coordinate of foci 1 of the second ellipse
c_y = y coordinate of foci 1 of the second ellipse
d_x = x coordinate of foci 2 of the second ellipse
d_y = y coordinate of foci 2 of the second ellipse

p_x = (a_x+b_x+c_x+d_x)/4 // i.e. the average of the foci x values
p_y = (a_y+b_y+c_y+d_y)/4 // i.e. the average of the foci y values

if r >= ( sqrt( (p_x + a_x)^2+(p_y + a_y)^2 ) + sqrt( (p_x + a_x)^2+(p_y + a_y)^2 ) )
then collision

If you really want the derivation of this let me know and I'll provide it. But it uses the idea that the sum of the distances between the foci of an ellipse and any point on the edge of an ellipse are a set distance apart (the semi major axis). And solves for a point that is on the edge of both ellipsoids and if one exist then their is a collision.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文