// forked from keim_at_Si's Arena Shooting in 100 Lines // LockOnForever.as // <Control> // Mouse Move : Move aim // Mouse Click : Shoot lock-on laser // // +Z //` | / // `----+-----------/ // ` | / | // ` | / | sc_depth // ` | / | // `| / | //------+------------+X // 0|` /sc_w | // | ` / | focalLength // | `/ | // | @ FP10's camera // package { import flash.display.*; import flash.geom.*; import flash.filters.*; import flash.text.*; import flash.events.*; [SWF(width="465", height="465", backgroundColor="0x4080ff", frameRate="30")] public class LockOnForever extends MovieClip { public const SC_WIDTH:int = 465, SC_HEIGHT:int = 465, SC_DEPTH:Number = 465, FOV:Number = 90; public const ENEMY_R:Number = 32, ENEMY_SPEED:Number = 2, ENEMY_COLOR:uint = 0x404040; public const LASER_R:Number = 4, LASER_SPEED:Number = 16, LASER_COLOR:uint = 0x8080ff; public const TRAIL_FRAME:int = 10, TRAIL_COLOR:uint = 0x4040ff, EXP_FRAME:int = 10, EXP_COLOR:uint = 0xff0000; public var m_ScoreField:TextField = new TextField(), m_IsMousePressed:Boolean; public var m_Laser:MovieClip = new MovieClip(), m_Range:MovieClip = new MovieClip(); public var m_Score:int = 0, m_Ticks:int = 0, m_EnemyPopDelay:int = 0, m_Locks:Array = []; public var m_LockGlow:Array = [new GlowFilter(0xff0000, 1, 16, 16, 255)], m_NearDist:Number; function LockOnForever() { transform.perspectiveProjection.fieldOfView = FOV; // focalLegth has changed too. m_NearDist = transform.perspectiveProjection.focalLength; stage.addEventListener(MouseEvent.MOUSE_DOWN, function(e:Event):void { m_IsMousePressed = true; } ); stage.addEventListener(MouseEvent.MOUSE_UP , function(e:Event):void { m_IsMousePressed = false; } ); $(m_Range, {x:SC_WIDTH / 2, y:SC_HEIGHT / 2}, 0xffffff, SC_WIDTH / 2 + 16); // for outcheck $(addChild(m_Laser), {visible:false, fn:updateLaser}, LASER_COLOR, LASER_R); $(addChild(m_ScoreField), {selectable:false, width:SC_WIDTH}); addEventListener(Event.ENTER_FRAME, updateScene); } public function updateScene(event:Event):void { // scene m_Ticks = (m_Laser.visible) ? (m_Ticks + 1) : 0; m_ScoreField.htmlText = "<font color='#ff4040' size='" + (m_Laser.visible ? "20" : "40") + "' face='_sans'>Chains:" + String(m_Score) + "</font>"; if (--m_EnemyPopDelay <= 0) { var ratio:Number = 1.0 + ((m_NearDist + SC_DEPTH) / m_NearDist - 1.0) * Math.random(); var ex:Number = SC_WIDTH / 2 + (SC_WIDTH / 2) * (Math.random() * 2 - 1) * ratio; var ey:Number = SC_HEIGHT / 2 - SC_HEIGHT / 2 * ratio - ENEMY_R; var ez:Number = -m_NearDist + m_NearDist * ratio; $(addChild(new MovieClip()), {x:ex, y:ey, z:ez, fn:updateEnemy}, ENEMY_COLOR, ENEMY_R); m_EnemyPopDelay = (12 + Math.random() * 25) * ((30 * 60 * 2) + m_Ticks) / (30 * 60 * 2); } } public function updateEnemy(e:Event):void { // enemy var a:* = e.target; a.y += ENEMY_SPEED; if (!a.hitTestObject(m_Range)) { kill(a); unlock(a); return; } if (m_Locks.indexOf(a) < 0 && a.hitTestPoint(stage.mouseX, stage.mouseY)) { m_Locks.push(a); } a.filters = (m_Locks.indexOf(a) < 0) ? [] : m_LockGlow; applyFog(a); } public function updateLaser(e:Event):void { // laser var a:* = e.target; if (!a.visible) { if (m_IsMousePressed && m_Locks.length > 0) { $(m_Laser, {x:stage.mouseX, y:stage.mouseY, z:0, visible:true}); m_Score = 0; } return; } $(addChild(new MovieClip()), {x:a.x, y:a.y, z:a.z, frame:0, fn:updateTrail}, TRAIL_COLOR, LASER_R); if (m_Locks.length == 0) { a.move.z = 0; } else { var t:* = m_Locks[0]; a.move = getPos(t).subtract(getPos(a)); if (a.move.length <= LASER_SPEED) { $(addChild(new MovieClip()), {x:t.x, y:t.y, z:t.z, frame:0, fn:updateExp}, EXP_COLOR, ENEMY_R); kill(t); unlock(t); m_Score++; } } if (a.move.normalize() == 0) { a.move = new Vector3D(0,-1,0); } a.move.scaleBy(LASER_SPEED); setPos(a, getPos(a).add(a.move)); a.visible = (m_Locks.length > 0) || a.hitTestObject(m_Range); } public function updateTrail(e:Event):void { // laser trail if (++e.target.frame >= TRAIL_FRAME) { kill(e.target); } applyFog(e.target); } public function updateExp(e:Event):void { // enemy explosion if ((e.target.alpha = (EXP_FRAME - (++e.target.frame)) / EXP_FRAME) == 0) { kill(e.target); } } public function $(a:*, props:*, color:uint=0, radius:Number=0):void { // property setter etc for (var p:String in props) { a[p] = props[p]; } if (props.fn) { a.addEventListener(Event.ENTER_FRAME, props.fn); } if (radius == 0) { return; } a.graphics.beginFill(color); a.graphics.drawRect(-radius, -radius, radius * 2 + 1, radius * 2 + 1); } public function kill(a:*):void { a.parent.removeChild(a).removeEventListener(Event.ENTER_FRAME, a.fn); } public function unlock(a:*):void { if (m_Locks.indexOf(a) >= 0) { m_Locks.splice(m_Locks.indexOf(a), 1); } } public function getPos(a:*):Vector3D { return new Vector3D(a.x, a.y, a.z); } public function setPos(a:*, v:Vector3D):void { a.x = v.x; a.y = v.y, a.z = v.z; } public function applyFog(a:*):void { a.alpha = 1.0 - a.z / SC_DEPTH / 2; } } } LockOnForever