2013-04-09 3 views
1

Я разрабатываю очень простую версию R-Type как работу для университета, но, несмотря на это, скорость корабля очень медленная, поэтому движение уродливое и неуклюжий. Я использую метод repaint для обновления экрана, есть другие методы или способы лучше, чем это?Проблемы с методом рисования Java, смешной скоростью обновления

Video of Movement

метод Paint на главной панели

@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 в

public void paint(Graphics2D g) { 

    g.drawImage(imagen,x,y,this); 
} 

метод шаг PJ в

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); 

} 
+0

попытка бенчмаркинга каждый шаг в методе краски на главной панели, чтобы увидеть, какая часть является самым медленным и вернитесь с результатом – Stephan

ответ

2
  • Изображение fondo должно быть увеличено до 1200x600.
  • Я не уверен, но нужен super.paint(g)? Вы также можете использовать paintComponent.

Обработка событий (кажется, что вы перемещаетесь на 1 пиксель при нажатии клавиши), должна быть выполнена правильно. Я бы установил направление и скорость (1px) и оставил его таймером качания для непрерывного перемещения.

Перекрашивание лучше всего выполнено упругим/гибким: repaint(20L) (50 кадров в секунду); событий, таких как key-down, возможно, с EventQueue.invokeLater(new Runnable() { ... });.

Специально вы можете использовать перерисовку с измененной зоной.

+1

PaintComponet будет предпочтительнее, но да, требуется super.paint. Лучше использовать таймер Swing отложенной перерисовки -IMHO – MadProgrammer

2

Вы можете найти отличный пример аналогичной программы here. В примере демонстрируется создание нового потока и с этим потоком спящий каждую итерацию через основной цикл.

Here - еще один вопрос об загрузке изображений для игр на Java.

Похоже, что свинг сам по себе довольно прикольный для использования изображений в играх. Возможно, вам захочется использовать более подходящую библиотеку.

+0

Swing в порядке для большинства игр в стиле 2D, о чем только подумать, что Swing использует процесс пассивного рендеринга, а это значит, что, хотя вы можете запросить перерисовку, вы не можете гарантировать, когда эта перекраска произойдет. – MadProgrammer

+0

Hi там Безумный! : D Да, я на самом деле не очень много развил игру на Java, я просто уходил от комментариев и еще чего-то в другой теме. Они, казалось, указывали на то, что, хотя Swing, возможно, не особенно плохо влияет на рендеринг и что-то еще, это просто не очень хорошо с изображениями.Если я правильно помню, я думаю, вы можете вызвать revalidate() перед repaint(), чтобы обеспечить перерисовку ... – MirroredFate

2

Ниже приведен простой пример с использованием фона как простого игрового цикла. Он обновляет состояние игровых объектов и вычисляет требуемую задержку, чтобы поддерживать требуемые fps.

Игра объект (Ship) обладает способностью ускорять/замедления в течение короткого периода времени

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); 
     } 

    } 

} 
Смежные вопросы