Je développe un jeu en utilisant le framework Java Swing. Est-ce que quelqu'un connaît un bon cadre basé sur Swing? Surtout, je me soucie de la performance de redessiner.Java cadre de jeu basé sur Swing. Aucun conseil?
Répondre
Cette simple boucle de jeu à temps fixe (je me suis adapté du crédit de référence à l'auteur) ne m'a jamais laissé tomber.
Il permet de tracer à 60 fps (ou peu importe), le hertz peut également être modifié, il active l'anti-aliasing via Graphics2D et quelques autres effets. L'exemple des auteurs originaux comprenait une vérification d'interpolation, mais je l'ai trouvé en me donnant quelques problèmes dans mes jeux comme des images scintillant dans et hors de leurs positions, donc j'ai gardé cela inclus, mais si vous rencontrez des problèmes au moins, vous saurez faisant):
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class GameLoopTest implements ActionListener {
private GamePanel gamePanel;
private JButton startButton;
private JButton quitButton;
private JButton pauseButton;
private boolean running = false;
private boolean paused = false;
public GameLoopTest() {
JFrame frame = new JFrame("Fixed Timestep Game Loop Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
gamePanel = new GamePanel(500, 500);
startButton = new JButton("Start");
quitButton = new JButton("Quit");
pauseButton = new JButton("Pause");
pauseButton.setEnabled(false);
JPanel buttonPanel = new JPanel();
buttonPanel.setLayout(new GridLayout(1, 2));
startButton.addActionListener(this);
quitButton.addActionListener(this);
pauseButton.addActionListener(this);
buttonPanel.add(startButton);
buttonPanel.add(pauseButton);
buttonPanel.add(quitButton);
frame.add(gamePanel);
frame.add(buttonPanel, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new GameLoopTest();
}
});
}
@Override
public void actionPerformed(ActionEvent e) {
Object s = e.getSource();
if (s == startButton) {
running = !running;
if (running) {
startButton.setText("Stop");
pauseButton.setEnabled(true);
runGameLoop();
} else {
startButton.setText("Start");
pauseButton.setEnabled(false);
}
} else if (s == pauseButton) {
paused = !paused;
if (paused) {
pauseButton.setText("Unpause");
} else {
pauseButton.setText("Pause");
}
} else if (s == quitButton) {
System.exit(0);
}
}
//Starts a new thread and runs the game loop in it.
public void runGameLoop() {
Thread loop = new Thread(new Runnable() {
@Override
public void run() {
gameLoop();
}
});
loop.start();
}
//Only run this in another Thread!
private void gameLoop() {
//This value would probably be stored elsewhere.
final double GAME_HERTZ = 30.0;
//Calculate how many ns each frame should take for our target game hertz.
final double TIME_BETWEEN_UPDATES = 1000000000/GAME_HERTZ;
//At the very most we will update the game this many times before a new render.
//If you're worried about visual hitches more than perfect timing, set this to 1.
final int MAX_UPDATES_BEFORE_RENDER = 5;
//We will need the last update time.
double lastUpdateTime = System.nanoTime();
//Store the last time we rendered.
double lastRenderTime = System.nanoTime();
//If we are able to get as high as this FPS, don't render again.
final double TARGET_FPS = 60;
final double TARGET_TIME_BETWEEN_RENDERS = 1000000000/TARGET_FPS;
//Simple way of finding FPS.
int lastSecondTime = (int) (lastUpdateTime/1000000000);
while (running) {
double now = System.nanoTime();
int updateCount = 0;
if (!paused) {
//Do as many game updates as we need to, potentially playing catchup.
while (now - lastUpdateTime > TIME_BETWEEN_UPDATES && updateCount < MAX_UPDATES_BEFORE_RENDER) {
updateGame();
lastUpdateTime += TIME_BETWEEN_UPDATES;
updateCount++;
}
//If for some reason an update takes forever, we don't want to do an insane number of catchups.
//If you were doing some sort of game that needed to keep EXACT time, you would get rid of this.
if (now - lastUpdateTime > TIME_BETWEEN_UPDATES) {
lastUpdateTime = now - TIME_BETWEEN_UPDATES;
}
//Render. To do so, we need to calculate interpolation for a smooth render.
float interpolation = Math.min(1.0f, (float) ((now - lastUpdateTime)/TIME_BETWEEN_UPDATES));
drawGame(interpolation);
lastRenderTime = now;
//Update the frames we got.
int thisSecond = (int) (lastUpdateTime/1000000000);
int frameCount = gamePanel.getFrameCount();
if (thisSecond > lastSecondTime) {
System.out.println("NEW SECOND " + thisSecond + " " + frameCount);
gamePanel.setFps(frameCount);
frameCount = 0;
lastSecondTime = thisSecond;
}
//Yield until it has been at least the target time between renders. This saves the CPU from hogging.
while (now - lastRenderTime < TARGET_TIME_BETWEEN_RENDERS && now - lastUpdateTime < TIME_BETWEEN_UPDATES) {
//allow the threading system to play threads that are waiting to run.
Thread.yield();
//This stops the app from consuming all your CPU. It makes this slightly less accurate, but is worth it.
//You can remove this line and it will still work (better), your CPU just climbs on certain OSes.
//FYI on some OS's this can cause pretty bad stuttering. Scroll down and have a look at different peoples' solutions to this.
//On my OS it does not unpuase the game if i take this away
try {
Thread.sleep(1);
} catch (Exception e) {
}
now = System.nanoTime();
}
}
}
}
private void updateGame() {
gamePanel.update();
}
private void drawGame(float interpolation) {
gamePanel.setInterpolation(interpolation);
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
gamePanel.repaint();
}
});
}
}
class GamePanel extends JPanel {
float interpolation;
float ballX, ballY, lastBallX, lastBallY;
int ballWidth, ballHeight;
float ballXVel, ballYVel;
float ballSpeed;
int lastDrawX, lastDrawY;
private int frameCount = 0;
private int fps = 0;
int width, height;
public GamePanel(int width, int height) {
super(true);
ballX = lastBallX = 100;
ballY = lastBallY = 100;
ballWidth = 25;
ballHeight = 25;
ballSpeed = 25;
ballXVel = (float) Math.random() * ballSpeed * 2 - ballSpeed;
ballYVel = (float) Math.random() * ballSpeed * 2 - ballSpeed;
this.width = width;
this.height = height;
}
public void setInterpolation(float interp) {
interpolation = interp;
}
public void update() {
lastBallX = ballX;
lastBallY = ballY;
ballX += ballXVel;
ballY += ballYVel;
if (ballX + ballWidth/2 >= getWidth()) {
ballXVel *= -1;
ballX = getWidth() - ballWidth/2;
ballYVel = (float) Math.random() * ballSpeed * 2 - ballSpeed;
} else if (ballX - ballWidth/2 <= 0) {
ballXVel *= -1;
ballX = ballWidth/2;
}
if (ballY + ballHeight/2 >= getHeight()) {
ballYVel *= -1;
ballY = getHeight() - ballHeight/2;
ballXVel = (float) Math.random() * ballSpeed * 2 - ballSpeed;
} else if (ballY - ballHeight/2 <= 0) {
ballYVel *= -1;
ballY = ballHeight/2;
}
}
public int getFrameCount() {
return frameCount;
}
public void setFrameCount(int frameCount) {
this.frameCount = frameCount;
}
void setFps(int fps) {
this.fps = fps;
}
private final static RenderingHints textRenderHints = new RenderingHints(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
private final static RenderingHints imageRenderHints = new RenderingHints(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
private final static RenderingHints colorRenderHints = new RenderingHints(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
private final static RenderingHints interpolationRenderHints = new RenderingHints(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
private final static RenderingHints renderHints = new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
public void applyRenderHints(Graphics2D g2d) {
g2d.setRenderingHints(textRenderHints);
g2d.setRenderingHints(imageRenderHints);
g2d.setRenderingHints(colorRenderHints);
g2d.setRenderingHints(interpolationRenderHints);
g2d.setRenderingHints(renderHints);
}
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
//applys effects like anti alising for images and tetx, as well as sets the renderinf value to quality etc
applyRenderHints(g2d);
g2d.setColor(Color.RED);
int drawX = (int) ((ballX - lastBallX) + lastBallX - ballWidth/2);
int drawY = (int) ((ballY - lastBallY) + lastBallY - ballHeight/2);
g2d.fillOval(drawX, drawY, ballWidth, ballHeight);
lastDrawX = drawX;
lastDrawY = drawY;
g2d.setColor(Color.BLACK);
g2d.drawString("FPS: " + fps, 5, 10);
frameCount++;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(width, height);
}
}
Référence:
Je ne peux pas croire combien de temps je viens de regarder ce point rouge impressionnant ... +1 – moeTi
@FakeMan voir la dernière mise à jour, il devrait fonctionner comme un charme –
Swing est très bien pour des jeux simples, mais si vous tenez vraiment à la performance de redessiner, vous devriez probablement jeter un oeil à l'un des cadres basés sur OpenGL. Exemples:
- http://www.lwjgl.org/ - assez une bibliothèque de niveau bas mais très rapide. OpenGL essentiellement brut.
- http://www.slick2d.org/ - une bibliothèque de jeu 2D populaire et assez facile à utiliser.
- http://jmonkeyengine.com/ - un bon choix si vous voulez un moteur 3D complet.
En particulier, si vous voulez faire des effets plus complexes (beaucoup de couleurs, ombrage, effets de transparence par exemple) alors vous aurez probablement besoin d'OpenGL.
+1 oui ce sont quelques cadres agréables –
slick2d a été déplacé à http://slick.ninjacave.com – ajb
- 1. Java, conseil de l'auditeur, conseil de comp swing nécessaire :(
- 2. Java Swing par défaut sur le cadre
- 3. Cadre BDD pour Java Swing?
- 4. Mastermind Jeu Java Swing, MouseListener
- 5. Effet de cadre coulissant dans Java Swing
- 6. Mips - conseil de jeu d'impression
- 7. Champ de jeu utilisant Swing
- 8. Opérations sur Java Swing
- 9. Composant d'éditeur basé sur Stencil pour Java/Swing?
- 10. javascript conseil placement des pièces de jeu
- 11. Redémarrer le jeu java basé sur la sélection de JOptionPane
- 12. Cadre Web basé sur Moose
- 13. NetBeans: ajout de Spring IOC à un projet de cadre d'application Swing basé sur maven
- 14. Java Swing ajouter un composant pour le jeu
- 15. organisation du code source pour un jeu basé sur Java
- 16. cadre java pour les transactions site basé
- 17. Basé sur Java FB.init
- 18. Cadre de jeu JavaScript
- 19. Cadre de jeu + Scala
- 20. Cadre de portail basé sur ASP.NET Slim
- 21. Cadre de développement d'agents basé sur C#
- 22. Cadre de plugin .net basé sur COM
- 23. Cadre de jeu - comment réparer UnsupportedClassVersionError sur JRE 6?
- 24. Android jeu basé sur les tuiles
- 25. Exemple de jeu cocos2d basé sur gameloop?
- 26. Cadre de jeu et JPA
- 27. J'ai échoué à installer ioncube sur godaddy. Aucun conseil?
- 28. Android concept de cadre de jeu
- 29. Java Swing design
- 30. java swing mise à jour du contenu dans le cadre
jetez un coup d'oeil à Play Framework et lisez les FAQ de ce site –
@NikolayKuznetsov Le cadre de jeu est un cadre pour les webapps, pas pour les applications Swing, et n'a rien à voir avec les jeux, malgré le nom "Play". – Jesper
@Jesper, vous avez raison, désolé. Swing est une sorte de cadre lui-même –