diff options
Diffstat (limited to 'src/ch/epfl/maze/graphics/GraphicComponent.java')
-rw-r--r-- | src/ch/epfl/maze/graphics/GraphicComponent.java | 432 |
1 files changed, 208 insertions, 224 deletions
diff --git a/src/ch/epfl/maze/graphics/GraphicComponent.java b/src/ch/epfl/maze/graphics/GraphicComponent.java index 2321714..e49a542 100644 --- a/src/ch/epfl/maze/graphics/GraphicComponent.java +++ b/src/ch/epfl/maze/graphics/GraphicComponent.java | |||
@@ -1,237 +1,221 @@ | |||
1 | package ch.epfl.maze.graphics; | 1 | package ch.epfl.maze.graphics; |
2 | 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; | 3 | import ch.epfl.maze.util.Action; |
11 | import ch.epfl.maze.util.Direction; | 4 | import ch.epfl.maze.util.Direction; |
12 | import ch.epfl.maze.util.Vector2D; | 5 | import ch.epfl.maze.util.Vector2D; |
13 | 6 | ||
7 | import javax.swing.*; | ||
8 | import java.awt.*; | ||
9 | import java.awt.geom.AffineTransform; | ||
10 | import java.awt.image.BufferedImage; | ||
11 | import java.awt.image.ImageObserver; | ||
12 | |||
14 | /** | 13 | /** |
15 | * Graphic component of an animal that will be drawn by an {@link Animation}. | 14 | * Graphic component of an animal that will be drawn by an {@link Animation}. |
16 | * | ||
17 | */ | 15 | */ |
18 | 16 | ||
19 | public final class GraphicComponent { | 17 | public final class GraphicComponent { |
20 | 18 | ||
21 | /* constants */ | 19 | /* constants */ |
22 | public static final int MAXIMUM_FRAMES = 4; | 20 | public static final int MAXIMUM_FRAMES = 4; |
23 | public static final int SQUARE_SIZE = Display.SQUARE_SIZE; | 21 | public static final int SQUARE_SIZE = Display.SQUARE_SIZE; |
24 | 22 | ||
25 | /* drawing variables */ | 23 | /* drawing variables */ |
26 | private final Vector2D mPosition; | 24 | private final Vector2D mPosition; |
27 | private final BufferedImage mImage; | 25 | private final BufferedImage mImage; |
28 | private Action mAction; | 26 | private Action mAction; |
29 | private boolean mRotate; | 27 | private boolean mRotate; |
30 | 28 | ||
31 | /** | 29 | /** |
32 | * Constructs a graphic component with the image of the animal, the position | 30 | * 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 | 31 | * at which the component needs to be drawn, and the corresponding action |
34 | * that it needs to perform. | 32 | * that it needs to perform. |
35 | * | 33 | * |
36 | * @param image | 34 | * @param image Image of animal |
37 | * Image of animal | 35 | * @param position Position at which the image will be drawn |
38 | * @param position | 36 | * @param action Action that the component needs to perform |
39 | * Position at which the image will be drawn | 37 | */ |
40 | * @param action | 38 | |
41 | * Action that the component needs to perform | 39 | public GraphicComponent(BufferedImage image, Vector2D position, Action action) { |
42 | */ | 40 | // sanity checks |
43 | 41 | if (image == null) { | |
44 | public GraphicComponent(BufferedImage image, Vector2D position, Action action) { | 42 | throw new IllegalArgumentException("BufferedImage cannot be null."); |
45 | // sanity checks | 43 | } |
46 | if (image == null) { | 44 | if (position == null) { |
47 | throw new IllegalArgumentException("BufferedImage cannot be null."); | 45 | throw new IllegalArgumentException("Position cannot be null."); |
48 | } | 46 | } |
49 | if (position == null) { | 47 | if (action == null) { |
50 | throw new IllegalArgumentException("Position cannot be null."); | 48 | action = new Action(Direction.NONE, false); |
51 | } | 49 | } |
52 | if (action == null) { | 50 | |
53 | action = new Action(Direction.NONE, false); | 51 | // default values |
54 | } | 52 | mImage = image; |
55 | 53 | mPosition = position; | |
56 | // default values | 54 | mRotate = true; |
57 | mImage = image; | 55 | mAction = action; |
58 | mPosition = position; | 56 | } |
59 | mRotate = true; | 57 | |
60 | mAction = action; | 58 | /** |
61 | } | 59 | * Notifies the component that it will die between two squares. |
62 | 60 | */ | |
63 | /** | 61 | |
64 | * Notifies the component that it will die between two squares. | 62 | public void willDieMoving() { |
65 | */ | 63 | mAction = new Action(mAction.getDirection(), mAction.isSuccessful(), true); |
66 | 64 | } | |
67 | public void willDieMoving() { | 65 | |
68 | mAction = new Action(mAction.getDirection(), mAction.isSuccessful(), true); | 66 | /** |
69 | } | 67 | * Asks the graphic component to paint itself on graphic environment, by |
70 | 68 | * performing a ratio of its action. | |
71 | /** | 69 | * |
72 | * Asks the graphic component to paint itself on graphic environment, by | 70 | * @param ratio Ratio of the action to be performed |
73 | * performing a ratio of its action. | 71 | * @param g Graphic environment |
74 | * | 72 | * @param targetWindow Window on which the graphic is being drawn |
75 | * @param ratio | 73 | */ |
76 | * Ratio of the action to be performed | 74 | |
77 | * @param g | 75 | public void paint(float ratio, Graphics2D g, ImageObserver targetWindow) { |
78 | * Graphic environment | 76 | if (mAction.getDirection() == Direction.NONE) { |
79 | * @param targetWindow | 77 | renderStuck(g, targetWindow); |
80 | * Window on which the graphic is being drawn | 78 | } else { |
81 | */ | 79 | if (ratio > 0.5) { |
82 | 80 | if (!mAction.diesBetweenSquares() && !mAction.isSuccessful()) { | |
83 | public void paint(float ratio, Graphics2D g, ImageObserver targetWindow) { | 81 | renderMove(1 - ratio, g, targetWindow, true); |
84 | if (mAction.getDirection() == Direction.NONE) { | 82 | } else if (!mAction.diesBetweenSquares()) { |
85 | renderStuck(g, targetWindow); | 83 | renderMove(ratio, g, targetWindow, false); |
86 | } else { | 84 | } |
87 | if (ratio > 0.5) { | 85 | } else { |
88 | if (!mAction.diesBetweenSquares() && !mAction.isSuccessful()) { | 86 | renderMove(ratio, g, targetWindow, false); |
89 | renderMove(1 - ratio, g, targetWindow, true); | 87 | } |
90 | } else if (!mAction.diesBetweenSquares()) { | 88 | } |
91 | renderMove(ratio, g, targetWindow, false); | 89 | } |
92 | } | 90 | |
93 | } else { | 91 | /** |
94 | renderMove(ratio, g, targetWindow, false); | 92 | * Draws the moving component on graphics environment and target window. |
95 | } | 93 | * <p> |
96 | } | 94 | * The function draws the animal at {@code (position + ratio*heading)}. |
97 | } | 95 | * |
98 | 96 | * @param ratio Ratio of action performed by animation | |
99 | /** | 97 | * @param g Graphic environment |
100 | * Draws the moving component on graphics environment and target window. | 98 | * @param targetWindow Frame display |
101 | * <p> | 99 | * @param buzz Buzzes the animal, used when he has just hit a wall |
102 | * The function draws the animal at {@code (position + ratio*heading)}. | 100 | */ |
103 | * | 101 | |
104 | * @param ratio | 102 | private void renderMove(float ratio, Graphics2D g, ImageObserver targetWindow, boolean buzz) { |
105 | * Ratio of action performed by animation | 103 | // transforms direction into vector |
106 | * @param g | 104 | Vector2D heading = mAction.getDirection().toVector().mul(SQUARE_SIZE); |
107 | * Graphic environment | 105 | Vector2D normalized = heading.normalize(); |
108 | * @param targetWindow | 106 | |
109 | * Frame display | 107 | // loads the correct frame |
110 | * @param buzz | 108 | BufferedImage img = cropImage(ratio, mAction.getDirection()); |
111 | * Buzzes the animal, used when he has just hit a wall | 109 | |
112 | */ | 110 | AffineTransform reset = new AffineTransform(); |
113 | 111 | ||
114 | private void renderMove(float ratio, Graphics2D g, ImageObserver targetWindow, boolean buzz) { | 112 | // applies translation |
115 | // transforms direction into vector | 113 | double newX = (mPosition.getX() + ratio * heading.getX()); |
116 | Vector2D heading = mAction.getDirection().toVector().mul(SQUARE_SIZE); | 114 | double newY = (mPosition.getY() + ratio * heading.getY()); |
117 | Vector2D normalized = heading.normalize(); | 115 | reset.translate(newX, newY); |
118 | 116 | ||
119 | // loads the correct frame | 117 | // applies rotation |
120 | BufferedImage img = cropImage(ratio, mAction.getDirection()); | 118 | double rotation = 0; |
121 | 119 | if (buzz) { | |
122 | AffineTransform reset = new AffineTransform(); | 120 | rotation = -(Math.PI / 6.0) * Math.sin((60 * ratio) / Math.PI); |
123 | 121 | } | |
124 | // applies translation | 122 | if (mRotate) { |
125 | double newX = (mPosition.getX() + ratio * heading.getX()); | 123 | rotation += Math.atan2(normalized.getY(), normalized.getX()) - Math.PI / 2; |
126 | double newY = (mPosition.getY() + ratio * heading.getY()); | 124 | } |
127 | reset.translate(newX, newY); | 125 | reset.rotate(rotation, SQUARE_SIZE / 2, SQUARE_SIZE / 2); |
128 | 126 | ||
129 | // applies rotation | 127 | // transforms and draws image |
130 | double rotation = 0; | 128 | g.setTransform(reset); |
131 | if (buzz) { | 129 | g.drawImage(img, 0, 0, targetWindow); |
132 | rotation = -(Math.PI / 6.0) * Math.sin((60 * ratio) / Math.PI); | 130 | |
133 | } | 131 | // inverts transformations |
134 | if (mRotate) { |