Swing - SPLessons

Swing BasedGame

Chapter 23

SPLessons 5 Steps, 3 Clicks
5 Steps - 3 Clicks

Swing BasedGame

Swing BasedGame

shape Description

Swing BasedGame, Developing a game is not  an easy issue, to develop the game programmer should have the knowledge with coding, most of the games will be developed by java language because of java consists of more packages. Here by using Swing components developer can build a game .

To develop the game developer need to have an idea about Swing events and Swing layouts. In every game object should move from one place to another place so ActionListeners must perform on the components, mathematical logic is the mandatory for every game to figure moving objects per second.


shape Example

Following is an Swing BasedGame.
GameLoopTest.java

import javax.swing.*;

import java.awt.*;

import java.awt.event.*;

 

public class GameLoopTest extends JFrame implements ActionListener

{

   private GamePanel gamePanel = new GamePanel();
   private JButton startButton = new JButton("Start");

   private JButton quitButton = new JButton("Quit");

   private JButton pauseButton = new JButton("Pause");

   private boolean running = false;

   private boolean paused = false;

   private int fps = 60;

   private int frameCount = 0;

    

   public GameLoopTest()

   {

      super("Fixed Timestep Game Loop Test");

      Container cp = getContentPane();

      cp.setLayout(new BorderLayout());

      JPanel p = new JPanel();

      p.setLayout(new GridLayout(1,2));

      p.add(startButton);

      p.add(pauseButton);

      p.add(quitButton);

      cp.add(gamePanel, BorderLayout.CENTER);

      cp.add(p, BorderLayout.SOUTH);

      setSize(500, 500);

       

      startButton.addActionListener(this);

      quitButton.addActionListener(this);

      pauseButton.addActionListener(this);

   }

    

   public static void main(String[] args)

   {

      GameLoopTest glt = new GameLoopTest();

      glt.setVisible(true);

   }

    

   public void actionPerformed(ActionEvent e)

   {

      Object s = e.getSource();

      if (s == startButton)

      {

         running = !running;

         if (running)

         {

            startButton.setText("Stop");

            runGameLoop();

         }

         else

         {

            startButton.setText("Start");

         }

      }

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

      {

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

            if (thisSecond > lastSecondTime)

            {

               System.out.println("NEW SECOND " + thisSecond + " " + frameCount);

               fps = 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)

           {

               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.

               try {Thread.sleep(1);} catch(Exception e) {}

             

               now = System.nanoTime();

            }

         }

      }

   }

    

   private void updateGame()

   {

      gamePanel.update();

   }

    

   private void drawGame(float interpolation)

   {

      gamePanel.setInterpolation(interpolation);

      gamePanel.repaint();

   }

    

   private class GamePanel extends JPanel

   {

      float interpolation;

      float ballX, ballY, lastBallX, lastBallY;

      int ballWidth, ballHeight;

      float ballXVel, ballYVel;

      float ballSpeed;

       

      int lastDrawX, lastDrawY;

       

      public GamePanel()

      {

         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;

      }

       

      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 void paintComponent(Graphics g)

      {

         //BS way of clearing out the old rectangle to save CPU.

         g.setColor(getBackground());

         g.fillRect(lastDrawX-1, lastDrawY-1, ballWidth+2, ballHeight+2);

         g.fillRect(5, 0, 75, 30);

          

         g.setColor(Color.RED);

         int drawX = (int) ((ballX - lastBallX) * interpolation + lastBallX - ballWidth/2);

         int drawY = (int) ((ballY - lastBallY) * interpolation + lastBallY - ballHeight/2);

         g.fillOval(drawX, drawY, ballWidth, ballHeight);

          

         lastDrawX = drawX;

         lastDrawY = drawY;

          

         g.setColor(Color.BLACK);

         g.drawString("FPS: " + fps, 5, 10);

          

         frameCount++;

      }

   }
}

Here created the class GameLoopTest that extends JFrame and implements ActionListener.

public class GameLoopTest extends JFrame implements ActionListener

Here three JButtons such as Start, Quit, Pause.

private JButton startButton = new JButton("Start");

   private JButton quitButton = new JButton("Quit");

   private JButton pauseButton = new JButton("Pause");

First-person shooter (FPS) is setted to 60.

 private int fps = 60;

JPanel() Creates a new JPanel with a double buffer and a flow layout. GridLayout()Creates a grid layout with a default of one column per component, in a single row.

 JPanel p = new JPanel();

      p.setLayout(new GridLayout(1,2));

Add action listeners to the three buttons.

startButton.addActionListener(this);

      quitButton.addActionListener(this);

      pauseButton.addActionListener(this);

Swing BasedGame – Calculate how many ns each frame should take for our target game hertz.

final double TIME_BETWEEN_UPDATES = 1000000000 / GAME_HERTZ;

We will need the last update time and Store the last time we rendered.

double lastUpdateTime = System.nanoTime();
      double lastRenderTime = System.nanoTime();

Swing BasedGame – 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++;

           }

Output
Game structure will be as follows.


Summary

shape Key Points

  • FPS stands for First-person shooter.
  • The getContentPane() method retrieves the content pane layer so that you can add an object to it.
  • A single panel is the right way to go when using Java Swing to create a Java game.