/**
* Copyright tepe ( http://wonderfl.net/user/tepe )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/j1cS
*/
package {
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.net.*;
import flash.utils.*;
import flash.geom.*;
public class FlashTest extends Sprite {
private var node1:ozmap = new ozmap();
private var so:SharedObject;
private var color1:uint = 0x223388;
private var color2:uint = 0x4488ff;
//private var dic:Dictionary = new Dictionary();
private var list:Array = new Array();
private var listCnt:int = 0;
private var soFlag:Boolean;
private var t:TextField = new TextField();
public function FlashTest() {
// write as3 code here..
graphics.beginFill(0);
graphics.drawRect(-1000,-500,2000,2000);
graphics.endFill();
so = SharedObject.getLocal("aaa");
if(so != null) soFlag = true;//セーブ可能
else soFlag = false;//セーブ不可
if(soFlag==true)load();
var sc:overScroll = new overScroll();
//sc.showArea=true;
sc.setArea(223,223,150);
sc.movSpeed=2;
sc.setTarget(node1.map);
addChild(sc);
addChild(node1);
var s:Sprite = new Sprite();
s.graphics.beginFill(0xffffff);
s.graphics.drawRect(0,0,465,465);
s.graphics.endFill();
clearBtn(435,435);
createBtn(30,435);
fullscrBtn(80,435);
//penBtn(130,435);
t.selectable = false;
//addChild(t);
//t.text = so.size.toString();
}
private function load():void{
if(so.data.list == undefined)return;
list = so.data.list;
listCnt = list.length;
for(var i:int=0;i<list.length;i++){
var base:Sprite = new Sprite();
base.x = list[i].x;
base.y = list[i].y;
base.name = list[i].name;
node1.addObject(base);
var t:TextField = new TextField();
t.z=0;
t.width = list[i].width;
t.height = list[i].height;
t.border = true;
t.background = true;
t.multiline = true;
t.type = "input";
t.text = list[i].text;
t.name = list[i].name;
base.addChild(t);
t.addEventListener(Event.CHANGE,onChange);
base.addEventListener(MouseEvent.MOUSE_DOWN,stDrag);
base.addEventListener(MouseEvent.MOUSE_UP,endDrag);
t.addEventListener(KeyboardEvent.KEY_UP,onKey);
}
}
private function onKey(e:KeyboardEvent):void{
if(e.shiftKey==true && e.keyCode==13){
createNode(e.currentTarget.parent.x,
e.currentTarget.parent.y+e.currentTarget.parent.height+10);
}
}
private var penMode:Boolean = false;
private var pen:freehandDraw;
private function penBtn(x:Number=0,y:Number=0):void{
var s:Sprite = new Sprite();
s.graphics.lineStyle(1,color2);
s.graphics.beginFill(color1);
s.graphics.drawCircle(0,0,20);
s.graphics.endFill();
addChild(s);
s.x = x;
s.y = y;
var t2:TextField = new TextField();
t2.text = "pen";
t2.textColor = 0xffffff;
t2.selectable = false;
t2.x = -19;
t2.y = -10;
s.addChild(t2);
s.addEventListener(MouseEvent.CLICK,function():void{
if(penMode==false){
pen = new freehandDraw();
node1.addObject(pen);
node1.browseOff();
penMode = true;
t2.text = "browse";
}
else{
pen.finalise();
penMode = false;
node1.browseOn();
t2.text = "pen";
}
});
}
private function fullscrBtn(x:Number=0,y:Number=0):void{
var s:Sprite = new Sprite();
s.graphics.lineStyle(1,color2);
s.graphics.beginFill(color1);
s.graphics.drawCircle(0,0,20);
s.graphics.endFill();
addChild(s);
s.x = x;
s.y = y;
var t2:TextField = new TextField();
t2.text = "fullScr";
t2.textColor = 0xffffff;
t2.selectable = false;
t2.x = -19;
t2.y = -10;
s.addChild(t2);
s.addEventListener(MouseEvent.CLICK,function():void{
if(stage.displayState == StageDisplayState.NORMAL){//
t2.text = "normal"
stage.displayState = StageDisplayState.FULL_SCREEN;
}
else{//
t2.text = "fullScr"
stage.displayState = StageDisplayState.NORMAL;
}
});
}
private function clearBtn(x:Number=0,y:Number=0):void{
var s:Sprite = new Sprite();
s.graphics.lineStyle(1,color2);
s.graphics.beginFill(color1);
s.graphics.drawCircle(0,0,20);
s.graphics.endFill();
addChild(s);
s.x = x;
s.y = y;
var t2:TextField = new TextField();
t2.text = "clear";
t2.textColor = 0xffffff;
t2.selectable = false;
t2.x = -13;
t2.y = -10;
s.addChild(t2);
s.addEventListener(MouseEvent.CLICK,function():void{
so.clear();
listCnt = 0;
list = null;
list = new Array();
node1.clear();
});
}
private function createBtn(x:Number=0,y:Number=0):void{
var s:Sprite = new Sprite();
s.graphics.lineStyle(1,color2);
s.graphics.beginFill(color1);
s.graphics.drawCircle(0,0,20);
s.graphics.endFill();
addChild(s);
s.x = x;
s.y = y;
var t2:TextField = new TextField();
t2.text = "add";
t2.textColor = 0xffffff;
t2.selectable = false;
t2.x = -13;
t2.y = -10;
s.addChild(t2);
s.addEventListener(MouseEvent.MOUSE_DOWN,function():void{
createNode(node1.mapX-50,node1.mapY-10,true);
});
}
private function createNode(x:Number,y:Number,drag:Boolean=false):void{
var base:Sprite = new Sprite();
base.x = x;
base.y = y;
base.name = listCnt.toString();
listCnt++;
node1.addObject(base);
var t:TextField = new TextField();
t.z=0;
t.width = 100;
t.height = 20;
t.border = true;
t.background = true;
t.multiline = true;
t.type = "input";
//t.text = "test";
t.name = base.name;
base.addChild(t);
if(drag==true)base.startDrag();
stage.focus = t;
var node:Object = new Object();
node.x = base.x;
node.y = base.y;
node.width = t.width;
node.height = t.height;
node.text = t.text;
node.name = t.name;
list.push(node);
so.data.list = list;
//t.addEventListener(MouseEvent.CLICK,tClick);
t.addEventListener(Event.CHANGE,onChange);
base.addEventListener(MouseEvent.MOUSE_DOWN,stDrag);
base.addEventListener(MouseEvent.MOUSE_UP,endDrag);
t.addEventListener(KeyboardEvent.KEY_UP,onKey);
}
//ドラッグ
private function stDrag(e:MouseEvent):void{
e.currentTarget.startDrag();
e.stopPropagation();
}
private function endDrag(e:MouseEvent):void{
e.currentTarget.stopDrag();
var i:int = parseInt(e.currentTarget.name);
list[i].x = e.currentTarget.x;
list[i].y = e.currentTarget.y;
so.data.list = list;
t.text = e.currentTarget.name + "\n";
t.appendText(e.currentTarget.x + "\n");
}
private function onChange(e:Event):void{
if(e.currentTarget.textWidth > 100-5){
e.currentTarget.width = e.currentTarget.textWidth+5;
}
e.currentTarget.height = e.currentTarget.textHeight+5;
var i:int = parseInt(e.currentTarget.name);
list[i].text = e.currentTarget.text;
list[i].width = e.currentTarget.width;
list[i].height = e.currentTarget.height;
so.data.list = list;
}
private function tClick(e:MouseEvent):void{
if(e.currentTarget.type == "input"){//
e.currentTarget.type = "dynamic";
e.currentTarget.selectable = false;
}
else{//
e.currentTarget.type = "input";
e.currentTarget.selectable = true;
}
}
}
}
//---------------------------------------------------------------------------------------
import flash.geom.*;
import flash.display.*;
import flash.events.*;
class overScroll extends Sprite{
private var target:DisplayObject;//スクロール対象
private var r:Number;//エリアサイズ
public var movSpeed:Number = 1;
private var speed:Number=0;
public var showArea:Boolean = false;
private var scrMode:Boolean = true;
private var move:Point = new Point();
public function overScroll(){
//init();
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
addEventListener(MouseEvent.MOUSE_OVER,overMouse);
addEventListener(MouseEvent.MOUSE_OUT,outMouse);
}
private function init():void{
removeEventListener(Event.ADDED_TO_STAGE, init);
//stage.removeEventListener(MouseEvent.MOUSE_DOWN,onDown);
}
public function setTarget(t:DisplayObject=null):void{
if(t==null){
removeEventListener(Event.ENTER_FRAME,onEnter);
removeEventListener(MouseEvent.MOUSE_OVER,overMouse);
removeEventListener(MouseEvent.MOUSE_OUT,outMouse);
}
target = t;
target.addEventListener(FocusEvent.FOCUS_OUT,function():void{
//showArea = true;
drawArea(0xff0000);
scrOn();
});
target.addEventListener(FocusEvent.FOCUS_IN,function():void{
//showArea = false;
drawArea(0x000000);
scrOff();
});
}
//スクロール領域の設定
public function setArea(x:Number,y:Number,r:Number):void{
this.x = x;
this.y = y;
this.r = r;
drawArea();
}
private function drawArea(color:uint=0xff0000):void{
graphics.clear();
if(showArea==false)graphics.beginFill(color,0);
else graphics.beginFill(color,0.5);
graphics.drawRect(-r,-r,r*2,r*2);
graphics.endFill();
}
//現在のスクロール停止
public function scrStop():void{
removeEventListener(Event.ENTER_FRAME,onEnter);
removeEventListener(Event.ENTER_FRAME,slowDown);
move.x=0; move.y=0; speed=0;
}
//スクロール有効
public function scrOn():void{
addEventListener(MouseEvent.MOUSE_OVER,overMouse);
addEventListener(MouseEvent.MOUSE_OUT,outMouse);
scrMode = true;
}
//スクロール無効
public function scrOff():void{
removeEventListener(Event.ENTER_FRAME,onEnter);
removeEventListener(MouseEvent.MOUSE_OVER,overMouse);
removeEventListener(MouseEvent.MOUSE_OUT,outMouse);
scrMode = false;
}
//マウスダウン
private function onDown(e:MouseEvent):void{
if(scrMode==false)return;
scrStop();
removeEventListener(MouseEvent.MOUSE_OVER,overMouse);
removeEventListener(MouseEvent.MOUSE_OUT,outMouse);
stage.addEventListener(MouseEvent.MOUSE_UP,onUp);
}
//マウスアップ
private function onUp(e:MouseEvent):void{
if(scrMode==false)return;
addEventListener(MouseEvent.MOUSE_OVER,overMouse);
addEventListener(MouseEvent.MOUSE_OUT,outMouse);
stage.removeEventListener(MouseEvent.MOUSE_UP,onUp);
}
//エリア内にロールオーバー
private function overMouse(e:MouseEvent):void{
if(scrMode==false)return;
stage.addEventListener(MouseEvent.MOUSE_DOWN,onDown);
stage.removeEventListener(Event.MOUSE_LEAVE,leave);
removeEventListener(Event.ENTER_FRAME,slowDown);
removeEventListener(Event.ENTER_FRAME,onEnter);
//state = "overMouse";
}
//エリアの外にロールアウト → スクロール領域
private function outMouse(e:MouseEvent):void{
if(scrMode==false)return;
stage.addEventListener(MouseEvent.MOUSE_DOWN,onDown);
stage.addEventListener(Event.MOUSE_LEAVE,leave);
addEventListener(Event.ENTER_FRAME,onEnter);
//state = "outMouse";
}
//ステージからロールアウト
private function leave(e:Event):void{
if(scrMode==false)return;
removeEventListener(Event.ENTER_FRAME,onEnter);
addEventListener(Event.ENTER_FRAME,slowDown);
//state = "mouseLeave";
stage.addEventListener(MouseEvent.MOUSE_MOVE,stageIn);
}
//ステージにロールオーバー → スクロール領域
private function stageIn(e:MouseEvent):void{
if(scrMode==false)return;
removeEventListener(Event.ENTER_FRAME,slowDown);
stage.removeEventListener(MouseEvent.MOUSE_MOVE,stageIn);
addEventListener(Event.ENTER_FRAME,onEnter);
}
//ステージ外に出た時の処理
private function slowDown(e:Event):void{
target.x -=move.x*movSpeed; target.y -=move.y*movSpeed;
move.x /= 1.02;move.y /= 1.02;
if(Math.abs(move.x)<0.1 && Math.abs(move.y)<0.1){//
removeEventListener(Event.ENTER_FRAME,slowDown);
stage.removeEventListener(MouseEvent.MOUSE_MOVE,stageIn);
}
}
//ステージ内、エリア外での処理
private function onEnter(e:Event):void{
if(speed < movSpeed)speed += movSpeed/100;
if(Math.abs(mouseX) > r){//
move.x = (mouseX/r)*speed;
target.x -= move.x;
}
if(Math.abs(mouseY) > r){//
move.y = (mouseY/r)*speed;
target.y -= move.y;
}
}
}
//---------------------------------------------------------------------------------------
//package ozworks {
import flash.geom.*;
import flash.display.*;
import flash.text.*;
import flash.events.*;
import flash.ui.*;
//public
class ozmap extends Sprite{
private var scale:Number = 1;
public var wheel:int;//ホイール回転量
private var zoom:Number = 1.0;//拡大率
private var mapBase:Sprite;
public var map:Sprite;//フィールド
private var scrFocusX:Number=0;
private var scrFocusY:Number = 0;
private var t5:TextField = new TextField();
//マップエリア
private var mapWidth:int;
private var mapHeight:int;
private var mapscale:int=0;
private var dragField:Sprite = new Sprite();
//ozmap状態フラグ
private const testMode:Boolean = false;//テスト表示
private var mapBrowseMode:Boolean;//マップ移動操作
private var mapDragMode:Boolean;//マップドラッグ中はtrue
private var mapRotationMode:Boolean;//マップ回転操作
//ズーム可能範囲
private var endZoomIn:int = -7;
private var endZoomOut:int = 15;
private var sizeX:Number;
private var sizeY:Number;
public function get mapX():Number {
return map.mouseX;
}
public function get mapY():Number {
return map.mouseY;
}
//コンストラクタ
public function ozmap():void {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
mapWidth = 1200;
mapHeight = 1000;
mapBase = new Sprite();//ズーム中心
if(testMode == true){
with( mapBase.graphics ){
lineStyle(1,0x00ff00,0.3);
moveTo(-100,0);
lineTo(100,0);
moveTo(0,-100);
lineTo(0,100);
}
}
addChild(mapBase);
//マップ上への配置
map = new Sprite();
map.addChild(dragField);
addEventListener(Event.ENTER_FRAME,onMove2);
if(testMode == true){
var t3:TextField = new TextField();
with(t3){
textColor = 0x0000ff;
selectable = false;
y = -20;
text = "map 0,0";
}
map.addChild(t3);
with( map.graphics ){
lineStyle(1,0x0000ff,0.3);
moveTo(-100,0);
lineTo(100,0);
moveTo(0,-100);
lineTo(0,100);
}
t5.textColor = 0xff0000;
addChild(t5);
}
browseOn();
mapBase.addChildAt(map,0);
dragField.doubleClickEnabled = true;
update();
}
private function init(e:Event = null):void
{
removeEventListener(Event.ADDED_TO_STAGE, init);
// スケールモードを「100 % 表示」に設定
stage.scaleMode = StageScaleMode.NO_SCALE;
mapWidth = stage.stageWidth;
mapHeight = stage.stageHeight;
// リサイズされたときに呼び出されるイベント
stage.addEventListener(Event.RESIZE, function(e:Event):void{
mapWidth = stage.stageWidth;
mapHeight = stage.stageHeight;
});
}
//フィールドに追加
public function addObject(s:DisplayObject=null):void {
if (s == null) return;
if (mapBrowseMode == true) {
browseOff();
map.addChild(s);
browseOn();
}
else {
map.addChild(s);
}
s.addEventListener(MouseEvent.MOUSE_DOWN,function():void{
wheel = 0;
});
}
//フィールドから除外
public function removeObject(s:DisplayObject = null):void {
if (s == null) return;
if (mapBrowseMode == true) {
browseOff();
map.removeChild(s);
browseOn();
}
else {
map.removeChild(s);
}
}
public function clear():void{
while(map.numChildren > 2){
map.removeChildAt(2);
}
}
public function get scaleSize():int{
return mapscale;
}
//マップ移動操作状態
public function get IsBrowseMode():Boolean{
return mapBrowseMode;
}
//マップドラッグスクロール状態
public function get IsDragMode():Boolean{
return mapDragMode;
}
//マップ回転操作状態
public function get IsRotationMode():Boolean{
return mapRotationMode;
}
//画面移動操作の受付 ON・OFF切り替え
public function browseOn():void {
//Mouse.hide();//マウスカーソル非表示
mapBrowseMode = true;
map.addEventListener(Event.ENTER_FRAME,setFieldDrag);
map.addEventListener(MouseEvent.MOUSE_DOWN,down);
map.addEventListener(MouseEvent.MOUSE_UP,up);
dragField.addEventListener(MouseEvent.DOUBLE_CLICK,onDouble);
this.addEventListener(MouseEvent.MOUSE_WHEEL,on_wheel,true);//ホイール操作
//map.addChild(dragField);
}
private function setFieldDrag(e:Event):void{
map.graphics.clear();
map.graphics.beginFill(0x000000,0.05);
map.graphics.drawRect(map.mouseX-5/map.scaleX,map.mouseY-5/map.scaleX,10/map.scaleX,10/map.scaleX);
map.graphics.endFill();
}
public function browseOff():void {
//Mouse.show();//マウスカーソル表示
wheel = 0;
mapBrowseMode = false;
map.removeEventListener(MouseEvent.MOUSE_DOWN,down);
map.removeEventListener(MouseEvent.MOUSE_UP, up);
dragField.removeEventListener(MouseEvent.DOUBLE_CLICK,onDouble);
this.removeEventListener(MouseEvent.MOUSE_WHEEL,on_wheel,true);//ホイール操作
//map.removeChild(dragField);
}
//ダブルクリックでマップブラウズモード解除 ⇒ オブジェクト操作モードに移行
private function onDouble(e:MouseEvent):void{
//browseOff();
//ホイール操作でブラウズモードに移行
stage.addEventListener(MouseEvent.MOUSE_WHEEL,function():void{
browseOn();
});
}
private function onMove2(e:Event=null):void {
dragField.x = map.mouseX;
dragField.y = map.mouseY;
var mx:Number = map.mouseX;
var my:Number = map.mouseY;
with(dragField.graphics){
clear();
//マップドラッグ用
beginFill(0x000000, 0);
drawCircle(0, 0, 20/(map.scaleX*zoom));
endFill();
lineStyle(0, 0xff0000, 0.8);
//drawCircle(0,0, 5);
//moveTo(0,0);
//lineTo(100/(map.scaleX*zoom),-50/(map.scaleX*zoom));
//lineTo(150/(map.scaleX*zoom),-50/(map.scaleX*zoom));
}
t5.x = mouseX + 100; t5.y = mouseY - 100;
t5.text = "x:" + mx.toString() + "\ny:" + my.toString();
t5.appendText("\nscale:" + map.scaleX*zoom + " "+map.numChildren.toString());
}
//マップドラッグ開始
private function down(e:MouseEvent):void{
wheel = 0;//ズーム操作ストップ
map.startDrag();
addEventListener(MouseEvent.MOUSE_MOVE,onMove);
stage.removeEventListener(Event.ENTER_FRAME,onFrame);
}
private function up(e:MouseEvent):void {
map.stopDrag();
removeEventListener(MouseEvent.MOUSE_MOVE,onMove);
}
//マップドラッグ中
private function onMove(e:MouseEvent):void{
update();
}
//ホイール操作
private function on_wheel(e:MouseEvent):void{
if(wheel == 0)update();
wheel += e.delta;
if(wheel != 0)addEventListener(Event.ENTER_FRAME,onFrame);
}
//ホイール操作 ズーム
private function onFrame(e:Event):void {
if(wheel==0){
removeEventListener(Event.ENTER_FRAME,onFrame);
}
on_zoom(1+(0.005*wheel));
}
//マップ表示位置を更新
private function update(z:Number=1, x:Number=0, y:Number=0, a:Number=0):void{
var mX:int,mY:int;
if(1<=z){//ズームイン
mX = mouseX;
mY = mouseY;//カーソル位置
}
else{//ズームアウト
mX = this.root.loaderInfo.width/2;
mY = this.root.loaderInfo.height / 2;//カーソル位置
}
//ズーム中心
mapBase.x = mX;
mapBase.y = mY;
//マップ位置
map.x -= (mX-scrFocusX)/zoom;
map.y -= (mY-scrFocusY)/zoom;
//フォーカス位置
scrFocusX = mX;
scrFocusY = mY;
}
//ズーム処理
private function on_zoom(z:Number=0):void{
if (z == 0) return;
if(z>1 && endZoomIn > mapscale){
wheel = 0;
}
else if(z<1 && endZoomOut < mapscale){
wheel = 0;
}
else zoom *= z;
if(2 < zoom){
with(map){
x+=x; y+=y;
scaleX = scaleY *= 2;
}
zoom /= 2;
mapscale--;
}
else if(zoom < 1.0){
with(map){
x-=x/2; y-=y/2;
scaleX = scaleY /= 2;
}
zoom *= 2;
mapscale++;
}
with(mapBase){
scaleX = scaleY = zoom;
}
update(z);//基準点更新
}
}
//}
//------------------------------------------------------------
// forked from knd's 曲線による補間
//package {
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Point;
import flash.utils.getTimer;
/**
* 補間して曲線を引きます
* 任意の時点の速度が推定できるので、筆圧のような効果を出してます。
* @author @kndys
*/
// [SWF(frameRate="12")]
//public
class freehandDraw extends Sprite{
public function freehandDraw():void {
if (stage) init();
else addEventListener(Event.ADDED_TO_STAGE, init);
}
private var press:Boolean = false;
private var curve:Curve = new Curve();
private var lastX:Number = mouseX, lastY:Number = mouseY;
private var lastT:int;
private var currX:Number = lastX, currY:Number = lastY;
private var currT:int;
private var lineNum:uint = 10;
private var position:Point = new Point();
private var velocity:Point = new Point();
private var draw:Function = function():void {
graphics.lineStyle(0, 0x110022);
if (curve.getPoint(position, 0.0)) {
graphics.moveTo(position.x, position.y);
for (var u:uint = 1; u <= lineNum; u++) {
var ratio:Number = Number(u) / lineNum;
curve.getPoint(position, ratio);
curve.getVelocity(velocity, ratio);
graphics.lineStyle(velocity.length * 5.0);
graphics.lineTo(position.x, position.y);
}
}
};
private function init(e:Event = null):void {
removeEventListener(Event.ADDED_TO_STAGE, init);
// entry point
// MOUSE_MOVE ではなく ENTER_FRAME を使う。
stage.addEventListener(Event.ENTER_FRAME,onEnter);
stage.addEventListener(MouseEvent.MOUSE_DOWN,onDown);
stage.addEventListener(MouseEvent.MOUSE_UP, onUp);
}
private function onEnter(e:Event):void {
currX = mouseX, currY = mouseY, currT = getTimer();;
if (press){
graphics.lineStyle(0, 0x4488ff, 0.5);
graphics.moveTo(lastX, lastY);
graphics.lineTo(currX, currY);
graphics.drawCircle(currX, currY, 5);
curve.push(currX, currY, currT); // 点(x,y,t)を追加
draw();
}
lastX = currX, lastY = currY, lastT = currT;
}
private function onDown(e:Event):void{
if (!press){
currX = mouseX, currY = mouseY, currT = getTimer();;
graphics.lineStyle(0, 0x4488ff, 0.5);
graphics.drawCircle(currX, currY, 5);
curve.push(lastX, lastY, lastT); // 開始点の速度を推測するためのダミー点
curve.push(currX, currY, currT); // 開始点
lastX = currX, lastY = currY, lastT = currT;
press = true;
}
}
private function onUp(e:Event):void {
if (press) {
currX = mouseX, currY = mouseY, currT = getTimer();;
curve.push(currX, currY, currT); //
draw();
curve.reset();
lastX = currX, lastY = currY, lastT = currT;
press = false;
}
}
//描画終了
public function finalise():void{
stage.removeEventListener(Event.ENTER_FRAME,onEnter);
stage.removeEventListener(MouseEvent.MOUSE_DOWN,onDown);
stage.removeEventListener(MouseEvent.MOUSE_UP, onUp);
}
}
//}
import flash.geom.Point;
/**
* 動点にはたらく加速度が時間tの1次関数になっているという前提のもと
* 離散点(x,y,t)間を曲線で補間する方法を思いつきました
* どうせ車輪の再発明でしょうけど
* @author @kndys
*/
internal class Curve
{
// (x,y,t) 3点と 初速(u0,v0) から曲線の式を求める
private var _x0:Number, _y0:Number,
_x1:Number, _y1:Number,
_x2:Number, _y2:Number;
private var _t0:Number, _t1:Number, _t2:Number;
private var _u0:Number, _v0:Number;
// dt = t - t0 として
// 位置を x(dt) = ax*dt^3 + bx*dt^2 + u0*dt + x0
// 速度を u(dt) = 3*ax*dt^2 + 2*bx*dt + u0;
// という関数でフィッティングする
private var _ax:Number, _bx:Number,
_ay:Number, _by:Number;
// 上記係数が求まると次回計算の初速も求まる
private var _u1:Number, _v1:Number;
// pushされた点の数
private var _sampleNum:uint;
public function Curve()
{
reset();
}
public function push(x:Number, y:Number, t:int):void
{
_x0 = _x1;
_x1 = _x2;
_x2 = x;
_y0 = _y1;
_y1 = _y2;
_y2 = y;
_t0 = _t1;
_t1 = _t2;
_t2 = t;
_sampleNum++;
if (_sampleNum < 3) return; // 3点目までは計算しない
_u0 = _u1;
_v0 = _v1;
var dx1:Number = _x1 - _x0;
var dx2:Number = _x2 - _x0;
var dy1:Number = _y1 - _y0;
var dy2:Number = _y2 - _y0;
var dt1:Number = _t1 - _t0;
var dt2:Number = _t2 - _t0;
if (dt2 == 0) dt2 = 1.0;
if (dt1 == 0) dt1 = 0.5 * dt2;
var k1:Number = 1.0 / (dt1 * dt1 * (dt1 - dt2));
var k2:Number = 1.0 / (dt2 * dt2 * (dt2 - dt1));
if (_sampleNum == 3)
{
_u0 = 0.0;
_v0 = 0.0;
}
var p1:Number = dx1 - _u0 * dt1;
var p2:Number = dx2 - _u0 * dt2;
var q1:Number = dy1 - _v0 * dt1;
var q2:Number = dy2 - _v0 * dt2;
_ax = p1 * k1 + p2 * k2;
_ay = q1 * k1 + q2 * k2;
_bx = - p1 * k1 * dt2 - p2 * k2 * dt1;
_by = - q1 * k1 * dt2 - q2 * k2 * dt1;
// 次回の初速を求めておく
_u1 = 3 * _ax * dt1 * dt1 + 2 * _bx * dt1 + _u0;
_v1 = 3 * _ay * dt1 * dt1 + 2 * _by * dt1 + _v0;
}
public function getPoint(dst:Point, ratio:Number):Boolean
{
if (_sampleNum < 3) return false;
_calcPoint(dst, _calcTime(ratio));
return true;
}
public function getVelocity(dst:Point, ratio:Number):Boolean
{
if (_sampleNum < 3) return false;
_calcVelocity(dst, _calcTime(ratio));
return true;
}
private function _calcTime(ratio:Number):Number
{
var dt:Number;
if (ratio <= 1.0)
{
dt = (_t1 - _t0) * ratio;
}
else
{
dt = _t1 + (_t2 - _t1) * (ratio - 1.0);
}
return dt;
}
private function _calcPoint(dst:Point, dt:Number):void
{
var dt2:Number = dt * dt;
var dt3:Number = dt2 * dt;
dst.x = _ax * dt3 + _bx * dt2 + _u0 * dt + _x0;
dst.y = _ay * dt3 + _by * dt2 + _v0 * dt + _y0;
}
private function _calcVelocity(dst:Point, dt:Number):void
{
var dt2:Number = dt * dt;
dst.x = 3 * _ax * dt2 + 2 * _bx * dt + _u0;
dst.y = 3 * _ay * dt2 + 2 * _by * dt + _v0;
}
public function reset():void
{
_sampleNum = 0;
}
}