/* Chompers eat hearts, and are destroyed by bombs. */ class Chomper implements Entity { static final float killRadiusBase = 5, killRadiusPerSize = 6.25, smellRadiusBase = 5, smellRadiusPerSize = 2.5; final static int defaultInitialSize = 4; int size, prevSize; final static int smallestSize = 2; final static int growAnimationLength = 75, growAnimationHalfPeriod = 5; int growAnimationT = -growAnimationLength; int walkAnimationBaseT = 0; float y; int minX, maxX; float x; boolean flipped; boolean dead; Chomper(int minX, int maxX, float y, int size) { this.minX = minX; this.maxX = maxX; this.y = y; this.size = size; this.dead = false; } Chomper(int minX, int maxX, float y) { this(minX, maxX, y, defaultInitialSize); } void doPhysics0() { float bestDistSq = 0; int besthi = -1, bestti = -1; for (int hi = 0; hi < theHearts.size(); ++hi) { Heart h = (Heart)theHearts.get(hi); for (int ti = 0; ti < Heart.trailLength; ti++) { boolean nearEnd = false; for (int ri = -1; ri <= 1; ri++) { if (!h.trailOn[(ti+ri+Heart.trailLength)%Heart.trailLength] && ti == (t/Heart.framesPerTrailPoint + ri + Heart.trailLength) % Heart.trailLength) { nearEnd = true; } } //if (nearEnd) // continue; float dsq = distsq(h.trailX[ti],h.trailY[ti],x,y); if (besthi == -1 || dsq < bestDistSq) { bestDistSq = dsq; besthi = hi; bestti = ti; } } } //if (besthi != -1) //println("besthi = " + besthi + " dsq = " + bestDistSq); float smellRadius = size * smellRadiusPerSize + smellRadiusBase; if (besthi != -1 && bestDistSq < sq(smellRadius)) { Heart h = (Heart)theHearts.get(besthi); float dx = h.trailX[(bestti+1)%Heart.trailLength]-h.trailX[bestti]; float dy = h.trailY[(bestti+1)%Heart.trailLength]-h.trailY[bestti]; /*if (bestDistSq > sq(size * smellRadius * .5)) { dx = h.trailX[(bestti+1)%Heart.trailLength]-x; dy = h.trailY[(bestti+1)%Heart.trailLength]-y; }*/ if (dx < 0 && !flipped) flipped = true; float ilen = 1.0/sqrt(dx*dx+dy*dy); x += 3*dx*ilen; y += 3*dy*ilen; } int tt = t % ((maxX - minX) * 2); flipped = tt >= maxX - minX; x = flipped ? 2 * maxX - minX - tt : minX + tt; // Detect hearts and bombs. for (int i = 0; i < theHearts.size(); ++ i) { Heart h = (Heart)theHearts.get(i); if (!h.dead && dist(h.x, h.y, x, y) < size * killRadiusPerSize + killRadiusBase) { playSound(monsterhit); h.die(); startGrowAnimation(size); ++ size; } } for (int i = 0; i < theBombs.size(); ++ i) { Bomb h = (Bomb)theBombs.get(i); if (dist(h.x, h.y, x, y) < size * killRadiusPerSize + killRadiusBase) { h.explode(); if (size == smallestSize) die(); else { startGrowAnimation(size); size = max(size / 2, smallestSize); } } } } void startGrowAnimation(int prevSize) { this.prevSize = prevSize; growAnimationT = t; walkAnimationBaseT = t + growAnimationLength; } void die() { theEntities.remove(this); dead = true; } void doPhysics1() { } void draw() { int drawSize, walkAnimationT; if (t <= growAnimationT + growAnimationLength) { drawSize = ((t - growAnimationT) / growAnimationHalfPeriod) % 2 == 1 ? size : prevSize; walkAnimationT = 0; } else { drawSize = size; walkAnimationT = t - walkAnimationBaseT; } walkAnimationT = t; chomperAnimation.display(x - chomperAnimation.w * drawSize / 2, y - chomperAnimation.h * drawSize / 2, walkAnimationT, true, drawSize, flipped); } void addToLevel() { theEntities.add(this); } void levelStart() { minX += leftBorder; maxX += leftBorder; } }