1. import java.awt.BorderLayout;
  2. import java.awt.Canvas;
  3. import java.awt.Color;
  4. import java.awt.Graphics2D;
  5. import java.awt.RenderingHints;
  6. import java.awt.event.AdjustmentEvent;
  7. import java.awt.event.AdjustmentListener;
  8. import java.awt.event.ComponentAdapter;
  9. import java.awt.event.ComponentEvent;
  10. import java.awt.image.BufferStrategy;
  11. import java.util.Random;
  12.  
  13. import javax.swing.JFrame;
  14. import javax.swing.JScrollBar;
  15.  
  16. /**
  17.  * This is simple example of Active Rendering strategy with interoperation between Swing
  18.  * <code>JScrollBar</code> component and rendering thread.
  19.  * @author Mersenne
  20.  *
  21.  */
  22. public class ActiveRenderingDemo {
  23.     // Based on code from http://www.gamedev.net/page/resources/_/technical/general-programming/java-games-active-rendering-r2418
  24.  
  25.     public static final int WORLD_WIDTH = 1600;
  26.     public static final int WORLD_HEIGHT = 480;
  27.  
  28.     // These fields will be read from rendering thread, but updated from Event Dispatch Thread
  29.     private static volatile int viewportWidth;
  30.     private static volatile int viewportHeight;
  31.     private static volatile int scrollPosition;
  32.  
  33.     private static int[][] spritesData;
  34.  
  35.     public static void main(String[] args) {
  36.         viewportWidth = 640;
  37.         viewportHeight = WORLD_HEIGHT;
  38.  
  39.         // Create frame with components
  40.         JFrame app = new JFrame();
  41.         app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  42.         app.setLayout(new BorderLayout());
  43.  
  44.         Canvas canvas = new Canvas();
  45.         canvas.setIgnoreRepaint(true);
  46.         canvas.setSize(viewportWidth, viewportHeight);
  47.         app.add(canvas, BorderLayout.CENTER);
  48.  
  49.         final JScrollBar scrollBar = new JScrollBar(JScrollBar.HORIZONTAL);
  50.         scrollBar.setMaximum(WORLD_WIDTH - viewportWidth);
  51.         app.add(scrollBar, BorderLayout.SOUTH);
  52.  
  53.         app.pack();
  54.         app.setVisible(true);
  55.  
  56.         // Listen for important events and adjust rendering parameters
  57.         canvas.addComponentListener(new ComponentAdapter() {
  58.             public void componentResized(ComponentEvent e) {
  59.                 viewportWidth = ((Canvas) e.getSource()).getWidth();
  60.                 viewportHeight = ((Canvas) e.getSource()).getHeight();
  61.                 scrollBar.setMaximum(WORLD_WIDTH - viewportWidth);
  62.             }
  63.         });
  64.         scrollBar.addAdjustmentListener(new AdjustmentListener() {
  65.             public void adjustmentValueChanged(AdjustmentEvent e) {
  66.                 scrollPosition = e.getValue();
  67.             }
  68.         });
  69.  
  70.         // Create "sprites"
  71.         initSprites();
  72.  
  73.         // Create buffer strategy and acquire buffer for rendering operations
  74.         canvas.createBufferStrategy(2);
  75.         BufferStrategy buffer = canvas.getBufferStrategy();
  76.  
  77.         try {
  78.             while (true) {
  79.                 // Create graphics on every rendering cycle
  80.                 Graphics2D g2d = (Graphics2D) buffer.getDrawGraphics();
  81.                 try {
  82.                     // I like smooth shapes
  83.                     g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
  84.                    
  85.                     // Paint background
  86.                     g2d.setColor(Color.YELLOW);
  87.                     g2d.fillRect(0, 0, viewportWidth, viewportHeight);
  88.  
  89.                     // Draw something
  90.                     renderSprites(g2d);
  91.  
  92.                     // Always check this before show()
  93.                     if (!buffer.contentsLost())
  94.                         buffer.show();
  95.  
  96.                     // "Game mechanics"
  97.                     moveSprites();
  98.                    
  99.                     // Limit framerate to 50 fps
  100.                     Thread.sleep(1000 / 50);
  101.                 } finally {
  102.                     g2d.dispose();
  103.                 }
  104.             }
  105.         } catch (InterruptedException ie) { }
  106.     }
  107.  
  108.     private static void initSprites() {
  109.         Random rand = new Random();
  110.         spritesData = new int[20][4];
  111.  
  112.         for (int[] spriteData : spritesData) {
  113.             spriteData[0] = rand.nextInt(WORLD_WIDTH);  // X
  114.             spriteData[1] = rand.nextInt(WORLD_HEIGHT); // Y
  115.             spriteData[2] = rand.nextInt(3) - 1;        // X movement delta
  116.             spriteData[3] = rand.nextInt(3) - 1;        // Y movement delta
  117.         }
  118.     }
  119.  
  120.     private static void renderSprites(Graphics2D g2d) {
  121.         final int spriteSize = 20;
  122.  
  123.         for (int[] spriteData : spritesData) {
  124.             int spriteX = spriteData[0];
  125.             int spriteY = spriteData[1];
  126.  
  127.             // Some simple calculations to make sprite more dynamic
  128.             int colorMod = Math.abs(255 - spriteX * 2 % 512);
  129.             int sizeModX = Math.abs(5 - spriteX % 10);
  130.             int sizeModY = Math.abs(5 - spriteY % 10);
  131.  
  132.             int curSpriteSizeX = spriteSize + sizeModX;
  133.             int curSpriteSizeY = spriteSize + sizeModY;
  134.  
  135.             // Fill body
  136.             g2d.setColor(new Color(colorMod, colorMod, 0));
  137.             g2d.fillOval(
  138.                     spriteX - curSpriteSizeX/2 - scrollPosition,
  139.                     spriteY - curSpriteSizeY/2,
  140.                     curSpriteSizeX,
  141.                     curSpriteSizeY);
  142.            
  143.             // Draw border
  144.             g2d.setColor(Color.BLACK);
  145.             g2d.drawOval(
  146.                     spriteX - curSpriteSizeX/2 - scrollPosition,
  147.                     spriteY - curSpriteSizeY/2,
  148.                     curSpriteSizeX,
  149.                     curSpriteSizeY);
  150.         }
  151.     }
  152.  
  153.     private static void moveSprites() {
  154.         for (int[] spriteData : spritesData) {
  155.             int spriteX = spriteData[0];
  156.             int spriteY = spriteData[1];
  157.             int spriteXmod = spriteData[2];
  158.             int spriteYmod = spriteData[3];
  159.  
  160.             int newSpriteX = spriteX + spriteXmod;
  161.             int newSpriteY = spriteY + spriteYmod;
  162.  
  163.             if (newSpriteX > WORLD_WIDTH) {
  164.                 newSpriteX = WORLD_WIDTH;
  165.                 spriteXmod = -spriteXmod;
  166.             } else if (newSpriteX < 0) {
  167.                 newSpriteX = 0;
  168.                 spriteXmod = -spriteXmod;
  169.             }
  170.  
  171.             if (newSpriteY > WORLD_HEIGHT) {
  172.                 newSpriteY = WORLD_HEIGHT;
  173.                 spriteYmod = -spriteYmod;
  174.             } else if (newSpriteY < 0) {
  175.                 newSpriteY = 0;
  176.                 spriteYmod = -spriteYmod;
  177.             }
  178.  
  179.             spriteData[0] = newSpriteX;
  180.             spriteData[1] = newSpriteY;
  181.             spriteData[2] = spriteXmod;
  182.             spriteData[3] = spriteYmod;
  183.         }
  184.     }
  185.  
  186. }