summaryrefslogtreecommitdiff
path: root/java/gjt/animation/Sprite.java
blob: e7840b7615b88a43586cc5ce83f9850602c669fe (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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
package gjt.animation;

import java.awt.*;
import java.util.Vector;
import gjt.Assert;
import gjt.Stopwatch;
import gjt.Util;

/**
 * A sequence of images which are animated and moved about on
 * a Playfield.<p>
 *
 * Each Sprite is constructed with a reference to it's 
 * Playfield, a Sequence, and a beginning position for it's 
 * upper left hand corner.<p>
 *
 * A Sprite's animation is controlled by invoking the following
 * methods:
 *<dl>
 *<dd> setMoveVector(Point)
 *<dd> setMoveInterval(long)
 *<dd> setImageChangeInterval(long)
 *<dd> setMainSequence(Sequence)
 *<dd> setSequence(Sequence)
 *</dl>
 *
 * @version 1.0, Apr 1 1996
 * @author  David Geary
 * @see     Sequence
 * @see     Playfield
 * @see     SpriteCollisionDetector
 * @see     gjt.test.SimpleAnimationTest
 * @see     gjt.test.BumpAnimationTest
 * @see     gjt.test.TwoDrinkersAnimationTest
 */
public class Sprite {
    private Playfield field;
    private Sequence currentSequence, mainSequence;
    private Stopwatch moveTimer = new Stopwatch();

    private Point ulhc       = new Point(0,0); 
    private Point start      = new Point(0,0);
    private Point moveVector = new Point(1,1);

    private Rectangle clip = new Rectangle(0,0);
    private Rectangle curBounds, lastBounds; 

    private int  width, height;
    private long moveInterval = 0;

    public Sprite(Playfield field, 
                  Sequence  sequence, 
                  Point     ulhc) {
        Assert.notNull(field);
        Assert.notNull(sequence);
        Assert.notNull(ulhc);

        this.field = field;
        this.ulhc  = ulhc;
        start.x    = ulhc.x;
        start.y    = ulhc.y;

        setSequence(sequence);
        setMainSequence(sequence);

        initializeBounds();
        moveTimer.start();
        currentSequence.start();
    }
    public Playfield getPlayfield() { return field;            }
    public Rectangle clipRect    () { return clip;             }
    public Rectangle curBounds   () { return curBounds;        }

    public int   width    () { return width;                   }
    public int   height   () { return height;                  }
    public void  reverseX () { moveVector.x = 0-moveVector.x;  }
    public void  reverseY () { moveVector.y = 0-moveVector.y;  }
    public void  reverse  () { reverseX(); reverseY();         }
    public Point start    () { return start;                   }

    public void  setMoveVector (Point p) { moveVector = p;     }
    public Point getMoveVector()         { return moveVector;  }

    public void play(Sequence sequence, long cycles) {
        setSequence(sequence);
        sequence.setCyclesPerAnimation(cycles);
        sequence.setCurrentCycle(0);
    }
    public void animate() {
        if(currentSequence.animationOver())
            currentSequence = mainSequence;

        if(timeToChangeImage()) currentSequence.advance();
        if(timeToMove())        move();
        if(needsRepainting())   field.paintSprite(this); 
    }
    public void setMainSequence(Sequence sequence) {
        mainSequence = sequence;
    }
    public Sequence getMainSequence() { 
        return mainSequence; 
    }
    public void setSequence(Sequence sequence) {
        currentSequence = sequence;

        if(curBounds != null)
            updateBounds();
    }
    public Sequence getSequence() { 
        return currentSequence; 
    }
    public boolean intersects(Sprite otherSprite) {
        return curBounds().intersects(otherSprite.curBounds());
    }
    public boolean willIntersect(Sprite otherSprite) {
        return 
          nextBounds().intersects(otherSprite.nextBounds());
    }
    public boolean timeToMove() {
        return moveTimer.elapsedTime() > moveInterval;
    }
    public boolean timeToChangeImage() {
        return currentSequence.timeToAdvanceCell();
    }
    public void moveTo(Point p) {
        ulhc = p;
        moveTimer.reset();
    }
    public boolean needsRepainting() {
        return currentSequence.needsRepainting(ulhc);
    }
    public void setMoveInterval(long interval) {
        moveInterval = interval;
    }
    public void setImageChangeInterval(long interval) {
        currentSequence.setAdvanceInterval(interval);
    }
    public void move() {
        ulhc.x += moveVector.x;
        ulhc.y += moveVector.y;
        updateBounds();
        moveTimer.reset();
    }
    public Point location() {
        return ulhc;
    }
    public Point nextLocation() {
        return new Point(ulhc.x + moveVector.x, 
                         ulhc.y + moveVector.y);
    }
    public Rectangle nextBounds() {
        Image nextImage = currentSequence.getNextImage();
        Point nextLoc   = nextLocation();

        return new Rectangle(
                        nextLoc.x, nextLoc.y, width, height);
    }
    public void paint(Graphics g) {
        currentSequence.paint(g, ulhc.x, ulhc.y, field);
    }
    private void initializeBounds() {
        Image curImage = currentSequence.getCurrentImage();

        width  = curImage.getWidth (field); 
        height = curImage.getHeight(field);

        curBounds = 
          new Rectangle(ulhc.x, ulhc.y, width, height);

        lastBounds = new Rectangle(curBounds.x, 
                                   curBounds.y,
                                   curBounds.width, 
                                   curBounds.height);

        clip = lastBounds.union(curBounds);
    }
    private void updateBounds() {
        Image curImage = currentSequence.getCurrentImage();

        lastBounds.width  = curBounds.width;
        lastBounds.height = curBounds.height;

        curBounds.width  = width  = curImage.getWidth(field);
        curBounds.height = height = curImage.getHeight(field);

        lastBounds.move(curBounds.x, curBounds.y);
        curBounds.move (ulhc.x, ulhc.y);

        clip = lastBounds.union(curBounds);
    }
}