Problems with Java's Paint method, ridiculous refresh velocity

|▌冷眼眸甩不掉的悲伤 提交于 2019-11-26 21:07:33
  • The image fondo should already be scaled to 1200x600.
  • I am not sure, but is super.paint(g) needed? You might also use paintComponent.

The event handling (you seem to be moving by 1 pixel on key down), must be done correctly. I would have set the direction and speed (1px), and leave it to a swing timer to do the continuous moving.

Repainting best is done resilient/flexible: repaint(20L) (50 frames per second); events like key-down maybe with EventQueue.invokeLater(new Runnable() { ... });.

Especially you might use repaint with the changed area.

You can find a great example of a similar program here. The example demonstrates creating a new thread and having that thread sleep every iteration through the main loop.

Here is another question about loading images for games in Java.

It looks like swing itself is pretty crummy for using images in games. You may want to consider using a more suitable library.

Below is simple example using a background as simple game loop. It updates the state of the game objects and calculates the required delay in order to maintain the required fps.

The game object (Ship) has the ability to accelerate/decelerate over a short period of time

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
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.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class AnimationTest {

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

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

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new GamePane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }

        });
    }

    public class GamePane extends JPanel {

        private Ship ship;

        public GamePane() {

            ship = new Ship();
            Thread thread = new Thread(new MainLoop(this));
            thread.setDaemon(true);
            thread.start();

            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();

            // Key controls...
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, false), "upPressed");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, false), "downPressed");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0, true), "upReleased");
            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0, true), "downReleased");

            am.put("upPressed", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    // Change the direction...
                    ship.setDirection(-1);
                    // Accelerate by 1 per frame
                    ship.setVelocity(1);
                }

            });
            am.put("downPressed", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    // Change direction
                    ship.setDirection(1);
                    // Accelerate by 1 per frame
                    ship.setVelocity(1);
                }

            });
            am.put("upReleased", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    // Deccelerate by 1 per frame
                    ship.setVelocity(-1);
                }

            });
            am.put("downReleased", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    // Deccelerate by 1 per frame
                    ship.setVelocity(-1);
                }

            });
        }

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

        public void updateState() {
            // Update the state of the game objects.
            // This would typically be better done in 
            // some kind of model
            ship.update(getWidth(), getHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            // Paint the game state...
            Graphics2D g2d = (Graphics2D) g.create();
            ship.paint(g2d);
            g2d.dispose();
        }

    }

    public class MainLoop implements Runnable {

        private GamePane pane;
        private int fps = 25;

        public MainLoop(GamePane pane) {
            this.pane = pane;
        }

        @Override
        public void run() {
            // Wait until the screen is ready
            while (pane.getHeight() <= 0) {
                try {
                    Thread.sleep(125);
                } catch (InterruptedException ex) {
                }
            }
            // Main loop
            while (true) {
                // Start time loop
                long startTime = System.currentTimeMillis();
                // Update the game state
                pane.updateState();
                // Calculate the amount of time it took to update
                long elasped = System.currentTimeMillis() - startTime;
                // Calculate the number of milliseconds we need to sleep
                long sleep = Math.round((1000f / fps) - elasped);
                pane.repaint();
                if (sleep > 0) {
                    try {
                        Thread.sleep(sleep);
                    } catch (InterruptedException ex) {
                    }
                }
            }
        }

    }

    public static class Ship {

        public static int MAX_SPEED = 8;
        private int direction = 0;
        private int velocity = 0;
        private int x;
        private int y;
        private int speed = 0;
        private Path2D shape;
        private boolean initState;

        public Ship() {
            shape = new Path2D.Float();
            shape.moveTo(0, 0);
            shape.lineTo(5, 5);
            shape.lineTo(0, 10);
            shape.lineTo(0, 0);
            shape.closePath();
            initState = true;
        }

        public void setDirection(int direction) {
            this.direction = direction;
        }

        public void setVelocity(int velocity) {
            this.velocity = velocity;
        }

        public void update(int width, int height) {
            if (initState) {
                y = (height - 10) / 2;
                initState = false;
            } else {
                // Add the velocity to the speed
                speed += velocity;
                // Don't over accelerate
                if (speed > MAX_SPEED) {
                    speed = MAX_SPEED;
                } else if (speed < 0) {
                    speed = 0;
                }
                // Adjust out position if we're moving
                if (speed > 0) {
                    y += (direction * speed);
                }

                // Bounds check...
                if (y - 5 < 0) {
                    y = 5;
                } else if (y + 5 > height) {
                    y = height - 5;
                }
            }
        }

        public void paint(Graphics2D g2d) {
            int yPos = y - 5;
            g2d.translate(10, yPos);
            g2d.fill(shape);
            g2d.translate(-10, -yPos);
        }

    }

}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!