名刺を受け止めてみる。
ITLのサイトで名刺を「RESET ALL CARDS」して
名刺をドラッグしたときの動きの再現方法の検討用。
// forked from nabe's 名刺を振り回してみる。
// forked from nabe's 名刺を投げてみる。
// forked from nabe's 名刺回転の検討の土台
// ITLのサイトで名刺を「RESET ALL CARDS」して
// 名刺をドラッグしたときの動きの再現方法の検討用。
// forked from nabe's ソースの雛形
package {
import flash.display.*;
import flash.events.*;
import flash.geom.*;
[SWF(width="465", height="465", backgroundColor="0xAABBCC", frameRate="12")];
public class BaseClass extends Sprite {
//画面サイズ。
private var W_:uint;
private var H_:uint;
//状態の管理。
private const statReleased:uint = 0;
private const statBeginDrag:uint = 1;
private const statDragging:uint = 2;
private const statEndDrag:uint = 3;
private var stat_:uint = statReleased;
//現在の移動・回転の速度。
private var vPos:Point = new Point(10, 5);
private var vRot:Number = 5;
//摩擦係数。運動神経がにぶい場合は値を大きくすると捕まえ易くなる。
private const fPos:Number = 0.03;
private const fRot:Number = 0.03;
//良く分からない係数。
private const kDrag:Number = 0.01;
//回転し易さ。慣性モーメントの反対?
private const kBeginRot:Number = 0.01;
//重心からのズレの影響度。慣性モーメントの比?
private const kBeginPos:Number = 0.02;
//移動速度の回転速度への転換。
private const kEndPos:Number = 0.5;
//投げ易さ。慣性質量の反対?
//名刺
private var card_:Sprite;
//マウスカーソル・重心の位置。
private var currentCur:Point = new Point();
private var lastCur:Point = new Point();
private var lastGC:Point = new Point();
public function BaseClass () {
//コンストラクタ。ここから全体の処理が開始する。
//1.初期化処理の呼び出しを仕込むに留める。
addEventListener(Event.ADDED_TO_STAGE, init_);
}
private function init_ (event_:Event):void {
//初期化処理。
//1.用済みのリスナ登録を解除する。
event_.target.removeEventListener(event_.type, arguments.callee);
//2.画面サイズを取得する。
W_ = stage.stageWidth;
H_ = stage.stageHeight;
//3.実際の処理を書き足す。
draw_();
//4.イベント処理を登録する。
updateCur();
addEventListener(Event.ENTER_FRAME, update_);
this.addEventListener(MouseEvent.MOUSE_DOWN, dragStart_);
stage.addEventListener(MouseEvent.MOUSE_UP, dragEnd_);
}
private function draw_ ():void {
//実際の表示内容を用意する。
//後で表示位置をずらすので独立したShapeとする。
card_ = new Sprite();
var graphics_:Graphics = card_.graphics;
graphics_.beginFill(0xCCCCFF);
graphics_.drawRect(-40, -80, 80, 160);
graphics_.endFill();
addChild(card_);
}
private function dragStart_ (event_:MouseEvent):void {
//ドラッグ開始時の処理。
if (stat_ == statReleased) stat_ = statBeginDrag;
}
private function dragEnd_ (event_:MouseEvent):void {
//ドラッグ終了時の処理。
if (stat_ == statDragging) stat_ = statEndDrag;
}
private function update_ (event_:Event):void {
updateCur();
var dPos:Point = currentCur.subtract(lastCur);
var dGC:Point = lastCur.subtract(lastGC);
switch (stat_) {
case statReleased:
//慣性で移動中の処理。
updatePos();
updateRot();
break;
case statBeginDrag:
//ドラッグ開始時の処理。
//マウスカーソルでつかむと、
//カーソル中心に回転し始める。
vRot *= 1 - dGC.length * kBeginRot;
//重心からのズレが大きいほど、回転速度は落ちそう。
//長方形の長い辺・短い辺に分けたズレの反映方法は不明。
vRot += (vPos.x * dGC.y - vPos.y * dGC.x) * kBeginPos;
//「重心の移動速度」と「ドラッグ地点と重心の変位」の外積が関係しそう。
//回転中心をカーソル位置にずらす。
card_.x = -mouseX;
card_.y = -mouseY;
x = currentCur.x;
y = currentCur.y;
this.startDrag();
stat_ = statDragging;
break;
case statDragging:
//ドラッグ中の処理。
//マウスカーソルを振り回すと、
//回転中心はカーソル位置に合わせて移動する。
//回転速度が変化する。
vRot -= (dPos.x * dGC.y - dPos.y * dGC.x) * kDrag;
//角加速度はドラッグ位置の重心からの変位とドラッグ方向の外積に比例するのか?
updateRot();
break;
case statEndDrag:
//ドラッグ終了時の処理。
//マウスカーソルを離すと、
//カーソル中心に回転していたものが移動し始める。
//vRot /= 1 - dGC.length * kBeginRot;
//重心からのズレが大きいほど、回転速度の変化が大きそう。
//ドラッグ開始時の逆操作か?
//角運動量が並進の運動量に変わるのか?
vPos.x = dPos.x * kEndPos;
vPos.y = dPos.y * kEndPos;
//重心からのズレが大きいほど、角運動量に変わりそう。
//角運動量に回る分は、ドラッグ位置の変位との外積を考える必要がありそう。
//回転中心を重心位置に戻す。
card_.x = 0;
card_.y = 0;
x = lastGC.x;
y = lastGC.y;
stopDrag();
stat_ = statReleased;
break;
}
}
private function updateCur ():void {
//マウスカーソル・重心の位置を更新する。
lastCur.x = currentCur.x;
lastCur.y = currentCur.y;
currentCur.x = parent.mouseX;
currentCur.y = parent.mouseY;
var temp_:Point = new Point(card_.x, card_.y);
temp_ = localToGlobal(temp_);
temp_ = parent.globalToLocal(temp_);
lastGC.x = temp_.x;
lastGC.y = temp_.y;
}
private function updatePos ():void {
//位置の更新。
//新しい座標を求める。
var newX:Number = x + vPos.x;
var newY:Number = y + vPos.y;
//座標を画面内に収める。
if (Math.abs(newX) > W_) newX = newX % W_;
if (Math.abs(newY) > W_) newY = newY % H_;
if (newX < 0) newX += W_;
if (newY < 0) newY += H_;
//現在の位置を更新する。
x = newX;
y = newY;
//摩擦を反映する。
vPos.x *= (1 - fPos);
vPos.y *= (1 - fPos);
}
private function updateRot ():void {
//角度の更新。
//現在の角度を更新する。
rotation += vRot;
//摩擦を反映する。
vRot *= (1 - fRot);
}
}
}