Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
776 views
in Technique[技术] by (71.8m points)

swing - Java rectangle collision detection confusion

I have made a simple 2D state change game using Bucky's slick Java tutorials, I modified this game and now want to set collisions on the map so that my player can not go through the house on the map. I think I kind of have a idea of how collisions work:

you make 2 rectangles using the following code:

public Rectangle getBounds() {
 return new Rectangle(x, y, width, height);

}

1 for the player and 1 for the obstacle, how would I put this into my code and how would I tell java that the rectangle for the obstacle is different to the player rectangle?

Then after making the 2 rectangles I would set up a if statement saying something like if intersects do this...

Hopefully after this I think it would work. Some more information on the game, it being a state change game it has a few methods, methods like init, render and update (where do I place my rectangles and if statements, in the update method?) also, its a overhead view game kind of like pokemon if that helps. If you require my code please ask, I did not want to put it on now to overcrowd this post.

Edit1:

package javagame;

import org.newdawn.slick.*;
import org.newdawn.slick.state.*;

public class Play extends BasicGameState{

    Animation bucky, movingUp, movingDown, movingLeft, movingRight, movingBL, movingBR, movingFL, movingFR;
    Image worldMap;
    boolean quit = false;//gives user to quit the game
    int[] duration = {200, 200};//how long frame stays up for
    float buckyPositionX = 0;
    float buckyPositionY = 0;
    float shiftX = buckyPositionX + 320;//keeps user in the middle of the screem
    float shiftY = buckyPositionY + 160;//the numbers are half of the screen size

    public Play(int state){
    }   
    public void init(GameContainer gc, StateBasedGame sbg) throws SlickException{
          worldMap = new Image("res/world.png");
          Image[] walkUp = {new Image("res/b.png"), new Image("res/b.png")}; //these are the images to be used in the "walkUp" animation
          Image[] walkDown = {new Image("res/f.png"), new Image("res/f.png")};
          Image[] walkLeft = {new Image("res/l.png"), new Image("res/l.png")};
          Image[] walkRight = {new Image("res/r.png"), new Image("res/r.png")};
          Image[] walkBL = {new Image("res/bl.png"), new Image("res/bl.png")};
          Image[] walkBR = {new Image("res/br.png"), new Image("res/br.png")};
          Image[] walkFL = {new Image("res/fl.png"), new Image("res/fl.png")};
          Image[] walkFR = {new Image("res/fr.png"), new Image("res/fr.png")};

    movingUp = new Animation(walkUp, duration, false);
    movingDown = new Animation(walkDown, duration, false);  
    movingLeft = new Animation(walkLeft, duration, false);  
    movingRight = new Animation(walkRight, duration, false);
    movingBL = new Animation(walkBL, duration, false);
    movingBR = new Animation(walkBR, duration, false);
    movingFL = new Animation(walkFL, duration, false);
    movingFR = new Animation(walkFR, duration, false);
    bucky = movingDown;//facing screen initially on startup
    }


    public void render(GameContainer gc, StateBasedGame sbg, Graphics g) throws SlickException{
    worldMap.draw(buckyPositionX, buckyPositionY);//position 0,0
    bucky.draw(shiftX, shiftY);//makes him appear at center of map
    g.drawString("Suraj's X: "+buckyPositionX+"
Suraj's Y: "+buckyPositionY,400,20);//tells us the position

    if(quit==true){
        g.drawString("Resume(R)", 250, 100);
        g.drawString("Main(M)", 250, 150);
        g.drawString("Quit Game(Q)", 250, 200);
        if(quit==false){
            g.clear();//wipe off everything from screen
        }
    }
    }

    public void update(GameContainer gc, StateBasedGame sbg, int delta)throws SlickException{
    Input input = gc.getInput();
    //up
    if(input.isKeyDown(Input.KEY_UP)){
        bucky = movingUp;//changes the image to his back
        buckyPositionY += 10;;//increase the Y coordinates of bucky (move him up)
        if(buckyPositionY>162){//if I reach the top 
            buckyPositionY -= 10;//stops any further movement in that direction
        }
    }

    //down
    if(input.isKeyDown(Input.KEY_DOWN)){
        bucky = movingDown;
        buckyPositionY -= 10;
        if(buckyPositionY<-600){
            buckyPositionY += 10;//basically change the direction if + make -
    }}
    //left
    if(input.isKeyDown(Input.KEY_LEFT)){
        bucky = movingLeft;
        buckyPositionX += 10;
        if(buckyPositionX>324){
            buckyPositionX -= 10;//delta * .1f
    }}
    //right
    if(input.isKeyDown(Input.KEY_RIGHT)){
        bucky = movingRight;
        buckyPositionX -= 10;
        if(buckyPositionX<-840){
            buckyPositionX += 10;
    }}




    //2 key combos start here
    if(input.isKeyDown(Input.KEY_RIGHT) && input.isKeyDown(Input.KEY_UP)){
        bucky = movingBR;
        buckyPositionX -= delta * .1f;
        if(buckyPositionX<-840){
            buckyPositionX += delta * .1f;
            if(buckyPositionY>162){
                buckyPositionY -= delta * .1f;
            }}}
    if(input.isKeyDown(Input.KEY_LEFT) && input.isKeyDown(Input.KEY_UP)){
        bucky = movingBL;
        buckyPositionX -= delta * .1f;
        if(buckyPositionX>324){
            buckyPositionX -= delta * .1f;
            if(buckyPositionY>162){
                buckyPositionY -= delta * .1f;
            }}}
    if(input.isKeyDown(Input.KEY_RIGHT) && input.isKeyDown(Input.KEY_DOWN)){
        bucky = movingFR;
        buckyPositionX -= delta * .1f;
        if(buckyPositionY<-600){
            buckyPositionY += delta * .1f;
            if(buckyPositionX<-840){
                buckyPositionX += delta * .1f;
            }}}
    if(input.isKeyDown(Input.KEY_LEFT) && input.isKeyDown(Input.KEY_DOWN)){
        bucky = movingFL;
        buckyPositionX -= delta * .1f;
        if(buckyPositionY<-600){
            buckyPositionY += delta * .1f;
            if(buckyPositionX>324){
                buckyPositionX -= delta * .1f;
            }}}

     //escape
    if(input.isKeyDown(Input.KEY_ESCAPE)){
        quit=true;
    }
    //when the menu is up
    if(quit==true){//is the menu on the screen
        if(input.isKeyDown(Input.KEY_R)){
            quit = false;//resumes the game, makes menu dissapear
        }
        if(input.isKeyDown(Input.KEY_M)){
            sbg.enterState(0);//takes you to the main menu
        }
        if(input.isKeyDown(Input.KEY_Q)){
            System.exit(0);//quits the game
        }
    }

}

    public int getID(){
        return 1;
    }
}

This is my Play class, the only other 2 class's I have are the main and the menu, I cant imagine the rectangle methods being made in the main or menu class so the only one left is the Play, but I dont understand how to make 2 different Rectangles (one for the player the other for the house) in the code I have done so far. If you require my main and my menu class please tell me.

Edit 3:

I have tried what you have said and made a Rectanglebase class and put the if sattement you had posted inside there but am getting errors, it is asking me to make a method for getX and getY in my player class also the public in fornt of the constructor also has a error:

public Rectanglebase{}//the public is saying syntax error

I also made a Home and Player class like you had said but am a bit confused on what I need to put in it, I put under the Home class:

return Rectangle(100,100,100,100);

but am getting errors, I am not sure if I did this correct or not. Also, in the player class for the x,y positions how would I set my float variables from my Play class for my player?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Here is an example of a Game Loop / Game Logic and collision detection via Rectangle2D#intersects(..) method .

It uses JPanel to draw everything on and Rectangle2D is used for Entity class (which is any object needed to be drawn to GamePanel which is our JPanel where everything is drawn).

The updateGame() method is where you will find the collision checking:

    private void updateGame() {

        if (entities.get(0).intersects(entities.get(1))) {
            System.out.println("Intersecting");
        }
         ....
    }

You are Player 1 and move with W,A,S,D. When you intersect Player 2, a println() will confirm the intersection.

enter image description here

GameLogic.java:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

/**
 *
 * @author David Kroukamp
 */
public class GameLogic {

    public GameLogic() {
        initComponents();
    }
    final GamePanel gp = new GamePanel(500, 500);

    private void initComponents() {

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        Entity entity1 = new Entity(100, 100, 100, 100, createWhiteImage());
        Entity entity2 = new Entity(300, 200, 100, 100, createBlackImage());

        gp.addEntity(entity1);
        gp.addEntity(entity2);//just a standing still JPanel

        setGamePanelKeyBindings(gp, entity1);

        frame.add(gp);

        frame.pack();
        frame.setVisible(true);

        //start the game loop which will repaint the screen
        runGameLoop();
    }
    //Starts a new thread and runs the game loop in it.

    public void runGameLoop() {
        Thread loop = new Thread(new Runnable() {
            @Override
            public void run() {
                gp.running.set(true);
                gp.gameLoop();
            }
        });
        loop.start();
    }

    private void setGamePanelKeyBindings(GamePanel gp, final Entity entity) {
        gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"), "D pressed");
        gp.getActionMap().put("D pressed", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                entity.RIGHT = true;
            }
        });

        gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"), "A pressed");
        gp.getActionMap().put("A pressed", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                entity.LEFT = true;
            }
        });

        gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("W"), "W pressed");
        gp.getActionMap().put("W pressed", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                entity.UP = true;
            }
        });

        gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("S"), "S pressed");
        gp.getActionMap().put("S pressed", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                entity.DOWN = true;
            }
        });
        gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released D"), "D released");
        gp.getActionMap().put("D released", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                entity.RIGHT = false;
            }
        });

        gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released A"), "A released");
        gp.getActionMap().put("A released", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                entity.LEFT = false;
            }
        });

        gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released W"), "W released");
        gp.getActionMap().put("W released", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                entity.UP = false;
            }
        });

        gp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released S"), "S released");
        gp.getActionMap().put("S released", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent ae) {
                entity.DOWN = false;
            }
        });
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new GameLogic();
            }
        });
    }

    private BufferedImage createWhiteImage() {
        BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = img.createGraphics();
        g2.setColor(Color.WHITE);
        g2.fillRect(0, 0, img.getWidth(), img.getHeight());
        return img;
    }

    private BufferedImage createBlackImage() {
        BufferedImage img = new BufferedImage(100, 100, BufferedImage.TYPE_INT_ARGB);
        Graphics2D g2 = img.createGraphics();
        g2.setColor(Color.BLACK);
        g2.fillRect(0, 0, img.getWidth(), img.getHeight());
        return img;
    }
}

class Entity extends Rectangle2D.Double {

    private int speed = 5;
    public boolean UP = false,
            DOWN = false,
            LEFT = false,
            RIGHT = false;
    private final BufferedImage image;

    public Entity(int x, int y, int width, int height, BufferedImage image) {
        super(x, y, width, height);
        this.width = width;
        this.height = height;
        this.image = image;
    }

    public BufferedImage getImage() {
        return image;
    }

    public void move() {
        if (UP) {
            y -= speed;
        }
        if (DOWN) {
            y += speed;
        }
        if (LEFT) {
            x -= speed;
        }
        if (RIGHT) {
            x += speed;
        }

    }
}

class GamePanel extends JPanel {

    private int width, height;
    private int frameCount = 0;
    private int fps = 0;
    public static AtomicBoolean running = new AtomicBoolean(false), paused = new AtomicBoolean(false);
    final ArrayList<Entity> entities = new ArrayList<>();

    GamePanel(int w, int h) {
        super(true);
        setIgnoreRepaint(true);//mustnt repaint itself the gameloop will do that
        setLayout(null);
        width = w;
        height = h;
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(width, height);
    }

    public void addEntity(Entity e) {
        entities.add(e);
    }

    //Only run this in another Thread!
    public void gameLoop() {
        //This value would probably be stored elsewhere.
        final double GAME_HERTZ = 30.0;
        //Calculate how many ns each frame should take for our target game hertz.
        final double TIME_BETWEEN_UPDATES = 1000000000 / GAME_HERTZ;
        //At the very most we will update the game this many times before a new render.
        //If you're worried about visual hitches more than perfect timing, set this to 1.
        final int MAX_UPDATES_BEFORE_RENDER = 5;
        //We will need the last update time.
        double lastUpdateTime = System.nanoTime();
        //Store the last time we rendered.
        double lastRenderTime = System.nanoTime();

        //If we are able to get as high as this FPS, don't render again.
        final double TARGET_FPS = 60;
        final double TARGET_TIME_BETWEEN_RENDERS = 1000000000 / TARGET_FPS;

        //Simple way of finding FPS.
        int lastSecondTime = (int) (lastUpdateTime / 1000000000);

        while (running.get()) {
            double now = System.nanoTime();
            int updateCount = 0;

            if (!paused.get()) {
                //Do as many game updates as we need to, potentially playing catchup.
                while (now - lastUpdateTime > TIME_BETWEEN_UPDATES && updateCount < MAX_UPDATES_BEFORE_RENDER) {
                    updateGame();
                    lastUpdateTime += TIME_BETWEEN_UPDATES;
                    updateCount++;
                }

                //If for some reason an update takes forever, we don't want to do an insane number of catchups.
                //If you were doing some sort of game that needed to keep EXACT time, you would get rid of this.
                if (now - lastUpdateTime > TIME_BETWEEN_UPDATES) {
                    lastUpdateTime = now - TIME_BETWEEN_UPDATES;
                }

                drawGame();
                lastRenderTime = now;

                //Update the frames we got.
                int thisSecond = (int) (lastUpdateTime / 1000000000);

                if (thisSecond > lastSecondTime) {
                    System.out.println("NEW SECOND " + thisSecond + " " + frameCount);
                    fps = frameCount;
                    frameCount = 0;
                    lastSecondTime = thisSecond;
                }

                //Yield until it has been at least the target time between renders. This saves the CPU from hogging.
                while (now - lastRenderTime < TARGET_TIME_BETWEEN_RENDERS && now - lastUpdateTime < TIME_BETWEEN_UPDATES) {
                    //allow the threading system to play threads that are waiting to run.
                    Thread.yield();

                    //This stops the app from consuming all your CPU. It makes this slightly less accurate, but is worth it.
                    //You can remove this line and it will still work (better), your CPU just climbs on certain OSes.
                    //FYI on some OS's this can cause pretty bad stuttering. Scroll down and have a look at different peoples' solutions to this.
                    //On my OS it does not unpuase the game if i take this away
                    try {
                        Thread.sleep(1);
                    } catch (Exception e) {
                    }

                    now = System.nanoTime();
                }
            }
        }
    }

    private void drawGame() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                repaint();
            }
        });
    }

    private void updateGame() {

        if (entities.get(0).intersects(entities.get(1))) {
            System.out.println("Intersecting");
        }

        for (Entity e : entities) {
            e.move();
        }
    }

    @Override
    protected void paintComponent(Graphics grphcs) {
        super.paintComponent(grphcs);
        Graphics2D g2d = (Graphics2D) grphcs;

        applyRenderHints(g2d);

        g2d.setColor(Color.GREEN);
        g2d.fillRect(0, 0, getWidth(), getHeight());

        for (Entity e : entiti

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...