In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

DANCE ON RADAR

DANCE ON RADAR
Avoid and destory incoming missiles.
<Operation>
Mouse: Change direction and speed.
Drag:  Lock missiles and move sideways.
/**
 * Copyright ABA ( http://wonderfl.net/user/ABA )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/wi2E
 */

// DANCE ON RADAR
//  Avoid and destory incoming missiles.
//  <Operation>
//   Mouse: Change direction and speed.
//   Drag:  Lock missiles and move sideways.
package {
	import flash.display.Sprite;
	[SWF(width="465", height="465", backgroundColor="0", frameRate="30")]
	public class Main extends Sprite {
		public function Main() { main = this; initializeFirst(); }
	}
}
// Initializers.
var initializePhase:int = 0;
function initialize():void {
	switch (initializePhase) {
		case 0: initializeBlurs(); cg = new Cg; initializeSounds(); break;
		case 1: player = new Player; break;
		case 2: field = new Field; break;
		case 3: Missile.initalize(); break;
		case 4: LockMissile.initalize(); break;
		case 5: Explosion.initalize(); break;
		case 6: Line.initialize(0); break;
		case 7: Line.initialize(1); break;
		case 8: Line.initialize(2); break;
		case 9: Line.initialize(3); break;
		default: startTitle(); initializePhase = -1; return;
	}
	initializePhase++;
	cg.print("CREATING DATA..." + int(Number(initializePhase / 10) * 100) + "%", 100, 200);
}
function initializeTitle():void {
	field.initialize();
}
function initializeGame():void {
	stopBgm();
	field.initialize();
	player.initialize();
	missiles = new Vector.<Missile>;
	lockMissiles = new Vector.<LockMissile>;
	explosions = new Vector.<Explosion>;
	lines = new Vector.<Line>;
	missileAppearsTicks = 0; missileAppearsDuration = 50;
	gameSpeed = 1.0;
	playBgm();
}
function initalizeGameOver():void {
	fadeOutBgm();
}
// Update a game frame.
var missileAppearsTicks:int, missileAppearsDuration:Number;
var gameSpeed:Number;
function update():void {
	field.draw();
	for (var i:int = 0; i < lines.length; i++) if (!lines[i].update()) { lines.splice(i, 1); i--; }
	for (i = 0; i < lockMissiles.length; i++) if (!lockMissiles[i].update()) { lockMissiles.splice(i, 1); i--; }
	for (i = 0; i < explosions.length; i++) if (!explosions[i].update()) { explosions.splice(i, 1); i--; }
	player.update();
	missileAppearsTicks--;
	if (isInGame && missileAppearsTicks <= 0) {
		missiles.push(new Missile);
		missileAppearsTicks = missileAppearsDuration;
	}
	missileAppearsDuration -= 0.01; if (missileAppearsDuration < 10) missileAppearsDuration = 50;
	gameSpeed += 0.0003;
	for (i = 0; i < missiles.length; i++) if (!missiles[i].update()) { missiles.splice(i, 1); i--; }
	cg.print(String(score), 10, 10);
}
function updateTitle():void {
	field.draw();
	field.pos.x -= 5; field.pos.y -= 1;
	cg.print("DANCE ON RADAR", 50, 80);
	cg.print("CLICK TO START", 50, 120);
	cg.print(String(score), 10, 10);
}
function updateGameOver():void {
	update();
	cg.print("GAME OVER", 50, 80);
}
// Player
var player:Player;
class Player {
	private const MAX_SPEED:Number = 32;
	public var pos:Vector3D = new Vector3D;
	public var angle:Number;
	private var shape:VectorShape, shieldShape:VectorShape;
	private var velAngle:Number, speed:Number;
	private var prevMousePos:Vector3D = new Vector3D, vel:Vector3D = new Vector3D;
	private var wasMousePressed:Boolean;
	private var shield:Number;
	private var ticks:int;
	public function Player() {
		shape = new VectorShape(function (g:Graphics):void {
			g.lineStyle(5, 0x00ff00, 0.5);
			g.moveTo(0, -16);
			g.lineTo(-12, 16);
			g.lineTo(0, 10);
			g.lineTo(12, 16);
			g.lineTo(0, -16);
		}, 32, 32, true, true);
		shieldShape = new VectorShape(function (g:Graphics):void {
			g.beginFill(0x00ff00, 0.1);
			g.moveTo(-8, -16); g.lineTo(8, -16); g.lineTo(8, 16); g.lineTo(-8, 16);
			g.endFill();
		}, 16, 32, false, false);
	}
	public function initialize():void {
		pos.x = pos.y = 0;
		angle = velAngle = PI; speed = 1;
		vel.x = vel.y = 0;
		prevMousePos.x = main.stage.mouseX; prevMousePos.y = main.stage.mouseY;
		wasMousePressed = false;
		ticks = 0;
		shield = 10;
	}
	public function update():void {
		if (isInGame) {
			var mx:Number = main.stage.mouseX, my:Number = main.stage.mouseY;
			var ox:Number = mx - pos.x - SCREEN_WIDTH / 2, oy:Number = my - pos.y - SCREEN_HEIGHT / 2;
			if (isMousePressed) {
				vel.x += ((mx - prevMousePos.x) * MAX_SPEED * 0.2 - vel.x) * 0.1;
				vel.y += ((my - prevMousePos.y) * MAX_SPEED * 0.2 - vel.y) * 0.1;
				wasMousePressed = true;
			} else {
				if (wasMousePressed) {
					fireLockMissiles();
					wasMousePressed = false;
				}
				angle += normalizeAnglePm(atan2(ox, oy) - angle) * 0.2 * gameSpeed;
				var s:Number = 1.0 - distance(ox, oy) / (SCREEN_WIDTH / 2) 
				if (s < 0.1) s = 0.1;
				var oa:Number = normalizeAnglePm(angle - velAngle);
				velAngle += oa * (MAX_SPEED - speed) / MAX_SPEED * 0.1;
				speed += ((1.0 - s) * MAX_SPEED - speed) * 0.05;
				var sr:Number = 0.1;
				if (s > field.scale) sr = 0.01;
				field.scale += (s - field.scale) * sr;
			}
			if (ticks % 5 == 0) lines.push(new Line(-field.pos.x, -field.pos.y, velAngle, 0));
			ticks++;
		} else {
			speed *= 0.9;
		}
		pos.x += (sin(angle + PI) * speed * 3 - pos.x) * 0.1;
		pos.y += (cos(angle + PI) * speed * 3 - pos.y) * 0.1;
		field.pos.x -= sin(velAngle) * speed * gameSpeed + vel.x;
		field.pos.y -= cos(velAngle) * speed * gameSpeed + vel.y;
		vel.x *= 0.95; vel.y *= 0.95;
		shape.draw(pos.x + SCREEN_WIDTH / 2, pos.y + SCREEN_HEIGHT / 2, angle, field.scale);
		if (isMousePressed) {
			var lx:Number = -field.pos.x, ly:Number = -field.pos.y;
			for (var i:int = 0; i < Missile.LOCK_DISTANCE / (Line.SIZE * 2.5); i++) {
				lx += sin(angle) * Line.SIZE * 2.5; ly += cos(angle) * Line.SIZE * 2.5;
				lines.push(new Line(lx, ly, angle, 2, 1));
			}
		}
		prevMousePos.x = mx; prevMousePos.y = my;
		if (isInGame) {
			shield += 0.02 * gameSpeed; if (shield > 10) shield = 10;
		}
		for (i = 0; i < shield; i++) shieldShape.draw(20 + i * 20, 440, 0, 1);
	}
	public function hit():void {
		playSe(2);
		shield -= 6;
		if (shield <= 0 && isInGame) startGameOver();
	}
}
// Missiles.
var missiles:Vector.<Missile> = new Vector.<Missile>;
class Missile {
	public static const LOCK_DISTANCE:Number = 2560, HIT_DISTANCE:Number = 64;
	private static var shape:VectorShape, lockShape:VectorShape;
	private const RANGE:Number = SCREEN_WIDTH * 7.0;
	public var pos:Vector3D = new Vector3D;
	public var isRemoved:Boolean;
	public var isLocked:Boolean, isFired:Boolean;
	private var angle:Number, speed:Number, angleSpeed:Number;
	private var ticks:int;
	public static function initalize():void {
		shape = new VectorShape(function (g:Graphics):void {
			g.lineStyle(5, 0xffff00, 0.5);
			g.moveTo(0, -16); g.lineTo(-4, 12); g.lineTo(0, 16); g.lineTo(4, 12); g.lineTo(0, -16);
		}, 32, 32, true, true);
		lockShape = new VectorShape(function (g:Graphics):void {
			g.lineStyle(7, 0xff8888, 0.5);
			g.moveTo(-24, -32); g.lineTo(32, -32);
			g.moveTo(32, -24); g.lineTo(0, 32);
			g.moveTo(-4, 32); g.lineTo(-32, -24);
		}, 64, 64, false, true);
	}
	public function Missile():void {
		var a:Number = randn(PI * 2);
		pos.x = -field.pos.x + sin(a) * RANGE;
		pos.y = -field.pos.y + cos(a) * RANGE;
		angle = normalizeAngle(a + PI);
		speed = 24 + randn(10) + randn(10);
		angleSpeed = 0.01 + randn(0.015) + randn(0.015);
	}
	public function update():Boolean {
		if (isRemoved) return false;
		if (ticks % 5 == 0) lines.push(new Line(pos.x, pos.y, angle, 1));
		ticks++;
		pos.x += sin(angle) * speed * gameSpeed;
		pos.y += cos(angle) * speed * gameSpeed;
		var ox:Number = pos.x + field.pos.x, oy:Number = pos.y + field.pos.y;
		var d:Number = distance(ox, oy);
		if (d > RANGE * 5 || d < HIT_DISTANCE) {
			if (d < HIT_DISTANCE) {
				player.hit();
				explosions.push(new Explosion(pos, -1));
			}
			removeLockMissile(this);
			return false;
		}
		var pa:Number = atan2(ox, oy);
		var oa:Number = normalizeAnglePm(pa + PI - angle);
		if (oa > angleSpeed) oa = angleSpeed;
		else if (oa < -angleSpeed) oa = -angleSpeed;
		angle += oa * gameSpeed;
		var sx:Number = ox * field.scale + player.pos.x + SCREEN_WIDTH / 2;
		var sy:Number = oy * field.scale + player.pos.y + SCREEN_HEIGHT / 2;
 		shape.draw(sx, sy, angle, field.scale);
		if (isLocked) {
			lockShape.draw(sx, sy, 0, field.scale);
		} else if (isMousePressed) {
			if (abs(normalizeAnglePm(pa - player.angle)) < 0.1 && d < LOCK_DISTANCE) {
				isLocked = true;
				playSe(0);
			}
		}
		return true;
	}
}
// Player's missiles locking on enemies' missiles.
var lockMissiles:Vector.<LockMissile>;
var enemyScores:Vector.<int> = new Vector.<int>(8);
var nextScoreIndex:int = 0;
class LockMissile {
	private static var shape:VectorShape;
	private static const SPEED:Number = 64, HIT_DISTANCE:Number = 64;
	public var target:Missile;
	private var pos:Vector3D = new Vector3D, speed:Number, angle:Number, angleSpeed:Number;
	private var scoreIndex:int;
	private var ticks:int;
	public static function initalize():void {
		shape = new VectorShape(function (g:Graphics):void {
			g.lineStyle(5, 0x00bbff, 0.5);
			g.moveTo(0, -16);
			g.lineTo(-4, 12);
			g.lineTo(0, 16);
			g.lineTo(4, 12);
			g.lineTo(0, -16);
		}, 32, 32, true, true);
	}
	public function LockMissile(target:Missile):void {
		this.target = target;
		pos.x = -field.pos.x;
		pos.y = -field.pos.y;
		var ox:Number = pos.x - target.pos.x, oy:Number = pos.y - target.pos.y;
		angle = player.angle + normalizeAnglePm(atan2(ox, oy) + PI - player.angle) / 2;
		speed = angleSpeed = 0;
		scoreIndex = nextScoreIndex;
	}
	public function update():Boolean {
		if (ticks % 5 == 0) lines.push(new Line(pos.x, pos.y, angle, 3));
		ticks++;
		speed += (SPEED - speed) * 0.05;
		pos.x += sin(angle) * speed * gameSpeed;
		pos.y += cos(angle) * speed * gameSpeed;
		var ox:Number = pos.x - target.pos.x, oy:Number = pos.y - target.pos.y;
		var d:Number = distance(ox, oy);
		if (d < HIT_DISTANCE) {
			if (isInGame) {
				score += enemyScores[scoreIndex];
				explosions.push(new Explosion(target.pos, enemyScores[scoreIndex]));
				if (enemyScores[scoreIndex] < 6400) enemyScores[scoreIndex] *= 2;
			}
			target.isRemoved = true;
			return false;
		}
		var pa:Number = atan2(ox, oy);
		var oa:Number = normalizeAnglePm(pa + PI - angle);
		if (oa > angleSpeed) oa = angleSpeed;
		else if (oa < -angleSpeed) oa = -angleSpeed;
		angle += oa * gameSpeed;
		ox = pos.x + field.pos.x; oy = pos.y + field.pos.y;
		var sx:Number = ox * field.scale + player.pos.x + SCREEN_WIDTH / 2;
		var sy:Number = oy * field.scale + player.pos.y + SCREEN_HEIGHT / 2;
 		shape.draw(sx, sy, angle, field.scale);
		angleSpeed += 0.002;
		return true;
	}
}
function fireLockMissiles():void {
	var isFiring:Boolean;
	for each (var m:Missile in missiles) {
		if (m.isLocked && !m.isFired) {
			isFiring = true; break;
		}
	}
	if (!isFiring) return;
	playSe(1);
	enemyScores[nextScoreIndex] = 100;
	for each (m in missiles) {
		if (m.isLocked && !m.isFired) {
			lockMissiles.push(new LockMissile(m));
			m.isFired = true;
		}
	}
	nextScoreIndex++; if (nextScoreIndex >= enemyScores.length) nextScoreIndex = 0;
}
function removeLockMissile(m:Missile):void {
	for (var i:int = 0; i < lockMissiles.length; i++) if (lockMissiles[i].target == m) { lockMissiles.splice(i, 1); return; }
}
// Explosion marks.
var explosions:Vector.<Explosion>;
class Explosion {
	private static var shape:VectorShape;
	private var pos:Vector3D = new Vector3D;
	private var score:int, ticks:int;
	public static function initalize():void {
		shape = new VectorShape(function (g:Graphics):void {
			g.lineStyle(7, 0xff0000, 0.5);
			g.moveTo(-32, -32); g.lineTo(32, 32);
			g.moveTo(32, -32); g.lineTo(-32, 32);
		}, 64, 64, false, true);
	}
	public function Explosion(p:Vector3D, score:int):void {
		pos.x = p.x; pos.y = p.y;
		this.score = score;
		ticks = 60;
	}
	public function update():Boolean {
		var ox:Number = pos.x + field.pos.x, oy:Number = pos.y + field.pos.y;
		var sx:Number = ox * field.scale + player.pos.x;
		var sy:Number = oy * field.scale + player.pos.y;
		var ax:Number = abs(sx);
		if (ax > SCREEN_WIDTH * 0.45) {
			sy *= SCREEN_WIDTH * 0.45 / ax;
			if (sx > SCREEN_WIDTH * 0.45) sx = SCREEN_WIDTH * 0.45;
			else sx = -SCREEN_WIDTH * 0.45;
		}
		var ay:Number = abs(sy);
		if (ay > SCREEN_HEIGHT * 0.45) {
			sx *= SCREEN_HEIGHT * 0.45 / ay;
			if (sy > SCREEN_HEIGHT * 0.45) sx = SCREEN_HEIGHT * 0.45;
			else sy = -SCREEN_HEIGHT * 0.45;
		}
		sx += SCREEN_WIDTH / 2; sy += SCREEN_HEIGHT / 2;
		shape.draw(sx, sy, 0, field.scale);
		if (score > 0) cg.print(String(score), sx, sy);
		ticks--;
		return (ticks > 0);
	}
}
// Trail lines.
var lines:Vector.<Line>;
class Line {
	public static const SIZE:Number = 32;
	private static var shapes:Vector.<VectorShape>;
	private var pos:Vector3D = new Vector3D, angle:Number, ticks:int;
	private var colorIndex:int;
	public static function initialize(i:int):void {
		var colors:Array = [ 0x00ff00, 0xffff00, 0xff0000, 0x00bbff ];
		if (shapes == null) shapes = new Vector.<VectorShape>(colors.length);
		shapes[i] = new VectorShape(function (g:Graphics):void {
			g.lineStyle(5, colors[i], 0.5);
			g.moveTo(0, -SIZE);
			g.lineTo(0, SIZE);
		}, SIZE * 2, SIZE * 2, true, true);
	}
	public function Line(x:Number, y:Number, angle:Number, colorIndex:int, ticks:int = 60) {
		pos.x = x; pos.y = y;
		this.angle = angle; this.colorIndex = colorIndex;
		this.ticks = ticks;
	}
	public function update():Boolean {
		var ox:Number = pos.x + field.pos.x, oy:Number = pos.y + field.pos.y;
		shapes[colorIndex].draw(ox * field.scale + player.pos.x + SCREEN_WIDTH / 2, oy * field.scale + player.pos.y + SCREEN_HEIGHT / 2, angle, field.scale);
		ticks--;
		return (ticks > 0);
	}
}
// Scrolling game field.
var field:Field;
class Field {
	private const GRID_SIZE:Number = 400;
	public var pos:Vector3D = new Vector3D, scale:Number;
	private var wShape:VectorShape, hShape:VectorShape;
	public function Field() {
		wShape = new VectorShape(function (g:Graphics):void {
			g.lineStyle(3, 0x008800, 0.25);
			g.moveTo(-SCREEN_WIDTH / 2, 0); g.lineTo( SCREEN_WIDTH / 2, 0);
		}, SCREEN_WIDTH, 3, false, false);
		hShape = new VectorShape(function (g:Graphics):void {
			g.lineStyle(3, 0x008800, 0.25);
			g.moveTo(0, -SCREEN_HEIGHT / 2); g.lineTo(0,  SCREEN_HEIGHT / 2);
		}, 3, SCREEN_HEIGHT, false, false);
	}
	public function initialize():void {
		pos.x = pos.y = 0;
		scale = 0.1;
	}
	public function draw():void {
		var s:Number = GRID_SIZE * scale;
		var x:Number = ((pos.x % GRID_SIZE) * scale + player.pos.x + SCREEN_WIDTH / 2) % s - s;
		for (; x < SCREEN_WIDTH + s; x += s) hShape.draw(x, SCREEN_HEIGHT / 2);
		var y:Number = ((pos.y % GRID_SIZE) * scale + player.pos.y + SCREEN_HEIGHT / 2) % s - s;
		for (; y < SCREEN_HEIGHT + s; y += s) wShape.draw(SCREEN_WIDTH / 2, y);
	}
}
const POLICY_FILE:String = "http://abagames.sakura.ne.jp/crossdomain.xml";
const SOUNDS_URL:String = "http://abagames.sakura.ne.jp/sounds/dance_on_radar/";
const BGM_FILE:String = "missiles_on_radar.mp3";
var seFiles:Array = ["lock.mp3", "missile.mp3", "explosion.mp3"];
import flash.display.*;
import flash.filters.*;
import flash.geom.*;
import flash.events.*;
import flash.text.*;
import flash.media.*;
import flash.net.*;
import flash.system.Security;
// Initialize a bitmapdata and events.
const SCREEN_WIDTH:int = 465;
const SCREEN_HEIGHT:int = 465;
var main:Main, bd:BitmapData, isMousePressed:Boolean;
function initializeFirst():void {
	bd = new BitmapData(SCREEN_WIDTH, SCREEN_HEIGHT, false);
	bd.fillRect(bd.rect, 0);
	main.addChild(new Bitmap(bd));
	main.stage.addEventListener(MouseEvent.MOUSE_DOWN, function (e:Event):void { isMousePressed = true; });
	main.stage.addEventListener(MouseEvent.MOUSE_UP, function (e:Event):void { isMousePressed = false; });
	main.addEventListener(Event.ENTER_FRAME, updateFrame);
}
// Update the frame.
function updateFrame(event:Event):void {
	bd.fillRect(bd.rect, 0);
	if (initializePhase >= 0) {
		initialize();
		return;
	}
	if (!isSoundsReady) return;
	bd.lock();
	if (isInGame) update();
	else if (isTitle) updateTitle();
	else updateGameOver();
	bd.unlock();
	updateSound();
	if (gameOverTicks > 0) {
		gameOverTicks--;
		if (gameOverTicks == 0) startTitle();
	}
	if (!isInGame && gameOverTicks < GAME_OVER_DURATION - 30 && isMousePressed) startGame();
}
// Handle game state (Title/In game/Game over).
const GAME_OVER_DURATION:int = 180;
var gameOverTicks:int, score:int;
function startTitle():void {
	initializeTitle();
	gameOverTicks = 0;
}
function startGame():void {
	initializeGame();
	score = 0;
	gameOverTicks = -1;
}
function startGameOver():void {
	initalizeGameOver();
	gameOverTicks = GAME_OVER_DURATION;
}
function get isInGame():Boolean {
	return (gameOverTicks < 0);
}
function get isTitle():Boolean {
	return (gameOverTicks == 0);
}
// Vector shape.
class VectorShape {
	private const ROTATION_COUNT:int = 32, SCALE_COUNT:int = 16;
	private var isRotative:Boolean;
	private var bds:Vector.<BitmapData> = new Vector.<BitmapData>;
	private var rect:Rectangle;
	private var scaleIndexOffset:int = 1;
	private var point:Point = new Point;
	public function VectorShape(df:Function, w:Number, h:Number, isRotative:Boolean, isScalable:Boolean) {
		var bdsCount:int = 1;
		if (isRotative) {
			bdsCount *= ROTATION_COUNT;
			scaleIndexOffset = ROTATION_COUNT;
		}
		if (isScalable) bdsCount *= SCALE_COUNT;
		var angle:Number = 0, scale:Number = 1;
		for (var i:int = 0; i < bdsCount; i++) {
			bds.push(createBitmapData(df, w, h, angle, scale));
			if (isRotative) {
				angle += 360.0 / ROTATION_COUNT;
				if (angle >= 360 - 1) angle = 0;
			}
			if (isScalable && angle == 0) {
				scale -= 1.0 / SCALE_COUNT;
			}
		}
		rect = bds[0].rect;
	}
	public function draw(x:int, y:int, angle:Number = 0.0, scale:Number = 1.0):void {
		var i:int = normalizeAngle(angle) / (PI * 2 / ROTATION_COUNT) + int((1.0 - scale) / (1.0 / SCALE_COUNT)) * scaleIndexOffset;
		if (i >= bds.length) return;
		point.x = x - rect.width / 2; point.y = y - rect.height / 2;
		bd.copyPixels(bds[i], rect, point);
	}
}
// Create a vector bitmap data.
const BLUR_SIZE:int = 48, BLUR_SIZE_SKIP:int = 4;
var blurs:Vector.<BlurFilter>;
function initializeBlurs():void {
	blurs = new Vector.<BlurFilter>(BLUR_SIZE / BLUR_SIZE_SKIP);
	for (var i:int = BLUR_SIZE_SKIP; i < BLUR_SIZE; i += BLUR_SIZE_SKIP) {
		var blur:BlurFilter = new BlurFilter;
		blur.blurX = blur.blurY = i;
		blurs[i / BLUR_SIZE_SKIP] = blur;
	}
}
function createBitmapData(df:Function, w:Number, h:Number, angle:Number, scale:Number):BitmapData {
	var bd:BitmapData = new BitmapData(w + BLUR_SIZE * 2, h + BLUR_SIZE * 2, true, 0);
	var bs:Sprite = new Sprite;
	var s:Shape = new Shape;
	bs.addChild(s);
	s.x = w / 2 + BLUR_SIZE; s.y = h / 2 + BLUR_SIZE;
	var g:Graphics = s.graphics;
	df(g);
	bd.lock();
	for (var i:int = 0; i < BLUR_SIZE / BLUR_SIZE_SKIP; i++) {
		s.rotation = 180 - angle;
		s.scaleX = s.scaleY = scale;
		if (i > 0) bs.filters = [blurs[i]];
		bd.draw(bs);
	}
	bd.unlock();
	return bd;
}
// Character graphics plane.
var cg:Cg;
class Cg {
	public static const PIXEL_WIDTH:int = 9, PIXEL_HEIGHT:int = int(PIXEL_WIDTH * 1.4);
	public static const strings:String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-=[]\\{}|;':\",./<>?";
	private var bds:Vector.<BitmapData> = new Vector.<BitmapData>;
	private var rect:Rectangle = new Rectangle(0, 0, PIXEL_WIDTH * 1.4 + BLUR_SIZE * 2, PIXEL_HEIGHT * 1.4 + BLUR_SIZE * 2);
	public function Cg() {
		for (var i:int = 0; i < strings.length; i++) {
			var bd:BitmapData = createCharacterBitmapData(strings.charAt(i));
			bds.push(bd);
		}
	}
	public function print(s:String, x:Number, y:Number):void {
		var p:Point = new Point;
		p.x = x - BLUR_SIZE; p.y = y - BLUR_SIZE;
		for (var i:int = 0; i < s.length; i++, p.x += PIXEL_WIDTH) {
			var c:int = strings.indexOf(s.charAt(i));
			if (c >= 0) bd.copyPixels(bds[c], rect, p);
		}
	}
}
// Create a character bitmap data.
function createCharacterBitmapData(c:String):BitmapData {
	var bd:BitmapData = new BitmapData(Cg.PIXEL_WIDTH * 1.4 + BLUR_SIZE * 2, Cg.PIXEL_HEIGHT * 1.4 + BLUR_SIZE * 2, true, 0);
	var bs:Sprite = new Sprite;
	var t:TextField = createTextField(0, 0, Cg.PIXEL_WIDTH + 1, bd.rect.width, bd.rect.height, 0x00ff00);
	t.text = c;
	var tm:TextLineMetrics = t.getLineMetrics(0);
	var ofs:Number = Number(Cg.PIXEL_WIDTH - tm.width) / 2;
	var tbd:BitmapData = new BitmapData(Cg.PIXEL_WIDTH * 1.4, Cg.PIXEL_HEIGHT * 1.4, true, 0);
	tbd.draw(t);
	var b:Bitmap = new Bitmap(tbd);
	b.blendMode = BlendMode.ADD;
	bs.addChild(b);
	b.x = ofs + BLUR_SIZE; b.y = BLUR_SIZE;
	bd.lock();
	for (var i:int = 0; i < BLUR_SIZE / BLUR_SIZE_SKIP; i++) {
		if (i > 0) bs.filters = [blurs[i]];
		bd.draw(bs);
	}
	bd.unlock();
	return bd;
}
// BGM an SEs.
var bgm:Sound, isSoundsReady:Boolean, bgmChannel:SoundChannel, bgmTransform:SoundTransform;
var ses:Vector.<Sound> = new Vector.<Sound>;
var isBgmFadingOut:Boolean;
function initializeSounds():void {
	Security.loadPolicyFile(POLICY_FILE);
	for each (var sef:String in seFiles) {
		var se:Sound = new Sound;
		se.load(new URLRequest(SOUNDS_URL + sef));
		ses.push(se);
	}
	bgm = new Sound();
	bgmTransform = new SoundTransform;
	bgm.addEventListener(Event.COMPLETE, function(e:Event):void { isSoundsReady = true; } );
	bgm.load(new URLRequest(SOUNDS_URL + BGM_FILE));
}
function playBgm():void {
	bgmTransform.volume = 1.0; isBgmFadingOut = false;
	bgmChannel = bgm.play(0, int.MAX_VALUE, bgmTransform);
}
function fadeOutBgm():void {
	if (bgmChannel == null) return;
	isBgmFadingOut = true;
}
function stopBgm():void {
	if (bgmChannel == null) return;
	bgmChannel.stop();
	bgmChannel = null;
}
function playSe(index:int):void {
	ses[index].play();
}
function updateSound():void {
	if (bgmChannel == null || !isBgmFadingOut) return;
	bgmTransform.volume -= 0.015;
	bgmChannel.soundTransform = bgmTransform;
	if (bgmTransform.volume <= 0.05) stopBgm();
}
// Utility functions.
var sin:Function = Math.sin, cos:Function = Math.cos, atan2:Function = Math.atan2; 
var sqrt:Function = Math.sqrt, abs:Function = Math.abs, PI:Number = Math.PI;
function createTextField(x:int, y:int, size:int, width:int, height:int, color:int):TextField {
	var fm:TextFormat = new TextFormat, fi:TextField = new TextField;
	fm.size = size; fm.color = color; fm.leftMargin = 0;
	fi.defaultTextFormat = fm; fi.x = x; fi.y = y; fi.width = width; fi.height = height; fi.selectable = false;
	return fi;
}
function randi(n:int):int {
	return Math.random() * n;
}
function randn(n:int):Number {
	return Math.random() * n;
}
function normalizeAngle(a:Number):Number {
	if (a >= PI * 2) return a % (PI * 2);
	else if (a < 0) return PI * 2 + a % (PI * 2);
	return a;
}
function normalizeAnglePm(a:Number):Number {
	a = normalizeAngle(a);
	if (a > PI) return a - PI * 2;
	return a;
}
function distance(x:Number, y:Number):Number {
	return sqrt(x * x + y * y);
}