※現在、「wonderfl build flash online」求人コンテンツ制作に関してのアンケートを実施中です!みなさまのお力添えを頂いて、続々とアンケート結果が集まっていますが、まだまだ募集しております。ご協力のほど、どうぞよろしくお願いいたします!

wonderfl運営事務局
→アンケートページ(※ログインしてからお答えいただけるようになっています。)

 notice: Flash editor updated! Join the development! Thanks to MiniBuilder


forked from : ABA's CircleCycle [diff(342)]

FAVORITE BY
:
CircleCycle fork
:
やばいたのしい
FORKED
  1. // forked from ABA's forked from: CircleCycle
  2. // forked from ABA's CircleCycle
  3. // CircleCycle.as
  4. //  Destroy circles and avoid incoming bullets.
  5. //  <Control>
  6. //   Movement: Arrow or [WASD] keys.
  7. //   Fire:    [Z] or [/] key.
  8. //   Slow:    [X] or [.] key.
  9. package
  10. {
  11.     import flash.display.Sprite;
  12.     [SWF(width="465", height="465", backgroundColor="0x000000", frameRate="30")]
  13.     public class CircleCycle extends Sprite
  14.     {
  15.         public function CircleCycle()
  16.         {
  17.             main = this;
  18.             initialize();
  19.         }
  20.     }
  21. }
  22. import flash.display.Sprite;
  23. import flash.display.Bitmap;
  24. import flash.display.BitmapData;
  25. import flash.geom.Rectangle;
  26. import flash.geom.Vector3D;
  27. import flash.text.TextField;
  28. import flash.text.TextFormat;
  29. import flash.text.TextFormatAlign;
  30. import flash.events.Event;
  31. import flash.events.KeyboardEvent;
  32. const SCREEN_WIDTH:int = 465, SCREEN_HEIGHT:int = 465;
  33. const BACKGROUND_BRIGHTNESS:int = 200;
  34. const BACKGROUND_COLOR:int = BACKGROUND_BRIGHTNESS * 0x10000 + BACKGROUND_BRIGHTNESS * 0x100 + BACKGROUND_BRIGHTNESS;
  35. const GAME_OVER_DURATION:int = 150, BLOCK_GAME_START_DURATION:int = 30;
  36. var main:Sprite;
  37. var screen:BitmapData = new BitmapData(SCREEN_WIDTH, SCREEN_HEIGHT, false0);
  38. var scoreField:TextField = new TextField, timeField:TextField = new TextField, messageField:TextField = new TextField;
  39. var gameOverTicks:int, score:int, stage:int, targetCircleCount:int, ticks:int, time:int;
  40. function initialize():void
  41. {
  42.     main.addChild(new Bitmap(screen));
  43.     main.stage.addEventListener(KeyboardEvent.KEY_DOWN, Key.onKeyDown);
  44.     main.stage.addEventListener(KeyboardEvent.KEY_UP,   Key.onKeyUp);
  45.     Field.initialize();
  46.     initializeBlurs();
  47.     scoreField = createTextField(SCREEN_WIDTH - 100010024, 0xff6666, TextFormatAlign.RIGHT);
  48.     timeField = createTextField(SCREEN_WIDTH / 2 - 120, SCREEN_HEIGHT - 4020040, 0xff6666, TextFormatAlign.RIGHT);
  49.     messageField = createTextField(SCREEN_WIDTH - 256025636, 0xff6666);
  50.     main.addChild(scoreField); main.addChild(timeField); main.addChild(messageField);
  51.     startTitle();
  52.     main.addEventListener(Event.ENTER_FRAME, update);
  53. }
  54. function update(event:Event):void
  55. {
  56.     screen.lock();
  57.     screen.fillRect(screen.rect, BACKGROUND_COLOR);
  58.     updateBlurs();
  59.     var i:int;
  60.     for (i = 0; i < sparks.length; i++)  if (!sparks[i].update())  { sparks.splice(i, 1);  i--; }
  61.     for (i = 0; i < shots.length; i++)   if (!shots[i].update())   { shots.splice(i, 1);   i--; }
  62.     for (i = 0; i < bonuses.length; i++) if (!bonuses[i].update()) { bonuses.splice(i, 1); i--; }
  63.     if (targetCircleCount <= 0) goToNextStage();
  64.     if (ticks % 50 == 0) addBackgroundCircles((rand() - 0.5) * Field.size.x * 1.5,
  65.                                               200.0 / (20.0 + stage), 5.0 + rand() * 2.0 + rand() * 2.0);
  66.     ticks++;
  67.     targetCircleCount = 0;
  68.     for each (var c:Circle in circles) c.update();
  69.     for (i = 0; i < circles.length; i++) if (!circles[i].exists)   { circles.splice(i, 1); i--; }
  70.     if (gameOverTicks < 0) Player.update();
  71.     for (i = 0; i < bullets.length; i++) if (!bullets[i].update()) { bullets.splice(i, 1); i--; }
  72.     Field.drawSideBoard();
  73.     screen.unlock();
  74.     if (gameOverTicks < 0)
  75.     {
  76.         time -= 33;
  77.         if (Key.button2) time -= 33;
  78.         if (time <= 0)
  79.         {
  80.             time = 0; startGameClear();
  81.         }
  82.         var msStr:String = String(time % 1000);
  83.         while (msStr.length < 3) msStr = "0" + msStr;
  84.         timeField.text = String(int(time / 1000)) + "\"" + msStr;
  85.     }
  86.     else
  87.     {
  88.         gameOverTicks++;
  89.         if (gameOverTicks == GAME_OVER_DURATION) startTitle();
  90.         if (Key.button1 && gameOverTicks > BLOCK_GAME_START_DURATION) startGame();
  91.     }
  92. }
  93. function goToNextStage():void
  94. {
  95.     if (rand() < 0.5) addTargetCircles((rand() - 0.5) * Field.size.x, 2,
  96.                                        200.0 / (20.0 + stage), 5.0 + rand() * 2.0 + rand() * 2.0false);
  97.     else              addTargetCircles((rand() - 0.5) * Field.size.x * 0.71,
  98.                                        400.0 / (20.0 + stage), 5.0 + rand() * 2.0 + rand() * 2.0true);
  99.     stage += 15;
  100. }
  101. function startTitle():void
  102. {
  103.     clearActors();
  104.     gameOverTicks = GAME_OVER_DURATION;
  105.     messageField.y = SCREEN_HEIGHT / 3 * 2; messageField.text = "CircleCycle";
  106. }
  107. function startGame():void
  108. {
  109.     clearActors();
  110.     Player.start();
  111.     gameOverTicks = -1;
  112.     messageField.text = "";
  113.     score = 0; scoreField.text = "0"; stage = 0; time = 60000;
  114. }
  115. function startGameOver():void
  116. {
  117.     gameOverTicks = 0;
  118.     messageField.y = SCREEN_HEIGHT / 2; messageField.text = "GAME OVER";
  119. }
  120. function startGameClear():void
  121. {
  122.     gameOverTicks = 0;
  123.     messageField.y = SCREEN_HEIGHT / 2; messageField.text = "COMPLETE!";
  124. }
  125. function clearActors():void
  126. {
  127.     shots = null; bullets = null; sparks = null; bonuses = null; circles = null;
  128.     shots = new Vector.<Shot>; bullets = new Vector.<Bullet>; sparks = new Vector.<Spark>; bonuses = new Vector.<Bonus>;
  129.     circles = new Vector.<Circle>; targetCircleCount = 0;
  130. }
  131. // Game actor base class.
  132. class Actor
  133. {
  134.     public var pos:Vector3D = new Vector3D;
  135. }
  136. class VelocityActor extends Actor
  137. {
  138.     public var vel:Vector3D = new Vector3D;
  139.     public var ticks:int, disappearTicks:int = 300;
  140.     public function update():Boolean
  141.     {
  142.         pos.incrementBy(vel);
  143.         ticks++;
  144.         if (!Field.contains(pos) || ticks > disappearTicks) return false;
  145.         return true;
  146.     }
  147. }
  148. // Player.
  149. class Player
  150. {
  151.     private static const COLLISION_SIZE:Number = 5.0;
  152.     private static const SPEED:Number = 9.0;
  153.     public static var pos:Vector3D = new Vector3D;
  154.     private static var fireTicks:int;
  155.     public static function start():void
  156.     {
  157.         pos.x = 0; pos.y = Field.size.y * 0.5;
  158.     }
  159.     public static function update():void
  160.     {
  161.         offset.x = offset.y = 0;
  162.         if (Key.left)  offset.x = -1;
  163.         if (Key.right) offset.x = 1;
  164.         if (Key.up)    offset.y = -1;
  165.         if (Key.down)  offset.y = 1;
  166.         if (offset.x != 0 && offset.y != 0) offset.scaleBy(0.7);
  167.         if (Key.button2) offset.scaleBy(0.5);
  168.         offset.scaleBy(SPEED); pos.incrementBy(offset);
  169.         if (pos.x < -SCREEN_WIDTH  / 2) pos.x = -SCREEN_WIDTH / 2;
  170.         if (pos.x >  SCREEN_WIDTH  / 2) pos.x =  SCREEN_WIDTH / 2;
  171.         if (pos.y < -SCREEN_HEIGHT / 2) pos.y = -SCREEN_HEIGHT / 2;
  172.         if (pos.y >  SCREEN_HEIGHT / 2) pos.y =  SCREEN_HEIGHT / 2;
  173.         Field.offsetX = pos.x * 0.33;
  174.         drawCircle(pos, 157, 0x008800, 0.5);
  175.         addBlur(pos.x, pos.y, 2020100200100);
  176.         if (fireTicks <= 0 && shots.length <= 14 && Key.button1)
  177.         {
  178.             fireTicks = 2;
  179.             var s:Shot;
  180.             for (var i:int = 0; i < 7; i++)
  181.             {
  182.                 s = new Shot;
  183.                 s.pos.x = pos.x; s.pos.y = pos.y;
  184.                 var a:Number = (i - 3) * 0.1;
  185.                 s.vel.x = sin(a) * 24.0; s.vel.y = -cos(a) * 24.0;
  186.                 shots.push(s);
  187.             }
  188.         }
  189.         fireTicks--;
  190.         for each (var b:Bullet in bullets)
  191.         {
  192.             if (Vector3D.distance(pos, b.pos) <= COLLISION_SIZE)
  193.             {
  194.                 addSparks(100, Player.pos.x, Player.pos.y, 30.015.0200100100);
  195.                 startGameOver(); break;
  196.             }
  197.         }
  198.     }
  199. }
  200. // Player's shots.
  201. var shots:Vector.<Shot>;
  202. class Shot extends VelocityActor
  203. {
  204.     override public function update():Boolean
  205.     {
  206.         for each (var c:Circle in circles) if (checkHit(c)) return false;
  207.         addBlur(pos.x, pos.y, 201550150100);
  208.         return super.update();
  209.     }
  210.     private function checkHit(c:Circle):Boolean
  211.     {
  212.         for each (var cc:Circle in c.children) if (cc.exists && checkHit(cc)) return true;
  213.         if (c.exists && c.hasCollision && Vector3D.distance(pos, c.pos) < c.spec.visualRadius + 20.0)
  214.         {
  215.             addSparks(1, pos.x, pos.y, 20.05.050150100);
  216.             c.damage(); return true;
  217.         }
  218.         return false;
  219.     }
  220. }
  221. // Circles' bullets.
  222. var bullets:Vector.<Bullet>;
  223. class Bullet extends VelocityActor
  224. {
  225.     public var baseVel:Vector3D = new Vector3D;
  226.     public var color:int, br:int, bg:int, bb:int, size:int;
  227.     override public function update():Boolean
  228.     {
  229.         var sz:Number = 1.5 + Math.sin(ticks * 0.2) * 0.4;
  230.         var a:Number = 0.8 + Math.sin(ticks * 0.45) * 0.2;
  231.         drawBox(pos.x, pos.y, size, size, color, sz, br * a, bg * a, bb * a);
  232.         if (ticks <= 15)
  233.         {
  234.             vel.x = baseVel.x * (ticks + 15) / 30.0; vel.y = baseVel.y * (ticks + 15) / 30.0;
  235.         }
  236.         else
  237.         {
  238.             vel.x = baseVel.x; vel.y = baseVel.y;
  239.         }
  240.         if (Key.button2) vel.scaleBy(0.5);
  241.         return super.update();
  242.     }
  243. }
  244. // Circles.
  245. var circles:Vector.<Circle>;
  246. class Circle extends Actor
  247. {
  248.     public var children:Vector.<Circle> = null;
  249.     public var isTop:Boolean, exists:Boolean = true;
  250.     public var spec:CircleSpec;
  251.     public var bulletSpeedRatio:Number = 1.0;
  252.     public var rollAngle:Number = 0, fireAngle:Number = 0, fireSpeed:Number, angleInterval:Number;
  253.     public var baseAngle:Number = 0;
  254.     public var ticks:int, shield:int;
  255.     public var hasCollision:Boolean, isTarget:Boolean, isDamaged:Boolean;
  256.     public var xReverse:Number = 1.0;
  257.     public var circleWidth:Number = 5.0;
  258.     public var color:int;
  259.     public function start():void
  260.     {
  261.         color = (int)(spec.r / 2) * 0x10000 + int(spec.g / 2) * 0x100 + int(spec.b / 2);
  262.         shield = spec.shield;
  263.     }
  264.     public function update():void
  265.     {
  266.         var vr:Number = spec.visualRadius;
  267.         if (spec.fireInterval > 0) vr *= ((ticks % spec.fireInterval) / spec.fireInterval * 0.5 + 1.0);
  268.         drawCircle(pos, vr, circleWidth, color);
  269.         var i:int;
  270.         if (isDamaged)
  271.         {
  272.             isDamaged = false;
  273.             var da:Number = ticks * 0.1, sr:Number = spec.visualRadius, bc:int = sr * 0.5;
  274.             for (i = 0; i < bc; i++)
  275.             {
  276.                 addBlur(pos.x + sr * sin(da), pos.y + sr * cos(da),
  277.                         9 + rand() * 79 + rand() * 7, rand() * 128 + 64, rand() * 128 + 12764);
  278.                 da += PI * 2 / bc;
  279.             }
  280.         }
  281.         if (spec.fireInterval > 0 && ticks % spec.fireInterval == 0 && pos.y < 0 &&
  282.             pos.x - Field.offsetX > -Field.size.x + Field.SIDE_BOARD_WIDTH &&
  283.             pos.x - Field.offsetX <  Field.size.x - Field.SIDE_BOARD_WIDTH &&
  284.             (!spec.isAimingBaseAngle || Vector3D.distance(pos, Player.pos) > 120))
  285.          {
  286.             var ba:Number;
  287.             if (spec.isAimingBaseAngle) ba = atan2(Player.pos.x - pos.x, Player.pos.y - pos.y);
  288.             else ba = baseAngle * xReverse;
  289.             ba += rollAngle + fireAngle;
  290.             var srv:Number = -spec.bulletSpeedWhipVel * 2 / spec.bulletCount;
  291.             for (i = 0; i < spec.bulletCount; i++) fire(ba, 1.0 + spec.bulletSpeedWhipVel + srv * i);
  292.         }
  293.         ticks++;
  294.         if (isTop && isTarget && pos.y < -Field.size.y * 0.5) pos.y += 7.0;
  295.         if (isTop && !isTarget)
  296.         {
  297.             pos.y += 3.0;
  298.             if (pos.y > Field.size.y + spec.radius) remove();
  299.         }
  300.         if (isTarget) targetCircleCount++;
  301.         if (children == nullreturn;
  302.         rollAngle = spec.rollAngle.getValue(ticks);
  303.         fireAngle = spec.fireAngle.getValue(ticks);
  304.         fireSpeed = spec.fireSpeed.getValue(ticks);
  305.         angleInterval = spec.angleInterval.getValue(ticks);
  306.         if (spec.isAimingRollAngle) rollAngle += atan2(Player.pos.x - pos.x, Player.pos.y - pos.y) * xReverse;
  307.         var a:Number = rollAngle - angleInterval * (children.length - 1) / 2 - angleInterval;
  308.         for each (var c:Circle in children)
  309.         {
  310.             a += angleInterval;
  311.             if (!c.exists) continue;
  312.             c.pos.x = pos.x + sin(a) * spec.radius * xReverse;
  313.             c.pos.y = pos.y + cos(a) * spec.radius;
  314.             c.baseAngle = a + fireAngle;
  315.             c.update();
  316.         }
  317.     }
  318.     private function fire(a:Number, sr:Number):void
  319.     {
  320.         var b:Bullet = new Bullet;
  321.         b.pos.x = pos.x; b.pos.y = pos.y;
  322.         var bs:Number = spec.bulletSpeed * bulletSpeedRatio * sr;
  323.         b.baseVel.x = sin(a) * bs; b.baseVel.y = cos(a) * bs;
  324.         b.size = spec.bulletSize;
  325.         b.br = spec.r; b.bg = spec.g; b.bb = spec.b;
  326.         b.color = int(b.br / 4) * 0x10000 + int(b.bg / 4) * 0x100 + int(b.bb / 4);
  327.         bullets.push(b);
  328.     }
  329.     public function damage():void
  330.     {
  331.         isDamaged = true;
  332.         shield--;
  333.         if (shield <= 0) remove(true);
  334.     }
  335.     public function remove(isDestroyed:Boolean = false):void
  336.     {
  337.         for each (var c:Circle in children) if (c.exists) c.remove();
  338.         children = null;
  339.         exists = false;
  340.         if (!isDestroyed) return;
  341.         var sa:Number = ticks * 0.1, sr:Number = spec.visualRadius, sc:int = sr * 0.5, i:int;
  342.         for (i = 0; i < sc; i++)
  343.         {
  344.             addSparks(1, pos.x + sr * sin(sa), pos.y + sr * cos(sa), 10.010.0, spec.r, spec.g, spec.b);
  345.             sa += PI * 2 / sc;
  346.         }
  347.         addBonuses(sr * sr * 2 / (abs(pos.y - Player.pos.y) + 30.0), pos.x, pos.y, 10.0);
  348.     }
  349.     public function setXReverse():void
  350.     {
  351.         xReverse = -1.0;
  352.         for each (var c:Circle in children) c.setXReverse();
  353.     }
  354. }
  355. class CircleSpec
  356. {
  357.     public static const FIX:int = 0, WEDGE:int = 1;
  358.     public var radius:Number, visualRadius:Number;
  359.     public var isRound:Boolean;
  360.     public var rollAngle:Waveform = new Waveform;
  361.     public var isAimingRollAngle:Boolean, isAimingBaseAngle:Boolean;
  362.     public var fireAngle:Waveform = new Waveform, fireSpeed:Waveform = new Waveform;
  363.     public var fireInterval:int = -1;
  364.     public var angleInterval:Waveform = new Waveform;
  365.     public var bulletSpeed:Number = 7.0, bulletSize:Number = 15.0;
  366.     public var bulletSpeedFanType:int, bulletSpeedFanVel:Number = 0;
  367.     public var fireDelayType:int, fireDelayVel:Number = 0;
  368.     public var bulletCount:int = 1, bulletSpeedWhipVel:Number = 0;
  369.     public var r:int, g:int, b:int;
  370.     public var childrenCount:int;
  371.     public var shield:int;
  372.     public function set(childrenCount:int, radius:Number, childRadius:Number):void
  373.     {
  374.         this.childrenCount = childrenCount;
  375.         this.radius = radius; visualRadius = radius + childRadius;
  376.         shield = radius;
  377.         rollAngle.width = (0.5 + rand() * 0.5) * ((int)(rand() * 2) * 2 - 1);
  378.         isRound = (rand() < 0.25);
  379.         if (isRound) {
  380.             rollAngle.type = Waveform.MONOTONE;
  381.             rollAngle.interval = 60 + rand() * 60;
  382.             if (rand() < 0.4) fireAngle.type = Waveform.MONOTONE;
  383.             fireAngle.width = (2.0 + rand() * 2.0) * ((int)(rand() * 2) * 2 - 1);
  384.             fireAngle.interval = 90 + rand() * 90;
  385.             if (rand() < 0.3) fireAngle.center = rand() * PI * 2;
  386.             angleInterval.center = PI * 2 / childrenCount;
  387.         }
  388.         else
  389.         {
  390.             isAimingRollAngle = true;
  391.             if (rand() < 0.3) rollAngle.type = Waveform.SIN;
  392.             rollAngle.interval = 120 + rand() * 90;
  393.             if (rand() < 0.3) angleInterval.type = Waveform.SIN;
  394.             angleInterval.center = ((2.0 + rand() * 2.0) / childrenCount) * ((int)(rand() * 2) * 2 - 1);
  395.             angleInterval.width = angleInterval.center * (0.3 + rand() * 0.3);
  396.             angleInterval.interval = 60 + rand() * 60;
  397.         }
  398.         if (rand() < 0.5) bulletSpeedFanType = WEDGE;
  399.         if (rand() < 0.5) bulletSpeedFanVel = (0.3 + rand() * 0.2) * ((int)(rand() * 2) * 2 - 1);
  400.         if (rand() < 0.5) fireDelayType = WEDGE;
  401.         if (rand() < 0.5) fireDelayVel = (8.0 + rand() * 6.0) * ((int)(rand() * 2) * 2 - 1);
  402.     }
  403. }
  404. class Waveform
  405. {
  406.     public static const FIX:int = 0, MONOTONE:int = 1, SIN:int = 2;
  407.     public var type:int = FIX, center:Number = 0, width:Number = 0, interval:int = 1;
  408.     public function getValue(ticks:int):Number
  409.     {
  410.         switch (type)
  411.         {
  412.             case FIX:      return center;
  413.             case MONOTONE: return center + width * ticks * 2 / interval;
  414.             case SIN:      return center + width * sin(PI * 2 * ticks / interval);
  415.         }
  416.         return 0;
  417.     }
  418. }
  419. function addTargetCircles(x:Number, depth:int, fireIntervalRatio:Number, bulletSpeed:Number, hasReversed:Boolean):void
  420. {
  421.     var radius:Number = (20 + rand() * 20) * depth;
  422.     var c:Circle = new Circle;
  423.     var rw:Number = 0;
  424.     if (hasReversed) rw = (rand() * 0.1 + 0.1) * Field.size.x;
  425.     var cy:Number = -Field.size.y * (1.0 + rand() * 2.0) - radius;
  426.     c.pos.x = x - rw; c.pos.y = cy;
  427.     c.isTop = true; c.hasCollision = true; c.isTarget = true;
  428.     var r:int, g:int, b:int;
  429.     r = 127 + rand() * 128; g = 127 + rand() * 128; b = 127 + rand() * 128;
  430.     var sps:Vector.<CircleSpec> = new Vector.<CircleSpec>;
  431.     var turretCount:int = createCircleSpecs(sps, radius, depth, r, g, b);
  432.     var sp:CircleSpec;
  433.     for each (sp in sps) if (sp.isRound) turretCount *= 0.75;
  434.     sp = sps[0];
  435.     sp.fireInterval = turretCount * fireIntervalRatio + 1;
  436.     sp.bulletSpeed = bulletSpeed; sp.bulletSize = 12.0 + depth * 2;
  437.     addCircleChildren(c, sps.length - 1, sps, 1.00);
  438.     circles.push(c);
  439.     if (hasReversed)
  440.     {
  441.         c = new Circle;
  442.         c.pos.x = x + rw; c.pos.y = cy;
  443.         c.isTop = true; c.hasCollision = true; c.isTarget = true;
  444.         addCircleChildren(c, sps.length - 1, sps, 1.00);
  445.         c.setXReverse();
  446.         circles.push(c);
  447.     }
  448. }
  449. function addBackgroundCircles(x:Number, fireIntervalRatio:Number, bulletSpeed:Number):void
  450. {
  451.     var radius:Number = (60 + rand() * 60);
  452.     var c:Circle = new Circle;
  453.     c.pos.x = x; c.pos.y = -Field.size.y - radius;
  454.     c.isTop = true;
  455.     c.circleWidth = 3.0;
  456.     var csp:CircleSpec = new CircleSpec;
  457.     csp.radius = 0; csp.visualRadius = 15.0; csp.childrenCount = 0;
  458.     csp.shield = 3;
  459.     csp.isAimingBaseAngle = true;
  460.     csp.bulletSpeed = bulletSpeed;
  461.     csp.r = csp.g = csp.b = 200;
  462.     var sp:CircleSpec = new CircleSpec;
  463.     sp.childrenCount = 3 + rand() * 7;
  464.     csp.fireInterval = sp.childrenCount * fireIntervalRatio + 1;
  465.     sp.radius = radius; sp.visualRadius = radius - csp.visualRadius;
  466.     sp.rollAngle.width = (0.5 + rand() * 0.5) * ((int)(rand() * 2) * 2 - 1);
  467.     sp.rollAngle.type = Waveform.MONOTONE;
  468.     sp.rollAngle.interval = 60 + rand() * 60;
  469.     sp.angleInterval.center = ((2.0 + rand() * 2.0) / sp.childrenCount);
  470.     if (rand() < 0.5) sp.fireDelayVel = (8.0 + rand() * 6.0) * ((int)(rand() * 2) * 2 - 1);
  471.     sp.r = sp.g = sp.b = 300;
  472.     c.children = new Vector.<Circle>;
  473.     var cct:int = 0;
  474.     for (var i:int = 0; i < sp.childrenCount; i++)
  475.     {
  476.         var cc:Circle = new Circle;
  477.         cc.hasCollision = true;
  478.         cc.spec = csp; cc.start();
  479.         cc.ticks = cct; cct += sp.fireDelayVel;
  480.         c.children.push(cc);
  481.     }
  482.     c.spec = sp; c.start();
  483.     circles.push(c);
  484. }
  485. function createCircleSpecs(sps:Vector.<CircleSpec>, radius:Number, depth:int, r:int, g:int, b:int):int
  486. {
  487.     var sp:CircleSpec = new CircleSpec;
  488.     sp.r = r; sp.g = g; sp.b = b;
  489.     var turretCount:int;
  490.     if (depth == 0)
  491.     {
  492.         sp.radius = 0; sp.visualRadius = radius; sp.childrenCount = 0;
  493.         if (rand() < 0.3)
  494.         {
  495.             sp.bulletCount = 2 + rand() * 5;
  496.             sp.bulletSpeedWhipVel = 0.2 + rand() * 0.2;
  497.             turretCount = sp.bulletCount * 0.75;
  498.         }
  499.         else turretCount = 1;
  500.     }
  501.     else
  502.     {
  503.         sp.childrenCount = 1 + rand() * 7;
  504.         var cr:Number = radius * (0.33 + rand() * 0.1);
  505.         sp.set(sp.childrenCount, radius, cr);
  506.         turretCount = createCircleSpecs(sps, cr, depth - 1, r, g, b) * sp.childrenCount;
  507.     }
  508.     sps.push(sp);
  509.     return turretCount;
  510. }
  511. function addCircleChildren(c:Circle, index:int, sps:Vector.<CircleSpec>,
  512.                            bulletSpeedRatio:Number, fireDelay:Number):void
  513. {
  514.     var sp:CircleSpec = sps[index];
  515.     var bsv:Number = -sp.bulletSpeedFanVel * 2 / sp.childrenCount;
  516.     var fdv:Number = -sp.fireDelayVel * 2 / sp.childrenCount;
  517.     if (sp.bulletSpeedFanType == CircleSpec.WEDGE) bsv *= 2;
  518.     if (sp.fireDelayType == CircleSpec.WEDGE) fdv *= 2;
  519.     if (sp.childrenCount > 0) c.children = new Vector.<Circle>;
  520.     for (var i:int = 0; i < sp.childrenCount; i++)
  521.     {
  522.         var cc:Circle = new Circle;
  523.         var bsr:Number;
  524.         if (sp.bulletSpeedFanType == CircleSpec.FIX || i < sp.childrenCount / 2) bsr = 1.0 + sp.bulletSpeedFanVel + bsv * i;
  525.         else bsr = 1.0 + sp.bulletSpeedFanVel + bsv * (sp.childrenCount - 1 - i);
  526.         var fd:Number;
  527.         if (sp.fireDelayType == CircleSpec.FIX || i < sp.childrenCount / 2) fd = sp.fireDelayVel + fdv * i;
  528.         else fd = sp.fireDelayVel + fdv * (sp.childrenCount - 1 - i);
  529.         addCircleChildren(cc, index - 1, sps, bsr * bulletSpeedRatio, fireDelay + fd);
  530.         c.children.push(cc);
  531.     }
  532.     c.bulletSpeedRatio = bulletSpeedRatio;
  533.     c.ticks = fireDelay;
  534.     c.spec = sp; c.start();
  535. }
  536. // Sparks.
  537. var sparks:Vector.<Spark>;
  538. class Spark extends VelocityActor
  539. {
  540.     public var size:Number;
  541.     public var r:int, g:int, b:int;
  542.     override public function update():Boolean
  543.     {
  544.         vel.scaleBy(0.99);
  545.         size *= 0.95;
  546.         r += (BACKGROUND_BRIGHTNESS - r) * 0.1;
  547.         g += (BACKGROUND_BRIGHTNESS - g) * 0.1;
  548.         b += (BACKGROUND_BRIGHTNESS - b) * 0.1;
  549.         var cr:Number = rand() + 0.5;
  550.         var br:int = r * cr, bg:int = g * cr, bb:int = b * cr;
  551.         if (br > 255) br = 255;
  552.         if (bg > 255) bg = 255;
  553.         if (bb > 255) bb = 255;
  554.         drawBox(pos.x, pos.y, size, size, r * 0x10000 + g * 0x100 + b, 1.5, br, bg, bb);
  555.         return super.update();
  556.     }
  557. }
  558. function addSparks(count:int, x:Number, y:Number, speed:Number, size:Number, r:int, g:int, b:int):void
  559. {
  560.     for (var i:int = 0; i < count; i++)
  561.     {
  562.         var s:Spark = new Spark;
  563.         s.pos.x = x; s.pos.y = y;
  564.         var a:Number = rand() * PI * 2, sp:Number = speed * (0.5 + rand());
  565.         s.vel.x = Math.sin(a) * sp; s.vel.y = Math.cos(a) * sp;
  566.         s.size = size;
  567.         s.r = r; s.g = g; s.b = b;
  568.         s.disappearTicks = 15 + 15 * rand();
  569.         sparks.push(s);
  570.     }
  571. }
  572. // Bonus items.
  573. var bonuses:Vector.<Bonus>;
  574. class Bonus extends VelocityActor
  575. {
  576.     public var isInhaled:Boolean;
  577.     override public function update():Boolean
  578.     {
  579.         var a:Number = ticks * 0.1;
  580.         for (var i:int = 0; i < 4; i++)
  581.         {
  582.             drawBox(pos.x + sin(a) * 10 - 5, pos.y + cos(a) * 10 - 588, 0x6688aa, 1.0150200150);
  583.             a += PI / 2;
  584.         }
  585.         if (isInhaled && gameOverTicks < 0)
  586.         {
  587.             vel.x += (Player.pos.x - pos.x) * 0.05; vel.y += (Player.pos.y - pos.y) * 0.05;
  588.         }
  589.         else vel.y += 0.5;
  590.         vel.scaleBy(0.9);
  591.         var d:Number = Vector3D.distance(pos, Player.pos);
  592.         if (isInhaled && d < 40.0 && gameOverTicks < 0)
  593.         {
  594.             score++; scoreField.text = String(score); return false;
  595.         }
  596.         else if (d < 120.0 && vel.length < 5.0) isInhaled = true;
  597.         return super.update();
  598.     }
  599. }
  600. function addBonuses(count:int, x:Number, y:Number, speed:Number):void
  601. {
  602.     for (var i:int = 0; i < count; i++)
  603.     {
  604.         var b:Bonus = new Bonus;
  605.         b.pos.x = x; b.pos.y = y;
  606.         var a:Number = rand() * PI * 2, sp:Number = speed * (0.5 + rand());
  607.         b.vel.x = Math.sin(a) * sp; b.vel.y = Math.cos(a) * sp;
  608.         bonuses.push(b);
  609.     }
  610. }
  611. // Game field.
  612. class Field
  613. {
  614.     public static const SIDE_BOARD_WIDTH:Number = SCREEN_WIDTH / 6;
  615.     public static var size:Vector3D = new Vector3D;
  616.     public static var offsetX:Number = 0;
  617.     public static function initialize():void
  618.     {
  619.         size.x = SCREEN_WIDTH * 1.1 / 2; size.y = SCREEN_HEIGHT * 1.1 / 2;
  620.     }
  621.     public static function drawSideBoard():void
  622.     {
  623.         rect.width = SIDE_BOARD_WIDTH; rect.height = SCREEN_HEIGHT; rect.y = 0;
  624.         rect.x = 0;                         screen.fillRect(rect, BACKGROUND_COLOR);
  625.         rect.x = SCREEN_WIDTH - rect.width; screen.fillRect(rect, BACKGROUND_COLOR);
  626.     }
  627.     public static function contains(p:Vector3D):Boolean
  628.     {
  629.         return (p.x >= -size.x && p.x <= size.x && p.y >= -size.y && p.y <= size.y);
  630.     }
  631. }
  632. // Blur effect.
  633. const BLUR_MAX_COUNT:int = 512, BLUR_HISTORY_COUNT:int = 6;
  634. var blurs:Vector.<Vector.<Blur>> = new Vector.<Vector.<Blur>>(BLUR_HISTORY_COUNT, true);
  635. var blurCounts:Vector.<int> = new Vector.<int>(BLUR_HISTORY_COUNT, true);
  636. var blurIndex:int;
  637. class Blur
  638. {
  639.     public var pos:Vector3D = new Vector3D;
  640.     public var width:Number, height:Number;
  641.     public var r:int, g:int, b:int;
  642.     public function update():void
  643.     {
  644.         rect.x = pos.x - width  / 2 - Field.offsetX; rect.width = width;
  645.         rect.y = pos.y - height / 2; rect.height = height;
  646.         screen.fillRect(rect, r * 0x10000 + g * 0x100 + b);
  647.         width *= 1.2; height *= 1.2;
  648.         r += (BACKGROUND_BRIGHTNESS - r) * 0.2;
  649.         g += (BACKGROUND_BRIGHTNESS - g) * 0.2;
  650.         b += (BACKGROUND_BRIGHTNESS - b) * 0.2;
  651.     }
  652. }
  653. function drawBox(x:Number, y:Number, w:int, h:int, color:int,
  654.                  blurSizeRatio:Number, br:int, bg:int, bb:int):void
  655. {
  656.     rect.x = x - w / 2 + SCREEN_WIDTH / 2 - Field.offsetX;
  657.     rect.y = y - h / 2 + SCREEN_HEIGHT / 2;
  658.     rect.width = w; rect.height = h;
  659.     screen.fillRect(rect, color);
  660.     if (blurSizeRatio > 0) addBlur(x, y, w * blurSizeRatio, h * blurSizeRatio, br, bg, bb);
  661. }
  662. function addBlur(x:Number, y:Number, w:Number, h:Number, r:int, g:int, b:int):void
  663. {
  664.     if (blurCounts[blurIndex] >= BLUR_MAX_COUNT) return;
  665.     var bl:Blur = blurs[blurIndex][blurCounts[blurIndex]];
  666.     bl.pos.x = x + SCREEN_WIDTH / 2; bl.pos.y = y + SCREEN_HEIGHT / 2;
  667.     bl.width = w; bl.height = h;
  668.     bl.r = r; bl.g = g; bl.b = b;
  669.     blurCounts[blurIndex]++;
  670. }
  671. function updateBlurs():void
  672. {
  673.     var bi:int = blurIndex + 1;
  674.     for (var i:int = 0; i < BLUR_HISTORY_COUNT; i++)
  675.     {
  676.         if (bi >= BLUR_HISTORY_COUNT) bi = 0;
  677.         for (var j:int = 0; j < blurCounts[bi]; j++) blurs[bi][j].update();
  678.         bi++;
  679.     }
  680.     blurIndex++;
  681.     if (blurIndex >= BLUR_HISTORY_COUNT) blurIndex = 0;
  682.     blurCounts[blurIndex] = 0;
  683. }
  684. function initializeBlurs():void
  685. {
  686.     for (var i:int = 0; i < BLUR_HISTORY_COUNT; i++)
  687.     {
  688.         var bs:Vector.<Blur> = new Vector.<Blur>(BLUR_MAX_COUNT, true);
  689.         for (var j:int = 0; j < BLUR_MAX_COUNT; j++) bs[j] = new Blur;
  690.         blurs[i] = bs; blurCounts[i] = 0;
  691.     }
  692.     blurIndex = 0;
  693. }
  694. // Utility classes, functions and variables.
  695. var pos:Vector3D = new Vector3D, offset:Vector3D = new Vector3D;
  696. var rect:Rectangle = new Rectangle;
  697. var rand:Function = Math.random, abs:Function = Math.abs;
  698. var sin:Function = Math.sin, cos:Function = Math.cos, atan2:Function = Math.atan2;
  699. var PI:Number = Math.PI;
  700. class Key
  701. {
  702.     public static var left:Boolean, up:Boolean, right:Boolean, down:Boolean;
  703.     public static var button1:Boolean, button2:Boolean;
  704.     public static function onKeyDown(event:KeyboardEvent):void
  705.     {
  706.         switch (event.keyCode)
  707.         {
  708.             case 0x25:case 0x41: left =    truebreak;
  709.             case 0x26:case 0x57: up =      truebreak;
  710.             case 0x27:case 0x44: right =   truebreak;
  711.             case 0x28:case 0x53: down =    truebreak;
  712.             case 0x5a:case 0xbf: button1 = truebreak;
  713.             case 0x58:case 0xbe: button2 = truebreak;
  714.         }
  715.     }
  716.     public static function onKeyUp(event:KeyboardEvent):void
  717.     {
  718.         switch (event.keyCode)
  719.         {
  720.             case 0x25:case 0x41: left =    falsebreak;
  721.             case 0x26:case 0x57: up =      falsebreak;
  722.             case 0x27:case 0x44: right =   falsebreak;
  723.             case 0x28:case 0x53: down =    falsebreak;
  724.             case 0x5a:case 0xbf: button1 = falsebreak;
  725.             case 0x58:case 0xbe: button2 = falsebreak;
  726.         }
  727.     }
  728. }
  729. function createTextField(x:int, y:int, width:int, size:int, color:int,
  730.                          align:String = TextFormatAlign.LEFT):TextField
  731. {
  732.     var fm:TextFormat = new TextFormat;
  733.     fm.font = "_typewriter"; fm.bold = true;
  734.     fm.size = size; fm.color = color; fm.align = align;
  735.     var fi:TextField = new TextField;
  736.     fi.defaultTextFormat = fm;
  737.     fi.x = x; fi.y = y; fi.width = width; fi.selectable = false;
  738.     return fi;
  739. }
  740. function drawCircle(p:Vector3D, radius:Number, width:Number, color:int, xRatio:Number = 1.0):void
  741. {
  742.     pos.x = p.x + SCREEN_WIDTH / 2 - Field.offsetX;
  743.     pos.y = p.y + SCREEN_HEIGHT / 2;
  744.     var c:int = radius * 1.5;
  745.     var a:Number = 0, oa:Number = PI * 2 / c;
  746.     rect.width = rect.height = width;
  747.     for (var i:int = 0; i < c; i++)
  748.     {
  749.         rect.x = pos.x + sin(a) * radius * xRatio - width / 2;
  750.         rect.y = pos.y + cos(a) * radius - width / 2;
  751.         screen.fillRect(rect, color);
  752.         a += oa;
  753.     }
  754. }
noswf
  1. // forked from ABA's forked from: CircleCycle
  2. // forked from ABA's CircleCycle
  3. // CircleCycle.as
  4. //  Destroy circles and avoid incoming bullets.
  5. //  <Control>
  6. //   Movement: Arrow or [WASD] keys.
  7. //   Fire:    [Z] or [/] key.
  8. //   Slow:    [X] or [.] key.
  9. package
  10. {
  11.     import flash.display.Sprite;
  12.     [SWF(width="465", height="465", backgroundColor="0x000000", frameRate="30")]
  13.     public class CircleCycle extends Sprite
  14.     {
  15.         public function CircleCycle()
  16.         {
  17.             main = this;
  18.             initialize();
  19.         }
  20.     }
  21. }
  22. import flash.display.Sprite;
  23. import flash.display.Bitmap;
  24. import flash.display.BitmapData;
  25. import flash.geom.Rectangle;
  26. import flash.geom.Vector3D;
  27. import flash.text.TextField;
  28. import flash.text.TextFormat;
  29. import flash.text.TextFormatAlign;
  30. import flash.events.Event;
  31. import flash.events.KeyboardEvent;
  32. const SCREEN_WIDTH:int = 465, SCREEN_HEIGHT:int = 465;
  33. const BACKGROUND_BRIGHTNESS:int = 200;
  34. const BACKGROUND_COLOR:int = BACKGROUND_BRIGHTNESS * 0x10000 + BACKGROUND_BRIGHTNESS * 0x100 + BACKGROUND_BRIGHTNESS;
  35. const GAME_OVER_DURATION:int = 150, BLOCK_GAME_START_DURATION:int = 30;
  36. var main:Sprite;
  37. var screen:BitmapData = new BitmapData(SCREEN_WIDTH, SCREEN_HEIGHT, false0);
  38. var scoreField:TextField = new TextField, timeField:TextField = new TextField, messageField:TextField = new TextField;
  39. var gameOverTicks:int, score:int, stage:int, targetCircleCount:int, ticks:int, time:int;
  40. function initialize():void
  41. {
  42.     main.addChild(new Bitmap(screen));
  43.     main.stage.addEventListener(KeyboardEvent.KEY_DOWN, Key.onKeyDown);
  44.     main.stage.addEventListener(KeyboardEvent.KEY_UP,   Key.onKeyUp);
  45.     Field.initialize();
  46.     initializeBlurs();
  47.     scoreField = createTextField(SCREEN_WIDTH - 100010024, 0xff6666, TextFormatAlign.RIGHT);
  48.     timeField = createTextField(SCREEN_WIDTH / 2 - 120, SCREEN_HEIGHT - 4020040, 0xff6666, TextFormatAlign.RIGHT);
  49.     messageField = createTextField(SCREEN_WIDTH - 256025636, 0xff6666);
  50.     main.addChild(scoreField); main.addChild(timeField); main.addChild(messageField);
  51.     startTitle();
  52.     main.addEventListener(Event.ENTER_FRAME, update);
  53. }
  54. function update(event:Event):void
  55. {
  56.     screen.lock();
  57.     screen.fillRect(screen.rect, BACKGROUND_COLOR);
  58.     updateBlurs();
  59.     var i:int;
  60.     for (i = 0; i < sparks.length; i++)  if (!sparks[i].update())  { sparks.splice(i, 1);  i--; }
  61.     for (i = 0; i < shots.length; i++)   if (!shots[i].update())   { shots.splice(i, 1);   i--; }
  62.     for (i = 0; i < bonuses.length; i++) if (!bonuses[i].update()) { bonuses.splice(i, 1); i--; }
  63.     if (targetCircleCount <= 0) goToNextStage();
  64.     if (ticks % 50 == 0) addBackgroundCircles((rand() - 0.5) * Field.size.x * 1.5,
  65.                                               200.0 / (20.0 + stage), 5.0 + rand() * 2.0 + rand() * 2.0);
  66.     ticks++;
  67.     targetCircleCount = 0;
  68.     for each (var c:Circle in circles) c.update();
  69.     for (i = 0; i < circles.length; i++) if (!circles[i].exists)   { circles.splice(i, 1); i--; }
  70.     if (gameOverTicks < 0) Player.update();
  71.     for (i = 0; i < bullets.length; i++) if (!bullets[i].update()) { bullets.splice(i, 1); i--; }
  72.     Field.drawSideBoard();
  73.     screen.unlock();
  74.     if (gameOverTicks < 0)
  75.     {
  76.         time -= 33;
  77.         if (Key.button2) time -= 33;
  78.         if (time <= 0)
  79.         {
  80.             time = 0; startGameClear();
  81.         }
  82.         var msStr:String = String(time % 1000);
  83.         while (msStr.length < 3) msStr = "0" + msStr;
  84.         timeField.text = String(int(time / 1000)) + "\"" + msStr;
  85.     }
  86.     else
  87.     {
  88.         gameOverTicks++;
  89.         if (gameOverTicks == GAME_OVER_DURATION) startTitle();
  90.         if (Key.button1 && gameOverTicks > BLOCK_GAME_START_DURATION) startGame();
  91.     }
  92. }
  93. function goToNextStage():void
  94. {
  95.     if (rand() < 0.5) addTargetCircles((rand() - 0.5) * Field.size.x, 2,
  96.                                        200.0 / (20.0 + stage), 5.0 + rand() * 2.0 + rand() * 2.0false);
  97.     else              addTargetCircles((rand() - 0.5) * Field.size.x * 0.71,
  98.                                        400.0 / (20.0 + stage), 5.0 + rand() * 2.0 + rand() * 2.0true);
  99.     stage += 15;
  100. }
  101. function startTitle():void
  102. {
  103.     clearActors();
  104.     gameOverTicks = GAME_OVER_DURATION;
  105.     messageField.y = SCREEN_HEIGHT / 3 * 2; messageField.text = "CircleCycle";
  106. }
  107. function startGame():void
  108. {
  109.     clearActors();
  110.     Player.start();
  111.     gameOverTicks = -1;
  112.     messageField.text = "";
  113.     score = 0; scoreField.text = "0"; stage = 0; time = 60000;
  114. }
  115. function startGameOver():void
  116. {
  117.     gameOverTicks = 0;
  118.     messageField.y = SCREEN_HEIGHT / 2; messageField.text = "GAME OVER";
  119. }
  120. function startGameClear():void
  121. {
  122.     gameOverTicks = 0;
  123.     messageField.y = SCREEN_HEIGHT / 2; messageField.text = "COMPLETE!";
  124. }
  125. function clearActors():void
  126. {
  127.     shots = null; bullets = null; sparks = null; bonuses = null; circles = null;
  128.     shots = new Vector.<Shot>; bullets = new Vector.<Bullet>; sparks = new Vector.<Spark>; bonuses = new Vector.<Bonus>;
  129.     circles = new Vector.<Circle>; targetCircleCount = 0;
  130. }
  131. // Game actor base class.
  132. class Actor
  133. {
  134.     public var pos:Vector3D = new Vector3D;
  135. }
  136. class VelocityActor extends Actor
  137. {
  138.     public var vel:Vector3D = new Vector3D;
  139.     public var ticks:int, disappearTicks:int = 300;
  140.     public function update():Boolean
  141.     {
  142.         pos.incrementBy(vel);
  143.         ticks++;
  144.         if (!Field.contains(pos) || ticks > disappearTicks) return false;
  145.         return true;
  146.     }
  147. }
  148. // Player.
  149. class Player
  150. {
  151.     private static const COLLISION_SIZE:Number = 5.0;
  152.     private static const SPEED:Number = 9.0;
  153.     public static var pos:Vector3D = new Vector3D;
  154.     private static var fireTicks:int;
  155.     public static function start():void
  156.     {
  157.         pos.x = 0; pos.y = Field.size.y * 0.5;
  158.     }
  159.     public static function update():void
  160.     {
  161.         offset.x = offset.y = 0;
  162.         if (Key.left)  offset.x = -1;
  163.         if (Key.right) offset.x = 1;
  164.         if (Key.up)    offset.y = -1;
  165.         if (Key.down)  offset.y = 1;
  166.         if (offset.x != 0 && offset.y != 0) offset.scaleBy(0.7);
  167.         if (Key.button2) offset.scaleBy(0.5);
  168.         offset.scaleBy(SPEED); pos.incrementBy(offset);
  169.         if (pos.x < -SCREEN_WIDTH  / 2) pos.x = -SCREEN_WIDTH / 2;
  170.         if (pos.x >  SCREEN_WIDTH  / 2) pos.x =  SCREEN_WIDTH / 2;
  171.         if (pos.y < -SCREEN_HEIGHT / 2) pos.y = -SCREEN_HEIGHT / 2;
  172.         if (pos.y >  SCREEN_HEIGHT / 2) pos.y =  SCREEN_HEIGHT / 2;
  173.         Field.offsetX = pos.x * 0.33;
  174.         drawCircle(pos, 157, 0x008800, 0.5);
  175.         addBlur(pos.x, pos.y, 2020100200100);
  176.         if (fireTicks <= 0 && shots.length <= 14 && Key.button1)
  177.         {
  178.             fireTicks = 2;
  179.             var s:Shot;
  180.             for (var i:int = 0; i < 7; i++)
  181.             {
  182.                 s = new Shot;
  183.                 s.pos.x = pos.x; s.pos.y = pos.y;
  184.                 var a:Number = (i - 3) * 0.1;
  185.                 s.vel.x = sin(a) * 24.0; s.vel.y = -cos(a) * 24.0;
  186.                 shots.push(s);
  187.             }
  188.         }
  189.         fireTicks--;
  190.         for each (var b:Bullet in bullets)
  191.         {
  192.             if (Vector3D.distance(pos, b.pos) <= COLLISION_SIZE)
  193.             {
  194.                 addSparks(100, Player.pos.x, Player.pos.y, 30.015.0200100100);
  195.                 startGameOver(); break;
  196.             }
  197.         }
  198.     }
  199. }
  200. // Player's shots.
  201. var shots:Vector.<Shot>;
  202. class Shot extends VelocityActor
  203. {
  204.     override public function update():Boolean
  205.     {
  206.         for each (var c:Circle in circles) if (checkHit(c)) return false;
  207.         addBlur(pos.x, pos.y, 201550150100);
  208.         return super.update();
  209.     }
  210.     private function checkHit(c:Circle):Boolean
  211.     {
  212.         for each (var cc:Circle in c.children) if (cc.exists && checkHit(cc)) return true;
  213.         if (c.exists && c.hasCollision && Vector3D.distance(pos, c.pos) < c.spec.visualRadius + 20.0)
  214.         {
  215.             addSparks(1, pos.x, pos.y, 20.05.050150100);
  216.             c.damage(); return true;
  217.         }
  218.         return false;
  219.     }
  220. }
  221. // Circles' bullets.
  222. var bullets:Vector.<Bullet>;
  223. class Bullet extends VelocityActor
  224. {
  225.     public var baseVel:Vector3D = new Vector3D;
  226.     public var color:int, br:int, bg:int, bb:int, size:int;
  227.     override public function update():Boolean
  228.     {
  229.         var sz:Number = 1.5 + Math.sin(ticks * 0.2) * 0.4;
  230.         var a:Number = 0.8 + Math.sin(ticks * 0.45) * 0.2;
  231.         drawBox(pos.x, pos.y, size, size, color, sz, br * a, bg * a, bb * a);
  232.         if (ticks <= 15)
  233.         {
  234.             vel.x = baseVel.x * (ticks + 15) / 30.0; vel.y = baseVel.y * (ticks + 15) / 30.0;
  235.         }
  236.         else
  237.         {
  238.             vel.x = baseVel.x; vel.y = baseVel.y;
  239.         }
  240.         if (Key.button2) vel.scaleBy(0.5);
  241.         return super.update();
  242.     }
  243. }
  244. // Circles.
  245. var circles:Vector.<Circle>;
  246. class Circle extends Actor
  247. {
  248.     public var children:Vector.<Circle> = null;
  249.     public var isTop:Boolean, exists:Boolean = true;
  250.     public var spec:CircleSpec;
  251.     public var bulletSpeedRatio:Number = 1.0;
  252.     public var rollAngle:Number = 0, fireAngle:Number = 0, fireSpeed:Number, angleInterval:Number;
  253.     public var baseAngle:Number = 0;
  254.     public var ticks:int, shield:int;
  255.     public var hasCollision:Boolean, isTarget:Boolean, isDamaged:Boolean;
  256.     public var xReverse:Number = 1.0;
  257.     public var circleWidth:Number = 5.0;
  258.     public var color:int;
  259.     public function start():void
  260.     {
  261.         color = (int)(spec.r / 2) * 0x10000 + int(spec.g / 2) * 0x100 + int(spec.b / 2);
  262.         shield = spec.shield;
  263.     }
  264.     public function update():void
  265.     {
  266.         var vr:Number = spec.visualRadius;
  267.         if (spec.fireInterval > 0) vr *= ((ticks % spec.fireInterval) / spec.fireInterval * 0.5 + 1.0);
  268.         drawCircle(pos, vr, circleWidth, color);
  269.         var i:int;
  270.         if (isDamaged)
  271.         {
  272.             isDamaged = false;
  273.             var da:Number = ticks * 0.1, sr:Number = spec.visualRadius, bc:int = sr * 0.5;
  274.             for (i = 0; i < bc; i++)
  275.             {
  276.                 addBlur(pos.x + sr * sin(da), pos.y + sr * cos(da),
  277.                         9 + rand() * 79 + rand() * 7, rand() * 128 + 64, rand() * 128 + 12764);
  278.                 da += PI * 2 / bc;
  279.             }
  280.         }
  281.         if (spec.fireInterval > 0 && ticks % spec.fireInterval == 0 && pos.y < 0 &&
  282.             pos.x - Field.offsetX > -Field.size.x + Field.SIDE_BOARD_WIDTH &&
  283.             pos.x - Field.offsetX <  Field.size.x - Field.SIDE_BOARD_WIDTH &&
  284.             (!spec.isAimingBaseAngle || Vector3D.distance(pos, Player.pos) > 120))
  285.          {
  286.             var ba:Number;
  287.             if (spec.isAimingBaseAngle) ba = atan2(Player.pos.x - pos.x, Player.pos.y - pos.y);
  288.             else ba = baseAngle * xReverse;
  289.             ba += rollAngle + fireAngle;
  290.             var srv:Number = -spec.bulletSpeedWhipVel * 2 / spec.bulletCount;
  291.             for (i = 0; i < spec.bulletCount; i++) fire(ba, 1.0 + spec.bulletSpeedWhipVel + srv * i);
  292.         }
  293.         ticks++;
  294.         if (isTop && isTarget && pos.y < -Field.size.y * 0.5) pos.y += 7.0;
  295.         if (isTop && !isTarget)
  296.         {
  297.             pos.y += 3.0;
  298.             if (pos.y > Field.size.y + spec.radius) remove();
  299.         }
  300.         if (isTarget) targetCircleCount++;
  301.         if (children == nullreturn;
  302.         rollAngle = spec.rollAngle.getValue(ticks);
  303.         fireAngle = spec.fireAngle.getValue(ticks);
  304.         fireSpeed = spec.fireSpeed.getValue(ticks);
  305.         angleInterval = spec.angleInterval.getValue(ticks);
  306.         if (spec.isAimingRollAngle) rollAngle += atan2(Player.pos.x - pos.x, Player.pos.y - pos.y) * xReverse;
  307.         var a:Number = rollAngle - angleInterval * (children.length - 1) / 2 - angleInterval;
  308.         for each (var c:Circle in children)
  309.         {
  310.             a += angleInterval;
  311.             if (!c.exists) continue;
  312.             c.pos.x = pos.x + sin(a) * spec.radius * xReverse;
  313.             c.pos.y = pos.y + cos(a) * spec.radius;
  314.             c.baseAngle = a + fireAngle;
  315.             c.update();
  316.         }
  317.     }
  318.     private function fire(a:Number, sr:Number):void
  319.     {
  320.         var b:Bullet = new Bullet;
  321.         b.pos.x = pos.x; b.pos.y = pos.y;
  322.         var bs:Number = spec.bulletSpeed * bulletSpeedRatio * sr;
  323.         b.baseVel.x = sin(a) * bs; b.baseVel.y = cos(a) * bs;
  324.         b.size = spec.bulletSize;
  325.         b.br = spec.r; b.bg = spec.g; b.bb = spec.b;
  326.         b.color = int(b.br / 4) * 0x10000 + int(b.bg / 4) * 0x100 + int(b.bb / 4);
  327.         bullets.push(b);
  328.     }
  329.     public function damage():void
  330.     {
  331.         isDamaged = true;
  332.         shield--;
  333.         if (shield <= 0) remove(true);
  334.     }
  335.     public function remove(isDestroyed:Boolean = false):void
  336.     {
  337.         for each (var c:Circle in children) if (c.exists) c.remove();
  338.         children = null;
  339.         exists = false;
  340.         if (!isDestroyed) return;
  341.         var sa:Number = ticks * 0.1, sr:Number = spec.visualRadius, sc:int = sr * 0.5, i:int;
  342.         for (i = 0; i < sc; i++)
  343.         {
  344.             addSparks(1, pos.x + sr * sin(sa), pos.y + sr * cos(sa), 10.010.0, spec.r, spec.g, spec.b);
  345.             sa += PI * 2 / sc;
  346.         }
  347.         addBonuses(sr * sr * 2 / (abs(pos.y - Player.pos.y) + 30.0), pos.x, pos.y, 10.0);
  348.     }
  349.     public function setXReverse():void
  350.     {
  351.         xReverse = -1.0;
  352.         for each (var c:Circle in children) c.setXReverse();
  353.     }
  354. }
  355. class CircleSpec
  356. {
  357.     public static const FIX:int = 0, WEDGE:int = 1;
  358.     public var radius:Number, visualRadius:Number;
  359.     public var isRound:Boolean;
  360.     public var rollAngle:Waveform = new Waveform;
  361.     public var isAimingRollAngle:Boolean, isAimingBaseAngle:Boolean;
  362.     public var fireAngle:Waveform = new Waveform, fireSpeed:Waveform = new Waveform;
  363.     public var fireInterval:int = -1;
  364.     public var angleInterval:Waveform = new Waveform;
  365.     public var bulletSpeed:Number = 7.0, bulletSize:Number = 15.0;
  366.     public var bulletSpeedFanType:int, bulletSpeedFanVel:Number = 0;
  367.     public var fireDelayType:int, fireDelayVel:Number = 0;
  368.     public var bulletCount:int = 1, bulletSpeedWhipVel:Number = 0;
  369.     public var r:int, g:int, b:int;
  370.     public var childrenCount:int;
  371.     public var shield:int;
  372.     public function set(childrenCount:int, radius:Number, childRadius:Number):void
  373.     {
  374.         this.childrenCount = childrenCount;
  375.         this.radius = radius; visualRadius = radius + childRadius;
  376.         shield = radius;
  377.         rollAngle.width = (0.5 + rand() * 0.5) * ((int)(rand() * 2) * 2 - 1);
  378.         isRound = (rand() < 0.25);
  379.         if (isRound) {
  380.             rollAngle.type = Waveform.MONOTONE;
  381.             rollAngle.interval = 60 + rand() * 60;
  382.             if (rand() < 0.4) fireAngle.type = Waveform.MONOTONE;
  383.             fireAngle.width = (2.0 + rand() * 2.0) * ((int)(rand() * 2) * 2 - 1);
  384.             fireAngle.interval = 90 + rand() * 90;
  385.             if (rand() < 0.3) fireAngle.center = rand() * PI * 2;
  386.             angleInterval.center = PI * 2 / childrenCount;
  387.         }
  388.         else
  389.         {
  390.             isAimingRollAngle = true;
  391.             if (rand() < 0.3) rollAngle.type = Waveform.SIN;
  392.             rollAngle.interval = 120 + rand() * 90;
  393.             if (rand() < 0.3) angleInterval.type = Waveform.SIN;
  394.             angleInterval.center = ((2.0 + rand() * 2.0) / childrenCount) * ((int)(rand() * 2) * 2 - 1);
  395.             angleInterval.width = angleInterval.center * (0.3 + rand() * 0.3);
  396.             angleInterval.interval = 60 + rand() * 60;
  397.         }
  398.         if (rand() < 0.5) bulletSpeedFanType = WEDGE;
  399.         if (rand() < 0.5) bulletSpeedFanVel = (0.3 + rand() * 0.2) * ((int)(rand() * 2) * 2 - 1);
  400.         if (rand() < 0.5) fireDelayType = WEDGE;
  401.         if (rand() < 0.5) fireDelayVel = (8.0 + rand() * 6.0) * ((int)(rand() * 2) * 2 - 1);
  402.     }
  403. }
  404. class Waveform
  405. {
  406.     public static const FIX:int = 0, MONOTONE:int = 1, SIN:int = 2;
  407.     public var type:int = FIX, center:Number = 0, width:Number = 0, interval:int = 1;
  408.     public function getValue(ticks:int):Number
  409.     {
  410.         switch (type)
  411.         {
  412.             case FIX:      return center;
  413.             case MONOTONE: return center + width * ticks * 2 / interval;
  414.             case SIN:      return center + width * sin(PI * 2 * ticks / interval);
  415.         }
  416.         return 0;
  417.     }
  418. }
  419. function addTargetCircles(x:Number, depth:int, fireIntervalRatio:Number, bulletSpeed:Number, hasReversed:Boolean):void
  420. {
  421.     var radius:Number = (20 + rand() * 20) * depth;
  422.     var c:Circle = new Circle;
  423.     var rw:Number = 0;
  424.     if (hasReversed) rw = (rand() * 0.1 + 0.1) * Field.size.x;
  425.     var cy:Number = -Field.size.y * (1.0 + rand() * 2.0) - radius;
  426.     c.pos.x = x - rw; c.pos.y = cy;
  427.     c.isTop = true; c.hasCollision = true; c.isTarget = true;
  428.     var r:int, g:int, b:int;
  429.     r = 127 + rand() * 128; g = 127 + rand() * 128; b = 127 + rand() * 128;
  430.     var sps:Vector.<CircleSpec> = new Vector.<CircleSpec>;
  431.     var turretCount:int = createCircleSpecs(sps, radius, depth, r, g, b);
  432.     var sp:CircleSpec;
  433.     for each (sp in sps) if (sp.isRound) turretCount *= 0.75;
  434.     sp = sps[0];
  435.     sp.fireInterval = turretCount * fireIntervalRatio + 1;
  436.     sp.bulletSpeed = bulletSpeed; sp.bulletSize = 12.0 + depth * 2;
  437.     addCircleChildren(c, sps.length - 1, sps, 1.00);
  438.     circles.push(c);
  439.     if (hasReversed)
  440.     {
  441.         c = new Circle;
  442.         c.pos.x = x + rw; c.pos.y = cy;
  443.         c.isTop = true; c.hasCollision = true; c.isTarget = true;
  444.         addCircleChildren(c, sps.length - 1, sps, 1.00);
  445.         c.setXReverse();
  446.         circles.push(c);
  447.     }
  448. }
  449. function addBackgroundCircles(x:Number, fireIntervalRatio:Number, bulletSpeed:Number):void
  450. {
  451.     var radius:Number = (60 + rand() * 60);
  452.     var c:Circle = new Circle;
  453.     c.pos.x = x; c.pos.y = -Field.size.y - radius;
  454.     c.isTop = true;
  455.     c.circleWidth = 3.0;
  456.     var csp:CircleSpec = new CircleSpec;
  457.     csp.radius = 0; csp.visualRadius = 15.0; csp.childrenCount = 0;
  458.     csp.shield = 3;
  459.     csp.isAimingBaseAngle = true;
  460.     csp.bulletSpeed = bulletSpeed;
  461.     csp.r = csp.g = csp.b = 200;
  462.     var sp:CircleSpec = new CircleSpec;
  463.     sp.childrenCount = 3 + rand() * 7;
  464.     csp.fireInterval = sp.childrenCount * fireIntervalRatio + 1;
  465.     sp.radius = radius; sp.visualRadius = radius - csp.visualRadius;
  466.     sp.rollAngle.width = (0.5 + rand() * 0.5) * ((int)(rand() * 2) * 2 - 1);
  467.     sp.rollAngle.type = Waveform.MONOTONE;
  468.     sp.rollAngle.interval = 60 + rand() * 60;
  469.     sp.angleInterval.center = ((2.0 + rand() * 2.0) / sp.childrenCount);
  470.     if (rand() < 0.5) sp.fireDelayVel = (8.0 + rand() * 6.0) * ((int)(rand() * 2) * 2 - 1);
  471.     sp.r = sp.g = sp.b = 300;
  472.     c.children = new Vector.<Circle>;
  473.     var cct:int = 0;
  474.     for (var i:int = 0; i < sp.childrenCount; i++)
  475.     {
  476.         var cc:Circle = new Circle;
  477.         cc.hasCollision = true;
  478.         cc.spec = csp; cc.start();
  479.         cc.ticks = cct; cct += sp.fireDelayVel;
  480.         c.children.push(cc);
  481.     }
  482.     c.spec = sp; c.start();
  483.     circles.push(c);
  484. }
  485. function createCircleSpecs(sps:Vector.<CircleSpec>, radius:Number, depth:int, r:int, g:int, b:int):int
  486. {
  487.     var sp:CircleSpec = new CircleSpec;
  488.     sp.r = r; sp.g = g; sp.b = b;
  489.     var turretCount:int;
  490.     if (depth == 0)
  491.     {
  492.         sp.radius = 0; sp.visualRadius = radius; sp.childrenCount = 0;
  493.         if (rand() < 0.3)
  494.         {
  495.             sp.bulletCount = 2 + rand() * 5;
  496.             sp.bulletSpeedWhipVel = 0.2 + rand() * 0.2;
  497.             turretCount = sp.bulletCount * 0.75;
  498.         }
  499.         else turretCount = 1;
  500.     }
  501.     else
  502.     {
  503.         sp.childrenCount = 1 + rand() * 7;
  504.         var cr:Number = radius * (0.33 + rand() * 0.1);
  505.         sp.set(sp.childrenCount, radius, cr);
  506.         turretCount = createCircleSpecs(sps, cr, depth - 1, r, g, b) * sp.childrenCount;
  507.     }
  508.     sps.push(sp);
  509.     return turretCount;
  510. }
  511. function addCircleChildren(c:Circle, index:int, sps:Vector.<CircleSpec>,
  512.                            bulletSpeedRatio:Number, fireDelay:Number):void
  513. {
  514.     var sp:CircleSpec = sps[index];
  515.     var bsv:Number = -sp.bulletSpeedFanVel * 2 / sp.childrenCount;
  516.     var fdv:Number = -sp.fireDelayVel * 2 / sp.childrenCount;
  517.     if (sp.bulletSpeedFanType == CircleSpec.WEDGE) bsv *= 2;
  518.     if (sp.fireDelayType == CircleSpec.WEDGE) fdv *= 2;
  519.     if (sp.childrenCount > 0) c.children = new Vector.<Circle>;
  520.     for (var i:int = 0; i < sp.childrenCount; i++)
  521.     {
  522.         var cc:Circle = new Circle;
  523.         var bsr:Number;
  524.         if (sp.bulletSpeedFanType == CircleSpec.FIX || i < sp.childrenCount / 2) bsr = 1.0 + sp.bulletSpeedFanVel + bsv * i;
  525.         else bsr = 1.0 + sp.bulletSpeedFanVel + bsv * (sp.childrenCount - 1 - i);
  526.         var fd:Number;
  527.         if (sp.fireDelayType == CircleSpec.FIX || i < sp.childrenCount / 2) fd = sp.fireDelayVel + fdv * i;
  528.         else fd = sp.fireDelayVel + fdv * (sp.childrenCount - 1 - i);
  529.         addCircleChildren(cc, index - 1, sps, bsr * bulletSpeedRatio, fireDelay + fd);
  530.         c.children.push(cc);
  531.     }
  532.     c.bulletSpeedRatio = bulletSpeedRatio;
  533.     c.ticks = fireDelay;
  534.     c.spec = sp; c.start();
  535. }
  536. // Sparks.
  537. var sparks:Vector.<Spark>;
  538. class Spark extends VelocityActor
  539. {
  540.     public var size:Number;
  541.     public var r:int, g:int, b:int;
  542.     override public function update():Boolean
  543.     {
  544.         vel.scaleBy(0.99);
  545.         size *= 0.95;
  546.         r += (BACKGROUND_BRIGHTNESS - r) * 0.1;
  547.         g += (BACKGROUND_BRIGHTNESS - g) * 0.1;
  548.         b += (BACKGROUND_BRIGHTNESS - b) * 0.1;
  549.         var cr:Number = rand() + 0.5;
  550.         var br:int = r * cr, bg:int = g * cr, bb:int = b * cr;
  551.         if (br > 255) br = 255;
  552.         if (bg > 255) bg = 255;
  553.         if (bb > 255) bb = 255;
  554.         drawBox(pos.x, pos.y, size, size, r * 0x10000 + g * 0x100 + b, 1.5, br, bg, bb);
  555.         return super.update();
  556.     }
  557. }
  558. function addSparks(count:int, x:Number, y:Number, speed:Number, size:Number, r:int, g:int, b:int):void
  559. {
  560.     for (var i:int = 0; i < count; i++)
  561.     {
  562.         var s:Spark = new Spark;
  563.         s.pos.x = x; s.pos.y = y;
  564.         var a:Number = rand() * PI * 2, sp:Number = speed * (0.5 + rand());
  565.         s.vel.x = Math.sin(a) * sp; s.vel.y = Math.cos(a) * sp;
  566.         s.size = size;
  567.         s.r = r; s.g = g; s.b = b;
  568.         s.disappearTicks = 15 + 15 * rand();
  569.         sparks.push(s);
  570.     }
  571. }
  572. // Bonus items.
  573. var bonuses:Vector.<Bonus>;
  574. class Bonus extends VelocityActor
  575. {
  576.     public var isInhaled:Boolean;
  577.     override public function update():Boolean
  578.     {
  579.         var a:Number = ticks * 0.1;
  580.         for (var i:int = 0; i < 4; i++)
  581.         {
  582.             drawBox(pos.x + sin(a) * 10 - 5, pos.y + cos(a) * 10 - 588, 0x6688aa, 1.0150200150);
  583.             a += PI / 2;
  584.         }
  585.         if (isInhaled && gameOverTicks < 0)
  586.         {
  587.             vel.x += (Player.pos.x - pos.x) * 0.05; vel.y += (Player.pos.y - pos.y) * 0.05;
  588.         }
  589.         else vel.y += 0.5;
  590.         vel.scaleBy(0.9);
  591.         var d:Number = Vector3D.distance(pos, Player.pos);
  592.         if (isInhaled && d < 40.0 && gameOverTicks < 0)
  593.         {
  594.             score++; scoreField.text = String(score); return false;
  595.         }
  596.         else if (d < 120.0 && vel.length < 5.0) isInhaled = true;
  597.         return super.update();
  598.     }
  599. }
  600. function addBonuses(count:int, x:Number, y:Number, speed:Number):void
  601. {
  602.     for (var i:int = 0; i < count; i++)
  603.     {
  604.         var b:Bonus = new Bonus;
  605.         b.pos.x = x; b.pos.y = y;
  606.         var a:Number = rand() * PI * 2, sp:Number = speed * (0.5 + rand());
  607.         b.vel.x = Math.sin(a) * sp; b.vel.y = Math.cos(a) * sp;
  608.         bonuses.push(b);
  609.     }
  610. }
  611. // Game field.
  612. class Field
  613. {
  614.     public static const SIDE_BOARD_WIDTH:Number = SCREEN_WIDTH / 6;
  615.     public static var size:Vector3D = new Vector3D;
  616.     public static var offsetX:Number = 0;
  617.     public static function initialize():void
  618.     {
  619.         size.x = SCREEN_WIDTH * 1.1 / 2; size.y = SCREEN_HEIGHT * 1.1 / 2;
  620.     }
  621.     public static function drawSideBoard():void
  622.     {
  623.         rect.width = SIDE_BOARD_WIDTH; rect.height = SCREEN_HEIGHT; rect.y = 0;
  624.         rect.x = 0;                         screen.fillRect(rect, BACKGROUND_COLOR);
  625.         rect.x = SCREEN_WIDTH - rect.width; screen.fillRect(rect, BACKGROUND_COLOR);
  626.     }
  627.     public static function contains(p:Vector3D):Boolean
  628.     {
  629.         return (p.x >= -size.x && p.x <= size.x && p.y >= -size.y && p.y <= size.y);
  630.     }
  631. }
  632. // Blur effect.
  633. const BLUR_MAX_COUNT:int = 512, BLUR_HISTORY_COUNT:int = 6;
  634. var blurs:Vector.<Vector.<Blur>> = new Vector.<Vector.<Blur>>(BLUR_HISTORY_COUNT, true);
  635. var blurCounts:Vector.<int> = new Vector.<int>(BLUR_HISTORY_COUNT, true);
  636. var blurIndex:int;
  637. class Blur
  638. {
  639.     public var pos:Vector3D = new Vector3D;
  640.     public var width:Number, height:Number;
  641.     public var r:int, g:int, b:int;
  642.     public function update():void
  643.     {
  644.         rect.x = pos.x - width  / 2 - Field.offsetX; rect.width = width;
  645.         rect.y = pos.y - height / 2; rect.height = height;
  646.         screen.fillRect(rect, r * 0x10000 + g * 0x100 + b);
  647.         width *= 1.2; height *= 1.2;
  648.         r += (BACKGROUND_BRIGHTNESS - r) * 0.2;
  649.         g += (BACKGROUND_BRIGHTNESS - g) * 0.2;
  650.         b += (BACKGROUND_BRIGHTNESS - b) * 0.2;
  651.     }
  652. }
  653. function drawBox(x:Number, y:Number, w:int, h:int, color:int,
  654.                  blurSizeRatio:Number, br:int, bg:int, bb:int):void
  655. {
  656.     rect.x = x - w / 2 + SCREEN_WIDTH / 2 - Field.offsetX;
  657.     rect.y = y - h / 2 + SCREEN_HEIGHT / 2;
  658.     rect.width = w; rect.height = h;
  659.     screen.fillRect(rect, color);
  660.     if (blurSizeRatio > 0) addBlur(x, y, w * blurSizeRatio, h * blurSizeRatio, br, bg, bb);
  661. }
  662. function addBlur(x:Number, y:Number, w:Number, h:Number, r:int, g:int, b:int):void
  663. {
  664.     if (blurCounts[blurIndex] >= BLUR_MAX_COUNT) return;
  665.     var bl:Blur = blurs[blurIndex][blurCounts[blurIndex]];
  666.     bl.pos.x = x + SCREEN_WIDTH / 2; bl.pos.y = y + SCREEN_HEIGHT / 2;
  667.     bl.width = w; bl.height = h;
  668.     bl.r = r; bl.g = g; bl.b = b;
  669.     blurCounts[blurIndex]++;
  670. }
  671. function updateBlurs():void
  672. {
  673.     var bi:int = blurIndex + 1;
  674.     for (var i:int = 0; i < BLUR_HISTORY_COUNT; i++)
  675.     {
  676.         if (bi >= BLUR_HISTORY_COUNT) bi = 0;
  677.         for (var j:int = 0; j < blurCounts[bi]; j++) blurs[bi][j].update();
  678.         bi++;
  679.     }
  680.     blurIndex++;
  681.     if (blurIndex >= BLUR_HISTORY_COUNT) blurIndex = 0;
  682.     blurCounts[blurIndex] = 0;
  683. }
  684. function initializeBlurs():void
  685. {
  686.     for (var i:int = 0; i < BLUR_HISTORY_COUNT; i++)
  687.     {
  688.         var bs:Vector.<Blur> = new Vector.<Blur>(BLUR_MAX_COUNT, true);
  689.         for (var j:int = 0; j < BLUR_MAX_COUNT; j++) bs[j] = new Blur;
  690.         blurs[i] = bs; blurCounts[i] = 0;
  691.     }
  692.     blurIndex = 0;
  693. }
  694. // Utility classes, functions and variables.
  695. var pos:Vector3D = new Vector3D, offset:Vector3D = new Vector3D;
  696. var rect:Rectangle = new Rectangle;
  697. var rand:Function = Math.random, abs:Function = Math.abs;
  698. var sin:Function = Math.sin, cos:Function = Math.cos, atan2:Function = Math.atan2;
  699. var PI:Number = Math.PI;
  700. class Key
  701. {
  702.     public static var left:Boolean, up:Boolean, right:Boolean, down:Boolean;
  703.     public static var button1:Boolean, button2:Boolean;
  704.     public static function onKeyDown(event:KeyboardEvent):void
  705.     {
  706.         switch (event.keyCode)
  707.         {
  708.             case 0x25:case 0x41: left =    truebreak;
  709.             case 0x26:case 0x57: up =      truebreak;
  710.             case 0x27:case 0x44: right =   truebreak;
  711.             case 0x28:case 0x53: down =    truebreak;
  712.             case 0x5a:case 0xbf: button1 = truebreak;
  713.             case 0x58:case 0xbe: button2 = truebreak;
  714.         }
  715.     }
  716.     public static function onKeyUp(event:KeyboardEvent):void
  717.     {
  718.         switch (event.keyCode)
  719.         {
  720.             case 0x25:case 0x41: left =    falsebreak;
  721.             case 0x26:case 0x57: up =      falsebreak;
  722.             case 0x27:case 0x44: right =   falsebreak;
  723.             case 0x28:case 0x53: down =    falsebreak;
  724.             case 0x5a:case 0xbf: button1 = falsebreak;
  725.             case 0x58:case 0xbe: button2 = falsebreak;
  726.         }
  727.     }
  728. }
  729. function createTextField(x:int, y:int, width:int, size:int, color:int,
  730.                          align:String = TextFormatAlign.LEFT):TextField
  731. {
  732.     var fm:TextFormat = new TextFormat;
  733.     fm.font = "_typewriter"; fm.bold = true;
  734.     fm.size = size; fm.color = color; fm.align = align;
  735.     var fi:TextField = new TextField;
  736.     fi.defaultTextFormat = fm;
  737.     fi.x = x; fi.y = y; fi.width = width; fi.selectable = false;
  738.     return fi;
  739. }
  740. function drawCircle(p:Vector3D, radius:Number, width:Number, color:int, xRatio:Number = 1.0):void
  741. {
  742.     pos.x = p.x + SCREEN_WIDTH / 2 - Field.offsetX;
  743.     pos.y = p.y + SCREEN_HEIGHT / 2;
  744.     var c:int = radius * 1.5;
  745.     var a:Number = 0, oa:Number = PI * 2 / c;
  746.     rect.width = rect.height = width;
  747.     for (var i:int = 0; i < c; i++)
  748.     {
  749.         rect.x = pos.x + sin(a) * radius * xRatio - width / 2;
  750.         rect.y = pos.y + cos(a) * radius - width / 2;
  751.         screen.fillRect(rect, color);
  752.         a += oa;
  753.     }
  754. }
noswf
  1. // forked from ABA's forked from: CircleCycle
  2. // CircleCycle.as
  3. //  Destroy circles and avoid incoming bullets.
  4. //  My ship extends every 200 points.
  5. //  <Operation>
  6. //   Movement   : Mouse
  7. //   Zoom & Slow: Click
  8. package {
  9.     import flash.display.Sprite;
  10.     [SWF(width="465", height="465", backgroundColor="0x000000", frameRate="30")]
  11.     public class CircleCycle extends Sprite { public function CircleCycle() { main = this; initialize(); } }
  12. }
  13. import flash.display.*;
  14. import flash.geom.*;
  15. import flash.text.*;
  16. import flash.events.*;
  17. const SCREEN_WIDTH:int = 465, SCREEN_HEIGHT:int = 465;
  18. const BACKGROUND_BRIGHTNESS:int = 200;
  19. const BACKGROUND_COLOR:int = BACKGROUND_BRIGHTNESS * 0x10000 + BACKGROUND_BRIGHTNESS * 0x100 + BACKGROUND_BRIGHTNESS;
  20. var main:Sprite, screen:BitmapData = new BitmapData(SCREEN_WIDTH, SCREEN_HEIGHT, false0);
  21. var scoreField:TextField = new TextField, messageField:TextField = new TextField;
  22. var score:int, extendScore:int, rank:Number = 0.0, stage:int = 0, targetCircleCount:int;
  23. var ticks:int, isMousePressed:Boolean;
  24. // Initialize UIs.
  25. function initialize():void {
  26.     main.addChild(new Bitmap(screen));
  27.     main.stage.addEventListener(MouseEvent.MOUSE_DOWN, function(e:Event):void { isMousePressed = true; } );
  28.     main.stage.addEventListener(MouseEvent.MOUSE_UP  , function(e:Event):void { isMousePressed = false; } );
  29.     Field.initialize();
  30.     initializeBlurs();
  31.     scoreField = createTextField(SCREEN_WIDTH - 100010024, 0xff6666, TextFormatAlign.RIGHT);
  32.     messageField = createTextField(SCREEN_WIDTH - 256025636, 0xff6666);
  33.     main.addChild(scoreField); main.addChild(messageField);
  34.     startTitle();
  35.     main.addEventListener(Event.ENTER_FRAME, update);
  36. }
  37. // Update the game frame.
  38. function update(event:Event):void {
  39.     screen.lock();
  40.     screen.fillRect(screen.rect, BACKGROUND_COLOR);
  41.     updateBlurs();
  42.     var i:int, spl:int = sparks.length, shl:int = shots.length, bnl:int = bonuses.length;
  43.     for (i = 0; i < spl; i++) if (!sparks[i].update())  { sparks.splice(i, 1);  i--; spl--; }
  44.     for (i = 0; i < shl; i++) if (!shots[i].update())   { shots.splice(i, 1);   i--; shl--; }
  45.     for (i = 0; i < bnl; i++) if (!bonuses[i].update()) { bonuses.splice(i, 1); i--; bnl--; }
  46.     if (targetCircleCount <= 0) addNextTarget();
  47.     if (ticks % 50 == 0)
  48.         addBackgroundCircles((rand() - 0.5) * Field.size.x * 1.5,
  49.                              20.0 / (1.0 + rank), 5.0 + rand() * 2.0 + rand() * 2.0);
  50.     ticks++;
  51.     targetCircleCount = 0;
  52.     for each (var c:Circle in circles) c.update();
  53.     var cl:int = circles.length;
  54.     for (i = 0; i < cl; i++) if (!circles[i].exists) { circles.splice(i, 1); i--; cl--; }
  55.     if (gameOverTicks < 0) Player.update();
  56.     var bl:int = bullets.length;
  57.     for (i = 0; i < bl; i++) if (!bullets[i].update()) { bullets.splice(i, 1); i--; bl--; }
  58.     Field.drawSideBoard();
  59.     Player.drawLeft();
  60.     screen.unlock();
  61.     if (gameOverTicks >= 0) {
  62.         gameOverTicks++; Player.zoom += (1.0 - Player.zoom) * 0.2;
  63.         if (gameOverTicks == GAME_OVER_DURATION) startTitle();
  64.         if (isMousePressed && gameOverTicks > BLOCK_GAME_START_DURATION) startGame();
  65.     }
  66. }
  67. function addNextTarget():void {
  68.     if (rand() < 0.5) addTargetCircles(0140.0 / (1 + rank), MIDS);
  69.     else if (rand() < 0.5)
  70.         addTargetCircles((rand() - 0.5) * Field.size.x * 0.7120.0 / (1.0 + rank), MID_2);
  71.     else
  72.         addTargetCircles((rand() - 0.5) * Field.size.x, 210.0 / (1.0 + rank), BIG);
  73.     rank += 1.0; stage++; if (stage % 10 == 0) rank -= 5.0;
  74. }
  75. // Game actor base class.
  76. class Actor {
  77.     public var pos:Vector3D = new Vector3D;
  78. }
  79. class VelocityActor extends Actor {
  80.     public var vel:Vector3D = new Vector3D;
  81.     public var ticks:int, disappearTicks:int = 300;
  82.     public function update():Boolean {
  83.         pos.incrementBy(vel);
  84.         ticks++;
  85.         if (!Field.contains(pos) || ticks > disappearTicks) return false;
  86.         return true;
  87.     }
  88. }
  89. // Player.
  90. class Player {
  91.     private static const COLLISION_SIZE:Number = 5.0;
  92.     public static var pos:Vector3D = new Vector3D, prevPos:Vector3D = new Vector3D;
  93.     public static var fireTicks:int, invincibleTicks:int, left:int;
  94.     public static var zoom:Number = 1.0;
  95.     public static function start():void {
  96.         pos.x = 0; pos.y = Field.size.y * 0.5; invincibleTicks = 0; left = 0; zoom = 1.0;
  97.     }
  98.     public static function update():void {
  99.         prevPos.x = pos.x; prevPos.y = pos.y;
  100.         var tx:Number = (main.stage.mouseX - SCREEN_WIDTH / 2) * 1.5;
  101.         var ty:Number = main.stage.mouseY - SCREEN_HEIGHT / 2;
  102.         pos.x += (tx - pos.x) * 0.3; pos.y += (ty - pos.y) * 0.3;
  103.         if (pos.x < -SCREEN_WIDTH  / 2) pos.x = -SCREEN_WIDTH / 2;
  104.         if (pos.x >  SCREEN_WIDTH  / 2) pos.x =  SCREEN_WIDTH / 2;
  105.         Field.offsetX = pos.x * 0.33;
  106.         if (isMousePressed) zoom += (2.0 - zoom) * 0.1;
  107.         else zoom += (1.0 - zoom) * 0.2;
  108.         if (score >= extendScore) {
  109.             if (left < 2) left++;
  110.             extendScore += 200;
  111.         }
  112.         if (invincibleTicks <= 0 || (invincibleTicks % 6) > 3) {
  113.             drawCircle(pos, 157, 0x008800, 0.5);
  114.             addBlur(pos.x, pos.y, 2020100200100);
  115.         }
  116.         invincibleTicks--;
  117.         if (invincibleTicks > 0return;
  118.         if (fireTicks <= 0 && shots.length <= 14) {
  119.             fireTicks = 2;
  120.             var s:Shot;
  121.             for (var i:int = 0; i < 7; i++) {
  122.                 s = new Shot;
  123.                 s.pos.x = pos.x; s.pos.y = pos.y;
  124.                 var a:Number = (i - 3) * 0.1;
  125.                 s.vel.x = sin(a) * 24.0; s.vel.y = -cos(a) * 24.0;
  126.                 shots.push(s);
  127.             }
  128.         }
  129.         fireTicks--;
  130.         p.x = (pos.x + prevPos.x) / 2; p.y = (pos.y + prevPos.y) / 2;
  131.         for each (var b:Bullet in bullets) {
  132.             if (Vector3D.distance(pos, b.pos)     <= COLLISION_SIZE ||
  133.                 Vector3D.distance(prevPos, b.pos) <= COLLISION_SIZE ||
  134.                 Vector3D.distance(p, b.pos)       <= COLLISION_SIZE) {
  135.                 addSparks(100, Player.pos.x, Player.pos.y, 30.015.0200100100);
  136.                 left--; if (left < 0) { startGameOver(); return; }
  137.                 invincibleTicks = 30;
  138.                 bullets = null; bullets = new Vector.<Bullet>;
  139.                 return;
  140.             }
  141.         }
  142.     }
  143.     public static function drawLeft():void {
  144.         p.x = 15; p.y = 20;
  145.         for (var i:int = 0; i < left; i++) {
  146.             drawCircleWithoutOffset(p, 157, 0x008800, 0.5);
  147.             p.x += 30;
  148.         }
  149.     }
  150. }
  151. // Player's shots.
  152. var shots:Vector.<Shot>;
  153. class Shot extends VelocityActor
  154. {
  155.     override public function update():Boolean {
  156.         for each (var c:Circle in circles) if (checkHit(c)) return false;
  157.         addBlur(pos.x, pos.y, 201550150100);
  158.         return super.update();
  159.     }
  160.     private function checkHit(c:Circle):Boolean {
  161.         for each (var cc:Circle in c.children) if (cc.exists && checkHit(cc)) return true;
  162.         if (c.exists && c.hasCollision && Vector3D.distance(pos, c.pos) < c.spec.visualRadius + 20.0) {
  163.             addSparks(1, pos.x, pos.y, 20.05.050150100);
  164.             c.damage(); return true;
  165.         }
  166.         return false;
  167.     }
  168. }
  169. // Circles.
  170. var circles:Vector.<Circle>;
  171. class Circle extends Actor {
  172.     public var children:Vector.<Circle> = null;
  173.     public var isTop:Boolean, exists:Boolean = true;
  174.     public var spec:CircleSpec;
  175.     public var bulletSpeedRatio:Number = 1.0;
  176.     public var rollAngle:Number = 0, fireAngle:Number = 0, fireSpeed:Number, angleInterval:Number;
  177.     public var baseAngle:Number = 0, lastFireAngle:Number = 0;
  178.     public var ticks:int, shield:int;
  179.     public var hasCollision:Boolean, isTarget:Boolean, isDamaged:Boolean;
  180.     public var speed:Number, targetY:Number = Field.size.y * 2;
  181.     public var xReverse:Number = 1.0;
  182.     public var circleWidth:Number = 5.0, color:int;
  183.     public function start():void {
  184.         color = (int)(spec.r / 2) * 0x10000 + int(spec.g / 2) * 0x100 + int(spec.b / 2);
  185.         shield = spec.shield;
  186.     }
  187.     public function update():void {
  188.         var vr:Number = spec.visualRadius;
  189.         if (spec.fireInterval > 0) vr *= ((ticks % spec.fireInterval) / spec.fireInterval * 0.5 + 1.0);
  190.         drawCircle(pos, vr, circleWidth, color);
  191.         var i:int;
  192.         if (isDamaged) {
  193.             isDamaged = false;
  194.             var da:Number = ticks * 0.1, sr:Number = spec.visualRadius, bc:int = sr * 0.5;
  195.             for (i = 0; i < bc; i++) {
  196.                 addBlur(pos.x + sr * sin(da), pos.y + sr * cos(da),
  197.                         9 + rand() * 79 + rand() * 7, rand() * 128 + 64, rand() * 128 + 12764);
  198.                 da += PI * 2 / bc;
  199.             }
  200.         }
  201.         if (spec.isAimingBaseAngle) lastFireAngle = atan2(Player.pos.x - pos.x, Player.pos.y - pos.y);
  202.         else lastFireAngle = baseAngle * xReverse;
  203.         lastFireAngle += rollAngle + fireAngle;
  204.         if (spec.fireInterval > 0 && ticks % spec.fireInterval == 0 && pos.y < 0 &&
  205.             pos.x - Field.offsetX > -Field.size.x + Field.SIDE_BOARD_WIDTH &&
  206.             pos.x - Field.offsetX <  Field.size.x - Field.SIDE_BOARD_WIDTH &&
  207.             (!spec.isAimingBaseAngle || Vector3D.distance(pos, Player.pos) > 120)) {
  208.             var srv:Number = spec.bulletSpeedWhipVel * 2 / spec.bulletCount;
  209.             var fd:int = 0;
  210.             var pc:Circle = nullif (spec.hasFireParent) pc = this;
  211.             for (i = 0; i < spec.bulletCount; i++) {
  212.                 fire(lastFireAngle, 1.0 - spec.bulletSpeedWhipVel + srv * i, fd, pc);
  213.                 fd += spec.fireWhipDelay;
  214.             }
  215.         }
  216.         ticks++;
  217.         if (isTop) {
  218.             if (pos.y < targetY) pos.y += speed;
  219.             else pos.y += speed * 0.3;
  220.             if (isTarget && pos.y > 0) pos.y += speed * 0.5;
  221.             if (pos.y > Field.size.y + spec.radius) remove();
  222.         }
  223.         if (isTarget) targetCircleCount++;
  224.         if (children == nullreturn;
  225.         rollAngle = spec.rollAngle.getValue(ticks);
  226.         fireAngle = spec.fireAngle.getValue(ticks);
  227.         fireSpeed = spec.fireSpeed.getValue(ticks);
  228.         angleInterval = spec.angleInterval.getValue(ticks);
  229.         if (spec.isAimingRollAngle) rollAngle += atan2(Player.pos.x - pos.x, Player.pos.y - pos.y) * xReverse;
  230.         var a:Number = rollAngle - angleInterval * (children.length - 1) / 2 - angleInterval;
  231.         for each (var c:Circle in children) {
  232.             a += angleInterval;
  233.             if (!c.exists) continue;
  234.             c.pos.x = pos.x + sin(a) * spec.radius * xReverse;
  235.             c.pos.y = pos.y + cos(a) * spec.radius;
  236.             c.baseAngle = a + fireAngle;
  237.             c.update();
  238.         }
  239.     }
  240.     private function fire(a:Number, sr:Number, delay:int, parentCircle:Circle):void {
  241.         var b:Bullet = new Bullet;
  242.         b.pos.x = pos.x; b.pos.y = pos.y;
  243.         var bs:Number = spec.bulletSpeed * bulletSpeedRatio * sr;
  244.         b.baseVel.x = sin(a) * bs; b.baseVel.y = cos(a) * bs; b.speed = bs;
  245.         b.delayTicks = delay; b.parentCircle = parentCircle;
  246.         b.size = spec.bulletSize;
  247.         b.br = spec.r; b.bg = spec.g; b.bb = spec.b;
  248.         b.color = int(b.br / 4) * 0x10000 + int(b.bg / 4) * 0x100 + int(b.bb / 4);
  249.         bullets.push(b);
  250.     }
  251.     public function damage():void {
  252.         isDamaged = true;
  253.         shield--;
  254.         if (shield <= 0) remove(true);
  255.     }
  256.     public function remove(isDestroyed:Boolean = false):void {
  257.         for each (var c:Circle in children) if (c.exists) c.remove();
  258.         children = null;
  259.         exists = false;
  260.         if (!isDestroyed) return;
  261.         var sa:Number = ticks * 0.1, sr:Number = spec.visualRadius, sc:int = sr * 0.5, i:int;
  262.         for (i = 0; i < sc; i++) {
  263.             addSparks(1, pos.x + sr * sin(sa), pos.y + sr * cos(sa), 10.010.0, spec.r, spec.g, spec.b);
  264.             sa += PI * 2 / sc;
  265.         }
  266.         addBonuses(sr * sr * 2 / (abs(pos.y - Player.pos.y) + 30.0), pos.x, pos.y, 10.0);
  267.     }
  268.     public function setXReverse():void {
  269.         xReverse = -1.0;
  270.         for each (var c:Circle in children) c.setXReverse();
  271.     }
  272. }
  273. class CircleSpec {
  274.     public static const FIX:int = 0, WEDGE:int = 1;
  275.     public var radius:Number, visualRadius:Number;
  276.     public var isRound:Boolean;
  277.     public var rollAngle:Waveform = new Waveform;
  278.     public var isAimingRollAngle:Boolean, isAimingBaseAngle:Boolean;
  279.     public var fireAngle:Waveform = new Waveform, fireSpeed:Waveform = new Waveform;
  280.     public var fireInterval:int = -1;
  281.     public var angleInterval:Waveform = new Waveform;
  282.     public var bulletSpeed:Number = 7.0, bulletSize:Number = 15.0;
  283.     public var bulletSpeedFanType:int, bulletSpeedFanVel:Number = 0;
  284.     public var fireDelayType:int, fireDelayVel:Number = 0;
  285.     public var bulletCount:int = 1;
  286.     public var bulletSpeedWhipVel:Number = 0, fireWhipDelay:int = 0, hasFireParent:Boolean;
  287.     public var r:int, g:int, b:int;
  288.     public var childrenCount:int;
  289.     public var shield:int;
  290.     public function set(childrenCount:int, radius:Number, childRadius:Number):void {
  291.         this.childrenCount = childrenCount;
  292.         this.radius = radius; visualRadius = radius + childRadius;
  293.         shield = radius;
  294.         rollAngle.width = (0.5 + rand() * 0.5) * ((int)(rand() * 2) * 2 - 1);
  295.         isRound = (rand() < 0.25);
  296.         if (isRound) {
  297.             rollAngle.type = Waveform.MONOTONE;
  298.             rollAngle.interval = 60 + rand() * 60;
  299.             if (rand() < 0.4) fireAngle.type = Waveform.MONOTONE;
  300.             fireAngle.width = (2.0 + rand() * 2.0) * ((int)(rand() * 2) * 2 - 1);
  301.             fireAngle.interval = 90 + rand() * 90;
  302.             if (rand() < 0.3) fireAngle.center = rand() * PI * 2;
  303.             angleInterval.center = PI * 2 / childrenCount;
  304.         } else {
  305.             isAimingRollAngle = true;
  306.             if (rand() < 0.3) rollAngle.type = Waveform.SIN;
  307.             rollAngle.interval = 120 + rand() * 90;
  308.             if (rand() < 0.3) angleInterval.type = Waveform.SIN;
  309.             angleInterval.center = ((2.0 + rand() * 2.0) / childrenCount) * ((int)(rand() * 2) * 2 - 1);
  310.             angleInterval.width = angleInterval.center * (0.3 + rand() * 0.3);
  311.             angleInterval.interval = 60 + rand() * 60;
  312.         }
  313.         if (rand() < 0.5) bulletSpeedFanType = WEDGE;
  314.         if (rand() < 0.5) bulletSpeedFanVel = (0.3 + rand() * 0.2) * ((int)(rand() * 2) * 2 - 1);
  315.         if (rand() < 0.5) fireDelayType = WEDGE;
  316.         if (rand() < 0.5) fireDelayVel = (8.0 + rand() * 6.0) * ((int)(rand() * 2) * 2 - 1);
  317.     }
  318. }
  319. class Waveform {
  320.     public static const FIX:int = 0, MONOTONE:int = 1, SIN:int = 2;
  321.     public var type:int = FIX, center:Number = 0, width:Number = 0, interval:int = 1;
  322.     public function getValue(ticks:int):Number {
  323.         switch (type) {
  324.             case FIX:      return center;
  325.             case MONOTONE: return center + width * ticks * 2 / interval;
  326.             case SIN:      return center + width * sin(PI * 2 * ticks / interval);
  327.         }
  328.         return 0;
  329.     }
  330. }
  331. const BIG:int = 0, MID_2:int = 1, MIDS:int = 2;
  332. function addTargetCircles(x:Number, depth:int, fireIntervalRatio:Number, type:int):void {
  333.     var bulletSpeed:Number = 5.0 + rand() * 2.0 + rand() * 2.0;
  334.     var radius:Number = (20 + rand() * 20) * depth;
  335.     var c:Circle = new Circle;
  336.     if (type == MIDS) x = (rand() - 0.5) * Field.size.x;
  337.     var rw:Number = 0;
  338.     if (type == MID_2) rw = (rand() * 0.1 + 0.1) * Field.size.x;
  339.     var cy:Number = -Field.size.y * (1.0 + rand() * 2.0) - radius;
  340.     c.pos.x = x - rw; c.pos.y = cy;
  341.     c.isTop = true; c.hasCollision = true; c.isTarget = true;
  342.     var spd:Number, ty:Number;
  343.     if (type != MIDS) {
  344.         spd = 5.0 + rand() * 2.0; ty = -Field.size.y * (0.5 + rand() * 0.2);
  345.     } else {
  346.         spd = 3.5 + rand(); ty = Field.size.y * 2;
  347.     }
  348.     c.speed = spd; c.targetY = ty;
  349.     var r:int, g:int, b:int;
  350.     r = 127 + rand() * 128; g = 127 + rand() * 128; b = 127 + rand() * 128;
  351.     var sps:Vector.<CircleSpec> = new Vector.<CircleSpec>;
  352.     var turretCount:int = createCircleSpecs(sps, radius, depth, r, g, b);
  353.     var sp:CircleSpec;
  354.     for each (sp in sps) if (sp.isRound) turretCount *= 0.75;
  355.     sp = sps[0];
  356.     sp.fireInterval = turretCount * fireIntervalRatio + 1;
  357.     sp.bulletSpeed = bulletSpeed; sp.bulletSize = 12.0 + depth * 2;
  358.     addCircleChildren(c, sps.length - 1, sps, 1.00);
  359.     circles.push(c);
  360.     if (type == MID_2) {
  361.         c = new Circle;
  362.         c.pos.x = x + rw; c.pos.y = cy;
  363.         c.isTop = true; c.hasCollision = true; c.isTarget = true;
  364.         c.speed = spd; c.targetY = ty;
  365.         addCircleChildren(c, sps.length - 1, sps, 1.00);
  366.         c.setXReverse();
  367.         circles.push(c);
  368.     } else if (type == MIDS) {
  369.         for (var i:int = 0; i < 3; i++) {
  370.             c = new Circle;
  371.             c.pos.x = (rand() - 0.5) * Field.size.x;
  372.             c.pos.y = -Field.size.y * (1.0 + rand()) - radius;
  373.             c.isTop = true; c.hasCollision = true; c.isTarget = true;
  374.             c.speed = spd;
  375.             addCircleChildren(c, sps.length - 1, sps, 1.00);
  376.             if (rand() < 0.5) c.setXReverse();
  377.             circles.push(c);
  378.         }
  379.     }
  380. }
  381. function addBackgroundCircles(x:Number, fireIntervalRatio:Number, bulletSpeed:Number):void {
  382.     var radius:Number = (60 + rand() * 60);
  383.     var c:Circle = new Circle;
  384.     c.pos.x = x; c.pos.y = -Field.size.y - radius;
  385.     c.isTop = true; c.speed = 3.0;
  386.     c.circleWidth = 3.0;
  387.     var csp:CircleSpec = new CircleSpec;
  388.     csp.radius = 0; csp.visualRadius = 15.0; csp.childrenCount = 0;
  389.     csp.shield = 3;
  390.     csp.isAimingBaseAngle = true;
  391.     csp.bulletSpeed = bulletSpeed;
  392.     csp.r = csp.g = csp.b = 200;
  393.     var sp:CircleSpec = new CircleSpec;
  394.     sp.r = sp.g = sp.b = 300;
  395.     if (rand() < 0.5) {
  396.         sp.radius = sp.visualRadius = radius;
  397.         c.spec = sp; c.start();
  398.         circles.push(c); return;
  399.     }
  400.     sp.childrenCount = 3 + rand() * 7;
  401.     csp.fireInterval = sp.childrenCount * fireIntervalRatio + 1;
  402.     sp.radius = radius; sp.visualRadius = radius - csp.visualRadius;
  403.     sp.rollAngle.width = (0.5 + rand() * 0.5) * ((int)(rand() * 2) * 2 - 1);
  404.     sp.rollAngle.type = Waveform.MONOTONE;
  405.     sp.rollAngle.interval = 60 + rand() * 60;
  406.     sp.angleInterval.center = ((2.0 + rand() * 2.0) / sp.childrenCount);
  407.     if (rand() < 0.5) sp.fireDelayVel = (8.0 + rand() * 6.0) * ((int)(rand() * 2) * 2 - 1);
  408.     c.children = new Vector.<Circle>;
  409.     var cct:int = 0;
  410.     for (var i:int = 0; i < sp.childrenCount; i++) {
  411.         var cc:Circle = new Circle;
  412.         cc.hasCollision = true;
  413.         cc.spec = csp; cc.start();
  414.         cc.ticks = cct; cct += sp.fireDelayVel;
  415.         c.children.push(cc);
  416.     }
  417.     c.spec = sp; c.start();
  418.     circles.push(c);
  419. }
  420. function createCircleSpecs(sps:Vector.<CircleSpec>, radius:Number, depth:int, r:int, g:int, b:int):int {
  421.     var sp:CircleSpec = new CircleSpec;
  422.     sp.r = r; sp.g = g; sp.b = b;
  423.     var turretCount:int;
  424.     if (depth == 0) {
  425.         sp.radius = 0; sp.visualRadius = radius; sp.childrenCount = 0;
  426.         if (rand() < 0.6) {
  427.             sp.bulletCount = 2 + rand() * 5;
  428.             sp.bulletSpeedWhipVel = 0.2 + rand() * 0.2;
  429.             if (rand() < 0.7) sp.fireWhipDelay = 2 + rand() * 4;
  430.             if (rand() < 0.7) sp.hasFireParent = true;
  431.             turretCount = sp.bulletCount * 0.75;
  432.         }
  433.         else turretCount = 1;
  434.     } else {
  435.         sp.childrenCount = 1 + rand() * 7;
  436.         var cr:Number = radius * (0.33 + rand() * 0.1);
  437.         sp.set(sp.childrenCount, radius, cr);
  438.         turretCount = createCircleSpecs(sps, cr, depth - 1, r, g, b) * sp.childrenCount;
  439.     }
  440.     sps.push(sp);
  441.     return turretCount;
  442. }
  443. function addCircleChildren(c:Circle, index:int, sps:Vector.<CircleSpec>,
  444.                            bulletSpeedRatio:Number, fireDelay:Number):void {
  445.     var sp:CircleSpec = sps[index];
  446.     var bsv:Number = -sp.bulletSpeedFanVel * 2 / sp.childrenCount;
  447.     var fdv:Number = -sp.fireDelayVel * 2 / sp.childrenCount;
  448.     if (sp.bulletSpeedFanType == CircleSpec.WEDGE) bsv *= 2;
  449.     if (sp.fireDelayType == CircleSpec.WEDGE) fdv *= 2;
  450.     if (sp.childrenCount > 0) c.children = new Vector.<Circle>;
  451.     for (var i:int = 0; i < sp.childrenCount; i++) {
  452.         var cc:Circle = new Circle;
  453.         var bsr:Number;
  454.         if (sp.bulletSpeedFanType == CircleSpec.FIX ||
  455.             i < sp.childrenCount / 2) bsr = 1.0 + sp.bulletSpeedFanVel + bsv * i;
  456.         else bsr = 1.0 + sp.bulletSpeedFanVel + bsv * (sp.childrenCount - 1 - i);
  457.         var fd:Number;
  458.         if (sp.fireDelayType == CircleSpec.FIX || i < sp.childrenCount / 2) fd = sp.fireDelayVel + fdv * i;
  459.         else fd = sp.fireDelayVel + fdv * (sp.childrenCount - 1 - i);
  460.         addCircleChildren(cc, index - 1, sps, bsr * bulletSpeedRatio, fireDelay + fd);
  461.         c.children.push(cc);
  462.     }
  463.     c.bulletSpeedRatio = bulletSpeedRatio;
  464.     c.ticks = fireDelay;
  465.     c.spec = sp; c.start();
  466. }
  467. // Circles' bullets.
  468. var bullets:Vector.<Bullet>;
  469. class Bullet extends VelocityActor {
  470.     public var baseVel:Vector3D = new Vector3D, speed:Number;
  471.     public var parentCircle:Circle, delayTicks:int = 0;
  472.     public var color:int, br:int, bg:int, bb:int, size:int;
  473.     override public function update():Boolean {
  474.         if (delayTicks > 0) {
  475.             delayTicks--;
  476.             if (delayTicks <= 0 && parentCircle != null) {
  477.                 pos.x = parentCircle.pos.x; pos.y = parentCircle.pos.y;
  478.                 baseVel.x = sin(parentCircle.lastFireAngle) * speed;
  479.                 baseVel.y = cos(parentCircle.lastFireAngle) * speed;
  480.                 parentCircle = null;
  481.             }
  482.             return true;
  483.         }
  484.         var sz:Number = 1.5 + Math.sin(ticks * 0.2) * 0.4;
  485.         var a:Number = 0.8 + Math.sin(ticks * 0.45) * 0.2;
  486.         drawBox(pos.x, pos.y, size, size, color, sz, br * a, bg * a, bb * a);
  487.         if (ticks <= 15) {
  488.             vel.x = baseVel.x * (ticks + 15) / 30.0; vel.y = baseVel.y * (ticks + 15) / 30.0;
  489.         } else {
  490.             vel.x = baseVel.x; vel.y = baseVel.y;
  491.         }
  492.         if (isMousePressed) vel.scaleBy(0.5);
  493.         return super.update();
  494.     }
  495. }
  496. // Sparks.
  497. var sparks:Vector.<Spark>;
  498. class Spark extends VelocityActor {
  499.     public var size:Number;
  500.     public var r:int, g:int, b:int;
  501.     override public function update():Boolean {
  502.         vel.scaleBy(0.99);
  503.         size *= 0.95;
  504.         r += (BACKGROUND_BRIGHTNESS - r) * 0.1;
  505.         g += (BACKGROUND_BRIGHTNESS - g) * 0.1;
  506.         b += (BACKGROUND_BRIGHTNESS - b) * 0.1;
  507.         var cr:Number = rand() + 0.5;
  508.         var br:int = r * cr, bg:int = g * cr, bb:int = b * cr;
  509.         if (br > 255) br = 255;
  510.         if (bg > 255) bg = 255;
  511.         if (bb > 255) bb = 255;
  512.         drawBox(pos.x, pos.y, size, size, r * 0x10000 + g * 0x100 + b, 1.5, br, bg, bb);
  513.         return super.update();
  514.     }
  515. }
  516. function addSparks(count:int, x:Number, y:Number, speed:Number, size:Number, r:int, g:int, b:int):void {
  517.     for (var i:int = 0; i < count; i++) {
  518.         var s:Spark = new Spark;
  519.         s.pos.x = x; s.pos.y = y;
  520.         var a:Number = rand() * PI * 2, sp:Number = speed * (0.5 + rand());
  521.         s.vel.x = Math.sin(a) * sp; s.vel.y = Math.cos(a) * sp;
  522.         s.size = size;
  523.         s.r = r; s.g = g; s.b = b;
  524.         s.disappearTicks = 15 + 15 * rand();
  525.         sparks.push(s);
  526.     }
  527. }
  528. // Bonus items.
  529. var bonuses:Vector.<Bonus>;
  530. class Bonus extends VelocityActor {
  531.     public var isInhaled:Boolean;
  532.     override public function update():Boolean {
  533.         var a:Number = ticks * 0.1;
  534.         for (var i:int = 0; i < 4; i++) {
  535.             drawBox(pos.x + sin(a) * 10 - 5, pos.y + cos(a) * 10 - 588, 0x6688aa, 1.0150200150);
  536.             a += PI / 2;
  537.         }
  538.         if (isInhaled && gameOverTicks < 0) {
  539.             vel.x += (Player.pos.x - pos.x) * 0.05; vel.y += (Player.pos.y - pos.y) * 0.05;
  540.         }
  541.         else vel.y += 0.5;
  542.         vel.scaleBy(0.9);
  543.         var d:Number = Vector3D.distance(pos, Player.pos);
  544.         if (isInhaled && d < 40.0 && gameOverTicks < 0) {
  545.             scoreField.text = String(score++); return false;
  546.         }
  547.         else if (d < 120.0 && vel.length < 5.0) isInhaled = true;
  548.         return super.update();
  549.     }
  550. }
  551. function addBonuses(count:int, x:Number, y:Number, speed:Number):void {
  552.     for (var i:int = 0; i < count; i++) {
  553.         var b:Bonus = new Bonus;
  554.         b.pos.x = x; b.pos.y = y;
  555.         var a:Number = rand() * PI * 2, sp:Number = speed * (0.5 + rand());
  556.         b.vel.x = Math.sin(a) * sp; b.vel.y = Math.cos(a) * sp;
  557.         bonuses.push(b);
  558.     }
  559. }
  560. // Game field.
  561. class Field {
  562.     public static const SIDE_BOARD_WIDTH:Number = SCREEN_WIDTH / 6;
  563.     public static var size:Vector3D = new Vector3D;
  564.     public static var offsetX:Number = 0;
  565.     public static function initialize():void {
  566.         size.x = SCREEN_WIDTH * 1.1 / 2; size.y = SCREEN_HEIGHT * 1.1 / 2;
  567.     }
  568.     public static function drawSideBoard():void {
  569.         rect.width = SIDE_BOARD_WIDTH; rect.height = SCREEN_HEIGHT; rect.y = 0;
  570.         rect.x = 0;                         screen.fillRect(rect, BACKGROUND_COLOR);
  571.         rect.x = SCREEN_WIDTH - rect.width; screen.fillRect(rect, BACKGROUND_COLOR);
  572.     }
  573.     public static function contains(p:Vector3D):Boolean {
  574.         return (p.x >= -size.x && p.x <= size.x && p.y >= -size.y && p.y <= size.y);
  575.     }
  576. }
  577. // Blur effect.
  578. const BLUR_MAX_COUNT:int = 512, BLUR_HISTORY_COUNT:int = 6;
  579. var blurs:Vector.<Vector.<Blur>> = new Vector.<Vector.<Blur>>(BLUR_HISTORY_COUNT, true);
  580. var blurCounts:Vector.<int> = new Vector.<int>(BLUR_HISTORY_COUNT, true);
  581. var blurIndex:int;
  582. class Blur {
  583.     public var pos:Vector3D = new Vector3D;
  584.     public var width:Number, height:Number;
  585.     public var r:int, g:int, b:int;
  586.     public function update():void {
  587.         if (Player.zoom < 1.1) {
  588.             rect.x = pos.x - width / 2 + SCREEN_WIDTH / 2 - Field.offsetX; 
  589.             rect.y = pos.y - height / 2 + SCREEN_HEIGHT / 2
  590.             rect.width = width; rect.height = height;
  591.         } else {
  592.             rect.width = width * Player.zoom; rect.height = height * Player.zoom;
  593.             rect.x = (pos.x - Player.pos.x) * Player.zoom + Player.pos.x - rect.width / 2 +
  594.                 SCREEN_WIDTH / 2 - Field.offsetX; 
  595.             rect.y = (pos.y - Player.pos.y) * Player.zoom + Player.pos.y - rect.height / 2 + SCREEN_HEIGHT / 2;
  596.         }
  597.         screen.fillRect(rect, r * 0x10000 + g * 0x100 + b);
  598.         width *= 1.2; height *= 1.2;
  599.         r += (BACKGROUND_BRIGHTNESS - r) * 0.2;
  600.         g += (BACKGROUND_BRIGHTNESS - g) * 0.2;
  601.         b += (BACKGROUND_BRIGHTNESS - b) * 0.2;
  602.     }
  603. }
  604. function drawBox(x:Number, y:Number, w:int, h:int, color:int, blurSizeRatio:Number, br:int, bg:int, bb:int):void {
  605.     if (Player.zoom < 1.1) {
  606.         rect.x = x - w / 2 + SCREEN_WIDTH / 2 - Field.offsetX;
  607.         rect.y = y - h / 2 + SCREEN_HEIGHT / 2;
  608.         rect.width = w; rect.height = h;
  609.     } else {
  610.         var sx:Number = (x - Player.pos.x) * Player.zoom + Player.pos.x;
  611.         var sy:Number = (y - Player.pos.y) * Player.zoom + Player.pos.y;
  612.         rect.x = sx - w / 2 + SCREEN_WIDTH / 2 - Field.offsetX;
  613.         rect.y = sy - h / 2 + SCREEN_HEIGHT / 2;
  614.         rect.width = w * Player.zoom; rect.height = h * Player.zoom;
  615.     }
  616.     screen.fillRect(rect, color);
  617.     if (blurSizeRatio > 0) addBlur(x, y, w * blurSizeRatio, h * blurSizeRatio, br, bg, bb);
  618. }
  619. function addBlur(x:Number, y:Number, w:Number, h:Number, r:int, g:int, b:int):void {
  620.     if (blurCounts[blurIndex] >= BLUR_MAX_COUNT) return;
  621.     var bl:Blur = blurs[blurIndex][blurCounts[blurIndex]];
  622.     bl.pos.x = x; bl.pos.y = y;
  623.     bl.width = w; bl.height = h;
  624.     bl.r = r; bl.g = g; bl.b = b;
  625.     blurCounts[blurIndex]++;
  626. }
  627. function updateBlurs():void {
  628.     var bi:int = blurIndex + 1;
  629.     for (var i:int = 0; i < BLUR_HISTORY_COUNT; i++) {
  630.         if (bi >= BLUR_HISTORY_COUNT) bi = 0;
  631.         for (var j:int = 0; j < blurCounts[bi]; j++) blurs[bi][j].update();
  632.         bi++;
  633.     }
  634.     blurIndex++;
  635.     if (blurIndex >= BLUR_HISTORY_COUNT) blurIndex = 0;
  636.     blurCounts[blurIndex] = 0;
  637. }
  638. function initializeBlurs():void {
  639.     for (var i:int = 0; i < BLUR_HISTORY_COUNT; i++) {
  640.         var bs:Vector.<Blur> = new Vector.<Blur>(BLUR_MAX_COUNT, true);
  641.         for (var j:int = 0; j < BLUR_MAX_COUNT; j++) bs[j] = new Blur;
  642.         blurs[i] = bs; blurCounts[i] = 0;
  643.     }
  644.     blurIndex = 0;
  645. }
  646. // Handle the game lifecycle.
  647. const GAME_OVER_DURATION:int = 150, BLOCK_GAME_START_DURATION:int = 30;
  648. var gameOverTicks:int;
  649. function startTitle():void {
  650.     clearActors();
  651.     gameOverTicks = GAME_OVER_DURATION;
  652.     messageField.y = SCREEN_HEIGHT / 3 * 2; messageField.text = "CircleCycle";
  653. }
  654. function startGame():void {
  655.     gameOverTicks = -1;
  656.     clearActors(); Player.start();
  657.     messageField.text = ""; scoreField.text = String(score = 0);
  658.     extendScore = 200; rank = 0.0; stage = 0;
  659. }
  660. function startGameOver():void {
  661.     gameOverTicks = 0; isMousePressed = false;
  662.     messageField.y = SCREEN_HEIGHT / 2; messageField.text = "GAME OVER";
  663. }
  664. function clearActors():void {
  665.     shots = null; bullets = null; sparks = null; bonuses = null; circles = null;
  666.     shots = new Vector.<Shot>; bullets = new Vector.<Bullet>; sparks = new Vector.<Spark>; bonuses = new Vector.<Bonus>;
  667.     circles = new Vector.<Circle>; targetCircleCount = 0;
  668. }
  669. // Utility classes, functions and variables.
  670. var p:Vector3D = new Vector3D, offset:Vector3D = new Vector3D;
  671. var rect:Rectangle = new Rectangle;
  672. var rand:Function = Math.random, abs:Function = Math.abs;
  673. var sin:Function = Math.sin, cos:Function = Math.cos, atan2:Function = Math.atan2;
  674. var PI:Number = Math.PI;
  675. function createTextField(x:int, y:int, width:int, size:int, color:int,
  676.                          align:String = TextFormatAlign.LEFT):TextField {
  677.     var fm:TextFormat = new TextFormat;
  678.     fm.font = "_typewriter"; fm.bold = true;
  679.     fm.size = size; fm.color = color; fm.align = align;
  680.     var fi:TextField = new TextField;
  681.     fi.defaultTextFormat = fm;
  682.     fi.x = x; fi.y = y; fi.width = width; fi.selectable = false;
  683.     return fi;
  684. }
  685. function drawCircle(pos:Vector3D, radius:Number, width:Number, color:int, xRatio:Number = 1.0):void {
  686.     if (Player.zoom < 1.1) {
  687.         p.x = pos.x + SCREEN_WIDTH / 2 - Field.offsetX;
  688.         p.y = pos.y + SCREEN_HEIGHT / 2;
  689.     } else {
  690.         p.x = (pos.x - Player.pos.x) * Player.zoom + Player.pos.x + SCREEN_WIDTH / 2 - Field.offsetX;
  691.         p.y = (pos.y - Player.pos.y) * Player.zoom + Player.pos.y + SCREEN_HEIGHT / 2;
  692.     }
  693.     drawCircleWithoutOffset(p, radius * Player.zoom, width, color, xRatio);
  694. }
  695. function drawCircleWithoutOffset(p:Vector3D, radius:Number, width:Number, color:int, xRatio:Number = 1.0):void {
  696.     var c:int = radius * 1.5;
  697.     var a:Number = 0, oa:Number = PI * 2 / c;
  698.     rect.width = rect.height = width;
  699.     for (var i:int = 0; i < c; i++) {
  700.         rect.x = p.x + sin(a) * radius * xRatio - width / 2;
  701.         rect.y = p.y + cos(a) * radius - width / 2;
  702.         screen.fillRect(rect, color);
  703.         a += oa;
  704.     }
  705. }
noswf
  1. // forked from ABA's forked from: CircleCycle
  2. // forked from ABA's CircleCycle
  3. // CircleCycle.as
  4. //  Destroy circles and avoid incoming bullets.
  5. //  <Control>
  6. //   Movement: Arrow or [WASD] keys.
  7. //   Fire:    [Z] or [/] key.
  8. //   Slow:    [X] or [.] key.
  9. package
  10. {
  11.     import flash.display.Sprite;
  12.     [SWF(width="465", height="465", backgroundColor="0x000000", frameRate="30")]
  13.     public class CircleCycle extends Sprite
  14.     {
  15.         public function CircleCycle()
  16.         {
  17.             main = this;
  18.             initialize();
  19.         }
  20.     }
  21. }
  22. import flash.display.Sprite;
  23. import flash.display.Bitmap;
  24. import flash.display.BitmapData;
  25. import flash.geom.Rectangle;
  26. import flash.geom.Vector3D;
  27. import flash.text.TextField;
  28. import flash.text.TextFormat;
  29. import flash.text.TextFormatAlign;
  30. import flash.events.Event;
  31. import flash.events.KeyboardEvent;
  32. const SCREEN_WIDTH:int = 465, SCREEN_HEIGHT:int = 465;
  33. const BACKGROUND_BRIGHTNESS:int = 40;
  34. const BACKGROUND_COLOR:int = BACKGROUND_BRIGHTNESS * 0x10000 + BACKGROUND_BRIGHTNESS * 0x100 + BACKGROUND_BRIGHTNESS;
  35. const GAME_OVER_DURATION:int = 150, BLOCK_GAME_START_DURATION:int = 30;
  36. var main:Sprite;
  37. var screen:BitmapData = new BitmapData(SCREEN_WIDTH, SCREEN_HEIGHT, false0);
  38. var scoreField:TextField = new TextField, timeField:TextField = new TextField, messageField:TextField = new TextField;
  39. var gameOverTicks:int, score:int, stage:int, targetCircleCount:int, ticks:int, time:int;
  40. function initialize():void
  41. {
  42.     main.addChild(new Bitmap(screen));
  43.     main.stage.addEventListener(KeyboardEvent.KEY_DOWN, Key.onKeyDown);
  44.     main.stage.addEventListener(KeyboardEvent.KEY_UP,   Key.onKeyUp);
  45.     Field.initialize();
  46.     initializeBlurs();
  47.     scoreField = createTextField(SCREEN_WIDTH - 100010024, 0xff6666, TextFormatAlign.RIGHT);
  48.     timeField = createTextField(SCREEN_WIDTH / 2 - 120, SCREEN_HEIGHT - 4020040, 0xff6666, TextFormatAlign.RIGHT);
  49.     messageField = createTextField(SCREEN_WIDTH - 256025636, 0xff6666);
  50.     main.addChild(scoreField); main.addChild(timeField); main.addChild(messageField);
  51.     startTitle();
  52.     main.addEventListener(Event.ENTER_FRAME, update);
  53. }
  54. function update(event:Event):void
  55. {
  56.     screen.lock();
  57.     screen.fillRect(screen.rect, BACKGROUND_COLOR);
  58.     updateBlurs();
  59.     var i:int;
  60.     for (i = 0; i < sparks.length; i++)  if (!sparks[i].update())  { sparks.splice(i, 1);  i--; }
  61.     for (i = 0; i < shots.length; i++)   if (!shots[i].update())   { shots.splice(i, 1);   i--; }
  62.     for (i = 0; i < bonuses.length; i++) if (!bonuses[i].update()) { bonuses.splice(i, 1); i--; }
  63.     if (targetCircleCount <= 0) goToNextStage();
  64.     if (ticks % 50 == 0) addBackgroundCircles((rand() - 0.5) * Field.size.x * 1.5,
  65.                                               200.0 / (20.0 + stage), 5.0 + rand() * 2.0 + rand() * 2.0);
  66.     ticks++;
  67.     targetCircleCount = 0;
  68.     for each (var c:Circle in circles) c.update();
  69.     for (i = 0; i < circles.length; i++) if (!circles[i].exists)   { circles.splice(i, 1); i--; }
  70.     if (gameOverTicks < 0) Player.update();
  71.     for (i = 0; i < bullets.length; i++) if (!bullets[i].update()) { bullets.splice(i, 1); i--; }
  72.     Field.drawSideBoard();
  73.     screen.unlock();
  74.     if (gameOverTicks < 0)
  75.     {
  76.         time -= 33;
  77.         if (Key.button2) time -= 33;
  78.         if (time <= 0)
  79.         {
  80.             time = 0; startGameClear();
  81.         }
  82.         var msStr:String = String(time % 1000);
  83.         while (msStr.length < 3) msStr = "0" + msStr;
  84.         timeField.text = String(int(time / 1000)) + "\"" + msStr;
  85.     }
  86.     else
  87.     {
  88.         gameOverTicks++;
  89.         if (gameOverTicks == GAME_OVER_DURATION) startTitle();
  90.         if (Key.button1 && gameOverTicks > BLOCK_GAME_START_DURATION) startGame();
  91.     }
  92. }
  93. function goToNextStage():void
  94. {
  95.     if (rand() < 0.5) addTargetCircles((rand() - 0.5) * Field.size.x, 2,
  96.                                        200.0 / (20.0 + stage), 5.0 + rand() * 2.0 + rand() * 2.0false);
  97.     else              addTargetCircles((rand() - 0.5) * Field.size.x * 0.71,
  98.                                        400.0 / (20.0 + stage), 5.0 + rand() * 2.0 + rand() * 2.0true);
  99.     stage += 15;
  100. }
  101. function startTitle():void
  102. {
  103.     clearActors();
  104.     gameOverTicks = GAME_OVER_DURATION;
  105.     messageField.y = SCREEN_HEIGHT / 3 * 2; messageField.text = "CircleCycle";
  106. }
  107. function startGame():void
  108. {
  109.     clearActors();
  110.     Player.start();
  111.     gameOverTicks = -1;
  112.     messageField.text = "";
  113.     score = 0; scoreField.text = "0"; stage = 0; time = 60000;
  114. }
  115. function startGameOver():void
  116. {
  117.     gameOverTicks = 0;
  118.     messageField.y = SCREEN_HEIGHT / 2; messageField.text = "GAME OVER";
  119. }
  120. function startGameClear():void
  121. {
  122.     gameOverTicks = 0;
  123.     messageField.y = SCREEN_HEIGHT / 2; messageField.text = "COMPLETE!";
  124. }
  125. function clearActors():void
  126. {
  127.     shots = null; bullets = null; sparks = null; bonuses = null; circles = null;
  128.     shots = new Vector.<Shot>; bullets = new Vector.<Bullet>; sparks = new Vector.<Spark>; bonuses = new Vector.<Bonus>;
  129.     circles = new Vector.<Circle>; targetCircleCount = 0;
  130. }
  131. // Game actor base class.
  132. class Actor
  133. {
  134.     public var pos:Vector3D = new Vector3D;
  135. }
  136. class VelocityActor extends Actor
  137. {
  138.     public var vel:Vector3D = new Vector3D;
  139.     public var ticks:int, disappearTicks:int = 300;
  140.     public function update():Boolean
  141.     {
  142.         pos.incrementBy(vel);
  143.         ticks++;
  144.         if (!Field.contains(pos) || ticks > disappearTicks) return false;
  145.         return true;
  146.     }
  147. }
  148. // Player.
  149. class Player
  150. {
  151.     private static const COLLISION_SIZE:Number = 5.0;
  152.     private static const SPEED:Number = 9.0;
  153.     public static var pos:Vector3D = new Vector3D;
  154.     private static var fireTicks:int;
  155.     public static function start():void
  156.     {
  157.         pos.x = 0; pos.y = Field.size.y * 0.5;
  158.     }
  159.     public static function update():void
  160.     {
  161.         offset.x = offset.y = 0;
  162.         if (Key.left)  offset.x = -1;
  163.         if (Key.right) offset.x = 1;
  164.         if (Key.up)    offset.y = -1;
  165.         if (Key.down)  offset.y = 1;
  166.         if (offset.x != 0 && offset.y != 0) offset.scaleBy(0.7);
  167.         if (Key.button2) offset.scaleBy(0.5);
  168.         offset.scaleBy(SPEED); pos.incrementBy(offset);
  169.         if (pos.x < -SCREEN_WIDTH  / 2) pos.x = -SCREEN_WIDTH / 2;
  170.         if (pos.x >  SCREEN_WIDTH  / 2) pos.x =  SCREEN_WIDTH / 2;
  171.         if (pos.y < -SCREEN_HEIGHT / 2) pos.y = -SCREEN_HEIGHT / 2;
  172.         if (pos.y >  SCREEN_HEIGHT / 2) pos.y =  SCREEN_HEIGHT / 2;
  173.         Field.offsetX = pos.x * 0.33;
  174.         drawCircle(pos, 157, 0x008800, 0.5);
  175.         addBlur(pos.x, pos.y, 2020100200100);
  176.         if (fireTicks <= 0 && shots.length <= 14 && Key.button1)
  177.         {
  178.             fireTicks = 2;
  179.             var s:Shot;
  180.             for (var i:int = 0; i < 7; i++)
  181.             {
  182.                 s = new Shot;
  183.                 s.pos.x = pos.x; s.pos.y = pos.y;
  184.                 var a:Number = (i - 3) * 0.1;
  185.                 s.vel.x = sin(a) * 24.0; s.vel.y = -cos(a) * 24.0;
  186.                 shots.push(s);
  187.             }
  188.         }
  189.         fireTicks--;
  190.         for each (var b:Bullet in bullets)
  191.         {
  192.             if (Vector3D.distance(pos, b.pos) <= COLLISION_SIZE)
  193.             {
  194.                 addSparks(100, Player.pos.x, Player.pos.y, 30.015.0200100100);
  195.                 startGameOver(); break;
  196.             }
  197.         }
  198.     }
  199. }
  200. // Player's shots.
  201. var shots:Vector.<Shot>;
  202. class Shot extends VelocityActor
  203. {
  204.     override public function update():Boolean
  205.     {
  206.         for each (var c:Circle in circles) if (checkHit(c)) return false;
  207.         addBlur(pos.x, pos.y, 201550150100);
  208.         return super.update();
  209.     }
  210.     private function checkHit(c:Circle):Boolean
  211.     {
  212.         for each (var cc:Circle in c.children) if (cc.exists && checkHit(cc)) return true;
  213.         if (c.exists && c.hasCollision && Vector3D.distance(pos, c.pos) < c.spec.visualRadius + 20.0)
  214.         {
  215.             addSparks(1, pos.x, pos.y, 20.05.050150100);
  216.             c.damage(); return true;
  217.         }
  218.         return false;
  219.     }
  220. }
  221. // Circles' bullets.
  222. var bullets:Vector.<Bullet>;
  223. class Bullet extends VelocityActor
  224. {
  225.     public var baseVel:Vector3D = new Vector3D;
  226.     public var color:int, br:int, bg:int, bb:int, size:int;
  227.     override public function update():Boolean
  228.     {
  229.         var sz:Number = 1.5 + Math.sin(ticks * 0.2) * 0.4;
  230.         var a:Number = 0.8 + Math.sin(ticks * 0.45) * 0.2;
  231.         drawBox(pos.x, pos.y, size, size, color, sz, br * a, bg * a, bb * a);
  232.         if (ticks <= 15)
  233.         {
  234.             vel.x = baseVel.x * (ticks + 15) / 30.0; vel.y = baseVel.y * (ticks + 15) / 30.0;
  235.         }
  236.         else
  237.         {
  238.             vel.x = baseVel.x; vel.y = baseVel.y;
  239.         }
  240.         if (Key.button2) vel.scaleBy(0.5);
  241.         return super.update();
  242.     }
  243. }
  244. // Circles.
  245. var circles:Vector.<Circle>;
  246. class Circle extends Actor
  247. {
  248.     public var children:Vector.<Circle> = null;
  249.     public var isTop:Boolean, exists:Boolean = true;
  250.     public var spec:CircleSpec;
  251.     public var bulletSpeedRatio:Number = 1.0;
  252.     public var rollAngle:Number = 0, fireAngle:Number = 0, fireSpeed:Number, angleInterval:Number;
  253.     public var baseAngle:Number = 0;
  254.     public var ticks:int, shield:int;
  255.     public var hasCollision:Boolean, isTarget:Boolean, isDamaged:Boolean;
  256.     public var xReverse:Number = 1.0;
  257.     public var circleWidth:Number = 5.0;
  258.     public var color:int;
  259.     public function start():void
  260.     {
  261.         color = (int)(spec.r / 2) * 0x10000 + int(spec.g / 2) * 0x100 + int(spec.b / 2);
  262.         shield = spec.shield;
  263.     }
  264.     public function update():void
  265.     {
  266.         var vr:Number = spec.visualRadius;
  267.         if (spec.fireInterval > 0) vr *= ((ticks % spec.fireInterval) / spec.fireInterval * 0.5 + 1.0);
  268.         drawCircle(pos, vr, circleWidth, color);
  269.         var i:int;
  270.         if (isDamaged)
  271.         {
  272.             isDamaged = false;
  273.             var da:Number = ticks * 0.1, sr:Number = spec.visualRadius, bc:int = sr * 0.5;
  274.             for (i = 0; i < bc; i++)
  275.             {
  276.                 addBlur(pos.x + sr * sin(da), pos.y + sr * cos(da),
  277.                         9 + rand() * 79 + rand() * 7, rand() * 128 + 64, rand() * 128 + 12764);
  278.                 da += PI * 2 / bc;
  279.             }
  280.         }
  281.         if (spec.fireInterval > 0 && ticks % spec.fireInterval == 0 && pos.y < 0 &&
  282.             pos.x - Field.offsetX > -Field.size.x + Field.SIDE_BOARD_WIDTH &&
  283.             pos.x - Field.offsetX <  Field.size.x - Field.SIDE_BOARD_WIDTH &&
  284.             (!spec.isAimingBaseAngle || Vector3D.distance(pos, Player.pos) > 120))
  285.          {
  286.             var ba:Number;
  287.             if (spec.isAimingBaseAngle) ba = atan2(Player.pos.x - pos.x, Player.pos.y - pos.y);
  288.             else ba = baseAngle * xReverse;
  289.             ba += rollAngle + fireAngle;
  290.             var srv:Number = -spec.bulletSpeedWhipVel * 2 / spec.bulletCount;
  291.             for (i = 0; i < spec.bulletCount; i++) fire(ba, 1.0 + spec.bulletSpeedWhipVel + srv * i);
  292.         }
  293.         ticks++;
  294.         if (isTop && isTarget && pos.y < -Field.size.y * 0.5) pos.y += 7.0;
  295.         if (isTop && !isTarget)
  296.         {
  297.             pos.y += 3.0;
  298.             if (pos.y > Field.size.y + spec.radius) remove();
  299.         }
  300.         if (isTarget) targetCircleCount++;
  301.         if (children == nullreturn;
  302.         rollAngle = spec.rollAngle.getValue(ticks);
  303.         fireAngle = spec.fireAngle.getValue(ticks);
  304.         fireSpeed = spec.fireSpeed.getValue(ticks);
  305.         angleInterval = spec.angleInterval.getValue(ticks);
  306.         if (spec.isAimingRollAngle) rollAngle += atan2(Player.pos.x - pos.x, Player.pos.y - pos.y) * xReverse;
  307.         var a:Number = rollAngle - angleInterval * (children.length - 1) / 2 - angleInterval;
  308.         for each (var c:Circle in children)
  309.         {
  310.             a += angleInterval;
  311.             if (!c.exists) continue;
  312.             c.pos.x = pos.x + sin(a) * spec.radius * xReverse;
  313.             c.pos.y = pos.y + cos(a) * spec.radius;
  314.             c.baseAngle = a + fireAngle;
  315.             c.update();
  316.         }
  317.     }
  318.     private function fire(a:Number, sr:Number):void
  319.     {
  320.         var b:Bullet = new Bullet;
  321.         b.pos.x = pos.x; b.pos.y = pos.y;
  322.         var bs:Number = spec.bulletSpeed * bulletSpeedRatio * sr;
  323.         b.baseVel.x = sin(a) * bs; b.baseVel.y = cos(a) * bs;
  324.         b.size = spec.bulletSize;
  325.         b.br = spec.r; b.bg = spec.g; b.bb = spec.b;
  326.         b.color = int(b.br / 4) * 0x10000 + int(b.bg / 4) * 0x100 + int(b.bb / 4);
  327.         bullets.push(b);
  328.     }
  329.     public function damage():void
  330.     {
  331.         isDamaged = true;
  332.         shield--;
  333.         if (shield <= 0) remove(true);
  334.     }
  335.     public function remove(isDestroyed:Boolean = false):void
  336.     {
  337.         for each (var c:Circle in children) if (c.exists) c.remove();
  338.         children = null;
  339.         exists = false;
  340.         if (!isDestroyed) return;
  341.         var sa:Number = ticks * 0.1, sr:Number = spec.visualRadius, sc:int = sr * 0.5, i:int;
  342.         for (i = 0; i < sc; i++)
  343.         {
  344.             addSparks(1, pos.x + sr * sin(sa), pos.y + sr * cos(sa), 10.010.0, spec.r, spec.g, spec.b);
  345.             sa += PI * 2 / sc;
  346.         }
  347.         addBonuses(sr * sr * 2 / (abs(pos.y - Player.pos.y) + 30.0), pos.x, pos.y, 10.0);
  348.     }
  349.     public function setXReverse():void
  350.     {
  351.         xReverse = -1.0;
  352.         for each (var c:Circle in children) c.setXReverse();
  353.     }
  354. }
  355. class CircleSpec
  356. {
  357.     public static const FIX:int = 0, WEDGE:int = 1;
  358.     public var radius:Number, visualRadius:Number;
  359.     public var isRound:Boolean;
  360.     public var rollAngle:Waveform = new Waveform;
  361.     public var isAimingRollAngle:Boolean, isAimingBaseAngle:Boolean;
  362.     public var fireAngle:Waveform = new Waveform, fireSpeed:Waveform = new Waveform;
  363.     public var fireInterval:int = -1;
  364.     public var angleInterval:Waveform = new Waveform;
  365.     public var bulletSpeed:Number = 7.0, bulletSize:Number = 15.0;
  366.     public var bulletSpeedFanType:int, bulletSpeedFanVel:Number = 0;
  367.     public var fireDelayType:int, fireDelayVel:Number = 0;
  368.     public var bulletCount:int = 1, bulletSpeedWhipVel:Number = 0;
  369.     public var r:int, g:int, b:int;
  370.     public var childrenCount:int;
  371.     public var shield:int;
  372.     public function set(childrenCount:int, radius:Number, childRadius:Number):void
  373.     {
  374.         this.childrenCount = childrenCount;
  375.         this.radius = radius; visualRadius = radius + childRadius;
  376.         shield = radius;
  377.         rollAngle.width = (0.5 + rand() * 0.5) * ((int)(rand() * 2) * 2 - 1);
  378.         isRound = (rand() < 0.25);
  379.         if (isRound) {
  380.             rollAngle.type = Waveform.MONOTONE;
  381.             rollAngle.interval = 60 + rand() * 60;
  382.             if (rand() < 0.4) fireAngle.type = Waveform.MONOTONE;
  383.             fireAngle.width = (2.0 + rand() * 2.0) * ((int)(rand() * 2) * 2 - 1);
  384.             fireAngle.interval = 90 + rand() * 90;
  385.             if (rand() < 0.3) fireAngle.center = rand() * PI * 2;
  386.             angleInterval.center = PI * 2 / childrenCount;
  387.         }
  388.         else
  389.         {
  390.             isAimingRollAngle = true;
  391.             if (rand() < 0.3) rollAngle.type = Waveform.SIN;
  392.             rollAngle.interval = 120 + rand() * 90;
  393.             if (rand() < 0.3) angleInterval.type = Waveform.SIN;
  394.             angleInterval.center = ((2.0 + rand() * 2.0) / childrenCount) * ((int)(rand() * 2) * 2 - 1);
  395.             angleInterval.width = angleInterval.center * (0.3 + rand() * 0.3);
  396.             angleInterval.interval = 60 + rand() * 60;
  397.         }
  398.         if (rand() < 0.5) bulletSpeedFanType = WEDGE;
  399.         if (rand() < 0.5) bulletSpeedFanVel = (0.3 + rand() * 0.2) * ((int)(rand() * 2) * 2 - 1);
  400.         if (rand() < 0.5) fireDelayType = WEDGE;
  401.         if (rand() < 0.5) fireDelayVel = (8.0 + rand() * 6.0) * ((int)(rand() * 2) * 2 - 1);
  402.     }
  403. }
  404. class Waveform
  405. {
  406.     public static const FIX:int = 0, MONOTONE:int = 1, SIN:int = 2;
  407.     public var type:int = FIX, center:Number = 0, width:Number = 0, interval:int = 1;
  408.     public function getValue(ticks:int):Number
  409.     {
  410.         switch (type)
  411.         {
  412.             case FIX:      return center;
  413.             case MONOTONE: return center + width * ticks * 2 / interval;
  414.             case SIN:      return center + width * sin(PI * 2 * ticks / interval);
  415.         }
  416.         return 0;
  417.     }
  418. }
  419. function addTargetCircles(x:Number, depth:int, fireIntervalRatio:Number, bulletSpeed:Number, hasReversed:Boolean):void
  420. {
  421.     var radius:Number = (20 + rand() * 20) * depth;
  422.     var c:Circle = new Circle;
  423.     var rw:Number = 0;
  424.     if (hasReversed) rw = (rand() * 0.1 + 0.1) * Field.size.x;
  425.     var cy:Number = -Field.size.y * (1.0 + rand() * 2.0) - radius;
  426.     c.pos.x = x - rw; c.pos.y = cy;
  427.     c.isTop = true; c.hasCollision = true; c.isTarget = true;
  428.     var r:int, g:int, b:int;
  429.     r = 127 + rand() * 128; g = 127 + rand() * 128; b = 127 + rand() * 128;
  430.     var sps:Vector.<CircleSpec> = new Vector.<CircleSpec>;
  431.     var turretCount:int = createCircleSpecs(sps, radius, depth, r, g, b);
  432.     var sp:CircleSpec;
  433.     for each (sp in sps) if (sp.isRound) turretCount *= 0.75;
  434.     sp = sps[0];
  435.     sp.fireInterval = turretCount * fireIntervalRatio + 1;
  436.     sp.bulletSpeed = bulletSpeed; sp.bulletSize = 12.0 + depth * 2;
  437.     addCircleChildren(c, sps.length - 1, sps, 1.00);
  438.     circles.push(c);
  439.     if (hasReversed)
  440.     {
  441.         c = new Circle;
  442.         c.pos.x = x + rw; c.pos.y = cy;
  443.         c.isTop = true; c.hasCollision = true; c.isTarget = true;
  444.         addCircleChildren(c, sps.length - 1, sps, 1.00);
  445.         c.setXReverse();
  446.         circles.push(c);
  447.     }
  448. }
  449. function addBackgroundCircles(x:Number, fireIntervalRatio:Number, bulletSpeed:Number):void
  450. {
  451.     var radius:Number = (60 + rand() * 60);
  452.     var c:Circle = new Circle;
  453.     c.pos.x = x; c.pos.y = -Field.size.y - radius;
  454.     c.isTop = true;
  455.     c.circleWidth = 3.0;
  456.     var csp:CircleSpec = new CircleSpec;
  457.     csp.radius = 0; csp.visualRadius = 15.0; csp.childrenCount = 0;
  458.     csp.shield = 3;
  459.     csp.isAimingBaseAngle = true;
  460.     csp.bulletSpeed = bulletSpeed;
  461.     csp.r = csp.g = csp.b = 200;
  462.     var sp:CircleSpec = new CircleSpec;
  463.     sp.childrenCount = 3 + rand() * 7;
  464.     csp.fireInterval = sp.childrenCount * fireIntervalRatio + 1;
  465.     sp.radius = radius; sp.visualRadius = radius - csp.visualRadius;
  466.     sp.rollAngle.width = (0.5 + rand() * 0.5) * ((int)(rand() * 2) * 2 - 1);
  467.     sp.rollAngle.type = Waveform.MONOTONE;
  468.     sp.rollAngle.interval = 60 + rand() * 60;
  469.     sp.angleInterval.center = ((2.0 + rand() * 2.0) / sp.childrenCount);
  470.     if (rand() < 0.5) sp.fireDelayVel = (8.0 + rand() * 6.0) * ((int)(rand() * 2) * 2 - 1);
  471.     sp.r = sp.g = sp.b = 300;
  472.     c.children = new Vector.<Circle>;
  473.     var cct:int = 0;
  474.     for (var i:int = 0; i < sp.childrenCount; i++)
  475.     {
  476.         var cc:Circle = new Circle;
  477.         cc.hasCollision = true;
  478.         cc.spec = csp; cc.start();
  479.         cc.ticks = cct; cct += sp.fireDelayVel;
  480.         c.children.push(cc);
  481.     }
  482.     c.spec = sp; c.start();
  483.     circles.push(c);
  484. }
  485. function createCircleSpecs(sps:Vector.<CircleSpec>, radius:Number, depth:int, r:int, g:int, b:int):int
  486. {
  487.     var sp:CircleSpec = new CircleSpec;
  488.     sp.r = r; sp.g = g; sp.b = b;
  489.     var turretCount:int;
  490.     if (depth == 0)
  491.     {
  492.         sp.radius = 0; sp.visualRadius = radius; sp.childrenCount = 0;
  493.         if (rand() < 0.3)
  494.         {
  495.             sp.bulletCount = 2 + rand() * 5;
  496.             sp.bulletSpeedWhipVel = 0.2 + rand() * 0.2;
  497.             turretCount = sp.bulletCount * 0.75;
  498.         }
  499.         else turretCount = 1;
  500.     }
  501.     else
  502.     {
  503.         sp.childrenCount = 1 + rand() * 7;
  504.         var cr:Number = radius * (0.33 + rand() * 0.1);
  505.         sp.set(sp.childrenCount, radius, cr);
  506.         turretCount = createCircleSpecs(sps, cr, depth - 1, r, g, b) * sp.childrenCount;
  507.     }
  508.     sps.push(sp);
  509.     return turretCount;
  510. }
  511. function addCircleChildren(c:Circle, index:int, sps:Vector.<CircleSpec>,
  512.                            bulletSpeedRatio:Number, fireDelay:Number):void
  513. {
  514.     var sp:CircleSpec = sps[index];
  515.     var bsv:Number = -sp.bulletSpeedFanVel * 2 / sp.childrenCount;
  516.     var fdv:Number = -sp.fireDelayVel * 2 / sp.childrenCount;
  517.     if (sp.bulletSpeedFanType == CircleSpec.WEDGE) bsv *= 2;
  518.     if (sp.fireDelayType == CircleSpec.WEDGE) fdv *= 2;
  519.     if (sp.childrenCount > 0) c.children = new Vector.<Circle>;
  520.     for (var i:int = 0; i < sp.childrenCount; i++)
  521.     {
  522.         var cc:Circle = new Circle;
  523.         var bsr:Number;
  524.         if (sp.bulletSpeedFanType == CircleSpec.FIX || i < sp.childrenCount / 2) bsr = 1.0 + sp.bulletSpeedFanVel + bsv * i;
  525.         else bsr = 1.0 + sp.bulletSpeedFanVel + bsv * (sp.childrenCount - 1 - i);
  526.         var fd:Number;
  527.         if (sp.fireDelayType == CircleSpec.FIX || i < sp.childrenCount / 2) fd = sp.fireDelayVel + fdv * i;
  528.         else fd = sp.fireDelayVel + fdv * (sp.childrenCount - 1 - i);
  529.         addCircleChildren(cc, index - 1, sps, bsr * bulletSpeedRatio, fireDelay + fd);
  530.         c.children.push(cc);
  531.     }
  532.     c.bulletSpeedRatio = bulletSpeedRatio;
  533.     c.ticks = fireDelay;
  534.     c.spec = sp; c.start();
  535. }
  536. // Sparks.
  537. var sparks:Vector.<Spark>;
  538. class Spark extends VelocityActor
  539. {
  540.     public var size:Number;
  541.     public var r:int, g:int, b:int;
  542.     override public function update():Boolean
  543.     {
  544.         vel.scaleBy(0.99);
  545.         size *= 0.95;
  546.         r += (BACKGROUND_BRIGHTNESS - r) * 0.1;
  547.         g += (BACKGROUND_BRIGHTNESS - g) * 0.1;
  548.         b += (BACKGROUND_BRIGHTNESS - b) * 0.1;
  549.         var cr:Number = rand() + 0.5;
  550.         var br:int = r * cr, bg:int = g * cr, bb:int = b * cr;
  551.         if (br > 255) br = 255;
  552.         if (bg > 255) bg = 255;
  553.         if (bb > 255) bb = 255;
  554.         drawBox(pos.x, pos.y, size, size, r * 0x10000 + g * 0x100 + b, 1.5, br, bg, bb);
  555.         return super.update();
  556.     }
  557. }
  558. function addSparks(count:int, x:Number, y:Number, speed:Number, size:Number, r:int, g:int, b:int):void
  559. {
  560.     for (var i:int = 0; i < count; i++)
  561.     {
  562.         var s:Spark = new Spark;
  563.         s.pos.x = x; s.pos.y = y;
  564.         var a:Number = rand() * PI * 2, sp:Number = speed * (0.5 + rand());
  565.         s.vel.x = Math.sin(a) * sp; s.vel.y = Math.cos(a) * sp;
  566.         s.size = size;
  567.         s.r = r; s.g = g; s.b = b;
  568.         s.disappearTicks = 15 + 15 * rand();
  569.         sparks.push(s);
  570.     }
  571. }
  572. // Bonus items.
  573. var bonuses:Vector.<Bonus>;
  574. class Bonus extends VelocityActor
  575. {
  576.     public var isInhaled:Boolean;
  577.     override public function update():Boolean
  578.     {
  579.         var a:Number = ticks * 0.1;
  580.         for (var i:int = 0; i < 4; i++)
  581.         {
  582.             drawBox(pos.x + sin(a) * 10 - 5, pos.y + cos(a) * 10 - 588, 0x6688aa, 1.0150200150);
  583.             a += PI / 2;
  584.         }
  585.         if (isInhaled && gameOverTicks < 0)
  586.         {
  587.             vel.x += (Player.pos.x - pos.x) * 0.05; vel.y += (Player.pos.y - pos.y) * 0.05;
  588.         }
  589.         else vel.y += 0.5;
  590.         vel.scaleBy(0.9);
  591.         var d:Number = Vector3D.distance(pos, Player.pos);
  592.         if (isInhaled && d < 40.0 && gameOverTicks < 0)
  593.         {
  594.             score++; scoreField.text = String(score); return false;
  595.         }
  596.         else if (d < 120.0 && vel.length < 5.0) isInhaled = true;
  597.         return super.update();
  598.     }
  599. }
  600. function addBonuses(count:int, x:Number, y:Number, speed:Number):void
  601. {
  602.     for (var i:int = 0; i < count; i++)
  603.     {
  604.         var b:Bonus = new Bonus;
  605.         b.pos.x = x; b.pos.y = y;
  606.         var a:Number = rand() * PI * 2, sp:Number = speed * (0.5 + rand());
  607.         b.vel.x = Math.sin(a) * sp; b.vel.y = Math.cos(a) * sp;
  608.         bonuses.push(b);
  609.     }
  610. }
  611. // Game field.
  612. class Field
  613. {
  614.     public static const SIDE_BOARD_WIDTH:Number = SCREEN_WIDTH / 6;
  615.     public static var size:Vector3D = new Vector3D;
  616.     public static var offsetX:Number = 0;
  617.     public static function initialize():void
  618.     {
  619.         size.x = SCREEN_WIDTH * 1.1 / 2; size.y = SCREEN_HEIGHT * 1.1 / 2;
  620.     }
  621.     public static function drawSideBoard():void
  622.     {
  623.         rect.width = SIDE_BOARD_WIDTH; rect.height = SCREEN_HEIGHT; rect.y