This repository has been archived by the owner on Oct 15, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathShip.js
308 lines (292 loc) · 14.6 KB
/
Ship.js
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
function Ship(x, y, length){
//interne Konstante
//besagt, dass ein Schiff nach oben gerichtet ist
const UP = 99;
//besagt, dass ein Schiff nach rechts greichtet ist
const RIGHT = 98;
//speichert die Position in "Pixel" als Vector
this.position = createVector(x, y);
//zeigt die momentane Rotation an
this.rotation = UP;
//speichert das momentan mittlere Feld, falls vorhanden
this.momentField = null;
//speichert die Indizes der überdeckten Felder und ob diese bereits beschossen wurden
// x = row des Feldes, y = col des Feldes, z = {0, 1} 0 = nicht, 1 = beschossen
//zudem indikator dafür ob das Spiel angefangen hat oder nicht, da am Anfang des Spieles
//die Felder jedes Schiffes in der Var gespeichert werden
this.coverdFields = null;
//idikator ob das schiff zerstört wurde oder nicht
this.destroyed = false;
//indikator ob das Schiff grade von der mouse bewegt wird oder nicht
this.dragging = false;
//zum initialisieren der Größe des Schiffes
this.setup = function(){
//die gleiche Größe wie ein Rechteck - 1/6 auf jeder Seite
this.wid = SIZE-SIZE/3;
this.heig = length*SIZE-SIZE/3;
}
//zum darstellen der Schiffes
this.show = function(){
rectMode(CENTER);
if(this.destroyed){
fill(235, 80, 0);
}else{
fill(255);
}
rect(this.position.x, this.position.y, this.wid, this.heig);
}
//rotiert das Schiff um seine eigene Achse
this.rotate = function(game){
if(this.coverdFields == null){
//wechselt die Höhe und die Breite
var temp = this.wid;
this.wid = this.heig;
this.heig = temp;
//wechselt die Rotation
this.rotation = (this.rotation == UP) ? RIGHT : UP;
//setzt das Schiff auf die neue richtige Position
if(this.momentField != null){
var posPix = game.centerPoints[this.momentField.x][this.momentField.y];
this.setShipInsideField(posPix.x, posPix.y, game);
}
}
}
//verbindet alle oberen setPosition methoden zu einer der man pixel(mouse)Koordinaten
//übergeben kann und das Schiff damit bewegen kann, sodass es auf dem übergebenen Feld
//einrastet, aber überall sonst nicht
this.setPositionInPixel = function(xPix, yPix, game){
//prüft ob das Spiel angefangen hat oder nicht
// -> wenn ja dann müssen die überdeckten Felder gespeichert sein
if(this.coverdFields == null){
//wenn des Schiff über dem Feld ist soll es einrasten
if(!this.setShipInsideField(xPix, yPix, game)){
//wenn nicht setzt das Schiff auf die übergebenen koordinaten ohne was zu ändern
this.setPositionOutOfField(xPix, yPix);
}
}
}
//setzt das Schiff inherhalb des Feldes ab sodass es nicht "übersteht"
this.setShipInsideField = function(xPix, yPix, game){
//convertiert die PixelPos in FelderIndizes
//falls xPix und yPix außerhalb des feldes wird abgebrochen und false returnt
this.momentField = game.convertPixPosInFieldIndex(xPix, yPix);
var pos = this.momentField;
//sollte diese indizes null sein wird abgebrochen
//zb wenn der mittelpunkt des schiffes außerhalb ist wird das Schiff nicht
//auf das Feld gerückt
if(pos != null && this.setCoverdFields(pos.x, pos.y)){
//falls etwas übersteht wird es hier gefunden
var lowestX = 0;
var lowestY = 0;
var maxX = game.centerPoints.length-1;
var maxY = game.centerPoints[maxX].length-1;
for(var coverdField of this.coverdFields){
//entweder steht es "unten" oder "oben" raus aber nicht beides
if(coverdField.x < lowestX){
lowestX = coverdField.x;
}else if(coverdField.x > maxX){
maxX = coverdField.x;
}
if(coverdField.y < lowestY){
lowestY = coverdField.y;
}else if(coverdField.y > maxY){
maxY = coverdField.y;
}
}
/**detailierte Beschreibung**
* wenn es links übersteht (negativer Übertrag) soll overflow der Betrag sein,
* damit man diesen nachher auf die Position addieren kann und der Mittelpunkt
* um besagten übertrag nach rechts verschoben wird.
*
* wenn es rechts übersteht (zu großer positvier Übertrag) soll um den Übertrag
* der Mittelpunkt nach links verschoben werden. Das passiert indem man die
* maximal größe von dem zu großen wert abzieht. Der übertrag wird negiert, damit
* man nacher auch einfach addieren kann um den Mittelpunkt nach rechts,
* und nicht nach links(ohne negierung) zu verschieben.
*
* ist kein Übertrag vorhanden wird Overflow mit 0 initalisiert
**/
var overflowX = (lowestX < 0) ? Math.abs(lowestX) :
(maxX > game.centerPoints.length-1) ? -(maxX - (game.centerPoints.length-1)) : 0;
var overflowY = (lowestY < 0) ? Math.abs(lowestY) :
(maxY > game.centerPoints[0].length-1) ? -(maxY - (game.centerPoints[0].length-1)) : 0;
this.coverdFields = null;
//das Schiff wird auf die Position + übertrag gestellt
return this.setAtField(parseInt(pos.x) + overflowX, parseInt(pos.y) + overflowY, game);
}else{
//print("FEHLER!!!");
return false;
}
}
//setzt das Schiff je nach Größe auf das richtige Feld
this.setAtField = function(x, y, game){
//checkt ob das Feld x,y existiert, bricht ab falls nicht
if(0 <= x && x < game.centerPoints.length && 0 <= y && y < game.centerPoints[x].length){
this.momentField = createVector(x, y);
//check ob das Schiff eine grade Länge hat
if(length%2 != 0){
//wenn nicht kann der Mittelpunkt als Position genommen werden
this.position = game.centerPoints[x][y].copy();
}else{
//wenn doch muss die Rotation mit bedacht werden
var dir = (this.rotation == UP) ? createVector(0,1) : createVector(1,0);
var center = game.centerPoints[x][y].copy();
//wenn es nach Oben zeigt muss es nach "unten" korrigiert
//werden sonst nach "Links" korrigiert werden
this.position = center.add(createVector((SIZE/2)*dir.x, (SIZE/2)*dir.y, 0));
}
return true;
}
return false;
}
//setzt das schiff auf die übergebene Position ohne irgendetwas zu prüfen
this.setPositionOutOfField = function(xPix, yPix){
this.position = createVector(xPix, yPix);
}
//prüft ob das Schiff an einer akzeptierten Position steht
//überdecken sowie direktes nebeneinander stehen von Schiffen ist nicht erlaubt
this.checkValidPosition = function(ships){
//prüft ob das Schiff selbst überhaupt auf dem Feld plaziert ist
if(this.setCoverdFields()){
//durchläuft jede schiffe
for(var ship of ships){
//ignoriert sich selbst und die bei denen die Position noch nicht
//bestimmt worden ist
if(ship != this && ship.coverdFields != null){
//durchläuft bei beiden Schiffen (das was geprüft wird und das
//was momentan ausgewählt ist durch die schleife davor) die
//überdeckten Felder
for(var otherField of ship.coverdFields){
for(var thisField of this.coverdFields){
//sollte sich herrausstellen, dass das Schiff nicht richtig
//positioniert worden ist werden die Felder gelöscht und es
//wird false zurück gegeben
if(this.checkShipNextAndOverEachOther(thisField, otherField)){
this.coverdFields = null;
return false;
}
}
}
}
}
return true;
}else{
return false;
}
}
//bekommt 2 Felder Felder Übergeben. Das eine ist ein Feld diese Schiffes (fieldFlex)
//und wir auch benutzt um die Felder um das Schiff herum zu prüfen
//das andere ist vom jeweiligen anderen Schiff(fieldStat) und ändert sich nicht
//die methode Prüft für jedes Feld ob das Feld selbst oder die 4 direkt drumherum
//liegenden, vom festenFeld des anderen Schiffes überdeckt werden
//ist das der Fall wird true zurück gegeben, sonst false
this.checkShipNextAndOverEachOther = function(fieldFlex, fieldStat){
return (fieldFlex.x == fieldStat.x && fieldFlex.y == fieldStat.y) ||
(fieldFlex.x-1 == fieldStat.x && fieldFlex.y == fieldStat.y) ||
(fieldFlex.x == fieldStat.x && fieldFlex.y-1 == fieldStat.y) ||
(fieldFlex.x+1 == fieldStat.x && fieldFlex.y == fieldStat.y) ||
(fieldFlex.x == fieldStat.x && fieldFlex.y+1 == fieldStat.y);
}
//speichert die übereckten Felder des Schiffes in coverdFields
this.setCoverdFields = function(){
if(this.momentField != null){
var index = 0;
this.coverdFields = [];
var start;
var end;
var index = 0;
if(length%2 != 0){
if(this.rotation == UP){
//wenn ungrade länge-1(=grade Zahl) halbieren und auf momentanePos rechnen
start = this.momentField.y - (length-1)/2;
//parseInt da sonst + als "concat" verstanden wird
end = parseInt(this.momentField.y) + (length-1)/2;
//wenn direction nach oben ändere den y wert bei jedem index
while(start+index <= end){
this.coverdFields[index] = createVector(this.momentField.x, start+index, EMPTY);
index++;
}
}else{
//wenn ungrade länge-1(=grade Zahl) halbieren und auf momentanePos rechnen
start = this.momentField.x - (length-1)/2;
//parseInt da sonst + als "concat" verstanden wird
end = parseInt(this.momentField.x) + (length-1)/2;
//wenn direction nach rechts ändere den x wert bei jedem index
while(start+index <= end){
this.coverdFields[index] = createVector(start+index, this.momentField.y, EMPTY);
index++;
}
}
}else{
if(this.rotation == UP){
//wenn grade halbiere die länge und setzte den start "zurück"
//bsp. länge 4 : ■■■■ halb 2 aber momPos ist nicht in der mitte deswegen +1
start = this.momentField.y - (length)/2 + 1;
//parseInt da sonst + als "concat" verstanden wird
end = parseInt(this.momentField.y) + length/2;
//wenn direction nach oben ändere den y wert bei jedem index
while(start+index <= end){
this.coverdFields[index] = createVector(this.momentField.x, start+index, EMPTY);
index++;
}
}else{
//wenn grade halbiere die länge und setzte den start "zurück"
//bsp. länge 4 : ■■■■ halb 2 aber momPos ist nicht in der mitte deswegen +1
start = this.momentField.x - (length)/2 + 1;
//parseInt da sonst + als "concat" verstanden wird
end = parseInt(this.momentField.x) + length/2;
//wenn direction nach rechts ändere den x wert bei jedem index
while(start+index <= end){
this.coverdFields[index] = createVector(start+index, this.momentField.y, EMPTY);
index++;
}
}
}
return true;
}
return false;
}
//errechnet vom Schiffmittelpunkt die äußersten Enden und checkt ob die mouse innerhalb ist
this.checkMouseInside = function(){
return (this.position.x-(this.wid/2) < mouseX && mouseX < this.position.x+(this.wid/2) &&
this.position.y-(this.heig/2) < mouseY && mouseY < this.position.y+(this.heig/2))
}
//prüft ob das Schiff auf dem Feld steht was beschossen wurde
this.checkHit = function(x, y, game){
//check ob das angegebene Feld und gespeicherte Felder exestieren
if(0 <= x && x < game.centerPoints.length &&
0 <= y && y < game.centerPoints[x].length && this.coverdFields != null){
//durchlaufe alle gespeicherten Felder und prüfe auf übereinstimung
for(var index in this.coverdFields){
var coverdField = this.coverdFields[index];
if(coverdField.x == x && coverdField.y == y && coverdField.z == EMPTY){
//wenn ja jetzte den Status des Feldes auf HIT und return true;
//hier wird nicht die hilfsVar benutzt, da der wert sonst nicht richtig
//zugewiesen wird
this.coverdFields[index] = createVector(x, y, HIT);
return true;
}
}
}
return false;
}
//prüft ob das Schiff versenkt wurde
this.checkDown = function(){
//checkt ob die überdeckten Felder gespeichert wurden
if(this.coverdFields != null){
//durchläuft alle überdeckten Felder und prüft die z koordinate welche den Status
//des Feldes enthält. Falls alle getroffen worden sind return true
for(var coverdField of this.coverdFields){
if(coverdField.z != HIT){
//wenn einer nicht getroffen wurde kann man abbrechen
return false;
}
}
//setzt destroyed auf true und returnt dass es zerstört wurde
this.destroyed = true;
return true;
}
//wenn die Felder noch nicht gespeichert wurden (das spiel hat noch nicht angefangen)
return false;
}
}