// SpriteVector Class // SpriteVector.java // Project 3, CIS 525 // Fall 2000 // By Terrence Burrows // Imports import java.awt.*; import java.util.*; /** This class handles all the details of maintaining a list of Sprite objects and the handling of the interactions between them. This class is taken directly from the book "Teach yourself Internet Game Programming with Java in 21 days" by Michael Morrison. See chapter 6 for details. */ public class SpriteVector extends Vector { protected Background background; /** SpriteVector constructor method - sets the background. */ public SpriteVector(Background back) { super(50, 10); background = back; } /** Get the background object. */ public Background getBackground() { return background; } /** Set the background. */ public void setBackground(Background back) { background = back; } /** This method allows Sprites to be placed randomly on the screen without overlapping. */ public Point getEmptyPosition(Dimension sSize) { Rectangle pos = new Rectangle(0, 0, sSize.width, sSize.height); Random rand = new Random(System.currentTimeMillis()); boolean empty = false; int numTries = 0; // Look for an empty position while (!empty && numTries++ < 50) { // Get a random position pos.x = Math.abs(rand.nextInt() % background.getSize().width); pos.y = Math.abs(rand.nextInt() % background.getSize().height); // Iterate through sprites, checking if position is empty boolean collision = false; for (int i = 0; i < size(); i++) { Rectangle testPos = ((Sprite)elementAt(i)).getPosition(); if (pos.intersects(testPos)) { collision = true; break; } } empty = !collision; } return new Point(pos.x, pos.y); } /** Returns a Sprite if the point lies within a Sprite. Searches list of all Sprite objects. */ Sprite isPointInside(Point pt) { // Iterate backward through the sprites, testing each for (int i = (size() - 1); i >= 0; i--) { Sprite s = (Sprite)elementAt(i); if (s.isPointInside(pt)) return s; } return null; } /** Iterate through Sprites, updating each */ public void update() { Sprite s, sHit; Rectangle lastPos; for (int i = 0; i < size(); ) { // Update the sprite s = (Sprite)elementAt(i); lastPos = new Rectangle(s.getPosition().x, s.getPosition().y, s.getPosition().width, s.getPosition().height); BitSet action = s.update(); // Check for the SA_ADDSPRITE action if (action.get(Sprite.SA_ADDSPRITE)) { // Add the sprite Sprite sToAdd = s.addSprite(action); if (sToAdd != null) { int iAdd = add(sToAdd); if (iAdd >= 0 && iAdd <= i) i++; } } // Check for the SA_RESTOREPOS action if (action.get(Sprite.SA_RESTOREPOS)) s.setPosition(lastPos); // Check for the SA_KILL action if (action.get(Sprite.SA_KILL)) { removeElementAt(i); continue; } // Test for collision int iHit = testCollision(s); if (iHit >= 0) if (collision(i, iHit)) s.setPosition(lastPos); i++; } } /** Draw the background and iterate through sprites, drawing each */ public void draw(Graphics g) { background.draw(g); for (int i = 0; i < size(); i++) ((Sprite)elementAt(i)).draw(g); } /** Use a binary search to find the right location to insert the new sprite (based on z-order). */ public int add(Sprite s) { int l = 0, r = size(), i = 0; int z = s.getZOrder(), zTest = z + 1; while (r > l) { i = (l + r) / 2; zTest = ((Sprite)elementAt(i)).getZOrder(); if (z < zTest) r = i; else l = i + 1; if (z == zTest) break; } if (z >= zTest) i++; insertElementAt(s, i); return i; } /** Check for collision with other sprites. */ protected int testCollision(Sprite test) { Sprite s; for (int i = 0; i < size(); i++) { s = (Sprite)elementAt(i); if (s == test) // don't check itself continue; if (test.testCollision(s)) return i; } return -1; } /** Swap velocities (bounce). */ protected boolean collision(int i, int iHit) { Sprite s = (Sprite)elementAt(i); Sprite sHit = (Sprite)elementAt(iHit); Point swap = s.getVelocity(); s.setVelocity(sHit.getVelocity()); sHit.setVelocity(swap); return true; } }