During the process of creating my latest game, I've come across the problem of collisions. In the last few games I've made, I've used a system of collision detection that relyed on two rectangle's methods. This seems to work, but doesn't provide a method for dissallowing an entity entry into an area. I've tried numerous different forumals, but none were able to kick an entity out of an area that shouldn't have anything in it.

Thanks!
Jack

Recommended Answers

All 8 Replies

It really shouldn't be any different from other collisions. Once you know the collision occurred, you just change the state of the colliding object to whatever result you intend. That may involve adjusting its velocity and position.

I know that, and I've got it working in the game, but I don't know how to tell where to put the entity after its been detected as to have collided with something.

I guess that depends on what you intend the behavior "kick something out" to mean. Does it bounce backward? Slide sideways? Pop out on the other side?

If you maintain a directional vector of any kind or separate x,y velocities, then you can determine the resulting position based upon the vector of incidence and whatever rules you decide for the outcome as I mentioned above.

You just need to examine the state at the time of collision. If you aren't saving it in a way that allows that, you may need to alter your objects to keep that information handy.

commented: helpful and concise +8

That's an interesting idea. I'm no math expert, so help me here. If I keep track of the entity's movement, and use the baic trigonometric functions (which could be tough, for me) to find the angle of movement, then I could look across the imaginary circle, and move the entity in that direction, no? I think I'll try that.

So, I've finished it (doesn't fully work), and I've got one of the four sides responding well. I did this by not using a previous x,y vector but by using the deltas from movement on the last frame of the game. I compare this with the keystrokes and determine which direction its moving. Then, when I dectect that, I reverse the angle of movement, and start moving the offending entity in that direction. This works on only one of the four directions, the top.

On a totally different note, if I've got an inner class, like a Thread working, and it needs to read from a member of its outer class, is using <Outclass Name>.this.<member to read> the best way, or can it be done in a better way?

Thanks, Jack

That sounds reasonable for a "bounce off" response. It's generally just a reversal of dx and/or dy. You can shortcut those easily with expressions like dx *= -1; to change the direction of delta x, etc. The various sides are just a matter of determining the surface of incidence.

Regarding the inner class question, yes, that is how you refer to the current instance of the parent class: ParentClassName.this.whatever()

Here's some example code that I didn't have time to finish up yesterday. It may clarify some of what I mentioned above:

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class BallCollision extends JPanel {

    Timer animationTimer;
    Ball ball;
    BadLands badlands;

    public BallCollision() {
        ball = new Ball(10,10,5);
        badlands = new BadLands(50,50,90,60);

        animationTimer = new Timer(50, new BallAnimation());
        animationTimer.start();
    }

    class Ball {
        Ellipse2D shape;
        float speedX = 5;
        float speedY = 3;

        public Ball(int x, int y, int radius){
            shape = new Ellipse2D.Float(x, y, radius*2, radius*2);
        }

        public void draw(Graphics2D g){
            g.setColor(Color.BLUE);
            g.fill(shape);
        }

        public void updatePosition(){
            if (shape.getX()<0 || shape.getMaxX()>getWidth()){
                speedX *= -1;
            }
            if (shape.getY()<0 || shape.getMaxY()>getHeight()){
                speedY *= -1;
            }
            shape.setFrameFromCenter(
                    new Point2D.Double(
                        shape.getCenterX()+speedX,
                        shape.getCenterY()+speedY),
                    new Point2D.Double(
                        shape.getX()+speedX,
                        shape.getY()+speedY));
        }

        public boolean collidesWith(Shape otherShape){
            return shape.intersects(otherShape.getBounds());
        }

        public void processCollision(Shape otherShape){
            Rectangle2D otherBounds = otherShape.getBounds2D();
            if ((shape.getCenterX()-speedX<otherBounds.getX() 
                    && shape.getCenterY()+speedY>otherBounds.getMinY()) 
                || (shape.getCenterX()-speedX>otherBounds.getX()+otherBounds.getWidth() 
                    && shape.getCenterY()+speedY>otherBounds.getMinY())) {
                // left/right collision
                speedX *= -1;
            }
            if ((shape.getCenterX()+speedX>otherBounds.getX() 
                    && shape.getCenterY()-speedY<otherBounds.getMinY()) 
                || (shape.getCenterX()+speedX>otherBounds.getX() 
                    && shape.getCenterY()+speedY>otherBounds.getMinY()+otherBounds.getHeight())) {
                // top/bottom collision
                speedY *= -1;
            }
        }
    }

    class BadLands {
        Rectangle2D shape;

        public BadLands(int x, int y, int width, int height){
            shape = new Rectangle2D.Float(x, y, width, height);
        }

        public void draw(Graphics2D g){
            g.setColor(Color.BLACK);
            g.fill(shape);
        }
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D)g;
        // this just makes the line look smoother, less pixelation when at an angle
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
            RenderingHints.VALUE_ANTIALIAS_ON);

        g2d.clearRect(0, 0, getWidth(), getHeight());
        badlands.draw(g2d);
        ball.draw(g2d);
    }

    class BallAnimation implements ActionListener {
        // this gets called every "tick" of the timer
        public void actionPerformed(ActionEvent e) {
            ball.updatePosition();
            if (ball.collidesWith(badlands.shape)){
                ball.processCollision(badlands.shape);
            }
            repaint();
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame f = new JFrame();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                BallCollision ballPanel = new BallCollision();
                f.add(ballPanel);
                f.setBounds(100, 100, 200, 200);
                f.setVisible(true);
            }
        });
    }
}

I found the problem! Thanks for all your help. :-)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.