简体   繁体   中英

how to constantly display shapes, but still repaint the screen?

While writing a simple Tron game with JFrame, I came across a bit of a problem. I'm not sure how I could keep the display for the "light cycle" as a line that stays on the displayed on the screen, but at the same time repainting the screen so that movement is still functional. Here's my code:(fyi, it all compiles and everything works as it's written here perfectly fine)

public class Tron extends JPanel{

    public static int x = 40;
    public static int y = 40;
    public static int h = 360;
    public static int k = 360;
    public final static int size = 10;
    public static int move = 1;
    public static int dir = 0;
    static final Tron m = new Tron();
    static final JFrame frame = new JFrame("1P Tron");

    public static void main(String[] args){

        frame.setSize(400,400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(m);
        m.setBackground(Color.black);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        Action actionRight = new AbstractAction(){
            public void actionPerformed(ActionEvent actionRightEvent){
                dir = 1;
                x += 5;
                if(x > 390){
                    x = -5;
                };
                m.repaint();
            }
        };

        Action actionLeft = new AbstractAction(){
            public void actionPerformed(ActionEvent actionLeftEvent){
                dir = 2;
                x -= 5;
                if(x < 0){
                    x = 395;
                };
                m.repaint();
            }
        };

        Action actionUp = new AbstractAction(){
            public void actionPerformed(ActionEvent actionUpEvent){
                dir = 3;
                y -= 5;
                if(y < 0){
                    y = 375;
                };
                m.repaint();
            }
        };

        Action actionDown = new AbstractAction(){
            public void actionPerformed(ActionEvent actionDownEvent){
                dir = 4;
                y += 5;
                if(y > 370){
                    y = 0;
                };
                m.repaint();
            }
        };


        KeyStroke right = KeyStroke.getKeyStroke("RIGHT");
        KeyStroke left = KeyStroke.getKeyStroke("LEFT");
        KeyStroke up = KeyStroke.getKeyStroke("UP");
        KeyStroke down = KeyStroke.getKeyStroke("DOWN");

        InputMap inputMap = m.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        inputMap.put(right, "RIGHT");
        inputMap.put(left, "LEFT");
        inputMap.put(up, "UP");
        inputMap.put(down, "DOWN");
        m.getActionMap().put("RIGHT", actionRight);
        m.getActionMap().put("LEFT", actionLeft);
        m.getActionMap().put("UP", actionUp);
        m.getActionMap().put("DOWN", actionDown);

    }

    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        draw(g);
    }

    public void draw(Graphics g){
        g.setColor(Color.BLUE);
        g.fillRect(x, y, size, size);
        g.drawString("Tron", 190, 390);
    }

}

Also, I want to know how I would go about making it so that when I press an arrow key, instead of just adding or subtracting from the x or y coords once, it continuously adds to it until another arrow is pressed.

edit: To make this question a little easier to understand, the python equivalent would be drawing a character at an x and y coord with the curses library, using the arrow keys to move it around the screen, but never calling stdscr.clear() .

edit: While searching around on the internet trying to figure out how to use g.drawPolygon() as MadProgrammer suggested, I came across an interesting idea to add a variable to help the program "remember" which key was last pressed and to add to the coords based on that. I thought this would eliminate the need for a polygon and that I could just use the Translate() method, but when I added the translation the program stopped working. Is there a different method I need to use instead, or did I do something else wrong? Here's the new code:

import javax.swing.*;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import java.awt.*;
import java.awt.event.*;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.List;

public class Tron extends JPanel{

    public static int x = 40;
    public static int y = 40;
    public static int h = 360;
    public static int k = 360;
    public static int size = 10;
    public static int move = 1;
    public static int dir = 1;
    static final Tron m = new Tron();
    static final JFrame frame = new JFrame("1P Tron");

    public static void main(String[] args){

        frame.setSize(400,400);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(m);
        m.setBackground(Color.black);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);

        Action actionRight = new AbstractAction(){
            public void actionPerformed(ActionEvent actionRightEvent){
                dir = 1;
            };
        };

        Action actionLeft = new AbstractAction(){
            public void actionPerformed(ActionEvent actionLeftEvent){
                dir = 2;
            };
        };

        Action actionUp = new AbstractAction(){
            public void actionPerformed(ActionEvent actionUpEvent){
                dir = 3;
            };
        };

        Action actionDown = new AbstractAction(){
            public void actionPerformed(ActionEvent actionDownEvent){
                dir = 4;          
            };
        };


        KeyStroke right = KeyStroke.getKeyStroke("RIGHT");
        KeyStroke left = KeyStroke.getKeyStroke("LEFT");
        KeyStroke up = KeyStroke.getKeyStroke("UP");
        KeyStroke down = KeyStroke.getKeyStroke("DOWN");

        InputMap inputMap = m.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        inputMap.put(right, "RIGHT");
        inputMap.put(left, "LEFT");
        inputMap.put(up, "UP");
        inputMap.put(down, "DOWN");
        m.getActionMap().put("RIGHT", actionRight);
        m.getActionMap().put("LEFT", actionLeft);
        m.getActionMap().put("UP", actionUp);
        m.getActionMap().put("DOWN", actionDown);

    }

    @Override
    protected void paintComponent(Graphics g){
        super.paintComponent(g);
        draw(g);
        p1_move(m);
    }

    public void p1_move(Tron m){
        if(dir == 1){
            if(x > 390){
                x = -5;
            };
            x += 5;
            m.repaint();
        }else if(dir == 2){
            if(x < 0){
                x = 395;
            };
            x -= 5;
            m.repaint();
        }else if(dir == 3){
            if(y < 0){
                y = 375;
            };
            y -= 5;
            m.repaint();
        }else if(dir == 4){
            if(y > 370){
                y = 0;
            };
            y += 5;
            m.repaint();
        }
    }

    public void draw(Graphics g){
        g.setColor(Color.BLUE);
        g.fillRect(40, 40, size, size);
        g.translate(x, y);
    }
}

By the way, in case anyone's wondering why all the java.Util.* 's are imported separately, I was going to use those originally to create an ArrayList , but decided against it and never got around to taking those out.

edit: one list edit on this question, my program's almost done. The last thing I want to know is how to put a random number generator in for my cpu player. originally it had a set path and "killed" itself after a few seconds if you survived long enough, but I thought it would be more fun if he just went on a random path. I already know how to write random number generators using java.util.Random , but the code for those always ends up being a lot longer than I would lie it to be for my game, so I was wondering if it would be possible to add it in just maybe five or six statements.

The basic idea is you need to place all the shapes into some kind of List so that when you your paintComponent method is called, you call wall the list and paint the shapes

My "general" idea would be to add a new Point to a List each time the player makes a turn. In your paintComponent method, you would simply paint lines from one point to the next.

One of the last actions in your paint process, I would be to simply draw a line from the last point to the players current position...

Update with example using Path2D

This is a very basic example of a concept using Path2D to maintain the cycle path. Having done it this way, I think you will it easier to use a List of Point s, as this would be easier to build the collision detection.

在此处输入图片说明

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.geom.Line2D;
import java.awt.geom.Path2D;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class LightCycles {

    public static void main(String[] args) {
        new LightCycles();
    }

    public LightCycles() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static class TestPane extends JPanel {

        private int xVelocity;
        private int yVelocity;

        protected static final int PLAYER_SIZE = 4;
        protected static final int DELTA = 4;

        private Point player;
        private Point lastTurn;
        private Path2D playerPath;

        public TestPane() {
            setBackground(Color.BLACK);
            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();

            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0), "left");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0), "right");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0), "up");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0), "down");

            am.put("left", new VelocityAction(-DELTA, 0));
            am.put("right", new VelocityAction(DELTA, 0));
            am.put("up", new VelocityAction(0, -DELTA));
            am.put("down", new VelocityAction(0, DELTA));

            xVelocity = DELTA;

            player = new Point(0, 100);
            lastTurn = new Point(player);
            playerPath = new Path2D.Float();
            playerPath.moveTo(0, 100); // Start position...

            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    player.x += xVelocity;
                    if (player.x > getWidth()) {
                        playerPath.lineTo(getWidth(), player.y);
                        playerPath.moveTo(0, player.y);
                        player.x = 0;
                        lastTurn = new Point(player);
                    }
                    if (player.x + PLAYER_SIZE < 0) {
                        playerPath.lineTo(0, player.y);
                        playerPath.moveTo(getWidth() - 1, player.y);
                        player.x = getWidth() - 1;
                        lastTurn = new Point(player);
                    }
                    player.y += yVelocity;
                    if (player.y > getHeight()) {
                        playerPath.lineTo(player.x, getHeight());
                        playerPath.moveTo(player.x, 0);
                        player.y = 0;
                        lastTurn = new Point(player);
                    }
                    if (player.y + PLAYER_SIZE < 0) {
                        playerPath.lineTo(player.x, 0);
                        playerPath.moveTo(player.x, getHeight() - 1);
                        player.y = getHeight() - 1;
                        lastTurn = new Point(player);
                    }
                    repaint();
                }
            });
            timer.start();
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setColor(Color.BLUE);
            g2d.draw(playerPath);
            g2d.draw(new Line2D.Float(lastTurn, player));
            g2d.drawRect(player.x - (PLAYER_SIZE / 2), player.y - (PLAYER_SIZE / 2), PLAYER_SIZE, PLAYER_SIZE);
            g2d.dispose();
        }

        public class VelocityAction extends AbstractAction {

            private final int xDelta;
            private final int yDelta;

            public VelocityAction(int xDelta, int yDelta) {
                this.xDelta = xDelta;
                this.yDelta = yDelta;
            }

            @Override
            public void actionPerformed(ActionEvent e) {
                xVelocity = xDelta;
                yVelocity = yDelta;
                lastTurn = new Point(player);
                playerPath.lineTo(player.x, player.y);
            }

        }
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM