diff options
author | Pacien TRAN-GIRARD | 2015-11-21 10:36:18 +0100 |
---|---|---|
committer | Pacien TRAN-GIRARD | 2015-11-21 10:36:18 +0100 |
commit | 655ac88f4e73b2df532a451aedf5a561ea1b0d2c (patch) | |
tree | ef6f914a465575f313e2b280bf0639d87a4cbd58 /src/ch/epfl/maze/graphics/GraphicComponent.java | |
parent | 56279eb59ccdea48b18daa027a5095d861b4e2f4 (diff) | |
download | maze-solver-655ac88f4e73b2df532a451aedf5a561ea1b0d2c.tar.gz |
Import project structure
Diffstat (limited to 'src/ch/epfl/maze/graphics/GraphicComponent.java')
-rw-r--r-- | src/ch/epfl/maze/graphics/GraphicComponent.java | 237 |
1 files changed, 237 insertions, 0 deletions
diff --git a/src/ch/epfl/maze/graphics/GraphicComponent.java b/src/ch/epfl/maze/graphics/GraphicComponent.java new file mode 100644 index 0000000..2321714 --- /dev/null +++ b/src/ch/epfl/maze/graphics/GraphicComponent.java | |||
@@ -0,0 +1,237 @@ | |||
1 | package ch.epfl.maze.graphics; | ||
2 | |||
3 | import java.awt.Graphics2D; | ||
4 | import java.awt.geom.AffineTransform; | ||
5 | import java.awt.image.BufferedImage; | ||
6 | import java.awt.image.ImageObserver; | ||
7 | |||
8 | import javax.swing.ImageIcon; | ||
9 | |||
10 | import ch.epfl.maze.util.Action; | ||
11 | import ch.epfl.maze.util.Direction; | ||
12 | import ch.epfl.maze.util.Vector2D; | ||
13 | |||
14 | /** | ||
15 | * Graphic component of an animal that will be drawn by an {@link Animation}. | ||
16 | * | ||
17 | */ | ||
18 | |||
19 | public final class GraphicComponent { | ||
20 | |||
21 | /* constants */ | ||
22 | public static final int MAXIMUM_FRAMES = 4; | ||
23 | public static final int SQUARE_SIZE = Display.SQUARE_SIZE; | ||
24 | |||
25 | /* drawing variables */ | ||
26 | private final Vector2D mPosition; | ||
27 | private final BufferedImage mImage; | ||
28 | private Action mAction; | ||
29 | private boolean mRotate; | ||
30 | |||
31 | /** | ||
32 | * Constructs a graphic component with the image of the animal, the position | ||
33 | * at which the component needs to be drawn, and the corresponding action | ||
34 | * that it needs to perform. | ||
35 | * | ||
36 | * @param image | ||
37 | * Image of animal | ||
38 | * @param position | ||
39 | * Position at which the image will be drawn | ||
40 | * @param action | ||
41 | * Action that the component needs to perform | ||
42 | */ | ||
43 | |||
44 | public GraphicComponent(BufferedImage image, Vector2D position, Action action) { | ||
45 | // sanity checks | ||
46 | if (image == null) { | ||
47 | throw new IllegalArgumentException("BufferedImage cannot be null."); | ||
48 | } | ||
49 | if (position == null) { | ||
50 | throw new IllegalArgumentException("Position cannot be null."); | ||
51 | } | ||
52 | if (action == null) { | ||
53 | action = new Action(Direction.NONE, false); | ||
54 | } | ||
55 | |||
56 | // default values | ||
57 | mImage = image; | ||
58 | mPosition = position; | ||
59 | mRotate = true; | ||
60 | mAction = action; | ||
61 | } | ||
62 | |||
63 | /** | ||
64 | * Notifies the component that it will die between two squares. | ||
65 | */ | ||
66 | |||
67 | public void willDieMoving() { | ||
68 | mAction = new Action(mAction.getDirection(), mAction.isSuccessful(), true); | ||
69 | } | ||
70 | |||
71 | /** | ||
72 | * Asks the graphic component to paint itself on graphic environment, by | ||
73 | * performing a ratio of its action. | ||
74 | * | ||
75 | * @param ratio | ||
76 | * Ratio of the action to be performed | ||
77 | * @param g | ||
78 | * Graphic environment | ||
79 | * @param targetWindow | ||
80 | * Window on which the graphic is being drawn | ||
81 | */ | ||
82 | |||
83 | public void paint(float ratio, Graphics2D g, ImageObserver targetWindow) { | ||
84 | if (mAction.getDirection() == Direction.NONE) { | ||
85 | renderStuck(g, targetWindow); | ||
86 | } else { | ||
87 | if (ratio > 0.5) { | ||
88 | if (!mAction.diesBetweenSquares() && !mAction.isSuccessful()) { | ||
89 | renderMove(1 - ratio, g, targetWindow, true); | ||
90 | } else if (!mAction.diesBetweenSquares()) { | ||
91 | renderMove(ratio, g, targetWindow, false); | ||
92 | } | ||
93 | } else { | ||
94 | renderMove(ratio, g, targetWindow, false); | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | |||
99 | /** | ||
100 | * Draws the moving component on graphics environment and target window. | ||
101 | * <p> | ||
102 | * The function draws the animal at {@code (position + ratio*heading)}. | ||
103 | * | ||
104 | * @param ratio | ||
105 | * Ratio of action performed by animation | ||
106 | * @param g | ||
107 | * Graphic environment | ||
108 | * @param targetWindow | ||
109 | * Frame display | ||
110 | * @param buzz | ||
111 | * Buzzes the animal, used when he has just hit a wall | ||
112 | */ | ||
113 | |||
114 | private void renderMove(float ratio, Graphics2D g, ImageObserver targetWindow, boolean buzz) { | ||
115 | // transforms direction into vector | ||
116 | Vector2D heading = mAction.getDirection().toVector().mul(SQUARE_SIZE); | ||
117 | Vector2D normalized = heading.normalize(); | ||
118 | |||
119 | // loads the correct frame | ||
120 | BufferedImage img = cropImage(ratio, mAction.getDirection()); | ||
121 | |||
122 | AffineTransform reset = new AffineTransform(); | ||
123 | |||
124 | // applies translation | ||
125 | double newX = (mPosition.getX() + ratio * heading.getX()); | ||
126 | double newY = (mPosition.getY() + ratio * heading.getY()); | ||
127 | reset.translate(newX, newY); | ||
128 | |||
129 | // applies rotation | ||
130 | double rotation = 0; | ||
131 | if (buzz) { | ||
132 | rotation = -(Math.PI / 6.0) * Math.sin((60 * ratio) / Math.PI); | ||
133 | } | ||
134 | if (mRotate) { | ||
135 | rotation += Math.atan2(normalized.getY(), normalized.getX()) - Math.PI / 2; | ||
136 | } | ||
137 | reset.rotate(rotation, SQUARE_SIZE / 2, SQUARE_SIZE / 2); | ||
138 | |||
139 | // transforms and draws image | ||
140 | g.setTransform(reset); | ||
141 | g.drawImage(img, 0, 0, targetWindow); | ||
142 | |||
143 | // inverts transformations | ||
144 | reset.rotate(-rotation, SQUARE_SIZE / 2, SQUARE_SIZE / 2); | ||
145 | reset.translate(-newX, -newY); | ||
146 | g.setTransform(reset); | ||
147 | } | ||
148 | |||
149 | /** | ||
150 | * Draws the still component on graphics environment and target window. | ||
151 | * <p> | ||
152 | * Draws a question mark if {@code mAction} is not successful | ||
153 | * | ||
154 | * @param g | ||
155 | * Graphic environment | ||
156 | * @param targetWindow | ||
157 | * Frame display | ||
158 | */ | ||
159 | |||
160 | private void renderStuck(Graphics2D g, ImageObserver targetWindow) { | ||
161 | // loads default frame of image with default direction | ||
162 | BufferedImage img = cropImage(-1, Direction.NONE); | ||
163 | |||
164 | AffineTransform reset = new AffineTransform(); | ||
165 | |||
166 | // applies translation | ||
167 | double newX = mPosition.getX(); | ||
168 | double newY = mPosition.getY(); | ||
169 | reset.translate(newX, newY); | ||
170 | |||
171 | // transforms and draws image | ||
172 | g.setTransform(reset); | ||
173 | g.drawImage(img, 0, 0, targetWindow); | ||
174 | |||
175 | // draws interrogation mark | ||
176 | if (!mAction.isSuccessful()) { | ||
177 | ImageIcon icon = new ImageIcon("img/unknown.png"); | ||
178 | g.drawImage(icon.getImage(), SQUARE_SIZE - icon.getIconWidth() - 2, 2, targetWindow); | ||
179 | } | ||
180 | |||
181 | // inverts translation | ||
182 | reset.translate(-newX, -newY); | ||
183 | g.setTransform(reset); | ||
184 | } | ||
185 | |||
186 | /** | ||
187 | * Transforms the image according to frame and movement. | ||
188 | * | ||
189 | * @param ratio | ||
190 | * The ratio of the action to perform | ||
191 | * @param dir | ||
192 | * The direction towards which the component faces | ||
193 | * @return The correct frame that faces towards the direction specified | ||
194 | */ | ||
195 | |||
196 | private BufferedImage cropImage(float ratio, Direction dir) { | ||
197 | int width = mImage.getWidth(); | ||
198 | int height = mImage.getHeight(); | ||
199 | int frames = width / SQUARE_SIZE; | ||
200 | int moves = height / SQUARE_SIZE; | ||
201 | |||
202 | // sanity checks | ||
203 | if (width % SQUARE_SIZE != 0 || height % SQUARE_SIZE != 0) { | ||
204 | throw new UnsupportedOperationException( | ||
205 | "Image size is not a multiple of " + SQUARE_SIZE + " pixels, but " + width + "x" + height); | ||
206 | } | ||
207 | if (moves > Direction.values().length) { | ||
208 | throw new UnsupportedOperationException( | ||
209 | "Image height has more than " + Direction.values().length + " moves (" + height + ")"); | ||
210 | } | ||
211 | if (frames > MAXIMUM_FRAMES) { | ||