不要让图形超出JFrame边界

时间:2015-12-01 20:41:56

标签: java swing user-interface jframe jpanel

虽然有类似的问题,但我认为我的代码设置略有不同。我的main方法中有一个JFrame。但是,我的构造函数中只有JPanel。我尝试将我的一些变量设置为静态,以便我可以在main方法中访问它们,并说,例如,如果此图形的x坐标加上其宽度大于frame.getWidth()..但是赢得了'因某种原因而工作。我不想用代码轰炸任何人,所以我会尝试提供主要信息,如果你需要更多,我会更新它。

   package finalProj;

   import javax.swing.JFrame;
   import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.Ellipse2D;

public class nonaMaingamePractice extends JPanel implements ActionListener, KeyListener {
    /**
     *
     */
    private static final long serialVersionUID = 1L;

    private static Ellipse2D ellipse;
    static Toolkit tools = Toolkit.getDefaultToolkit();
    static int screenWidth = (int)(Math.round(tools.getScreenSize().getWidth()));
    static int screenHeight = (int)(Math.round(tools.getScreenSize().getHeight()));
    private static Rectangle paddleRect;
    JLabel text = new JLabel("cool");
    Timer timeMove = new Timer(1, this);
    Timer timeBall = new Timer(10, new timeBall());
    private static double x = screenWidth/2, y = (screenHeight*0.8), xx = 0, yy = 0, score = 0, Ox = screenWidth/2, Oy = screenHeight/2, Oyy = 0, width = 100, height = 30;
    public  nonaMaingamePractice(){
            setLayout(new BorderLayout());
            timeBall.start();               
            timeMove.start();
            addKeyListener(this);
            setFocusable(true);

            JPanel panelNorth = makePanel();
            panelNorth.setBackground(Color.CYAN);
            add(panelNorth, BorderLayout.NORTH);

            JLabel scoreLabel = new JLabel("Score: " + score);
            panelNorth.add(scoreLabel);


    }
    public void paintComponent(Graphics g){

            super.paintComponent(g);
            g.setColor(Color.BLUE);
            paddleRect = new Rectangle((int)x, (int)y, (int)width, (int)height);
            ellipse = new Ellipse2D.Double(Ox, Oy+Oyy, 50, 50);
            Graphics2D graphics = (Graphics2D)g;
            graphics.fill(paddleRect);             
            graphics.fill(ellipse);

    }
    @Override
    public void actionPerformed(ActionEvent e) {
            x = x + xx;
            y = y + yy;

            if(x<0){
                    x=0;
                    xx=0;
            }


            repaint();

    }

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

    }
    @Override
    public void keyPressed(KeyEvent e) {
            int c = e.getKeyCode();
            if(c==KeyEvent.VK_RIGHT){
                    xx=1;
            }else if(c==KeyEvent.VK_LEFT){
                    xx=-1;
            }

    }
    @Override
    public void keyReleased(KeyEvent e) {
            xx=0;

    }
     protected JPanel makePanel() {
            @SuppressWarnings("serial")

                    JPanel pane = new JPanel() {

                @Override
                public Dimension getPreferredSize() {
                    return new Dimension(100, 30);
                }
            };
            pane.setBackground(Color.CYAN);
            return pane;
        }

     protected class timeBall implements ActionListener{
         Timer timeWhateva = new Timer(100, this);

            @Override
            public void actionPerformed(ActionEvent e) {

                    try{
                        System.out.println(paddleRect.getX());
                        if(ellipse.intersects(paddleRect)){
                            timeWhateva.start();
                                Oy+=-1;
                                System.out.println(ellipse.getX() + " " + ellipse.getY());

                        }else if(!ellipse.intersects(paddleRect)){
                            Oyy+=1;
                        }
                }catch(RuntimeException NullPointerException){
                        System.out.println(NullPointerException.getMessage());
                }
                    repaint();
            }



     }


            public static void main(String[] args){

                    nonaMaingamePractice main = new nonaMaingamePractice();
                    JFrame frame = new JFrame();
                    frame.add(main);
                    frame.setVisible(true);
                    frame.setTitle("Project 4 game");
                    frame.setSize(screenWidth, screenHeight);
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            }
 }

1 个答案:

答案 0 :(得分:1)

好的,所以似乎有些事情是错误的。

首先,不要依赖static进行交叉对象交流,这是一个非常糟糕的主意,它会让你痛苦地咬你。相反,将信息传递给需要它的类。

其次,我专注于拥有一个Timer(或者#34;主循环&#34;),它负责更新游戏的当前状态和安排重新绘制。这是Model-View-Controller范例的基本概念

我要做的第一件事就是完全拆开你的代码并重建它......

首先,我想要一些界面,它提供有关游戏当前状态的信息,我可以将实例传递给游戏的其他部分,以便他们做出决定并更新游戏状态...

public interface GameView {
    public boolean isKeyRightPressed();
    public boolean isKeyLeftPressed();
    public Dimension getSize();
    public void updateState();
}

这提供了有关左右键状态,视图大小的信息,并提供了一些基本功能来请求视图更新它的当前状态

接下来,我们需要一些方法来模拟游戏的状态......

import java.awt.Rectangle;
import java.awt.geom.Ellipse2D;

public interface GameModel {
    public Rectangle getPaddle();
    public Ellipse2D getBall();
    public void ballWasMissed();
}

因此,这基本上保持了关于球拍和球的信息,并提供了一种方法,通过该手段,主游戏循环&#34;可以提供有关游戏状态的通知回到模型

接下来,我们需要实际的主游戏循环&#34;或控制器。这负责更新模型的状态并更新视图......

import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;

public class MainLoop implements ActionListener {

    private GameView gameView;
    private GameModel gameModel;
    private int ballYDelta = 1;

    public MainLoop(GameView gameView, GameModel gameModel) {
        this.gameView = gameView;
        this.gameModel = gameModel;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        Rectangle paddle = gameModel.getPaddle();
        Ellipse2D ball = gameModel.getBall();
        // Update the paddle position...
        if (gameView.isKeyLeftPressed()) {
            paddle.x--;
        } else if (gameView.isKeyRightPressed()) {
            paddle.x++;
        }
        // Correct for overflow...
        if (paddle.x < 0) {
            paddle.x = 0;
        } else if (paddle.x + paddle.width > gameView.getSize().width) {
            paddle.x = gameView.getSize().width - paddle.width;
        }

        // Update the ball position...
        Rectangle bounds = ball.getBounds();
        bounds.y += ballYDelta;
        if (bounds.y < 0) {
            bounds.y = 0;
            ballYDelta *= -1;
        } else if (bounds.y > gameView.getSize().height) {
            // Ball is out of bounds...
            // Notify the gameView so it knows what to do when the ball goes
            // out of the game view's viewable, ie update the score...
            // Reset ball position to just out side the top of the view...
            gameModel.ballWasMissed();
            bounds.y = -bounds.height;
        } else if (paddle.intersects(bounds)) {
            // Put the ball to the top of the paddle
            bounds.y = paddle.y - bounds.height;
            // Bounce
            ballYDelta *= -1;
        }
        ball.setFrame(bounds);

        // Update the view
        gameView.updateState();
    }

}

这基本上是我们决定对象当前位置和更新位置的地方。在这里,我们检查&#34;越界&#34;适当的位置和更新状态(例如,球可以&#34;反弹&#34;并改变方向)

delta值非常小,所以你可能想要使用那些

最后,我们需要能够将所有这些结合在一起的东西......

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.Timer;

public class NonaMaingamePractice extends JPanel implements KeyListener, GameView {

    /**
     *
     */
    private static final long serialVersionUID = 1L;

    JLabel text = new JLabel("cool");

    private Timer timeBall;
    private GameModel model;

    private boolean init = false;
    private boolean rightIsPressed;
    private boolean leftIsPressed;

    public NonaMaingamePractice() {
        setLayout(new BorderLayout());
        addKeyListener(this);
        setFocusable(true);

        JPanel panelNorth = makePanel();
        panelNorth.setBackground(Color.CYAN);
        add(panelNorth, BorderLayout.NORTH);

        JLabel scoreLabel = new JLabel("Score: " + 0);
        panelNorth.add(scoreLabel);

        addComponentListener(new ComponentAdapter() {
            @Override
            public void componentResized(ComponentEvent e) {
                if (getWidth() > 0 && getHeight() > 0 && !init) {
                    init = true;
                    model = new DefaultGameModel(getSize());
                    timeBall = new Timer(40, new MainLoop(NonaMaingamePractice.this, model));
                    timeBall.start();
                } else if (model != null) {
                    model.getPaddle().y = (getHeight() - model.getPaddle().height) - 10;
                }
            }

        });

    }

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

    @Override
    public void paintComponent(Graphics g) {

        super.paintComponent(g);
        g.setColor(Color.BLUE);
        Graphics2D graphics = (Graphics2D) g;
        if (model != null) {
            graphics.fill(model.getPaddle());
            graphics.fill(model.getBall());
        }

    }

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

    }

    @Override
    public void keyPressed(KeyEvent e) {
        int c = e.getKeyCode();
        if (c == KeyEvent.VK_RIGHT) {
            rightIsPressed = true;
        } else if (c == KeyEvent.VK_LEFT) {
            leftIsPressed = true;
        }
    }

    @Override
    public void keyReleased(KeyEvent e) {
        int c = e.getKeyCode();
        if (c == KeyEvent.VK_RIGHT) {
            rightIsPressed = false;
        } else if (c == KeyEvent.VK_LEFT) {
            leftIsPressed = false;
        }
    }

    protected JPanel makePanel() {
        @SuppressWarnings("serial")

        JPanel pane = new JPanel() {

            @Override
            public Dimension getPreferredSize() {
                return new Dimension(100, 30);
            }
        };
        pane.setBackground(Color.CYAN);
        return pane;
    }

    @Override
    public boolean isKeyRightPressed() {
        return rightIsPressed;
    }

    @Override
    public boolean isKeyLeftPressed() {
        return leftIsPressed;
    }

    @Override
    public void updateState() {
        // Maybe update the score??
        repaint();
    }

    public static void main(String[] args) {

        NonaMaingamePractice main = new NonaMaingamePractice();
        JFrame frame = new JFrame();
        frame.add(main);
        frame.setVisible(true);
        frame.setTitle("Project 4 game");
        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }
}