1 package com.jed.core;
2
3 import com.jed.actor.AbstractEntity;
4 import com.jed.util.Vector2f;
5 import org.colapietro.number.util.Doubles;
6 import com.jed.actor.Boundary;
7 import com.jed.state.MapTile;
8
9 import javax.annotation.Nonnull;
10
11
12
13
14
15
16 public class Collision implements Comparable<Collision> {
17
18
19
20
21 private static final int NONE = 0;
22
23
24
25
26 private static final int SAT = 1;
27
28
29
30
31 private static final int SWEPT_X = 2;
32
33
34
35
36 private static final int SWEPT_Y = 3;
37
38
39
40
41 private int collisionType = NONE;
42
43
44
45
46 private final AbstractEntity a;
47
48
49
50
51 private final AbstractEntity b;
52
53
54
55
56 private double minXDistance, minYDistance;
57
58
59
60
61 private double smallestDisplacement;
62
63
64
65
66 private MinMax xEntityMinMax, xSEntityMinMax, yEntityMinMax, ySEntityMinMax;
67
68
69
70
71 private final boolean isDebugViewEnabled;
72
73
74
75
76
77
78
79
80
81 @Deprecated
82 public Collision(AbstractEntity a, AbstractEntity b) {
83 this.a = a;
84 this.b = b;
85 this.isDebugViewEnabled = false;
86 }
87
88
89
90
91
92
93
94
95 public Collision(AbstractEntity a, AbstractEntity b, boolean isDebugViewEnabled) {
96 this.a = a;
97 this.b = b;
98 this.isDebugViewEnabled = isDebugViewEnabled ;
99 }
100
101
102
103
104
105 public double smallestDisplacement() {
106 return smallestDisplacement;
107 }
108
109
110
111
112
113 public boolean detectCollision() {
114
115
116
117 Vector2f xAxis = new Vector2f(1, 0);
118 Vector2f yAxis = new Vector2f(0, 1);
119
120 xEntityMinMax = new MinMax(a.getBounds(), xAxis);
121 xSEntityMinMax = new MinMax(b.getBounds(), xAxis);
122 minXDistance = Math.abs(xEntityMinMax.getIntervalDistance(xSEntityMinMax));
123
124 yEntityMinMax = new MinMax(a.getBounds(), yAxis);
125 ySEntityMinMax = new MinMax(b.getBounds(), yAxis);
126 minYDistance = Math.abs(yEntityMinMax.getIntervalDistance(ySEntityMinMax));
127
128 boolean separateX =
129 xEntityMinMax.max < xSEntityMinMax.min ||
130 xSEntityMinMax.max < xEntityMinMax.min;
131
132 boolean separateY =
133 yEntityMinMax.max < ySEntityMinMax.min ||
134 ySEntityMinMax.max < yEntityMinMax.min;
135
136
137 if (!separateX && !separateY) {
138 collisionType = SAT;
139 } else
140
141
142 if (a.getMovement().x != 0 || a.getMovement().y != 0) {
143 if (Math.abs(a.getMovement().dotProduct(yAxis)) > minYDistance &&
144 !(xEntityMinMax.max <= xSEntityMinMax.min || xSEntityMinMax.max <= xEntityMinMax.min)) {
145
146 collisionType = SWEPT_Y;
147 } else if (Math.abs(a.getMovement().dotProduct(xAxis)) > minXDistance &&
148 !(yEntityMinMax.max <= ySEntityMinMax.min || ySEntityMinMax.max <= yEntityMinMax.min)) {
149
150 collisionType = SWEPT_X;
151 }
152 }
153
154 smallestDisplacement = minXDistance < minYDistance ? minXDistance : minYDistance;
155
156
157 if(isDebugViewEnabled) {
158 if (collisionType != NONE) {
159 ((MapTile) b).setColliding(true);
160 } else {
161 ((MapTile) b).setEvaluating(true);
162 }
163 }
164
165 return collisionType != NONE;
166
167 }
168
169
170
171
172 public void resolveCollision() {
173
174
175 if (collisionType == SAT) {
176
177 if (minYDistance != 0) {
178
179
180
181
182
183
184
185
186 if (Doubles.compareDoubles(minXDistance, a.getAcceleration()) || minXDistance < minYDistance) {
187 if (xEntityMinMax.min > xSEntityMinMax.min) {
188 a.getPosition().x += minXDistance;
189 } else {
190 a.getPosition().x -= minXDistance;
191 }
192
193 a.getMovement().x = 0;
194 }
195
196 else {
197 if (yEntityMinMax.min > ySEntityMinMax.min) {
198 a.getPosition().y += minYDistance;
199 } else {
200 a.getPosition().y -= minYDistance;
201 a.collideDown(b);
202 }
203 a.getMovement().y = 0;
204
205 }
206 }
207
208
209 if (minYDistance == 0 && a.getMovement().y == 0 && yEntityMinMax.min < ySEntityMinMax.min) {
210 a.collideDown(b);
211 }
212 }
213
214 else if (collisionType == SWEPT_Y) {
215
216 if (yEntityMinMax.min > ySEntityMinMax.min) {
217
218 if (a.getMovement().y <= 0 && minXDistance != 0) {
219 a.getPosition().y -= minYDistance;
220 a.getMovement().y = 0;
221 }
222 } else {
223
224 if (a.getMovement().y >= 0 && minXDistance != 0) {
225 a.getMovement().y = 0;
226 a.getPosition().y += minYDistance;
227 a.collideDown(b);
228 }
229 }
230
231 }
232
233 else if (collisionType == SWEPT_X) {
234 if (xEntityMinMax.min > xSEntityMinMax.min) {
235 a.getPosition().x -= minXDistance;
236 } else {
237 a.getPosition().x += minXDistance;
238 }
239 }
240
241 }
242
243
244
245
246
247
248 private class MinMax {
249
250
251
252
253 public double min, max;
254
255
256
257
258
259
260 public MinMax(@Nonnull Boundary boundary, Vector2f axis) {
261 max = boundary.vertices[0].add(boundary.getWorldPosition()).dotProduct(axis);
262 min = boundary.vertices[0].add(boundary.getWorldPosition()).dotProduct(axis);
263
264 double current;
265 for (int i = 1; i < boundary.vertices.length; i++) {
266 current = boundary.vertices[i].add(boundary.getWorldPosition()).dotProduct(axis);
267 if (min > current) {
268 min = current;
269 }
270
271 if (current > max) {
272 max = current;
273 }
274 }
275 }
276
277
278
279
280
281
282 public double getIntervalDistance(@Nonnull MinMax b) {
283 if (this.min < b.min) {
284 return b.min - this.max;
285 } else {
286 return this.min - b.max;
287 }
288 }
289
290 }
291
292 @Override
293 public int compareTo(@Nonnull Collision c) {
294 if (collisionType == SAT) {
295 if (c.collisionType != SAT) {
296 return -1;
297 } else {
298 return
299 Doubles.compareDoubles(smallestDisplacement, c.smallestDisplacement) ? 0 :
300 smallestDisplacement < c.smallestDisplacement ? -1 : 1;
301 }
302 } else if (collisionType == SWEPT_Y) {
303 if (c.collisionType == SAT) {
304 return 1;
305 } else if (c.collisionType == SWEPT_X) {
306 return -1;
307 } else {
308 return
309 Doubles.compareDoubles(minYDistance,c.minYDistance) ? 0 :
310 minYDistance < c.minYDistance ? -1 : 1;
311 }
312 } else if (collisionType == SWEPT_X) {
313 if (c.collisionType != SWEPT_X) {
314 return 1;
315 } else {
316 return
317 Doubles.compareDoubles(minXDistance,c.minXDistance) ? 0 :
318 minXDistance < c.minXDistance ? -1 : 1;
319 }
320
321 }
322 return 0;
323 }
324 }