001 package com.croftsoft.apps.mars.model.seri; 002 003 import java.awt.*; 004 import java.io.*; 005 import java.util.*; 006 007 import com.croftsoft.core.lang.NullArgumentException; 008 import com.croftsoft.core.math.geom.Point2DD; 009 import com.croftsoft.core.math.geom.PointXY; 010 import com.croftsoft.core.math.geom.ShapeLib; 011 import com.croftsoft.core.util.ArrayKeeper; 012 import com.croftsoft.core.util.ArrayLib; 013 import com.croftsoft.core.util.StableArrayKeeper; 014 015 import com.croftsoft.apps.mars.ai.DefaultTankOperator; 016 import com.croftsoft.apps.mars.ai.TankOperator; 017 018 import com.croftsoft.apps.mars.model.AmmoDump; 019 import com.croftsoft.apps.mars.model.AmmoDumpAccessor; 020 import com.croftsoft.apps.mars.model.Bullet; 021 import com.croftsoft.apps.mars.model.Damageable; 022 import com.croftsoft.apps.mars.model.Game; 023 import com.croftsoft.apps.mars.model.Impassable; 024 import com.croftsoft.apps.mars.model.Model; 025 import com.croftsoft.apps.mars.model.ModelAccessor; 026 import com.croftsoft.apps.mars.model.Obstacle; 027 import com.croftsoft.apps.mars.model.Tank; 028 import com.croftsoft.apps.mars.model.TankAccessor; 029 import com.croftsoft.apps.mars.model.World; 030 031 /********************************************************************* 032 * A World implementation. 033 * 034 * @version 035 * 2003-05-11 036 * @since 037 * 2003-04-03 038 * @author 039 * <a href="https://www.croftsoft.com/">David Wallace Croft</a> 040 *********************************************************************/ 041 042 public final class SeriWorld 043 implements World, Serializable 044 ////////////////////////////////////////////////////////////////////// 045 ////////////////////////////////////////////////////////////////////// 046 { 047 048 private static final long serialVersionUID = 0L; 049 050 // 051 052 private final Random random; 053 054 private final SeriAmmoDump.Shared seriAmmoDumpShared; 055 056 private final ArrayKeeper modelArrayKeeper; 057 058 private final Point2DD center; 059 060 private final java.util.List modelList; 061 062 ////////////////////////////////////////////////////////////////////// 063 ////////////////////////////////////////////////////////////////////// 064 065 public SeriWorld ( 066 Random random, 067 SeriAmmoDump.Shared seriAmmoDumpShared ) 068 ////////////////////////////////////////////////////////////////////// 069 { 070 modelArrayKeeper = new StableArrayKeeper ( new Model [ 0 ] ); 071 072 center = new Point2DD ( ); 073 074 NullArgumentException.check ( this.random = random ); 075 076 NullArgumentException.check ( 077 this.seriAmmoDumpShared = seriAmmoDumpShared ); 078 079 modelList = new ArrayList ( ); 080 } 081 082 ////////////////////////////////////////////////////////////////////// 083 ////////////////////////////////////////////////////////////////////// 084 085 public void clear ( ) 086 ////////////////////////////////////////////////////////////////////// 087 { 088 modelArrayKeeper.setArray ( new Model [ 0 ] ); 089 } 090 091 public AmmoDump createAmmoDump ( 092 double centerX, 093 double centerY ) 094 ////////////////////////////////////////////////////////////////////// 095 { 096 SeriAmmoDump seriAmmoDump = new SeriAmmoDump ( 097 this, 098 centerX, 099 centerY, 100 seriAmmoDumpShared.ammoMax, 101 seriAmmoDumpShared ); 102 103 modelArrayKeeper.insert ( seriAmmoDump ); 104 105 return seriAmmoDump; 106 } 107 108 public Bullet createBullet ( 109 double originX, 110 double originY, 111 double heading ) 112 ////////////////////////////////////////////////////////////////////// 113 { 114 SeriBullet seriBullet 115 = new SeriBullet ( this, originX, originY, heading ); 116 117 modelArrayKeeper.insert ( seriBullet ); 118 119 return seriBullet; 120 } 121 122 public Obstacle createObstacle ( 123 double centerX, 124 double centerY, 125 double radius, 126 double radiusMin, 127 Rectangle driftBounds ) 128 ////////////////////////////////////////////////////////////////////// 129 { 130 SeriObstacle seriObstacle = new SeriObstacle ( 131 this, centerX, centerY, radius, radiusMin, random, driftBounds ); 132 133 modelArrayKeeper.insert ( seriObstacle ); 134 135 return seriObstacle; 136 } 137 138 public Tank createTank ( 139 double centerX, 140 double centerY, 141 Color color ) 142 ////////////////////////////////////////////////////////////////////// 143 { 144 SeriTank seriTank = new SeriTank ( this, centerX, centerY, color ); 145 146 TankOperator tankOperator = new DefaultTankOperator ( random ); 147 148 seriTank.setTankOperator ( tankOperator ); 149 150 tankOperator.setTankConsole ( seriTank ); 151 152 modelArrayKeeper.insert ( seriTank ); 153 154 return seriTank; 155 } 156 157 public void remove ( Model model ) 158 ////////////////////////////////////////////////////////////////////// 159 { 160 modelArrayKeeper.remove ( model ); 161 } 162 163 ////////////////////////////////////////////////////////////////////// 164 ////////////////////////////////////////////////////////////////////// 165 166 public AmmoDump [ ] getAmmoDumps ( 167 PointXY pointXY, 168 AmmoDump [ ] ammoDumps ) 169 ////////////////////////////////////////////////////////////////////// 170 { 171 return ( AmmoDump [ ] ) getModels ( 172 pointXY, 173 ammoDumps, 174 AmmoDump.class ); 175 } 176 177 public Damageable [ ] getDamageables ( 178 Shape shape, 179 Damageable [ ] damageables ) 180 ////////////////////////////////////////////////////////////////////// 181 { 182 return ( Damageable [ ] ) getModels ( 183 shape, 184 damageables, 185 Damageable.class ); 186 } 187 188 public Impassable [ ] getImpassables ( ) 189 ////////////////////////////////////////////////////////////////////// 190 { 191 return ( Impassable [ ] ) 192 modelArrayKeeper.getArray ( Impassable.class ); 193 } 194 195 public Iterator getImpassables ( 196 Shape shape, 197 Model model ) 198 ////////////////////////////////////////////////////////////////////// 199 { 200 modelList.clear ( ); 201 202 Impassable [ ] impassables = getImpassables ( ); 203 204 for ( int i = 0; i < impassables.length; i++ ) 205 { 206 Impassable impassable = impassables [ i ]; 207 208 if ( ( impassable != model ) 209 && impassable.isActive ( ) 210 && ShapeLib.intersects ( shape, impassable.getShape ( ) ) ) 211 { 212 modelList.add ( impassable ); 213 } 214 } 215 216 return modelList.iterator ( ); 217 } 218 219 220 public Model [ ] getModels ( ) 221 ////////////////////////////////////////////////////////////////////// 222 { 223 return ( Model [ ] ) modelArrayKeeper.getArray ( ); 224 } 225 226 public ModelAccessor [ ] getModelAccessors ( 227 ModelAccessor [ ] modelAccessors ) 228 ////////////////////////////////////////////////////////////////////// 229 { 230 return getModelAccessors ( ( Shape ) null, modelAccessors ); 231 } 232 233 public ModelAccessor [ ] getModelAccessors ( 234 Shape shape, 235 ModelAccessor [ ] modelAccessors ) 236 ////////////////////////////////////////////////////////////////////// 237 { 238 Model [ ] allModels = getModels ( ); 239 240 if ( shape == null ) 241 { 242 return allModels; 243 } 244 245 NullArgumentException.check ( modelAccessors ); 246 247 int index = 0; 248 249 for ( int i = 0; i < allModels.length; i++ ) 250 { 251 Model model = allModels [ i ]; 252 253 if ( ShapeLib.intersects ( shape, model.getShape ( ) ) ) 254 { 255 if ( index < modelAccessors.length ) 256 { 257 modelAccessors [ index ] = model; 258 } 259 else 260 { 261 modelAccessors = ( ModelAccessor [ ] ) 262 ArrayLib.append ( modelAccessors, model ); 263 } 264 265 index++; 266 } 267 } 268 269 if ( index < modelAccessors.length ) 270 { 271 modelAccessors [ index ] = null; 272 } 273 274 return modelAccessors; 275 } 276 277 public Obstacle [ ] getObstacles ( ) 278 ////////////////////////////////////////////////////////////////////// 279 { 280 return ( Obstacle [ ] ) 281 modelArrayKeeper.getArray ( Obstacle.class ); 282 } 283 284 public Tank [ ] getTanks ( ) 285 ////////////////////////////////////////////////////////////////////// 286 { 287 return ( Tank [ ] ) modelArrayKeeper.getArray ( Tank.class ); 288 } 289 290 ////////////////////////////////////////////////////////////////////// 291 ////////////////////////////////////////////////////////////////////// 292 293 public void prepare ( ) 294 ////////////////////////////////////////////////////////////////////// 295 { 296 Model [ ] models = getModels ( ); 297 298 for ( int i = 0; i < models.length; i++ ) 299 { 300 models [ i ].prepare ( ); 301 } 302 } 303 304 public void update ( double timeDelta ) 305 ////////////////////////////////////////////////////////////////////// 306 { 307 Model [ ] models = getModels ( ); 308 309 for ( int i = 0; i < models.length; i++ ) 310 { 311 models [ i ].update ( timeDelta ); 312 } 313 } 314 315 ////////////////////////////////////////////////////////////////////// 316 ////////////////////////////////////////////////////////////////////// 317 318 public void fireBullet ( 319 double originX, 320 double originY, 321 double heading ) 322 ////////////////////////////////////////////////////////////////////// 323 { 324 boolean bulletFired = false; 325 326 Bullet [ ] bullets = ( Bullet [ ] ) 327 modelArrayKeeper.getArray ( Bullet.class ); 328 329 for ( int i = 0; i < bullets.length; i++ ) 330 { 331 Bullet bullet = bullets [ i ]; 332 333 if ( !bullet.isActive ( ) 334 && !bullet.isUpdated ( ) ) 335 { 336 bullet.fire ( originX, originY, heading ); 337 338 bulletFired = true; 339 340 break; 341 } 342 } 343 344 if ( !bulletFired ) 345 { 346 createBullet ( originX, originY, heading ); 347 } 348 } 349 350 public boolean isBlockedByObstacle ( Shape shape ) 351 ////////////////////////////////////////////////////////////////////// 352 { 353 Obstacle [ ] obstacles = getObstacles ( ); 354 355 for ( int i = 0; i < obstacles.length; i++ ) 356 { 357 Obstacle obstacle = obstacles [ i ]; 358 359 if ( obstacle.isActive ( ) 360 && ShapeLib.intersects ( shape, obstacle.getShape ( ) ) ) 361 { 362 return true; 363 } 364 } 365 366 return false; 367 } 368 369 public boolean isBlocked ( 370 Shape shape, 371 Model model ) 372 ////////////////////////////////////////////////////////////////////// 373 { 374 Impassable [ ] impassables = getImpassables ( ); 375 376 for ( int i = 0; i < impassables.length; i++ ) 377 { 378 Impassable impassable = impassables [ i ]; 379 380 if ( ( impassable != model ) 381 && impassable.isActive ( ) 382 && ShapeLib.intersects ( shape, impassable.getShape ( ) ) ) 383 { 384 return true; 385 } 386 } 387 388 return false; 389 } 390 391 public boolean isBlocked ( Model model ) 392 ////////////////////////////////////////////////////////////////////// 393 { 394 return isBlocked ( model.getShape ( ), model ); 395 } 396 397 public PointXY getClosestAmmoDumpCenter ( PointXY pointXY ) 398 ////////////////////////////////////////////////////////////////////// 399 { 400 AmmoDumpAccessor ammoDumpAccessor = ( AmmoDumpAccessor ) 401 getModelClosest ( pointXY, AmmoDumpAccessor.class, null ); 402 403 if ( ammoDumpAccessor != null ) 404 { 405 return 406 ShapeLib.getCenter ( ammoDumpAccessor.getShape ( ), center ); 407 } 408 409 return null; 410 } 411 412 public PointXY getClosestEnemyTankCenter ( 413 PointXY pointXY, 414 Color friendColor ) 415 ////////////////////////////////////////////////////////////////////// 416 { 417 double closestDistance = Double.POSITIVE_INFINITY; 418 419 int index = -1; 420 421 TankAccessor [ ] tankAccessors = ( TankAccessor [ ] ) 422 modelArrayKeeper.getArray ( TankAccessor.class ); 423 424 for ( int i = 0; i < tankAccessors.length; i++ ) 425 { 426 TankAccessor tankAccessor = tankAccessors [ i ]; 427 428 if ( tankAccessor.isActive ( ) 429 && !tankAccessor.getColor ( ).equals ( friendColor ) ) 430 { 431 double distance = pointXY.distanceXY ( 432 ShapeLib.getCenter ( tankAccessor.getShape ( ), center ) ); 433 434 435 if ( distance < closestDistance ) 436 { 437 closestDistance = distance; 438 439 index = i; 440 } 441 } 442 } 443 444 if ( index > -1 ) 445 { 446 return ShapeLib.getCenter ( 447 tankAccessors [ index ].getShape ( ), center ); 448 } 449 450 return null; 451 } 452 453 public Model getModel ( 454 PointXY pointXY, 455 Class [ ] classes, 456 Model model ) 457 ////////////////////////////////////////////////////////////////////// 458 { 459 double x = pointXY.getX ( ); 460 461 double y = pointXY.getY ( ); 462 463 Model [ ] models = getModels ( ); 464 465 for ( int i = 0; i < models.length; i++ ) 466 { 467 Model otherModel = models [ i ]; 468 469 if ( ( otherModel != model ) 470 && otherModel.isActive ( ) 471 && otherModel.getShape ( ).contains ( x, y ) ) 472 { 473 for ( int j = 0; j < classes.length; j++ ) 474 { 475 if ( classes [ j ].isInstance ( otherModel ) ) 476 { 477 return otherModel; 478 } 479 } 480 } 481 } 482 483 return null; 484 } 485 486 ////////////////////////////////////////////////////////////////////// 487 ////////////////////////////////////////////////////////////////////// 488 489 private Model [ ] getModels ( Class c ) 490 ////////////////////////////////////////////////////////////////////// 491 { 492 if ( c == null ) 493 { 494 return ( Model [ ] ) modelArrayKeeper.getArray ( ); 495 } 496 497 return ( Model [ ] ) modelArrayKeeper.getArray ( c ); 498 } 499 500 private Model [ ] getModels ( 501 PointXY pointXY, 502 Model [ ] models, 503 Class c ) 504 ////////////////////////////////////////////////////////////////////// 505 { 506 Model [ ] allModels = getModels ( c ); 507 508 if ( pointXY == null ) 509 { 510 return allModels; 511 } 512 513 NullArgumentException.check ( models ); 514 515 double x = pointXY.getX ( ); 516 517 double y = pointXY.getY ( ); 518 519 int index = 0; 520 521 for ( int i = 0; i < allModels.length; i++ ) 522 { 523 Model model = allModels [ i ]; 524 525 if ( model.isActive ( ) 526 && model.getShape ( ).contains ( x, y ) ) 527 { 528 if ( index < models.length ) 529 { 530 models [ index ] = model; 531 } 532 else 533 { 534 models = ( Model [ ] ) ArrayLib.append ( models, model ); 535 } 536 537 index++; 538 } 539 } 540 541 if ( index < models.length ) 542 { 543 models [ index ] = null; 544 } 545 546 return models; 547 } 548 549 private Model [ ] getModels ( 550 Shape shape, 551 Model [ ] models, 552 Class c ) 553 ////////////////////////////////////////////////////////////////////// 554 { 555 Model [ ] allModels = getModels ( c ); 556 557 if ( shape == null ) 558 { 559 return allModels; 560 } 561 562 NullArgumentException.check ( models ); 563 564 int index = 0; 565 566 for ( int i = 0; i < allModels.length; i++ ) 567 { 568 Model model = allModels [ i ]; 569 570 if ( model.isActive ( ) 571 && ShapeLib.intersects ( shape, model.getShape ( ) ) ) 572 { 573 if ( index < models.length ) 574 { 575 models [ index ] = model; 576 } 577 else 578 { 579 models = ( Model [ ] ) ArrayLib.append ( models, model ); 580 } 581 582 index++; 583 } 584 } 585 586 if ( index < models.length ) 587 { 588 models [ index ] = null; 589 } 590 591 return models; 592 } 593 594 private Damageable [ ] getDamageables ( ) 595 ////////////////////////////////////////////////////////////////////// 596 { 597 return ( Damageable [ ] ) 598 modelArrayKeeper.getArray ( Damageable.class ); 599 } 600 601 private Model getModelClosest ( 602 PointXY pointXY, 603 Class c, 604 Model model ) 605 ////////////////////////////////////////////////////////////////////// 606 { 607 int index = -1; 608 609 double closestDistance = Double.POSITIVE_INFINITY; 610 611 Model [ ] models = ( Model [ ] ) modelArrayKeeper.getArray ( ); 612 613 for ( int i = 0; i < models.length; i++ ) 614 { 615 Model otherModel = models [ i ]; 616 617 if ( ( otherModel != model ) 618 && otherModel.isActive ( ) 619 && c.isInstance ( otherModel ) ) 620 { 621 double distance = ShapeLib.getCenter ( 622 otherModel.getShape ( ), center ).distanceXY ( pointXY ); 623 624 if ( distance < closestDistance ) 625 { 626 closestDistance = distance; 627 628 index = i; 629 } 630 } 631 } 632 633 if ( index > -1 ) 634 { 635 return models [ index ]; 636 } 637 638 return null; 639 } 640 641 ////////////////////////////////////////////////////////////////////// 642 ////////////////////////////////////////////////////////////////////// 643 }