Problems with the Java Paint method, ridiculous update speed

I am developing a very simple version of R-Type as a job for the university, but despite this, the shipโ€™s speed is very slow, so the movement is ugly and clumsy. I use the repaint method to refresh the screen, are there other methods or better ways than it?

Motion video

Main panel drawing method

@Override public void paint(Graphics g) { super.paint(g); Graphics2D g2 = (Graphics2D) g; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.drawImage(fondo, 0, 0,1200,600,this); pj.paint(g2); g2D=g2; } 

PJ painting method

 public void paint(Graphics2D g) { g.drawImage(imagen,x,y,this); } 

PJ move method

 public void move (KeyEvent e) { int dx = 0; int dy = 0; int code = e.getKeyCode(); switch (code) { case KeyEvent.VK_Q: dy-=1; break; case KeyEvent.VK_A: dy+=1; break; case KeyEvent.VK_P: dx+=1; break; case KeyEvent.VK_O: dx-=1; break; } int x = (getX()<maxX&&getX()!=0) ? getX()+dx : getX(); int y = (getY()<maxY&&getY()!=0) ? getY()+dy : getY(); if (getY()>=maxY||getY()==0) { if (dy==+1) y=y+1; } setPosicion(x, y); } 
+1
source share
3 answers
  • The fondo image should already be scaled to 1200x600.
  • I'm not sure, but is super.paint(g) needed? You can also use paintComponent .

Event processing (you seem to move 1 pixel when you press a key) should be done correctly. I would set the direction and speed (1px) and leave it with a swing timer to make continuous movement.

Best repaint elastic / flexible: repaint(20L) (50 frames per second); possibly using EventQueue.invokeLater(new Runnable() { ... }); .

In particular, you can use redrawing with a changed area.

+2
source

You can find a great example of a similar program here . The example demonstrates creating a new thread and with this thread sleeping every iteration through the main loop.

Here's another question about downloading images for Java games.

Swing seems to be very cool for using images in games. You might want to use a more suitable library.

+2
source

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

Game object ( Ship ) has the ability to speed up / slow down for 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); } } } 
+2
source

Source: https://habr.com/ru/post/944092/


All Articles