帮助四方乒乓球比赛 - 检查碰撞 [英] Help with four way pong game - check for collision

查看:90
本文介绍了帮助四方乒乓球比赛 - 检查碰撞的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在制作一个4 Way Pong Program。我知道我的拨片会随着鼠标的移动而移动,并且球将在屏幕周围反弹。



我在考虑如何解决问题时陷入困境检查球和桨之间的碰撞(这将增加得分)以及球和JPanel边缘之间的碰撞(这将结束游戏)。



非常感谢任何指导...



游戏等级



I am working on a 4 Way Pong Program. I have it to the point where my paddles will move with mouse movement, and the ball will bounce around the screen.

I am stuck when it comes to figuring out how to check for collisions between the ball and the paddles (which will increase the score) and between the ball and the edges of the JPanel (which will end the game).

Any guidance is greatly appreciated...

Game Class

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Game extends JPanel {

    JFrame window = new JFrame();
    Timer timer = new Timer(30, new ActionHandler());
    ArrayList<Ball> balls = new ArrayList<Ball>();
    ArrayList<Paddle> horizPaddles = new ArrayList<Paddle>();
    ArrayList<Paddle> vertPaddles = new ArrayList<Paddle>();
    Paddle pTop;
    Paddle pBottom;
    Paddle pRight;
    Paddle pLeft;
    Ball b;
    int score = 0;
    JLabel scoreLabel;

    //==========================================================
    public Game() {

        window.setBounds(100,100,900,500);
        window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        window.setTitle("4 Way Pong");
        window.setResizable(false);

        JPanel scorePanel = new JPanel(true);

        scoreLabel = new JLabel("Current Score: " + Integer.toString(score));
        scoreLabel.setFont(new Font("sansserif", Font.PLAIN, 20));
        scoreLabel.setForeground(Color.RED);
        scorePanel.add(scoreLabel);

        JPanel buttons = new JPanel(true);

        Container con = window.getContentPane();    
        con.setLayout(new BorderLayout());
        con.add(this, BorderLayout.CENTER);
        con.add(buttons, BorderLayout.SOUTH);
        con.add(scorePanel, BorderLayout.NORTH);

        this.setBackground(Color.BLACK);
        this.addMouseMotionListener(new MouseMoved());

        ButtonCatch bc = new ButtonCatch();

        JButton btn;
        btn = new JButton("New Game");
        btn.addActionListener(bc);
        buttons.add(btn); 

        btn = new JButton("Swap Colors");
        btn.addActionListener(bc);
        buttons.add(btn); 

        btn = new JButton("High Scores");
        btn.addActionListener(bc);
        buttons.add(btn); 

        btn = new JButton("Save Score");
        btn.addActionListener(bc);
        buttons.add(btn); 

        btn = new JButton("Quit");
        btn.addActionListener(bc);
        buttons.add(btn); 

        timer.start();

        window.setVisible(true);
    }

    //==========================================================
    public static void main(String[] args) {             
        new Game();
    }

    //==========================================================
    public void update() {
        for(Ball b : balls) {
            b.move(getWidth() + 30, getHeight() + 25);
        }


        //checkSideCollision();
        //checkHorizPaddleCollision();
        //checkVertPaddleCollision();
        repaint();
    }

    //==========================================================
    public void checkSideCollision() {
        if(b.getyPos() > getHeight()) {
            JOptionPane.showMessageDialog(null, "Game Over.  You Scored " + score + ".", "GAME OVER", JOptionPane.INFORMATION_MESSAGE);
            System.exit(0);
        }
    }

    //==========================================================
    public void checkHorizPaddleCollision() {
        if(b.getxPos() == pBottom.getX() && b.getyPos() == pBottom.getY()) {
            //b.yPos = b.yPos - 5;
            score++;
        }
    }

    //==========================================================
    public void checkVertPaddleCollision() {

    }

    //==========================================================
    public class ButtonCatch implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            switch(e.getActionCommand()) {
            case "Quit":        JOptionPane.showMessageDialog(null, "You Quit... No Score Recorded", "Game Over", JOptionPane.INFORMATION_MESSAGE); System.exit(0);
            case "New Game":    newGame(); break;
            case "Swap Colors": swapColors(); break;
            case "High Scores": try { displayScores(); } catch (Exception e1) { System.out.println(e1.getMessage()); } break;
            case "Save Score":   try { saveScore(); } catch (Exception e2) { System.out.println(e2.getMessage()); } break;
            }
        }   
    }

    //==========================================================
    public void paint(Graphics g) {
        super.paint(g);

        for(Ball b : balls) {
            b.draw(g);
        }

        for(Paddle p : horizPaddles) {
            p.draw((Graphics2D) g);
        }

        for(Paddle p : vertPaddles) {
            p.draw((Graphics2D) g);
        }
    }

    //==========================================================
    //FIX FOR DISPLAYING SCORES
    private void displayScores() throws Exception { 

    }

    //==========================================================
    //FIX -- Store Score in a File
    private void saveScore() throws Exception {
        int userScore = score;
        String name = JOptionPane.showInputDialog("Enter Your Name: ");
        JOptionPane.showMessageDialog(null, "Saved!\n" + name + " scored " + userScore, "Score Recorded", JOptionPane.INFORMATION_MESSAGE);
    }

    //==========================================================
    private void swapColors() {
        for(Ball b : balls) {
            if(b.color.equals(Color.red)) { 
                b.setColor(Color.yellow);
            } else if (b.color.equals(Color.yellow)) {
                b.setColor(Color.blue);
            } else {
                b.setColor(Color.red);
            }
        }
    }

    //==========================================================
    private void newGame() {
        //CREATE BALL
        balls.clear();

        b = new Ball();
        b.color = Color.red;
        b.dx = (int)(Math.random() * 4) + 1;
        b.dy = (int)(Math.random() * 4) + 1;
        b.xPos = (int)(Math.random() * 4) + 1;
        b.yPos = (int)(Math.random() * 4) + 1;

        balls.add(b);

        //CREATE PADDLES
        horizPaddles.clear();
        vertPaddles.clear();

            // bottom
        pBottom = new Paddle();
        pBottom.x = getWidth() / 2;
        pBottom.y = getHeight();
        pBottom.setX(pBottom.getX()-20);
        pBottom.setY(pBottom.getY()-20);
        pBottom.setWidth(100);
        pBottom.setHeight(20);
        horizPaddles.add(pBottom);

            //top
        pTop = new Paddle();
        pTop.x = getWidth() / 2;
        pTop.y = getHeight();
        pTop.setX(0 + pTop.getX());
        pTop.setY(0);
        pTop.setWidth(100);
        pTop.setHeight(20);
        horizPaddles.add(pTop);

            //left
        pLeft = new Paddle();
        pLeft.x = getWidth() / 2;
        pLeft.y = getHeight();
        pLeft.setX(0);
        pLeft.setY(pLeft.getY() / 2);
        pLeft.setWidth(20);
        pLeft.setHeight(100);
        vertPaddles.add(pLeft);

            //right
        pRight = new Paddle();
        pRight.x = getWidth() / 2;
        pRight.y = getHeight();
        pRight.setX(875);
        pRight.setY(pRight.getY() / 2);
        pRight.setWidth(20);
        pRight.setHeight(100);
        vertPaddles.add(pRight);

        timer.start();

    }

    //==========================================================
    public class ActionHandler implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent arg0) {
            update();
        }

    }

    //==========================================================
    public class MouseMoved implements MouseMotionListener {

        @Override 
        public void mouseMoved(MouseEvent e) {
            for(Paddle p : horizPaddles) {
                p.x = e.getX();
            }

            for(Paddle p : vertPaddles) {
                p.y = e.getY();
            }
        }

        @Override public void mouseDragged(MouseEvent e) {}

    }

}





Paddle Class





Paddle Class

import java.awt.Color;
import java.awt.Graphics2D;

public class Paddle implements Drawable{
    public int x, y, width, height;

    public Paddle() {
        super();
    }

    public Paddle(int x, int y, int width, int height) {
        super();
        setX(x);
        setY(y);
        setWidth(width);
        setHeight(height);
    }

    @Override
    public void draw(Graphics2D g) {
        g.setColor(Color.green);
        g.fillRect(x, y, width, height);
    }

    public int getX() {
        return x;
    }

    public void setX(int x) {
        this.x = x;
    }

    public int getY() {
        return y;
    }

    public void setY(int y) {
        this.y = y;
    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

}





球类





Ball Class

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.io.IOException;
import java.io.RandomAccessFile;

import javax.swing.JPanel;

public class Ball implements Comparable<Ball>, Cloneable{
    private static int count = 0;
    public static final int NAME_LENGTH = 20;
    public String name = "";
    public int xPos=0, yPos=0, dx = 3, dy = 2;
    public Color color = Color.red;

    public static void resetCounter() { count = 0; }

    public Ball() {name = "Rock: " + ++count;}

    public Ball(RandomAccessFile file) {
        load(file);
    }

    public void load(RandomAccessFile file) {
        try {
            xPos = file.readInt();
            yPos = file.readInt();
            dx = file.readInt();
            dy = file.readInt();
            color = new Color( file.readInt() );

            byte[] n = new byte[NAME_LENGTH];
            file.readFully(n);
            name = new String(n).trim();
            System.out.println(name);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public void save(RandomAccessFile file) {
        try {
            file.writeInt(xPos);
            file.writeInt(yPos);
            file.writeInt(dx);
            file.writeInt(dy);
            file.writeInt(color.getRGB());
            file.writeBytes( getStringBlock(name, NAME_LENGTH) );

        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    private String getStringBlock(String string, int len) {
        StringBuilder sb = new StringBuilder(name);
        sb.setLength(len);
        return sb.toString();       
    }


    public void draw(Graphics g) {
        g.setColor(color);
        g.fillOval(xPos, yPos, 25, 25);
        g.setColor(Color.black);
        g.drawOval(xPos, yPos, 25, 25);
    }

    public void setColor(Color c) {
        color = c;
    }

    public void move(int width, int height) {
        xPos+=dx;
        yPos+=dy;

        if(xPos + 50 > width) {
            xPos = width - 50;
            dx = -dx;
        } 

        if(yPos + 50 > height) {
            yPos = height - 50;
            dy = -dy;
        } 

        if(xPos < 0) {
            xPos = 0;
            dx = -dx;
        }

        if(yPos < 0) {
            yPos = 0;
            dy = -dy;
        }
    }

    @Override
    public int compareTo(Ball arg0) {

        return 0;
    }

    public int getxPos() {
        return xPos;
    }

    public int getyPos() {
        return yPos;
    }

}





提前再次感谢您的帮助!



Thanks again in advance for any help!

推荐答案

警告 - 我没有查看你的代码:



通常你会处理每个项目的边界框你想测试碰撞 - 假设你的桨是相对长方形的,那么每个的边界框应该很容易确定。



对于球,大概是圆形的,边界框是一个正方形,边=球的直径,以球的中心为中心。再次,简单的确定。



现在,因为有四个蝙蝠和一个球,我会让你的桨类检查与球的碰撞(假设桨)不要相互碰撞)



当一个边界框中的一个点位于另一个边界内时发生碰撞,因此对于划桨来说



让它的左下角为Xp,Yp,它的宽度为Wp,高度为Hp



球是左下角拐角Xb,Yb和宽度高度为Wb,Hb



您的碰撞检查将类似......



If(Xp>(Xb + Wb))返回false; // Paddle完全在球的右边

If((Xp + Wp)< Xb)返回false; //桨完全在球的左边



...



等等



与边缘的碰撞可以类似地完成 - 即使用相同的原理,但检查球是否在屏幕的边界框内,而不是在它之外。



碰撞的一件事是你需要允许隧道掘进;这就是你的模拟的粒度意味着在一个框架中,球是比如蝙蝠面前的一个像素,而在下一个框架中,它是蝙蝠背后的一个像素(例如,你的球以10像素行进)每帧和你的球棒是2像素宽,球每帧6像素)



当球未通过球拍时这也是一个问题;球可以反弹,但是立即(下一帧)它仍然接触球拍。您可以使用某种计时器来避免这种情况(每x帧动画仅碰撞一次)
caveat - I haven't looked at your code:

Normally you would deal with a bounding box for each item you want to test for collision - assuming your paddles are relatively rectangular, then the bounding box for each should be simple to determine.

For the ball, presumably circular, the bounding box is a square, of side = diameter of ball, centered at the ball's centre. Again, simple to determine.

Now, as there are four bats and one ball, I would have your paddle class check for a collision with the ball (assuming the paddles don't collide with one another)

Collisions occur when a point in one bounding box is inside the other, so for the paddle

let its bottom left corner be at Xp, Yp and it has a width of Wp and height of Hp

The ball is bottom left corner Xb, Yb and width height at Wb, Hb

Your collision check would be something like...

If (Xp > (Xb + Wb)) return false; // Paddle is entirely to the right of the ball
If ((Xp + Wp) < Xb) return false; // Paddle is entirely to the left of the ball

...

and so on

Collision with the edges can be done similarly - i.e. use the same principal, but checking that the ball is within the bounding box of the screen, rather than outside it.

One thing with collisions is that you need to allow for tunneling; this is where, the granularity of your simulation means that in one frame the ball is, say, one pixel infront of the bat, and in the next it is one pixel (say) behind the bat (e.g. your ball is travelling at 10 pixels per frame and your bat is 2 pixels wide and the ball is 6 pixels per frame)

This is also a problem when the ball doesn't pass right through the paddle; The ball may bounce, but immediately (next frame) it is still touching the paddle. You can use a timer of some sort to avoid this (only collide once per x frames of animation)


这篇关于帮助四方乒乓球比赛 - 检查碰撞的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆