-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathGhost.java
More file actions
309 lines (276 loc) · 11.7 KB
/
Ghost.java
File metadata and controls
309 lines (276 loc) · 11.7 KB
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
//Bogachan Arslan, Kaan Cinar, Onder Soydal, Sinan Karabocuoglu
//Pacman Midterm
//18.05.18
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
public abstract class Ghost {
protected int xPos;
protected int yPos;
private int defaultX;
private int defaultY;
protected int SIZE;
private int wallWidth=0;
protected Color COLOR;
public Shape boundary;
private AffineTransform af;
private Random r=new Random();
private int velocity=1;
private int lengthMoved=0;
private boolean moving=false;
private Shape[][] maze;
public char direction='N';
private boolean directionManuallySet=false;
public int movementMode=0; // 0-->Scatter, 1-->Chase, 2-->Escape
protected int timeToScatter;
private final int timeToChase=15;
private final int timeToEscape=15;
private boolean oppositeDirection=false;
private int secondsCounter=0;
public Ghost(int initialX,int initialY,int vel,int squareSize,int width, Shape[][] grid){
maze=grid;
xPos=initialX;
defaultX=initialX;
defaultY=initialY;
yPos=initialY;
velocity=vel;
SIZE=squareSize;
wallWidth=width;
af=AffineTransform.getTranslateInstance(0,0);
boundary=new Rectangle2D.Double(initialX-SIZE/2,initialY-SIZE/2,SIZE,SIZE);
//The timer that will keep track of time to switch between modes
Timer timer=new Timer();
TimerTask chronometer=new TimerTask(){
@Override
public void run() {
secondsCounter++;
}
};
timer.schedule(chronometer,0,1000);
}
public void drawGhost(Graphics2D g2,int pacmanX,int pacmanY,char pacmanDirection){
g2.setStroke(new BasicStroke(0));
g2.setColor((movementMode==1)?Color.RED:Color.GREEN);
//g2.draw(boundary.getBounds());
g2.setColor(COLOR);
//To switch between modes if their relative times are up
switch (movementMode){
case 0:
if(secondsCounter>=timeToScatter){ movementMode=1; secondsCounter=0; }
break;
case 1:
if(secondsCounter>=timeToChase){ movementMode=0; secondsCounter=0; }
break;
case 2:
g2.setColor(Color.BLUE);
if(secondsCounter==6 || secondsCounter==8) g2.setColor(COLOR);
if(secondsCounter>=timeToEscape){ movementMode=1; secondsCounter=0; }
}
if(moving) {
for(int i=0;i<velocity;i++){
boundary = af.createTransformedShape(boundary);
lengthMoved++;
xPos=(int)boundary.getBounds().getX()+SIZE/2;
yPos=(int)boundary.getBounds().getY()+SIZE/2;
if(lengthMoved==(/*SIZE+wallWidth*/52)) { moving=false; break;}
}
} else {
lengthMoved=0;
af=AffineTransform.getTranslateInstance(0,0);
initiateMovement(pacmanX,pacmanY,pacmanDirection);
}
double scaleFactor=SIZE*3/8;
//For circular head and horizontal rectangular body
g2.fillArc((int)(xPos-scaleFactor),(int) (yPos-scaleFactor),(int)(2*scaleFactor),(int)(2*scaleFactor),0,180);
g2.fillRect((int)(xPos-scaleFactor),yPos,(int)(2*scaleFactor),(int)(scaleFactor/2));
//For triangular legs(?)
int[] TX={(int)(xPos-scaleFactor),(int)(xPos-scaleFactor),(int)(xPos-scaleFactor),(int)(xPos-scaleFactor/2),xPos,(int)(xPos+scaleFactor/2),(int)(xPos+scaleFactor),(int)(xPos+scaleFactor)};
int[] TY={(int)(yPos+scaleFactor/2),(int)(yPos+scaleFactor),(int)(yPos+scaleFactor),(int)(yPos+scaleFactor/2),(int)(yPos+scaleFactor),(int)(yPos+scaleFactor/2),(int)(yPos+scaleFactor),(int)(yPos+scaleFactor/2)};
g2.fillPolygon(TX,TY,8);
//g2.fillPolygon(legCoordinatesX(),legCoordinatesY(),8); TODO y u no work??
//For Eyes
g2.setColor(Color.WHITE);
g2.fillOval((int)(xPos-2*scaleFactor/3),(int)(yPos-2*scaleFactor/3),(int)(2*scaleFactor/3),(int)(2*scaleFactor/3));
g2.fillOval((xPos),(int)(yPos-2*scaleFactor/3),(int)(2*scaleFactor/3),(int)(2*scaleFactor/3));
g2.setColor(Color.BLACK);
g2.fillOval(eyePositionX(direction)[0],eyePositionY(direction),(int)(scaleFactor/3),(int)(scaleFactor/3));
g2.fillOval(eyePositionX(direction)[1],eyePositionY(direction),(int)(scaleFactor/3),(int)(scaleFactor/3));
//g2.fillOval((int)(xPos-scaleFactor/2),(int)(yPos-scaleFactor/3),(int)(scaleFactor/3),(int)(scaleFactor/3));
//g2.fillOval((int)(xPos+scaleFactor/4),(int)(yPos-2*scaleFactor/3),(int)(scaleFactor/3),(int)(scaleFactor/3));
}
private int[] legCoordinatesX(){
double scaleFactor=SIZE*3/8;
double legShiftFactor=(lengthMoved/SIZE)*scaleFactor;
double position6=(legShiftFactor>=(scaleFactor/2))? ((xPos-scaleFactor)+(legShiftFactor-(scaleFactor/2))) : ((xPos+scaleFactor/2)+legShiftFactor);
int[] xPoints = {(int)(xPos-scaleFactor),(int)(xPos-scaleFactor),(int)(xPos-scaleFactor+legShiftFactor),(int)(xPos-scaleFactor/2+legShiftFactor),(int)(xPos+legShiftFactor),(int)position6,(int)(xPos+scaleFactor),(int)(xPos+scaleFactor)};
return xPoints;
}
private int[] legCoordinatesY(){
double scaleFactor=SIZE*3/8;
double legShiftFactor=(lengthMoved/SIZE)*scaleFactor;
double yshiftFactor=Math.abs(legShiftFactor-scaleFactor/2);
int[] yPoints={(int)(yPos+scaleFactor/2),(int)(yPos+scaleFactor/2+yshiftFactor),(int)(yPos+scaleFactor),(int)(yPos+scaleFactor/2),(int)(yPos+scaleFactor),(int)(yPos+scaleFactor/2),(int)(yPos+scaleFactor/2+yshiftFactor),(int)(yPos+scaleFactor/2)};
return yPoints;
}
private int[] eyePositionX(char direction){
double scaleFactor=SIZE*3/8;
int[] eyesX=new int[2];
switch(direction){
case 'S':
eyesX[0]=(int)(xPos-scaleFactor/2);
eyesX[1]=(int)(xPos+scaleFactor/6);
break;
case 'N':
eyesX[0]=(int)(xPos-scaleFactor/2);
eyesX[1]=(int)(xPos+scaleFactor/6);
break;
case 'E':
eyesX[0]=(int)(xPos-scaleFactor/3);
eyesX[1]=(int)(xPos+scaleFactor/3);
break;
case 'W':
eyesX[0]=(int)(xPos-2*scaleFactor/3);
eyesX[1]=(xPos);
break;
}
return eyesX;
}
private int eyePositionY(char direction){
double scaleFactor=SIZE*3/8;
switch(direction){
case 'S':
return (int)(yPos-scaleFactor/3);
case 'N':
return (int)(yPos-2*scaleFactor/3);
case 'E':
return (int)(yPos-2*scaleFactor/3);
case 'W':
return (int)(yPos-2*scaleFactor/3);
}
return (int)(yPos-scaleFactor/3);
}
public abstract ArrayList<Character> determineDirectionOrder(int pacmanX, int pacmanY,char pacmanDirection);
protected ArrayList<Character> generateRandomDirections(){
ArrayList<Character> directions=new ArrayList<Character>();
ArrayList<Character> possibilities=new ArrayList<Character>();
possibilities.add('N');possibilities.add('S');possibilities.add('E');possibilities.add('W');
for(int i=0;i<4;i++){
int randomIndex=r.nextInt(possibilities.size());
directions.add(possibilities.remove(randomIndex));
}
return directions;
}
private void initiateMovement(int pacX,int pacY,char pacDir){
ArrayList<Character> directions=(movementMode==1)? determineDirectionOrder(pacX,pacY,pacDir) : generateRandomDirections();
directions=addReverseToLast(directions);
char selectedDirection='0';
for(int i=0;i<directions.size();i++){
Shape tempBoundary=boundary;
char currentDir=directions.get(i);
switch(currentDir){
case 'N':
tempBoundary=createTranslatedShape(boundary,0,-(SIZE+wallWidth)/2);
break;
case 'S':
tempBoundary=createTranslatedShape(boundary,0,(SIZE+wallWidth)/2);
break;
case 'E':
tempBoundary=createTranslatedShape(boundary,(SIZE+wallWidth)/2,0);
break;
case 'W':
tempBoundary=createTranslatedShape(boundary,-(SIZE+wallWidth)/2,0);
break;
}
if(moveSafe(tempBoundary)){
selectedDirection=currentDir;
break;
}
}
int xVel=0;
int yVel=0;
if(directionManuallySet) directionManuallySet=false;
else direction=(oppositeDirection)? reverseDirection() : selectedDirection;
switch (direction){
case 'N': xVel=0; yVel=-1; break;
case 'S': xVel=0; yVel=1; break;
case 'E': xVel=1; yVel=0;break;
case 'W': xVel=-1; yVel=0; break;
}
af.translate(xVel,yVel);
moving=true;
}
public void enterEscapeMode(){
movementMode=2;
oppositeDirection=true;
}
protected char reverseDirection(){
oppositeDirection=false;
switch (direction) {
case 'N': return 'S';
case 'S': return 'N';
case 'E': return 'W';
case 'W': return 'E';
}
return direction;
}
//To not reverse direction unless absolutely necessary, add the reverse of the current direction to the end of list
//Note: For some reason removing the direction using .remove with the character as a parameter
//raises an indexoutofbounds error so I had to manually locate index and then remove and add
protected ArrayList<Character> addReverseToLast(ArrayList<Character> directions){
int indexToRemove=0;
for(int i=0;i<directions.size();i++){
if(directions.get(i).equals(reverseDirection())) indexToRemove=i;
}
directions.add(directions.remove(indexToRemove));
return directions;
}
private Shape createTranslatedShape(Shape s,int xShift,int yShift){
AffineTransform newTransformation=AffineTransform.getTranslateInstance(xShift, yShift);
return newTransformation.createTransformedShape(s);
}
private boolean intersects(Shape movable, Shape still){
boolean intersects=false;
if(still!=null && still.getBounds2D().intersects(movable.getBounds2D())){
intersects=true;
}
return intersects;
}
private boolean moveSafe(Shape tempBoundary){ //TODO the safe move function doesn't check if movement shifts ghost out of the pane if no walls surround the game area
for(Shape[] line:maze){
for(Shape wall:line){
if(intersects(tempBoundary,wall)) return false;
}
}
return true;
}
//Ghost is eaten so is sent back to starting position
public void ghostEaten(){
boundary=new Rectangle2D.Double(defaultX-SIZE/2,defaultY-SIZE/2,SIZE,SIZE);
xPos=defaultX;
yPos=defaultY;
movementMode=0;
secondsCounter=0;
moving=false;
}
public void teleport(int newX,int newY){
boundary=new Rectangle2D.Double(newX-SIZE/2,newY-SIZE/2,SIZE,SIZE);
xPos=newX;
yPos=newY;
moving=false;
}
public void setDirection(char dir){
directionManuallySet=true;
direction=dir;
}
public int getX(){
return xPos;
}
public int getY(){
return yPos;
}
}