Download presentation
Presentation is loading. Please wait.
1
1 CS2200 Software Development Lecture: Simple 2-d Animation in Java A.O’Riordan, 2009 Based on two examples from K Brown (2007) and D. Brackeen (2004)
2
2 Simple 2-D Animation in Java ●Simple 2D Graphics Animation can be implemented in Java ●Animation by redrawing gives illusion of motion ●Frequent updates gives smoother motion ●Can update part of screen or entire screen (cartoon animation) ●Can use Timer or (better) Threads
3
3 Display Options 2D Graphics and Animation/ Games can be run as ●Applets ●Run in web browser ●Can’t save info such as preferences ●Have to be on-line ●Windowed, e.g. in a JPanel ●Can easily switch applications ●UI elements can be distraction ●Full-screen ●Usually best option ●take full control of visual presentation
4
4 Performance Performance is a key issue in Java graphics/animation/games and is hard to predict because of many contributing factors: ●Efficiency of Java application ●Efficiency of JVM implementation ●Underlying operating system ●Computer (available memory, processor speed, bus speed, etc.) ●Display (E.g. monitor refresh rate) ●Video card (E.g. available video memory)
5
5 Swing Timer ●A Swing timer (an instance of javax.swing.Timer) fires one or more action events after a specified delay ●Don't confuse Swing timers with the general-purpose timer facility that was added to the java.util package in Java 1.3 ●Sun recommend using Swing timers rather than general-purpose timers for GUI-related tasks because Swing timers all share the same, pre-existing timer thread and the GUI-related task automatically executes on the event-dispatch thread ●You can use Swing timers in two ways: ●To perform a task once, after a delay ●To perform a task repeatedly.
6
6 Animation using Timer (javax.swing) ●animation is simply a sequence of images with slight changes between them ●how do we time changes to the display? ●use the Timer class in package javax.swing ●Constructor public Timer(int delay, ActionListener lstnr) creates an internal Thread object; every delay milliseconds it creates an ActionEvent to which lstnr responds ●other important methods of Timer include start() and stop()
7
7 Timer methods ● void addActionListener (ActionListener listener) - registers the object referenced by listener as an action listener ● int getDelay() returns the current time delay in milliseconds ● void setDelay(int delay) - sets the time delay in milliseconds ● boolean isRunning() - returns true if the Timer object is running ● void start() - starts the Timer object ● void stop() - stops the Timer object ● void setRepeats(boolean flag) – set the timer to go off only once (flag=false)
8
8 AnimatedLabel Example import java.awt.*; import java.awt.event.*; import javax.swing.*; public class AnimatedLabel extends JLabel { private Timer timer; private int frameNumber; //the constructor goes here... public void startAnimation() { timer.start(); }
9
9 AnimatedLabel Constructor public AnimatedLabel(int theStart) { super(); frameNumber = theStart; ActionListener lstnr = new ActionListener() { public void actionPerformed(ActionEvent ae) { if (frameNumber > 0) { setText(“ " + frameNumber); frameNumber--; } else if (frameNumber == 0) setText(“Lift Off!"); } }; timer = new Timer(500, lstnr); // every second }
10
10 Test Driver for AnimatedLabel public static void main(String[] args) { AnimatedLabel lbl = new AnimatedLabel(10); lbl.setFont(new Font(null, Font.PLAIN, 24)); JFrame frm = new JFrame("Timer demo"); Container contentPane = frm.getContentPane(); contentPane.add(lbl); frm.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent we) { System.exit(0); } }); frm.setBounds(100, 300, 200, 100); frm.setVisible(true); lbl.startAnimation(); }
11
11 Animating an image To get the appearance of motion, we need to refresh the display between 10 and 20 times per second public AnimationDemo() { super(); images = new ImageIcon[NUM_IMAGES]; for (int i=0; i< NUM_IMAGES; i++) images[i] = new ImageIcon("duke" + i + ".gif"); timer = new Timer(50, new ActionListener() { public void actionPerformed(ActionEvent ae) { frameNumber++; setIcon(images[frameNumber % NUM_IMAGES]); } }); }
12
12 "polite" use of resources ●if the animation can become invisible (e.g. window iconified) we could suspend it to stop consuming resources ●include in the WindowAdapter: public void windowIconified(WindowEvent we) { demo.stopAnimation(); } public void windowDeiconified(WindowEvent we) { demo.startAnimation(); } ●and for the AnimationDemo class include a method public void stopAnimation() { timer.stop(); }
13
13 "politeness" to the user ●you should allow users to switch off distracting animation e.g. by clicking on them ●to the constructor, add addMouseListener(new MouseAdapter() { public void mousePressed(MouseEvent me) { if (frozen) { frozen = false; startAnimation(); } else { frozen = true; stopAnimation(); } }); private boolean frozen = false; public void startAnimation() { if (!frozen) timer.start(); }
14
14 Animated custom painting ●simply change the handler for the timer to call repaint() ●and override paintComponent(Graphics g) public void actionPerformed(ActionEvent ae)) { frameNumber++; repaint(); } public void paintComponent(Graphics g) { super.paintComponent(g); g.drawoval(insets.left + frameNumber % availWidth; insets.top + availHeight /2, 20, 20); }
15
15 Applet Example with thread (not polite) import java.awt.*; import java.applet.*; import java.util.*; public class clock extends Applet implements Runnable { Date d; Thread runner; public void paint(Graphics g) { g.drawString(d.toString(),10,50); } public void start() { while (runner == null) { runner = new Thread(this); runner.start(); } public void run() { while (true) { d = new Date(); repaint(); try { Thread.sleep(1000); } catch(InterruptedException e) { }; }
16
16 Full-Screen Graphics ●Screen Resolution ●Number of horizontal and vertical picture elements (pixels) ●Depends on capabilities of video card and monitor ●E.g. 800x600, 1024x768, 1280x1024 ●Bit Depth ●Number of colours that can be displayed ●E.g. 8, 16, 24, and 32 bit ●Screen Refresh Rate ●E.g. 60Hz, 75Hz ●Java class DisplayMode sets the display mode, e.g. DisplayMode mode = new DisplayMode(800, 600, 16, 75);
17
17 Setting GraphicsEnvironment and GraphicsDevice // Using a JFrame object JFrame window = new JFrame(); // Set Display Mode – resolution, etc. DisplayMode displayMode = new DisplayMode(800, 600, 16, DisplayMode.REFRESH_RATE_UNKNOWN); // Set GraphicsEnvironment GraphicsEnvironment environment = GraphicsEnvironment.getLocalGraphicsEnvironment(); // Set Graphics Device GraphicsDevice dev = environment.getDefaultScreenDevice();
18
18 setDisplayMode() window.setUndecorated(true); Window.setResizable(false); // Set Full Screen device.setFullScreenWindow(window); //Display Mode (throws Exception) if (displayMode != null && device.isDisplayChangeSupported()) { try { device.setDisplayMode(displayMode); } catch (IllegalArgumentException ex) { } }
19
19 Waiting for painting // painting is in a separate thread so may want to wait. public synchronized void repaintAndWait() { repaint(); try { wait(); } catch (InterruptedException e) {} } public synchronized void paint(Graphics g) { //do painting here notifyAll(); }
20
20 Cartoon animation Sequence of images (frames) display one after the other So many frames per second, e.g. 20 Animation may loop or repeat subsequences
21
21 Cartoon: Animation class public class Animation { private ArrayList frames; private int currFrameIndex; private long animTime; private long totalDuration; public Animation() { frames = new ArrayList(); totalDuration = 0; start(); } public synchronized void addFrame(Image image, long duration) { totalDuration += duration; framw.add(new AnimFrame(image, totalDuration)); } public synchronized void start() { animTime = 0; currFrameIndex =0; }
22
22 Continued… public synchronized void update(long elapsedTime) { if (frame.size() > 1) { animTime += elapsedTime; if (animTime >= totalDuration) { animTime = animTime % totalDuration; currFrameIndex = 0; } while (animTime > getFrame(currFrameIndex).endTime) { currFrameIndex++; } public synchronized Image getImage() { if (frames.size() = 0) { return null; } else return getFrame(currFrame(currFrameIndex).image; }
23
23 Continued. private AnimFrame getFrame(int i) { return (AnimFrame)frames.get(i); } // inner class AnimFrame private class AnimFrame { Image image; long endTime; public AnimFrame(Image image, long endTime) { this.image = image; this.endTime = endTime; }
24
24 Cartoon: Test public class AnimationTest { public static void main(String args[]) { DisplayMode displayMode(600, 800, 16, DisplayMode.REFRESH_RATE_UNKNOWN); AnimationTest test = new AnimationTest(); test.run(displayMode); } private static final long DEMO_TIME = 9000; private Image bgImage; private Animation anim; private Image loadImage(String fileName) { return new ImageIcon(filename).getImage(); }
25
25 Test continued… public void loadImages() { bgIamge = loadImage(“images/background.jpg”); Image frame1 = loadImage(“image/frame1.png”); // and so on Anim = new Animation(); Anim.addFrame(frame1, 1000); // and so on } public void run(DisplayMode displayMode) { // set up screen loadImages(); animateLoop(); }
26
26 Test continued. public void animationLoop() { long startTime = System.currentTimeMillis(); long currTime = startTime; while (currTime – startTime < DEMO_TIME) ( long elapsedTime = System.currentTimeMillis() – currTime; currTime += elapsedTime; anim.update(elapsedTime); Graphics g = screen.getFullScreenWindow().getGraphics(); draw(g); g.dispose(); try {Thread.sleep(20);} catch (InterruptedException ex) { } } public void draw(Graphics g) { g.drawImage(bgImage, 0, 0, null); g.drawImage(anim.getImage(), 0, 0, null); }
27
27 Removing Artefacts (solutions not covered) ●Aliasing ●minimizing the distortion artefacts known as aliasing through anti-aliasing – remove jagged edges on lines and fonts ●Java RenderingHints class ●Flicker ●Caused by drawing directly to screen ●Double Buffering - technique for minimizing the delay in input/output operations which use a buffer ▪Have a back buffer and a screen buffer; Draw to back buffer and copy across ▪At any one time, one page is actively being displayed by the monitor, while the background page is being drawn ●Page Flipping – display pointer that can switch between two the buffers – no copying ●Tearing ●Onscreen image appearing to be slightly out of alignment or 'torn' in parts ●Caused by flipping or copying during screen refresh ●Java BufferStrategy class
28
28 Java Games Book: Developing Games in Java, David Brackeen, 2004. Code examples here http://www.brackeen.com/javagamebook/http://www.brackeen.com/javagamebook/ Example: 2-D Platform Game http://www.brackeen.com/javagamebook/tilegame.jnlp This game demonstrates: * Thread pools (in the sound manager) * Full screen mode, hardware-accelerated graphics, animation, and sprites * Keyboard input * Sound, music, and sound filters * Parallax scrolling, tile-based maps, gravity, jumping, and collisions * Simulated timer accuracy * Art and sound creation techniques * Game states (loading, intro sequence, main game)
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.