summaryrefslogtreecommitdiff
path: root/src/ch/epfl/maze/graphics/GraphicComponent.java
diff options
context:
space:
mode:
authorPacien TRAN-GIRARD2015-11-21 10:36:18 +0100
committerPacien TRAN-GIRARD2015-11-21 10:36:18 +0100
commit655ac88f4e73b2df532a451aedf5a561ea1b0d2c (patch)
treeef6f914a465575f313e2b280bf0639d87a4cbd58 /src/ch/epfl/maze/graphics/GraphicComponent.java
parent56279eb59ccdea48b18daa027a5095d861b4e2f4 (diff)
downloadmaze-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.java237
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 @@
1package ch.epfl.maze.graphics;
2
3import java.awt.Graphics2D;
4import java.awt.geom.AffineTransform;
5import java.awt.image.BufferedImage;
6import java.awt.image.ImageObserver;
7
8import javax.swing.ImageIcon;
9
10import ch.epfl.maze.util.Action;
11import ch.epfl.maze.util.Direction;
12import ch.epfl.maze.util.Vector2D;
13
14/**
15 * Graphic component of an animal that will be drawn by an {@link Animation}.
16 *
17 */
18
19public 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) {