summaryrefslogtreecommitdiff
path: root/java/gjt/animation/Playfield.java
blob: 386c0fb24c47b91c444aba016b10d5fe24a5a1c6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
package gjt.animation;

import java.awt.*;
import java.util.Enumeration;
import java.util.Vector;
import gjt.Util;

/**
 * A surface upon which Sprites are animated.  Playfields are 
 * responsible for animating the sprites.<p>
 *
 * Each Playfield comes complete with two collision detectors:
 * an edge collision detector and a sprite collision detector.
 *
 * Playfield is an abstract class:  extensions must implement
 * the following methods:
 * <dl>
 * <dd> void paintBackground(Graphics)
 * <dd> void void spriteCollision(Sprite sprite, Sprite other)
 * <dd> void void edgeCollision  (Sprite sprite, Sprite other)
 * </dl>
 *
 * @version 1.0, Apr 1 1996
 * @author  David Geary
 * @see     CollisionArena
 * @see     Sprite
 * @see     SpriteCollisionDetector
 * @see     EdgeCollisionDetector
 * @see     gjt.test.SimpleAnimationTest
 * @see     gjt.test.BumpAnimationTest
 * @see     gjt.test.TwoDrinkersAnimationTest
 */
public abstract class Playfield extends    Canvas 
                                implements Runnable, 
                                           CollisionArena {
    protected Vector    sprites = new Vector();
    private   boolean   running = false;
    private   Insets    insets  = new Insets(0,0,0,0);

    private   Thread                  animationThread;
    private   Image                   bgoffscreen, 
                                      workplaceBuffer;
    private   Dimension               offscreenSize;
    private   EdgeCollisionDetector   edgeCollisionDetector;
    private   SpriteCollisionDetector spriteCollisionDetector;

    abstract public void paintBackground(Graphics g);

    public Playfield() {
        edgeCollisionDetector   = 
            new EdgeCollisionDetector(this);
        spriteCollisionDetector =
            new SpriteCollisionDetector(this);
    }
    public void      stop      ()  { running = false;  }
    public boolean   running   ()  { return running;   }
    public Dimension getSize   ()  { return size();    }
    public Insets    getInsets ()  { return insets;    }
    public Vector    getSprites()  { return sprites;   }

    public void addSprite(Sprite sprite) { 
        sprites.addElement(sprite); 
    }
    public void setInsets(Insets insets) {
        this.insets = insets;
    }
    public void start() {
        animationThread = new Thread(this);
        running = true;
        animationThread.start();
    }
    public void paint(Graphics g) {
        if(needNewOffscreenBuffer()) {
            workplaceBuffer   = createOffscreenImage(size());
            bgoffscreen = createOffscreenImage(size());
            paintBackground(bgoffscreen.getGraphics());
        }
        g.drawImage(bgoffscreen, 0, 0, this);
        paintSprites();
    }
    public void reshape(int x, int y, int w, int h) {
        super.reshape(x,y,w,h);
        repaint();
    }
    public void run() {
        while(running == true) {
            edgeCollisionDetector.detectCollisions  ();
            spriteCollisionDetector.detectCollisions();

            animateSprites();
            Thread.currentThread().yield();
        }
        animationThread = null;
    }
    private boolean needNewOffscreenBuffer() {
        return (workplaceBuffer == null              || 
                bgoffscreen     == null              ||
                size().width  != offscreenSize.width ||
                size().height != offscreenSize.height);
    }
    private Image createOffscreenImage(Dimension size) {
        Image image = createImage(size.width, size.height);
        Util.waitForImage(this, image);
        offscreenSize = size;
        return image;
    }
    protected void animateSprites() {
        Sprite      nextSprite;
        Enumeration e = sprites.elements();

        while(e.hasMoreElements()) {
            nextSprite = (Sprite)e.nextElement();
            nextSprite.animate();
        }
    }
    protected void paintSprites() {
        Sprite      nextSprite;
        Enumeration e = sprites.elements();

        while(e.hasMoreElements()) {
            nextSprite = (Sprite)e.nextElement();
            paintSprite(nextSprite);
        }
    }
    protected void paintSprite(Sprite sprite) {
        Graphics  g    = getGraphics();
        Graphics  wpg  = workplaceBuffer.getGraphics();
        Rectangle clip = sprite.clipRect();

        wpg.clipRect(clip.x, clip.y, clip.width, clip.height);
        wpg.drawImage(bgoffscreen, 0, 0, this);
        sprite.paint(wpg);

        g.clipRect (clip.x, clip.y, clip.width, clip.height);
        g.drawImage(workplaceBuffer, 0, 0, this);

        g.dispose();
        wpg.dispose();
    }
}