Овальное обнаружение столкновения не работает должным образом - PullRequest
1 голос
/ 14 мая 2010

Итак, я пытаюсь реализовать тест, в котором овал может соединяться с кружком, но он не работает.

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();
    }
}

Ответы [ 4 ]

2 голосов
/ 20 июня 2010

Является ли использование овалов абсолютным требованием? Вы можете аппроксимировать столкновения между причудливыми фигурами, представляя их несколькими кругами. Таким образом, вы можете использовать очень простое обнаружение столкновений между кругами и при этом достичь высокого уровня точности для зрителя.

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)
}

альтернативный текст http://strd6.com/wp-content/uploads/2010/06/circle_collisions.png

0 голосов
/ 29 мая 2014

Если вы можете найти свои фокусы, вы можете проверить наличие столкновений с помощью псевдокода ниже. ВНИМАНИЕ это работает только для двух эллиптических столкновений (эллипс и круговые столкновения также работают).

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

Если вы действительно хотите получить это, дайте мне знать, и я предоставлю это. Но он использует идею о том, что сумма расстояний между фокусами эллипса и любой точкой на краю эллипса составляет заданное расстояние друг от друга (большая полуось). И решает для точки, которая находится на краю обоих эллипсоидов, и если они существуют, то это столкновение.

0 голосов
/ 13 ноября 2011

Если вы планируете реализовать больше фигур и / или вам нужно минимальное расстояние между фигурами, вы можете начать использовать GJK : вам нужно будет только реализовать вспомогательные функции для каждой новой фигуры. Если время вычислений также имеет решающее значение, GJK - это то, на что вы должны обратить внимание, но для этого, безусловно, потребуется больше программирования.

0 голосов
/ 19 мая 2010

Найти пересечение сложнее, чем вы думаете. Ваш 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
}
...