Queen and Manservant -女王様と下僕-
[ Queen and Manservant 女王様と下僕 ]
*
* --------------------------------------------------
*
* 女王様の気分となって
* あなたの足で下僕を、思う存分踏みつけてやってください。
* アイコンたちは女王様に忠誠を誓った下僕の方々です。
*
* 思う存分、下僕を踏みつけたら、Replayボタンをおしてみましょう。
* 様々なアングルから踏みつけた感触に思い浸ることができます。
*
* --------------------------------------------------
*
* inspired by
* 女王様とおつぶやき
* http://joousama.kayac.com/
*
* resource by
* 女王様の下僕一覧 (Twitterのリプレイを参照)
* http://joousama.kayac.com/footman/list
* http://twitter.com/JOOUSAMA/followers
*
* --------------------------------------------------
*
* <注意>
* Flash Player 10.1 beta2だと、なぜかクロスドメインエラーで再生できません。
* FP10.0だと問題ないので、見れないと思ったらFP10をご利用下さい。
*
/**
* Copyright clockmaker ( http://wonderfl.net/user/clockmaker )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/g1vz
*/
/**
* [ Queen and Manservant 女王様と下僕 ]
*
* --------------------------------------------------
*
* 女王様の気分となって
* あなたの足で下僕を、思う存分踏みつけてやってください。
* アイコンたちは女王様に忠誠を誓った下僕の方々です。
*
* 思う存分、下僕を踏みつけたら、Replayボタンをおしてみましょう。
* 様々なアングルから踏みつけた感触に思い浸ることができます。
*
* --------------------------------------------------
*
* inspired by
* 女王様とおつぶやき
* http://joousama.kayac.com/
*
* resource by
* 女王様の下僕一覧 (Twitterのリプレイを参照)
* http://joousama.kayac.com/footman/list
* http://twitter.com/JOOUSAMA/followers
*
* --------------------------------------------------
*
* <注意>
* Flash Player 10.1 beta2だと、なぜかクロスドメインエラーで再生できません。
* FP10.0だと問題ないので、見れないと思ったらFP10をご利用下さい。
*
*/
// forked from checkmate's Checkmate Vol.6 Professional
package {
import com.bit101.components.*;
import flash.display.*;
import flash.events.*;
import flash.geom.*;
import flash.net.*;
import flash.system.*;
import flash.ui.*;
import flash.utils.*;
import Box2D.Collision.Shapes.*;
import Box2D.Collision.b2AABB;
import Box2D.Common.Math.b2Vec2;
import Box2D.Dynamics.*;
import Box2D.Dynamics.Joints.*;
import jp.progression.casts.CastDocument;
import jp.progression.commands.lists.LoaderList;
import jp.progression.commands.lists.SerialList;
import jp.progression.commands.net.LoadBitmapData;
import jp.progression.commands.net.LoadURL;
import jp.progression.data.Resource;
import jp.progression.data.getResourceById;
import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.easing.Cubic;
import org.libspark.betweenas3.easing.Quad;
import org.libspark.betweenas3.easing.Sine;
import org.libspark.betweenas3.tweens.ITween;
import org.papervision3d.cameras.CameraType;
import org.papervision3d.core.effects.view.ReflectionView;
import org.papervision3d.core.proto.MaterialObject3D;
import org.papervision3d.materials.BitmapMaterial;
import org.papervision3d.materials.WireframeMaterial;
import org.papervision3d.materials.utils.MaterialsList;
import org.papervision3d.objects.DisplayObject3D;
import org.papervision3d.objects.primitives.*;
[SWF(width="465", height="465", frameRate="30", backgroundColor="0x0")]
public class CheckmateProfessional extends CastDocument {
public static const OBJ_NUM:int = 40;
public static const OBJ_SIZE:int = 40;
public static const URL_QUEEN_IMG:String = "http://assets.wonderfl.net/images/related_images/1/10/10b4/10b47406acc3bb8fcb59297590b1d953ceab8df2";
public static const URL_TWITTER_API:String = "http://search.twitter.com/search.atom?q=%40JOOUSAMA&rpp=" + OBJ_NUM;
private static const IMG_HEIGHT:int = 465 * 2;
private static const IMG_WIDTH:int = 121;
private static const IS_DEBUG:Boolean = false;
private static const LOADER_CONTEXT:LoaderContext = new LoaderContext(true);
// array of objs
private var _2dIcon:Array = [];
private var _2dQueen:MovieClip;
private var _3dCubes:Array = [];
private var _3dQueen:Plane;
private var _3dWorld:ReflectionView;
private var _arrayIndex:int;
private var _box2dArr:Array = [];
private var _data:Array = [];
private var _iconContainer:Sprite;
private var _isMouseDown:Boolean;
private var _isRecording:Boolean = false;
private var _isReplay:Boolean = false;
private var _loadingLabel:Label;
private var _loadingProgress:ProgressBar;
private var _loadingTween:ITween;
private var _recoardSprite:Sprite;
private var _recordIconsArr:Array = [];
private var _recordQueenArr:Array = [];
private var _replayCnt:int;
private var _replayDirection:int = 1;
private var _uiBtn:PushButton;
private var m_draggedBody:b2Body;
private var m_iterations:int;
private var m_mouseJoint:b2MouseJoint;
private var m_physScale:Number;
private var m_timeStep:Number;
private var m_wallHeight:Number;
private var m_wallWidth:Number;
private var m_world:b2World;
private var mouseXWorldPhys:Number;
private var mouseYWorldPhys:Number;
override protected function atReady():void {
/*
アルゴリズムでエロスを表現してください。
公序良俗は守ってください。
Create sexy expression through algorithm.
DO NOT be offensive to public order and morals.
*/
new SerialList(null,
initSwf,
startLoading,
new LoadURL(new URLRequest(URL_TWITTER_API)),
parseXml,
function():void {
var cmd:LoaderList = new LoaderList();
cmd.onProgress = function():void {
_loadingProgress.value = cmd.percent / 100;
};
for (var i:int = 0; i < _data.length; i++)
cmd.addCommand(
new LoadBitmapData(new URLRequest(_data[i].img), {
context: LOADER_CONTEXT,
catchError: function(target:Object, error:Error):void {
// targetはCommand.scopeプロパティ。何もしなければエラーが発生したコマンド
target.executeComplete();
}
})
);
cmd.addCommand(new LoadBitmapData(new URLRequest(URL_QUEEN_IMG), {context: LOADER_CONTEXT}));
this.parent.insertCommand(cmd);
},
stopLoading,
initView,
record
).execute();
}
/**
* Create Box2D World
*/
private function createBox2dWorld():void {
// init Box2D
m_iterations = 10;
m_timeStep = 1 / stage.frameRate;
m_physScale = 30;
var worldAABB:b2AABB = new b2AABB();
worldAABB.lowerBound.Set(0, 0);
worldAABB.upperBound.Set(stage.stageWidth, stage.stageHeight);
var gravity:b2Vec2 = new b2Vec2(0, 10);
var doSleep:Boolean = true;
m_world = new b2World(worldAABB, gravity, doSleep);
//デバック用
if (IS_DEBUG) {
var dbgDraw:b2DebugDraw = new b2DebugDraw();
var dbgSprite:Sprite = new Sprite();
dbgSprite.mouseChildren = false;
dbgSprite.mouseEnabled = false;
addChild(dbgSprite);
dbgDraw.m_sprite = dbgSprite;
dbgDraw.m_drawScale = 30.0;
dbgDraw.m_fillAlpha = 0.3;
dbgDraw.m_lineThickness = 1.0;
dbgDraw.m_alpha = 1.0;
dbgDraw.m_xformScale = 1.0;
dbgDraw.m_drawFlags = b2DebugDraw.e_shapeBit;
m_world.SetDebugDraw(dbgDraw);
}
// craete wall for Box2D
var wallShapeDef:b2PolygonDef = new b2PolygonDef();
var wallBodyDef:b2BodyDef = new b2BodyDef();
var wall:b2Body;
m_wallWidth = stage.stageWidth;
m_wallHeight = stage.stageHeight;
// left wall
wallShapeDef.SetAsBox(1 / m_physScale, m_wallHeight / 2 / m_physScale);
wallBodyDef.position.Set(0, m_wallHeight / 2 / m_physScale);
wall = m_world.CreateBody(wallBodyDef);
wall.CreateShape(wallShapeDef);
// right wall
wallBodyDef.position.Set(m_wallWidth / m_physScale, m_wallHeight / 2 / m_physScale);
wall = m_world.CreateBody(wallBodyDef);
wall.CreateShape(wallShapeDef);
// upper wall
wallShapeDef.SetAsBox(m_wallWidth / 2 / m_physScale, 1 / m_physScale);
wallBodyDef.position.Set(m_wallWidth / 2 / m_physScale, 0);
var upperWall:b2Body = m_world.CreateBody(wallBodyDef);
upperWall.CreateShape(wallShapeDef);
// bottom wall
wallBodyDef.position.Set(m_wallWidth / 2 / m_physScale, m_wallHeight / m_physScale);
wall = m_world.CreateBody(wallBodyDef);
wall.CreateShape(wallShapeDef);
wall.SetMassFromShapes();
//
var jShape:b2PolygonDef = new b2PolygonDef();
jShape.SetAsBox(IMG_WIDTH / m_physScale / 2, IMG_HEIGHT / m_physScale / 2);
jShape.density = 10;
jShape.friction = 10;
jShape.restitution = 0.5;
var jBodyDef:b2BodyDef = new b2BodyDef();
jBodyDef.position.Set(200 / m_physScale, 200 / m_physScale);
var jBody:b2Body = m_world.CreateBody(jBodyDef);
jBody.CreateShape(jShape);
jBody.SetUserData(_2dQueen);
jBody.SetMassFromShapes();
_box2dArr.push(jBody);
// create joints
var jointDef:b2DistanceJointDef = new b2DistanceJointDef();
jointDef.Initialize(
upperWall,
jBody,
upperWall.GetPosition(),
jBody.GetPosition());
var joint:b2DistanceJoint = m_world.CreateJoint(jointDef) as b2DistanceJoint;
joint.m_length = 1;
joint.m_frequencyHz = 1.5;
joint.m_dampingRatio = 1;
for (var i:int = 0; i < _2dIcon.length; i++) {
var icon:MovieClip = _2dIcon[i];
var boxShape:b2PolygonDef = new b2PolygonDef();
boxShape.SetAsBox(OBJ_SIZE / m_physScale / 2, OBJ_SIZE / m_physScale / 2);
boxShape.density = 10;
boxShape.friction = 10;
boxShape.restitution = 0.5;
var bodyDef:b2BodyDef = new b2BodyDef();
bodyDef.position.Set(icon.x / m_physScale, icon.y / m_physScale);
var body:b2Body = m_world.CreateBody(bodyDef);
body.CreateShape(boxShape);
body.SetUserData(i);
body.SetMassFromShapes();
_box2dArr.push(body);
}
}
private function getUrl(e:Event):void {
navigateToURL(new URLRequest("http://joousama.kayac.com/"), "_blank");
}
private function iconDoubleClickHandler(e:MouseEvent):void {
navigateToURL(new URLRequest(e.currentTarget.extra.uri), "_blank");
}
private function iconMouseOutHandler(e:MouseEvent):void {
if (!_isMouseDown)
Mouse.cursor = MouseCursor.ARROW;
}
private function iconMouseOverHandler(e:MouseEvent):void {
Mouse.cursor = MouseCursor.HAND;
}
/**
* get number of clicked obj
* @param event
*/
private function iconMousePressHandler(e:MouseEvent):void {
_arrayIndex = (e.currentTarget as MovieClip).extra.arrayPosI;
}
/**
* Create 2D World
*/
private function initIcon2D():void {
_iconContainer = new Sprite();
addChild(_iconContainer);
var cnt:int = 0;
_2dIcon = [];
for (var i:int = 0; i < _data.length; i++) {
var icon:MovieClip = new MovieClip();
icon.graphics.beginFill(0x333333);
icon.graphics.drawRect(-OBJ_SIZE / 2, -OBJ_SIZE / 2, OBJ_SIZE, OBJ_SIZE);
icon.extra = {arrayPosI: i};
icon.x = (OBJ_SIZE * i) % stage.stageWidth + Math.random() * 20;
icon.y = (OBJ_SIZE * i) % stage.stageHeight + Math.random() * 20 + 50;
var res:Resource = getResourceById(_data[i].img);
var img:Bitmap = new Bitmap(res.toBitmapData());
img.width = OBJ_SIZE - 4;
img.height = OBJ_SIZE - 4;
img.x = -(OBJ_SIZE - 4) / 2 >> 0;
img.y = -(OBJ_SIZE - 4) / 2 >> 0;
icon.addChild(img);
icon.extra.uri = _data[i].uri;
icon.doubleClickEnabled = true;
var menu:ContextMenu = new ContextMenu();
menu.hideBuiltInItems();
var it:ContextMenuItem = new ContextMenuItem(_data[i].uri);
it.addEventListener(ContextMenuEvent.MENU_ITEM_SELECT, function(e:Event):void {
navigateToURL(new URLRequest(e.currentTarget.caption), "_blank");
});
menu.customItems = [it]
icon.contextMenu = menu;
_iconContainer.addChild(icon);
_2dIcon[i] = icon;
}
cnt++;
}
private function initPV3D():void {
_3dWorld = new ReflectionView(0, 0, true, false, CameraType.TARGET);
addChild(_3dWorld);
_3dWorld.surfaceHeight = -465;
var res:Resource = getResourceById(URL_QUEEN_IMG);
var m:BitmapMaterial = new BitmapMaterial(res.toBitmapData());
m.doubleSided = true;
_3dQueen = new Plane(m, IMG_WIDTH, IMG_HEIGHT, 2, 2);
_3dWorld.scene.addChild(_3dQueen);
for (var i:int = 0; i < _data.length; i++) {
res = getResourceById(_data[i].img);
var mat:MaterialObject3D;
if (res.data == null)
mat = new WireframeMaterial(0x808080);
else
mat = new BitmapMaterial(res.toBitmapData());
var cube:Cube = new Cube(new MaterialsList({all: mat}), OBJ_SIZE, OBJ_SIZE, OBJ_SIZE, 1, 1, 1, 0, Cube.FRONT);
_3dWorld.scene.addChild(cube);
_3dCubes[i] = cube;
}
}
private function initQueen():void {
_2dQueen = new MovieClip()
var res:Resource = getResourceById(URL_QUEEN_IMG);
var img:Bitmap = new Bitmap(res.toBitmapData());
img.x = -IMG_WIDTH / 2 >> 0;
img.y = -IMG_HEIGHT / 2 >> 0;
_2dQueen.addChild(img);
_2dQueen.addEventListener(MouseEvent.MOUSE_DOWN, iconMousePressHandler);
_2dQueen.addEventListener(MouseEvent.ROLL_OVER, iconMouseOverHandler);
_2dQueen.addEventListener(MouseEvent.ROLL_OUT, iconMouseOutHandler);
_2dQueen.addEventListener(MouseEvent.DOUBLE_CLICK, iconDoubleClickHandler);
_2dQueen.extra = {arrayPosI: 0};
_iconContainer.addChild(_2dQueen);
}
private function initSwf():void {
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
stage.quality = StageQuality.LOW;
graphics.beginFill(0x0);
graphics.drawRect(0, 0, stage.stageWidth, stage.height);
}
private function initUI():void {
var title:Label = new Label(this, 10, 10, "Queen and Manservant");
title.scaleX = title.scaleY = 2;
new Label(this, 10, 40, "DRAG FOOT OF QUEEN, AND REPLAY");
_uiBtn = new PushButton(this, 10, 60, "Replay", replayTo3D);
new Label(this, 280, 20, "INSPIRED BY http://joousama.kayac.com/");
new PushButton(this, 360, 40, "LINK", getUrl);
}
private function initView():void {
// init 2D World
initIcon2D();
initQueen();
// init Box2D World
createBox2dWorld()
initPV3D();
// init vars for drag
_arrayIndex = -1;
_isMouseDown = false;
// addEvent
addEventListener(Event.ENTER_FRAME, loop);
stage.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
initUI();
}
/**
* Enter Frame
* @param event
*/
private function loop(event:Event):void {
// update Box2D step
if (_isRecording) {
updateMouseWorld();
mouseDrag();
m_world.Step(m_timeStep, m_iterations);
// sync position to PV3D from Box2D
for (var bb:b2Body = m_world.GetBodyList(); bb; bb = bb.GetNext()) {
if (bb.GetUserData() is int) {
var cnt:int = bb.GetUserData();
_2dIcon[cnt].x = bb.GetPosition().x * m_physScale;
_2dIcon[cnt].y = bb.GetPosition().y * m_physScale;
_2dIcon[cnt].rotation = bb.GetAngle() * (180 / Math.PI);
// save
if (_recordIconsArr[cnt] == null)
_recordIconsArr[cnt] = [];
_recordIconsArr[cnt].push({x: _2dIcon[cnt].x, y: _2dIcon[cnt].y, rotation: _2dIcon[cnt].rotation});
}
if (bb.GetUserData() == _2dQueen) {
_2dQueen.x = bb.GetPosition().x * m_physScale;
_2dQueen.y = bb.GetPosition().y * m_physScale;
_2dQueen.rotation = bb.GetAngle() * (180 / Math.PI);
// save
_recordQueenArr.push({x: _2dQueen.x, y: _2dQueen.y, rotation: _2dQueen.rotation});
}
}
// 点滅
_recoardSprite.visible = getTimer() % 500 > 250;
} else if (_isReplay) {
if (_replayCnt >= _recordQueenArr.length - 1)
_replayDirection = -1;
else if (_replayCnt == 0)
_replayDirection = 1;
var sabunX:int = -_3dWorld.viewport.width / 2 >> 0;
var sabunY:int = +_3dWorld.viewport.height / 2 >> 0;
for (var i:int = 0; i < _3dCubes.length; i++) {
var o:Object = _recordIconsArr[i][_replayCnt];
_3dCubes[i].x = o.x + sabunX;
_3dCubes[i].y = -1 * o.y + sabunY;
_3dCubes[i].rotationZ = -1 * o.rotation;
}
_3dQueen.x = _recordQueenArr[_replayCnt].x + sabunX;
_3dQueen.y = -1 * _recordQueenArr[_replayCnt].y + sabunY;
_3dQueen.z = 0;
_3dQueen.rotationZ = -1 * _recordQueenArr[_replayCnt].rotation;
_replayCnt += _replayDirection;
_3dWorld.singleRender();
}
}
/**
* Mouse Down
* @param event
*/
private function mouseDownHandler(event:MouseEvent):void {
_isMouseDown = true;
}
/**
* Drag And Drop
*/
private function mouseDrag():void {
if (_isMouseDown && !m_mouseJoint) {
m_draggedBody = null;
if (_arrayIndex > -1)
m_draggedBody = _box2dArr[_arrayIndex];
if (m_draggedBody) {
var md:b2MouseJointDef = new b2MouseJointDef();
md.body1 = m_world.GetGroundBody();
md.body2 = m_draggedBody;
md.target.Set(mouseXWorldPhys, mouseYWorldPhys);
md.maxForce = 3000 * m_draggedBody.GetMass();
md.timeStep = m_timeStep;
m_mouseJoint = m_world.CreateJoint(md) as b2MouseJoint;
m_draggedBody.WakeUp();
}
}
if (!_isMouseDown) {
if (m_mouseJoint) {
m_world.DestroyJoint(m_mouseJoint);
m_mouseJoint = null;
}
}
if (m_mouseJoint) {
var p2:b2Vec2 = new b2Vec2(mouseXWorldPhys, mouseYWorldPhys);
m_mouseJoint.SetTarget(p2);
}
}
/**
* Mouse Up
* @param event
*/
private function mouseUpHandler(event:MouseEvent):void {
Mouse.cursor = MouseCursor.ARROW;
_isMouseDown = false;
_arrayIndex = -1;
}
private function parseXml():void {
default xml namespace=new Namespace("http://www.w3.org/2005/Atom");
var xml:XML = XML(getResourceById(URL_TWITTER_API).toString());
for (var i:int = 0; i < xml.entry.length(); i++) {
var img:String = xml.entry[i].link.(@type == "image/png").@href;
_data.push({
img: xml.entry[i].link.(@type == "image/png").@href,
name: xml.entry[i].author.name,
uri: xml.entry[i].author.uri
});
}
}
private function record():void {
_isRecording = true;
_isReplay = false;
_recoardSprite = new Sprite();
_recoardSprite.graphics.beginFill(0xFF0000);
_recoardSprite.graphics.drawCircle(130, 68, 10);
addChild(_recoardSprite);
}
private function replayTo3D(e:Event):void {
_isRecording = false;
_isReplay = true;
_replayCnt = 0;
removeChild(_iconContainer);
removeChild(_uiBtn);
removeChild(_recoardSprite);
var tw:ITween = BetweenAS3.serial(
BetweenAS3.tween(_3dWorld.camera, {x: 0, y: 0, z: -446}, {x: 0, y: 0, z: -346}, 7, Quad.easeInOut),
BetweenAS3.tween(_3dWorld.camera, {x: 300, y: -200, z: -346}, {x: -300, y: -200, z: -346}, 8, Sine.easeInOut),
BetweenAS3.func(function():void {
_3dWorld.camera.target = null;
_3dWorld.camera.rotationX = 0;
_3dWorld.camera.rotationY = 20;
_3dWorld.camera.rotationZ = 0;
}),
BetweenAS3.tween(_3dWorld.camera, {x: -100, y: -150, z: -150}, {x: 300, y: -150, z: -150}, 8, Sine.easeInOut),
BetweenAS3.func(function():void {
_3dWorld.camera.target = DisplayObject3D.ZERO;
}),
BetweenAS3.tween(_3dWorld.camera, {x: 300, y: 300, z: -346}, {x: 400, y: 400, z: -200}, 7, Cubic.easeInOut),
BetweenAS3.tween(_3dWorld.camera, {x: -200, y: -200, z: -346}, {x: 0, y: -300, z: -340}, 10, Sine.easeInOut)
);
tw.stopOnComplete = false;
tw.play();
}
private function startLoading():void {
_loadingLabel = new Label(this, stage.stageWidth / 2 - 40, stage.stageHeight / 2 - 10, "NOW LOADING");
_loadingTween = BetweenAS3.tween(_loadingLabel, {alpha: 1}, {alpha: 0.25}, 0.05);
_loadingTween = BetweenAS3.serial(_loadingTween, BetweenAS3.reverse(_loadingTween));
_loadingTween.stopOnComplete = false;
_loadingTween.play();
_loadingProgress = new ProgressBar(this, stage.stageWidth / 2 - 57, stage.stageHeight / 2 + 10);
}
private function stopLoading():void {
removeChild(_loadingLabel);
removeChild(_loadingProgress);
_loadingTween.stop();
_loadingTween = null;
}
/**
* get mouse position, and convert box2d scale
*/
private function updateMouseWorld():void {
mouseXWorldPhys = mouseX / m_physScale;
mouseYWorldPhys = mouseY / m_physScale;
}
}
}