CS 4812: Java - PowerPoint PPT Presentation

1 / 26
About This Presentation
Title:

CS 4812: Java

Description:

This eliminates most of the flicker, but what if we increase the size and ... We stop the flicker associated with the white washing of our canvas, but still ... – PowerPoint PPT presentation

Number of Views:37
Avg rating:3.0/5.0
Slides: 27
Provided by: davidd1
Category:
Tags: flicker | java

less

Transcript and Presenter's Notes

Title: CS 4812: Java


1
CS 4812 Java
  • Lecture 98
  • Animation Double Buffering

2
Animation
  • Animation can be difficult in Java because of the
    flicker associated with the repainting of
    components.
  • This brief presentation discusses techniques
    useful for avoiding this problem.
  • The discussion on double-buffering presents
    concepts central to working with light-weight
    components.

3
Animation The Flicker Problem
  • Lets write a simple applet to create some
    animation.
  • How would we animate a simple bouncing ball?
  • If we use the metaphor of a movie, we can imagine
    the paint method rendering a single slice of
    time. Each call to the paint method therefore
    draws an individual frame of our animation.

4
Simple Animation Applet
  • import java.awt.
  • import java.applet.
  • public class buff extends Applet
  • int x10, y10, dx1, dy2
  • public void init()super.init()
  • public void paint (Graphics g)
  • g.setColor(Color.gray)
  • g.fillRect(0,0,size().width,
    size().height)
  • g.setColor(Color.red)
  • g.fillOval(x,y, 10,10)
  • xdx
  • ydy
  • if (xgtsize().width-10 x lt10) dx-1
  • if (ygtsize().height-10 y lt10)dy-1
  • repaint()

5
Simple animation applet
  • Our simple applet follows this logic
  • At each call of the paint method, erase the
    entire canvas area, then draw the ball in its
    new location, and add some values to the x, y
    position of the ball.
  • Some simple bounds checking is provided, and the
    repaint() call from within paint create an
    animation loop for us.

6
Problem The Flicker
  • As written, the applet works o.k., but has an
    annoying flicker.
  • Whats causing this? Well, each call to paint
    causes Java to whipe out the entire canvas,
    before our code even gets executed.
  • Our canvas is therefore redrawn twice--once with
    a white wash, and a second time with our
    background.

7
Solution Override update()
  • The culprit is update(), a method called by Java
    with each call to paint().
  • We can eliminate the flicker by merely overriding
    update
  • public void update (Graphics g)
  • paint(g)

8
Overriding update . . .
  • import java.awt.
  • import java.applet.
  • public class buff extends Applet
  • int x10, y10, dx1, dy2
  • public void init()super.init()
  • public void paint (Graphics g)
  • g.setColor(Color.gray) g.fillRect(0,0,size().wid
    th, size().height) g.setColor(Color.red)
    g.fillOval(x,y, 10,10) xdx ydy if
    (xgtsize().width-10 x lt10) dx-1
  • if (ygtsize().height-10 y lt10) dy-1
  • repaint()
  • public void update(Graphics g)
  • paint (g)

9
Problem solve? No.
  • This eliminates most of the flicker, but what if
    we increase the size and complexity of the object
    we are drawing?
  • Lets change the dimensions of the ball and see
    what happens.
  • . . . On a slow system, the drawing of the ball
    tends to flicker with our gray background. This
    becomes more pronounced as we increase the
    complexity of the paint methods code.

10
Eliminating Flicker
  • By overriding update, weve only addressed half
    of the problem. We stop the flicker associated
    with the white washing of our canvas, but still
    must endure the gray wash caused by our code.
  • The heart of the problem We draw gray pixels on
    an area, and then replace them with our red
    pixels. The video memory cannot refresh these
    changes smoothly.

11
Solution Limited Drawing Areas
  • One temporary solution is to only erase the
    portions of the canvas that have changed.

(Repaint only the box bounding the changed area)
12
Limited updating a limited solution
  • Erasing only the areas that have changed may
    provide some help, but does not solve the
    essential problem.
  • With many redrawn areas, we lose an economy of
    scale, and redraw some areas many times!

13
The Best Solution Buffers
  • Since the problem stems from the differing rates
    at which memory is written and and video is
    displayed, we can just use a buffer.
  • Our drawing could take place in a buffered
    graphics area. When we are done, the final image
    is blitted to the screen all at once--no more
    piece meal updating.

14
Double-Buffering
  • Draw off-screen, blit to on-screen

Graphics osG
Graphics g
15
Mechanics of Double Buffering
  • To accomplish this, well need some tools
  • An off-screen image, upon which we draw
  • A graphics context for that off-screen image
  • Some way of making sure the size of the
    off-screen image matches the onscreen drawing
    area--even if the applet is resized!
  • Some way of making sure we create the off-screen
    image the first time

16
Mechanics of Double-Buffering
  • Some useful instance variables
  • Image osImg // off-screen image
  • Graphics osG // off-screen graphics
  • boolean startOuttrue / first time painting or
    not? /
  • Dimension curD // current size of off-screen
    stuff

17
Mechanics of Double-Buffering
  • Now, we can modify our paint method.
  • First, lets make sure we create the off-screen
    drawing area upon startup
  • public void paint (Graphics g)
  • // is this the first time we are painting?
  • if (startOut)
  • curD getSize()
  • osImg createImage (curD.width, curD.height)
  • osG osImg.getGraphics()
  • startOut false
  • . . . .

18
Mechanics of Double-Buffering
  • Now, lets check to see if the applet has been
    resized
  • // has the component been resized?
  • if ((curD.width ! size().width) (curD.height
    ! size().height))
  • curD size()
  • osImg createImage (curD.width, curD.height)
  • osG osImg.getGraphics()

19
Mechanics of Double-Buffering
  • Now, we draw as usual, except that we use the
    osG reference, not the more familiar g
    object.
  • When we are done, the LAST line of our paint
    (before repaint(), that is), should blit the
    off-screen image to screen
  • g.drawImage (osImg,0,0,this)

20
Summary Steps
  • -instance variables
  • Image osImg // off-screen image
  • Graphics osG // off-screen graphics
  • boolean startOut true // first time painting
    or not?
  • Dimension curD // current size of off-screen
    stuff
  • -override update()
  • public void update (Graphics g)
  • paint(g)
  • -override paint()
  • public void paint (Graphics g)
  • // is this the first time we are painting?
  • if (startOut)
  • curD size()
  • osImg createImage (curD.width,
    curD.height)
  • osG osImg.getGraphics()
  • startOut false

21
Summary Steps (Contd)
  • // has the component been resized?
  • if ((curD.width ! size().width)
    (curD.height ! size().height))
  • curD size()
  • osImg createImage (curD.width,
    curD.height)
  • osG osImg.getGraphics()
  • -in the remainder of paint(), draw the
    canvas/component as normal, but use osG rather
    than g as the Graphics object on which to draw.
    Then at the end of paint()
  • // make changes to off-screen graphics visible
    on screen
  • g.drawImage (osImg,0,0,this)

22
An example
  • Lets add complexity to our bouncing ball
    example, to test the double-buffering.
  • Lets add a Ball class, with random ball
    properties.
  • Then, lets create an array of Balls, each draw
    an updated in its own manner . . .

23
Ball.java
  • import java.awt.Color
  • class Ball
  • Color c int x, y, dx, dy
  • public Ball ()
  • x (int)(Math.random()200)
  • y (int)(Math.random()200)
  • dx (int)(Math.random()3)1
  • dy (int)(Math.random()4)1
  • c new Color ((int)(Math.random()255),
  • (int) (Math.random()255),
  • (int)(Math.random()255))

24
Buff.java
  • import java.awt.
  • import java.applet.
  • public class buff extends Applet
  • Image osImg // off-screen image
  • Graphics osG // off-screen graphics
  • boolean startOut true/ first time painting or
    not?/
  • Dimension curD/ current size of off-screen
    stuff/
  • int x10, y10, dx1, dy2, MAX15, i
  • Ball b
  • public void init()super.init()
  • b new BallMAX
  • for (i0 iltMAX i)
  • bi new Ball()

25
Buff.java (contd)
  • public void paint (Graphics g)
  • // is this the first time we are painting?
  • if (startOut) curD getSize()
  • osImg createImage (curD.width, curD.height)
  • osG osImg.getGraphics()
  • startOut false
  • // has the component been resized?
  • if ((curD.width ! size().width) (curD.height
    ! size().height))
  • curD size()
  • osImg createImage (curD.width, curD.height)
  • osG osImg.getGraphics()

26
Buff.java (contd)
  • osG.setColor(Color.gray)
  • osG.fillRect(0,0,size().width, size().height)
  • for (i0 ilt MAX i) osG.setColor(bi.c)
  • osG.fillOval(bi.x,bi.y, 10,10)
  • bi.xbi.dx bi.ybi.dy
  • if (bi.xgtsize().width-10 bi.x lt10)
  • bi.dx-1
  • if (bi.ygtsize().height-10 bi.y lt10)
  • bi.dy-1
  • g.drawImage (osImg,0,0,this) repaint()
  • public void update(Graphics g)
  • paint (g)
Write a Comment
User Comments (0)
About PowerShow.com