// compute velocity & position (cube included) and draw dot (exploded or not) void Cube::animate(Cube* cubes, const float dts) { static const float deadzone = 2.0f; static const float accelScale = 0.6f; static const float damping = 0.995f; if (lifeCounter <= 0) return; for (uint8_t d=0; d<dot_n; d++) { // if dot neither hidden nor exploded, animate it: if (not (vid.sprites[d].isHidden() || dots[d].exp)) { Float2 accel = id.accel().xy(); if (accel.len2() > deadzone * deadzone) dots[d].vel += accel * accelScale; dots[d].vel *= damping; Float2 step = dots[d].vel * dts; Float2 candidate = dots[d].pos + step; // Does this dot want to leave the cube ? Side mySide = (candidate.y < minPos.y) ? TOP : // 0 (candidate.x < minPos.x) ? LEFT : // 1 (candidate.y > maxPos.y) ? BOTTOM : // 2 (candidate.x > maxPos.x) ? RIGHT : // 3 NO_SIDE; // -1 bool stayHere = true; // default CubeID hisID; // neighbor CubeID Side hisSide = NO_SIDE; // his side number that touches mySide if (mySide != NO_SIDE) { // avoids cubeAt(NO_SIDE) error Neighborhood myNbh(id); hisID = myNbh.cubeAt(mySide); if (hisID.isDefined()) { // ...same with sideOf(NO_SIDE) Neighborhood hisNbh(hisID); hisSide = hisNbh.sideOf(id); stayHere = cubes[hisID].isFull(); } } if (stayHere) { // will this dot stay? if (mySide==TOP || mySide==BOTTOM) // bounce vertically? dots[d].vel.y = -dots[d].vel.y; if (mySide==LEFT || mySide==RIGHT) // ...horizontally? dots[d].vel.x = -dots[d].vel.x; dots[d].pos += dots[d].vel * dts; // finish calculation vid.sprites[d].setImage(DotIMG); // draw the dot vid.sprites[d].move(dots[d].pos); } else { // move to neighbor dots[d].pos += step; // finish calculation moveDot(d, cubes[hisID], mySide, hisSide); } } } collisionCheck(); displayDamages(); }
RGB565 calculateMandelbrot(UInt2 pixel) { /* * Calculate one pixel of a Mandelbrot fractal, * using continuous shading based on a renormalizing technique. * * Reference: http://linas.org/art-gallery/escape/escape.html */ const float radius2 = 400.f; const unsigned maxIters = 12; const float scale = 0.022f; const Int2 center = LCD_center + vec(25, 0); // We use Float2 vectors to store complex numbers Float2 z = vec(0, 0); Float2 c = (pixel - center) * scale; unsigned iters = 0; float modulus2; // Traditional Mandelbrot iteration do { z = z.cmul(z) + c; modulus2 = z.len2(); } while (++iters <= maxIters && modulus2 <= radius2); // A couple extra iterations z = z.cmul(z) + c; z = z.cmul(z) + c; iters += 2; // Continuous shading, taking into account the iteration number as well // as how far outside the escape radius we are. float mu = (iters - log(log(z.len())) / M_LN2) / maxIters; if (mu < 1.0f) { // Exterior of fractal return calculateColorPalette(mu); } else { // Interior (didn't escape within our limit, or NaN) return RGB565::fromRGB(0x000000); } }
// check distance between dots and mark them as exploded if too close void Cube::collisionCheck() { for (uint8_t i=0; i<dot_n; i++) if (not vid.sprites[i].isHidden() && !dots[i].exp) for (uint8_t j=i+1; j<dot_n; j++) if (not vid.sprites[j].isHidden() && !dots[i].exp) { Float2 dif = dots[i].pos - dots[j].pos; // are the dots too close ? if (dif.len2() < SPR_size.len2()/4) { dots[i].pos -= dif/2; // bring dots closer dots[j].pos += dif/2; // to each other dots[i].exp = exploDuration; dots[j].exp = exploDuration; #if ACCURATE == 1 // use a binary map to check if we hit or miss Conan: dots[i].bnd = isHit(dots[i].pos); dots[j].bnd = isHit(dots[j].pos); #else // ...or use a FlatAssetImage but it's less accurate: Float2 o = SPR_size/2; // offset to sprite center uint16_t linPosI = uint16_t( (dots[i].pos.x+o.x)/8 ) + uint16_t( (dots[i].pos.y+o.y)/8 ) * ConanIMG.tileWidth() ; uint16_t linPosJ = uint16_t( (dots[j].pos.x+o.x)/8 ) + uint16_t( (dots[j].pos.y+o.y)/8 ) * ConanIMG.tileWidth() ; // D'oh! need band aid ? dots[i].bnd = (ConanIMG.tile(linPosI) != whiteTile); dots[j].bnd = (ConanIMG.tile(linPosJ) != whiteTile && linPosJ != linPosI); #endif // D'oh! need band aid ? if (dots[i].bnd) lifeCounter -= 5; if (dots[j].bnd) lifeCounter -= 5; } } if (lifeCounter <= 0) win(); }