如何检测碰撞?

时间:2011-10-24 08:14:26

标签: java image collision-detection

我在世界范围内有一个两个图像(一只猫和一只狗),这是我的Board类。只有当我按下箭头键时,猫才会随机移动,而狗只会移动。我现在的问题是,如果两个图像之间发生碰撞,我怎么能让猫消失?任何答案或想法都将非常感激。

这是我尝试过的......

public class Cat extends Sprite implements ImageObserver
{
private java.awt.Image catImage;

private final Board board;
private double x;
private double y;
private double speed;
private double angle;
private boolean visible;

public Cat(Board board, double x, double y, double speed)
{
    this.board = board;
    this.x = x;
    this.y = y;
    this.speed = convertToMeterPerSecond(speed);
    visible = true;

    URL iU = this.getClass().getResource("cat.gif");
    ImageIcon icon = new ImageIcon(iU);
    catImage = icon.getImage();
}

public Image getImage()
{
    return catImage;
}

public void move(long dt)
{
    double dt_s = dt / 1e9;
    double dx_m = speed * dt_s * Math.sin(angle);
    double dy_m = speed * dt_s * Math.cos(angle);

    final double right_wall = board.x1_world;
    final double up_wall = board.y1_world;
    final double down_wall = 0.0;
    final double left_wall = 0.0;

    x += dx_m;
    y += dy_m;

    if (x >= right_wall)
    {
        x = right_wall;

        setRandomDirection();
    }
    if (y > up_wall)
    {
         y = up_wall;
        setRandomDirection();
    }
    if (x <= left_wall)
    {
        x = left_wall;
        setRandomDirection();
    }
    if (y < down_wall)
    {
         y = down_wall;
        setRandomDirection();
    }

}

public void setRandomDirection()
{
    Cat myObject = this;
    myObject.setAngle(Math.PI * 2 * Math.random());
}

@Override
public void render(Graphics2D g2d)
{
    AffineTransform t = g2d.getTransform();
    double height = 0.3; //meter
    double width = 0.3;  //meter

    double cat_footy = height;
    double cat_footx = width / 2;

    int xx = board.convertToPixelX(x - cat_footx);
    int yy = board.convertToPixelY(y + cat_footy);

    g2d.translate(xx, yy);

    double x_expected_pixels = width * board.meter;
    double y_expected_pixels = height * board.meter;

    double x_s = x_expected_pixels / ((ToolkitImage) catImage).getWidth();
    double y_s = y_expected_pixels / ((ToolkitImage) catImage).getHeight();

    double w = ((ToolkitImage) catImage).getWidth();
    double h = ((ToolkitImage) catImage).getHeight();


    g2d.scale(x_s, y_s);
    g2d.drawImage(getImage(), 0, 0, this); // upper left corner
    g2d.setColor(Color.BLACK);
    g2d.drawRect(0, 0, (int) w, (int) h);
    g2d.setTransform(t);
}

public void moveAt(double distance_x, double distance_y)
{
    this.x = (int) distance_x;
    this.y = (int) distance_y;
}

@Override
public Rectangle getBounds()
{
    double w = ((ToolkitImage) catImage).getWidth();
    double h = ((ToolkitImage) catImage).getHeight();

    return new Rectangle((int) x, (int) y, (int) w, (int) h);
}

public void setAngle(double angle)
{
    this.angle = angle;
}

public boolean isVisible()
{
    return visible;
}

public void setVisible(Boolean visible)
{
    this.visible = visible;
}

@Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
{
    return true;
}
}

我的Cat课程

public class Dog extends Sprite implements ImageObserver
{
private java.awt.Image humanImage;
private final Board board;
private double x;
private double y;
private double speed;
private boolean visible;
private double angle;
private double dx_m;
private double dy_m;

public Dog(Board board, double x, double y, double speed)
{
    this.board = board;
    this.x = x;
    this.y = y;
    this.speed = convertToMeterPerSecond(speed);
    visible = true;

    URL iU = this.getClass().getResource("dog.jpg");
    ImageIcon icon = new ImageIcon(iU);
    dogImage = icon.getImage();

}

public Image getImage()
{
    return dogImage;
}

public void keyPressed(KeyEvent e)
{

    int key = e.getKeyCode();

    if (key == KeyEvent.VK_LEFT)
    {
        dx_m = -0.3;
    }

    if (key == KeyEvent.VK_RIGHT)
    {
        dx_m = 0.3;
    }

    if (key == KeyEvent.VK_UP)
    {
        dy_m = 0.3;
    }

    if (key == KeyEvent.VK_DOWN)
    {
        dy_m = -0.3;

    }
}

public void keyReleased(KeyEvent e)
{
    int key = e.getKeyCode();

    if (key == KeyEvent.VK_LEFT)
    {
        dx_m = 0;
    }

    if (key == KeyEvent.VK_RIGHT)
    {
        dx_m = 0;
    }

    if (key == KeyEvent.VK_UP)
    {
        dy_m = 0;
    }

    if (key == KeyEvent.VK_DOWN)
    {
        dy_m = 0;
    }
}

@Override
public void move(long dt)
{
    double dt_s = dt / 1e9;

    final double right_wall = board.x1_world;
    final double up_wall = board.y1_world;
    final double down_wall = 0.0;
    final double left_wall = 0.0;

    x += dx_m;
    y += dy_m;
    if (x <= left_wall)
    {
        x = left_wall;
    }
    if (x >= right_wall)
    {
        x = right_wall;
    }

    if (y <= down_wall)
    {
        y = down_wall;
    }
    if (y >= up_wall)
    {
        y=up_wall;
    }
}

public void setRandomDirection()
{
    Dog myObject = this;
    myObject.setAngle(Math.PI * 2 * Math.random());
}

@Override
public void render(Graphics2D g2d)
{
    AffineTransform t = g2d.getTransform();

    final double dogHeight = 1.6;// meter
    final double dogWidth = 1.8;  //meter

    final double foot_position_y = dogHeight;
    final double foot_position_x = dogWidth / 2;

    int xx = board.convertToPixelX(x - foot_position_x); // to find the upper-left corner
    int yy = board.convertToPixelY(y + foot_position_y); // to find the upper-left corner

    g2d.translate(xx, yy);

    // ratio for actual Image size

    double x_expected_pixels = dogHeight * board.meter;
    double y_expected_pixels = dogWidth * board.meter;

    double w = ((ToolkitImage) dogImage).getWidth();
    double h = ((ToolkitImage) dogImage).getHeight();

    double x_s = x_expected_pixels / w;
    double y_s = y_expected_pixels / h;

    g2d.scale(x_s, y_s);
    g2d.drawImage(getImage(), 0, 0, this); // upper left corner
    g2d.setColor(Color.BLACK);
    g2d.drawRect(0, 0, (int) w, (int) h);
    g2d.setTransform(t);

}

@Override
public void moveAt(double distance_x, double distance_y)
{
    this.x = distance_x;
    this.y = distance_y;
}

public void setAngle(double angle)
{
    this.angle = angle;
}

@Override
public Rectangle getBounds()
{
    double width = ((ToolkitImage) dogImage).getWidth();
    double height = ((ToolkitImage) dogImage).getHeight();
    return new Rectangle((int) x, (int) y, (int) width, (int) height);
}

public boolean isVisible()
{
    return visible;
}

public void setVisible(Boolean visible)
{
    this.visible = visible;
}

@Override
public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
{
    return true;
}
}

为我的狗课

public class Board extends Canvas
{
private Cat cat;
public static final long SECOND = 1000 * 1000 * 1000;

public double meter;//PIXEL
private HumanBeing humanBeing;

/**
 * ascending from 0 to N
 * 0 : most far way...
 * N : is the closest (painted the last)
 */
private final java.util.List<Sprite> z_sorted_sprites = new ArrayList<Sprite>();

private BufferStrategy strategy;

int x0_pixel;
int y0_pixel;

int x1_pixel;
int y1_pixel;

double x1_world;
double y1_world;
private final Frame frame;


public Board(Frame frame, double meter)
{
    addKeyListener(new TAdapter());
    this.frame = frame;
    this.setIgnoreRepaint(true);

    this.meter = meter;

    setFocusable(true);
    dog = new Dog(this, 5, 5, 40);

    init();

    addComponentListener(new ComponentAdapter()
    {
        @Override
        public void componentResized(ComponentEvent e)
        {
            render();
        }
    });
}

public void init()
{

    z_sorted_sprites.add(new Cat(this, 0, 0, 30));
    z_sorted_sprites.add(new Cat(this, 1, 1, 10));
    z_sorted_sprites.add(new Cat(this, 2, 2, 20));
    z_sorted_sprites.add(new Cat(this, 3, 3, 100));

}

public void render()
{
    setupStrategy();

    x0_pixel = 0;
    y0_pixel = 0;

    x1_pixel = getWidth();
    y1_pixel = getHeight();

    x1_world = x1_pixel / meter;
    y1_world = y1_pixel / meter;

    Graphics2D g2d = (Graphics2D) strategy.getDrawGraphics();

    g2d.setBackground(Color.lightGray);
    g2d.clearRect(0, 0, x1_pixel, y1_pixel);

    g2d.setColor(Color.BLACK);

    for (double x = 0; x < x1_world; x++)
    {
        for (double y = 0; y < y1_world; y++)
        {
            int xx = convertToPixelX(x);
            int yy = convertToPixelY(y);

            g2d.drawOval(xx, yy, 2, 2);
        }
    }

    for (Sprite z_sorted_sprite : z_sorted_sprites)
    {
        z_sorted_sprite.render(g2d);
    }
    dog.render(g2d);

    g2d.dispose();

    strategy.show();

    Toolkit.getDefaultToolkit().sync();
}


public int convertToPixelX(double distance)
{
    return (int) (distance * meter);
}

public int convertToPixelY(double y_world)
{
    return (int) (y1_pixel - (y_world * meter));
}

public void onZoomUpdated(int value)
{
    meter = value;
    render();
}

private void setupStrategy()
{
    if (strategy == null)
    {
        this.createBufferStrategy(2);
        strategy = this.getBufferStrategy();
    }
}

public void start() throws InterruptedException
{
    long prevLoopStart = System.nanoTime();

    Avg avg = new Avg();

    while (true)
    {
        final long loopStart = System.nanoTime();
        final long dt = loopStart - prevLoopStart;

        for (Sprite sprite : z_sorted_sprites)
        {
            sprite.move(dt);

        }
        dog.move(dt);

        render();


        frame.onFpsUpdated(1.0 / dt * SECOND, avg.add(loopStart));

        final long elapsed_ns = System.nanoTime() - loopStart;

        long expected_elapsed_ms = 1000 / 60;
        long elapsed_ms = (long) (elapsed_ns / (1000.0 * 1000.0));
        long sleep_ms = expected_elapsed_ms - elapsed_ms;

        if (sleep_ms > 0)
        {
            Thread.sleep(sleep_ms  /* ms */);
        }

        prevLoopStart = loopStart;

    }
}

private void checkCollision()
{
    Rectangle r2 = cat.getBounds();
    Rectangle r3 = dog.getBounds();

    if (r3.intersects(r2))
    {
        dog.setVisible(false);
        cat.setVisible(false);
    }


}

static class Avg
{
    java.util.List<Long> ticks = new ArrayList<Long>();

    /**
     * @return the rate for the last second
     */
    int add(long tick)
    {
        ticks.add(0, tick);

        if (ticks.size() < 2)
        {
            return -1;
        }

        int last = -1;

        for (int pos = ticks.size() - 1; pos >= 0; pos--)
        {
            if (tick - ticks.get(pos) <= SECOND)
            {
                last = pos;
                break;
            }
        }

        while (ticks.size() - 1 > last)
        {
            ticks.remove(ticks.size() - 1);
        }

        return ticks.size();
    }
}

private class TAdapter extends KeyAdapter
{
    public void keyReleased(KeyEvent e)
    {
        dog.keyReleased(e);
    }

    public void keyPressed(KeyEvent e)
    {
        dog.keyPressed(e);
    }
}
}

我的董事会班级

public abstract class Sprite
{
public Sprite()
{

}

public Rectangle getBounds()
{
    return new Rectangle();
}


public static double convertToMeterPerSecond(double speed)
{
    // 25 km / hour
    //  25000 m / 3600 s
    return speed / 3.6;
}

public abstract void move(long dt);

public abstract void moveAt(double distance_x, double distance_y);

public abstract void render(Graphics2D g2d);

public abstract void setVisible(Boolean visible);

}

我的精灵课

public boolean checkCollisions(java.util.List<Sprite> sprites)
{
    Dog dog = this;
    Rectangle r1 = dog.getBounds();

    for (int i = 0; i < sprites.size(); i++)
    {
        Rectangle r2 = sprites.get(i).getBounds();
        if (r1.intersects(r2))
        {
            sprites.remove(i);
        }
    }
    return true;
}

3 个答案:

答案 0 :(得分:1)

你已经提供了很多代码,但正如Sibbo所说,我没有看到你的checkCollisions方法在任何地方被调用。它应该被称为游戏的每个循环。

Check out this tutorial,请特别查看gameLoop类中的Game方法。当我制作一个需要大量碰撞检测的基于精灵的游戏时,本教程帮助了我很多。

答案 1 :(得分:0)

我实现了检测猫和狗的位置在棋盘类中重叠的方法,因为棋盘是唯一“知道”狗和猫的实例。实现非常简单:比较坐标(类似dog.x + dog.width < cat.x || dog.x > cat.x + cat.width等等)

如果将来你可以实现更通用的方法,那么如果你想添加鼠标,你将能够重用代码。

答案 2 :(得分:0)

dog类不会覆盖getBounds()方法。因此,每次检查矩形(0,0,0,0)是否相交(例如,3,4,50,50)(如果cat位于(3,4))。

你在哪里调用checkCollision()方法?

修改

在Dog类中创建一个类似checkCollision()的方法:

public boolean checkCollision(Sprite s) {...}

当检测到碰撞时,它应该返回true。对于z_sorted_sprites中的每个Sprite,从Board.start()方法调用此方法。如果它返回true,则从列表中删除Sprite。