user843916
user843916

Reputation:

How to detect a collision?

I'm having a two image(a cat and a dog) inside the world which is in my Board class. The cat moves in a random direction while the dog move only when I press the arrow keys. My problem now is that how can I make the cat disappear whenever there is a collision between the two images? Any answer or idea would be much appreciated.

Here's what I've tried...

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

for my Cat class

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

for my Dog class

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

For my Board class

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

}

For my sprite class

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

Upvotes: 3

Views: 307

Answers (3)

Sibbo
Sibbo

Reputation: 3914

The dog class doesn't overwrite the getBounds() method. So everytime you check if the rectangle (0, 0, 0, 0) intersects for example (3, 4, 50, 50) (if the cat is at (3, 4)).

Where do you call the checkCollision() method?

EDIT:

Create a method like your checkCollision() in your Dog class:

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

It should return true, when a collision is detected. Call this method from the Board.start() method for every Sprite in z_sorted_sprites. IF it returns true, remove the Sprite from the list.

Upvotes: 0

ubiquibacon
ubiquibacon

Reputation: 10667

You have given a lot of code, but as Sibbo said, I don't see your checkCollisions method being called anywhere. It should be called every loop of your game.

Check out this tutorial, specifically look at the gameLoop method in the Game class. When I made a sprite based game that required a lot of collision detection this tutorial helped me out a lot.

Upvotes: 1

AlexR
AlexR

Reputation: 115328

I'd implement method that detects that positions of cat and dog overlap in the board class since board is the only instance that "knows" both dog and cat. The implementation is pretty simple: compare coordinates (something like dog.x + dog.width < cat.x || dog.x > cat.x + cat.width etc, etc.

If future you can implement more generic method, so if you will wish to add mouse you will be able to reuse the code.

Upvotes: 0

Related Questions