0

I am programming my first actually 2D game(Pac-Man). I think game looks good,but I have one big problem - Collision. Object still going through the wall.I'm stuck with it so I decided to ask for help real programmers with great experience. (Of course I did some research, but I don't want to do things like COPY and Paste, because I didn't understand). As I said, game is almost done, just all I need to do is keep pacman from going through. Like example I draw large white rectangle as platform. I hope somebody is able to help me. Throughout this project I've learned much and collision is something which I understand, but don't know how correctly program it. I think I am close to figure it out, but something is missing.

PS: I've created window in WindowBuilder, so compiling might be a problem :(

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.border.EmptyBorder;

public class Main extends JFrame implements ActionListener{
    JPanel contentPane;
    Rectangle packman ;
    Rectangle platform;
    Rectangle secondPlat;

    private int count = 0;
    private int x = 170, y = 50;
    private int xVel = 1, yVel = 1;
    Timer timer;

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Main frame = new Main();
        frame.setVisible(true);
    }

    public Main() {
        // TODO Auto-generated constructor stub
        this.setSize(500,500);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        setContentPane(contentPane);
        getContentPane().setBackground(Color.gray);
        packman = new Rectangle(x,y,50,50);
        platform = new Rectangle(100,70,50,100);
        secondPlat = new Rectangle(220,50,50,100);
        timer = new Timer(0,this);
        timer.start();
        this.addKeyListener(new KeyListener() {

            @Override
            public void keyTyped(KeyEvent e) {
                // TODO Auto-generated method stub
            }

            @Override
            public void keyReleased(KeyEvent e) {
                // TODO Auto-generated method stub
                switch(e.getKeyCode()) {
                    case 37: //doleva
                    count = 1;  
                    repaint();
                    break;
                case 38: //nahorů       
                    count = 2;  
                    repaint();
                    break;
                case 39://doprava           
                    count = 3;          
                    repaint();
                    break;
                case 40://dolů      
                    count =4;   
                    repaint();
                    break;
                }
            }

            @Override
            public void keyPressed(KeyEvent e) {
                // TODO Auto-generated method stub
                System.out.println("Char" + e.getKeyCode());
                System.out.println("Hod" + e.getKeyCode());
            }
        });
    }

    @Override
    public void paint(Graphics g) {
        // TODO Auto-generated method stub
        super.paint(g);
        g.drawRect(x,y,packman.width,packman.height);
        g.setColor(Color.blue);
        g.fillRect(x,y,packman.width,packman.height);

        g.drawRect(platform.x,platform.y,platform.width,platform.height);
        g.setColor(Color.blue);
            
        g.drawRect(secondPlat.x,secondPlat.y,secondPlat.width,secondPlat.height);
        g.setColor(Color.blue);
    }

    @Override
    public void actionPerformed(ActionEvent arg0) {
        // TODO Auto-generated method stub
        if (count == 1) {
            x = x - xVel;
            repaint();
            zkontrolujKolizi();
        }
        
        if (count ==2) {
            y = y - yVel;
            repaint();
            zkontrolujKolizi();
        }
        if (count ==3) {
            x = x + xVel;
            repaint();
            zkontrolujKolizi();
        }
        if (count ==4) {
            y  = y+yVel; 
            repaint();
            zkontrolujKolizi();
        }
    }

    public void zkontrolujKolizi() {
        // TODO Auto-generated method stub
        if (packman.intersects(platform) || packman.intersects(secondPlat)) {
            System.out.println("Got ya!");
        }
    }
}
Abra
  • 19,142
  • 7
  • 29
  • 41
PeteJerk
  • 14
  • 2
  • The code does not compile, since a few classes are missing, but it's strange to me that you check collision before actually moving the objects. Normally you should do the check in the "animation" code (that is missing, so I cannot check it). – Rocco May 03 '21 at 09:10
  • @Rocco I got advice that I should post minimum code for understanding my problem,so I didn't add simple classes like ghost or packman.I added moving animation – PeteJerk May 03 '21 at 09:27
  • I understand, but please check better what a MRE is: https://stackoverflow.com/help/minimal-reproducible-example, it must be minimal, but complete; this means you have to start from scratch, creating a new project that reproduces the problem. If you just remove parts to reduce the size, then it will not compile and is hard to find the problem just with a visual inspection (without mentioning the fact that many people will not even try in this case). – Rocco May 03 '21 at 09:40
  • @Rocco Ok,I created new project with less code.My problem is,that rectangle ,,Pacman" is stilll able to going through,even I've used intersect method.I hope I did than before – PeteJerk May 03 '21 at 10:22
  • OK,but I'm not painting components,or did I?I'm little bit confused?I've never used PaintComponenent for painting – PeteJerk May 03 '21 at 11:02
  • Ok, now the problem is clear, I'll post the needed changes in a minute – Rocco May 03 '21 at 11:05

2 Answers2

1

In your code you update x and y, but this is not done in the "packman" object, that always sits at its initial position; so when you check intersection with the wall the packman is always at (170,50); I changed both the animation method to reflect the changes in packman and the paint method, so that you use the updated packman coordinates.

Animation:

@Override
public void actionPerformed(ActionEvent arg0) {
    // TODO Auto-generated method stub
    if (count == 1) {
        packman.x = packman.x - xVel;
        repaint();
        zkontrolujKolizi();
        
    
    }
    
    if (count ==2) {
        packman.y = packman.y - yVel;
        repaint();
        zkontrolujKolizi();
    }
    if (count ==3) {
        packman.x = packman.x + xVel;
        repaint();
        zkontrolujKolizi();
    }
    if (count ==4) {
        packman.y  = packman.y+yVel; 
        repaint();
        zkontrolujKolizi();
    }
    
    
}

Paint:

@Override
    public void paint(Graphics g) {
        // TODO Auto-generated method stub
        super.paint(g);
        g.drawRect(packman.x,packman.y,packman.width,packman.height);
        g.setColor(Color.blue);
        g.fillRect(packman.x,packman.y,packman.width,packman.height);
        
        g.drawRect(platform.x,platform.y,platform.width,platform.height);
        g.setColor(Color.blue);
        
        g.drawRect(secondPlat.x,secondPlat.y,secondPlat.width,secondPlat.height);
        g.setColor(Color.blue);
        
    }

Of course, there is much more to refactor in the code, but this is the reason why the collisions were not detected.

To avoid moving through the walls, calculate new position, check collision, if true, rollback the position changes:

@Override
public void actionPerformed(ActionEvent arg0) {
    int rollbackX=packman.x;
    int rollbackY=packman.y;

    switch (count) {
    case 1:
        packman.x = packman.x - xVel;
        break;
    case 2:
        packman.y = packman.y - yVel;
        break;
    case 3:
        packman.x = packman.x + xVel;
        break;
    case 4:
        packman.y  = packman.y+yVel;
        break;
    }

    //Collision found, rollback
    if (zkontrolujKolizi()) {
        packman.x=rollbackX;
        packman.y=rollbackY;
    } else {        
        repaint();
    }
}

public boolean zkontrolujKolizi() {
    return packman.intersects(platform) || packman.intersects(secondPlat);
}
Rocco
  • 1,098
  • 5
  • 11
  • Ok,it looks good the collision is detected,but how not to allow an object to pass through?Should I use getHeight() and Width() methods like when I don't want to leave screen.If you know what I mean :D – PeteJerk May 03 '21 at 11:15
  • @PeteJerk To avoid moving through the walls, calculate new position, check collision, if true, rollback the position changes, see the new code at the end. – Rocco May 03 '21 at 11:42
  • Ok,it works thank.I implemented it to my project for pacman,everything with collision works good,but after colliding the Jlabel with gif just literally fly away to nowhere:D :D – PeteJerk May 03 '21 at 12:41
  • Can I have another question?I don't know if you read my answer – PeteJerk May 03 '21 at 19:06
  • @PeteJerk If is about painting better open a new question, instead of modifying this one – Rocco May 03 '21 at 20:27
0

before collision after collision I've used exactly same,but just with moving object

 @Override
        public void actionPerformed(ActionEvent e) {
            //This is my actually code I've implemented from your answer
            int rollbackX = packRect.x;
            int rollbackY = packRect.y;
    
        switch (count) {
        case 1:
            packman.setCoordinatesX(packman.getCoordinatesX() - xVel);
            gifLabel.setLocation(packman.getCoordinatesX(), packman.getCoordinatesY()-38);
            packRect.x = packRect.x - xVel;
            collectPoint();
    //      repaint();
            break;
    
        case 2:
            packman.setCoordinatesY(packman.getCoordinatesY() - yVel);
            gifLabel.setLocation(packman.getCoordinatesX(), packman.getCoordinatesY()-38);
            packRect.y = packRect.y - yVel;
            sbirejBody();
    //      repaint();
            break;
        case 3:
            packman.setCoordinatesX(packman.getCoordinatesX() + xVel);
            gifLabel.setLocation(packman.getCoordinatesX(), packman.getCoordinatesY()-38);
            packRect.x = packRect.x + xVel;
            collectPoint();
    //      repaint();
            break;
        case 4:
            packman.setCoordinatesY(packman.getCoordinatesY() + yVel);
            gifLabel.setLocation(packman.getCoordinatesX(), packman.getCoordinatesY()-38);
            packRect.y  = packRect.y+yVel; 
            collectPoint();
        //  repaint();
            break;
        }
        
      

  int originX = packRect.x;
int originY = packRect.y;
packRect.setLocation(originX, originY); 
packman.setCoordinatesX(originX);
packman.setCoordinatesY(originY);
gifLabel.setLocation(originX, originY);
if (checkCollision) {
    rollbackX= originX;
    rollbackY = originY;
    
}else {
    repaint();
}
 packRect.setLocation(originX, originY); 
    packman.setCoordinatesX(originX);
    packman.setCoordinatesY(originY);
    gifLabel.setLocation(originX, originY);
}

public boolean checkCollision() {
    return packman.intersects(platform) || packman.intersects(secondPlat);
}
PeteJerk
  • 14
  • 2
  • Wait wait, now your packman is no longer the rect so you have to restore the previous coordinates on all objects that you changed before the collision check. – Rocco May 03 '21 at 22:09
  • @Rocco Something like this?I edited my question – PeteJerk May 04 '21 at 08:14