ソースはこんな感じ
]]>package
{
import flash.display.Sprite;
import flash.events.MouseEvent;
/**
書道クラス
*/
public class Shodo extends Sprite
{
//半紙
private var paper:Sprite;
//一つ前の座標
private var oldX1:Number;
private var oldY1:Number;
//二つ前の座標
private var oldX2:Number;
private var oldY2:Number;
//一つ前の幅
private var oldW:Number;
//筆の太さ
private var strength:Number = 20;
//筆の太さの幅(太さ-太さの幅=最小の太さ)
private var range:Number = 12;
//筆の変化幅
private var limitDistance:Number = 30;
public function Shodo(w:Number = 100,h:Number = 100)
{
initPaper(w,h);
}
// **************************************** 表示領域の初期化
private function initPaper(w,h):void
{
//半紙を配置する
paper = new Sprite();
addChild(paper);
paper.graphics.beginFill(0xffffff);
paper.graphics.drawRect(0, 0, w, h);
//マウスが半紙上で押されるのを検知
paper.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
}
// **************************************** マウスが押された。
private function mouseDownHandler(e:MouseEvent):void
{
//マウスの動きを検知
addEventListener(MouseEvent.MOUSE_MOVE,mouseMoveHandler)
//ステージにマウスボタンが離されるリスナーを配置
stage.addEventListener(MouseEvent.MOUSE_UP, mouseUpHandler);
//筆を置いたときのイメージを置いた座標に配置
var hajime:Hajime = new Hajime();
hajime.x = paper.mouseX;
hajime.y = paper.mouseY;
paper.addChild(hajime);
//座標の履歴をとりあえず格納
oldX1 = paper.mouseX;
oldY1 = paper.mouseY;
oldX2 = paper.mouseX;
oldY2 = paper.mouseY;
oldW = strength;
}
// **************************************** マウスが離された。
private function mouseUpHandler(e:MouseEvent):void
{
//リスナーを削除
removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveHandler)
//前座標と前々座標の距離、角度、拡大率を求める。
var distance:Number = Math.sqrt((oldX1 - oldX2) * (oldX1 - oldX2) + (oldY1 - oldY2) * (oldY1 - oldY2));
var deg:Number = Math.atan2(oldY1 - oldY2, oldX1 - oldX2) * 180 / Math.PI;
var scale:Number = oldW / strength;
//マウスボタンを離す前の2座標の距離に応じて、トメやハライのイメージを配置する。
var postfix:Sprite;
if (distance > 25) {
postfix = new Harai();
} else if (distance > 10) {
postfix = new Hane();
} else {
postfix = new Tome();
}
postfix.x = oldX1;
postfix.y = oldY1;
postfix.scaleX = postfix.scaleY = scale;
postfix.rotation = deg;
paper.addChild(postfix);
}
// **************************************** マウスが動いた
private function mouseMoveHandler(e:MouseEvent):void
{
//前座標との距離、角度を求める。幅wも適当に求める。(変化幅以上に移動していたら最大細さ。それ以内はそれに比例した細さ。)
var distance:Number = Math.sqrt((paper.mouseX - oldX1) * (paper.mouseX - oldX1) + (paper.mouseY - oldY1) * (paper.mouseY - oldY1));
var w:Number = distance > limitDistance?(strength - range):(strength - range * distance / limitDistance);
var deg:Number = Math.atan2(paper.mouseY - oldY1, paper.mouseX - oldX1) * 180 / Math.PI;
//原点に下底前幅、上底現幅、高さ現距離の台形を描き(エルボーとして前幅の円も原点に配置)、
var s:Sprite = new Sprite();
s.graphics.beginFill(0, 1);
s.graphics.drawCircle(0, 0, oldW / 2);
s.graphics.endFill()
s.graphics.beginFill(0, 1);
s.graphics.moveTo(0, -oldW / 2)
s.graphics.lineTo(distance, -w / 2);
s.graphics.lineTo(distance, w / 2);
s.graphics.lineTo(0, oldW / 2);
s.graphics.lineTo(0, -oldW / 2)
s.graphics.endFill()
//前座標に求めた角度に回転させて配置する。
s.rotation = deg;
s.x = oldX1;
s.y = oldY1;
paper.addChild(s);
//履歴を格納
oldX2 = oldX1;
oldY2 = oldY1;
oldX1 = paper.mouseX;
oldY1 = paper.mouseY;
oldW = w;
}
// **************************************** 半紙クリアのメソッド
public function clearPaper() {
for (var i:int = paper.numChildren; i > 0; i--)
{
paper.removeChildAt(i - 1);
}
}
}
}
使い方は
//Shodoを作成
shodo = new Shodo(480,330);
addChild(shodo);
//枠を描く
var f:Sprite = new Sprite();
f.graphics.lineStyle(0,0x666666);
f.graphics.drawRect(0,0,480,330);
addChild(f);
//ボタンを配置
var clearBtn:Button = new Button()
clearBtn.y = 336;
clearBtn.label = 'clear';
clearBtn.addEventListener(MouseEvent.CLICK,onClickHandler)
addChild(clearBtn);
function onClickHandler(e:MouseEvent):void {
shodo.clearPaper();
}
こんな感じです。筆圧感知ができないと思うので(マウスが前提ですし...)移動した距離によって(すなわちマウスの速さによって)線の太さを決めています。早く動かすと細くなるイメージで、そこは適当に計算して決めています。
イメージだけのクラスの作成に悩んでしまったので、トメ、ハネ、ハライ、ハジメのイメージはFLA内でそれぞれTome,Hane,Harai,Hajimeの名前でActionScriptに書き出ししています。
]]>ちょうど波紋エフェクトなどを作成したときに、ひとコマずつBitmapDataにして加工するのをやったので「磨りガラスもこれでイケるな」と思い、早速作成してみました。
ソースはこんな感じ
]]>package jp.norisuke {
import flash.display.*;
import flash.events.Event;
import flash.filters.BlurFilter;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.text.TextField;
public class GroundGlass extends MovieClip {
public var bitmap:Bitmap;
public var source:DisplayObject;
public var applyWidth:Number;
public var applyHeight:Number;
public var blurX:Number;
public var blurQuality:int;
public var backgroundColor:uint;
//
private var frameRateText:TextField;
//コンストラクタ
public function GroundGlass(obj:DisplayObject, w:Number, h:Number, b:Number = 16, q:int = 2, gColor:uint = 0xffffff, gAlpha:Number = 0.5, bgColor:uint = 0xffffffff)
{
source = obj;
applyWidth = w;
applyHeight = h;
blurX = b;
blurQuality = q;
backgroundColor = bgColor;
//
bitmap = new Bitmap();
addChild(bitmap);
//
var shape:Shape = new Shape();
shape.graphics.beginFill(gColor, gAlpha);
shape.graphics.drawRect(0, 0, applyWidth, applyHeight);
addChild(shape);
//
frameRateText = new TextField()
//addChild(frameRateText);
//
addEventListener(Event.ENTER_FRAME, start);
}
public function start(e:Event):void {
//
var s:Number=new Date().getMilliseconds()
//
var dx:Number
var sourceBitmapData:BitmapData = new BitmapData(source.width, source.height,true,backgroundColor)
var targetBitmapData:BitmapData = new BitmapData(applyWidth,applyHeight,true,0);
var sourceRect:Rectangle = new Rectangle(x, y, applyWidth, applyHeight);
sourceBitmapData.draw(source);
targetBitmapData.copyPixels(sourceBitmapData, sourceRect, new Point(0, 0));
targetBitmapData.applyFilter(targetBitmapData, new Rectangle(0, 0, targetBitmapData.width, targetBitmapData.height), new Point(0, 0), new BlurFilter(blurX,blurX,blurQuality));
bitmap.bitmapData = targetBitmapData;
//
if (new Date().getMilliseconds() - s >0) {
frameRateText.text = Math.floor(1000 / (new Date().getMilliseconds() - s)) + 'fps';
}
//
}
}
}
使い方は
addChild(obj);
var gg:GroundGlass = new GroundGlass(obj,width,height,blurStrength,quority,color,alha);
gg.x =10;
gg.y = 50;
addChild(gg);
といった感じです。引数は(磨りガラス効果をかけるオブジェクト、巾、高さ、ぼかしの強さ、ぼかしのクオリティ、ガラスの色、ガラスの透明度(アルファ))。与えるオブジェクトは(0,0)の位置にあるのが前提です。
]]>値段の高さから購入を躊躇していたのですが、遅まきながら先日意を決して手に入れました。
内容は、AS3.0の基本をすこしと、簡単な数学(三角関数がメイン)から始まって初歩の物理とその応用を利用してAS3.0アニメーションを作成するものです。
いままでなんとなく作ってきたものが、物理を利用して理論的に組み立てて作成できるようになります。この点が応用を考えると非常に大きいと思います。(まぁなんとなくやっているのがイケナイのですが(^^; )
全体的に図とサンプルとなるスクリプトを示して、わかりやすく解説してくれていますので「物理とか数学はよくわからない」と言う人にもとっつきやすいと思います。
触れられている項目は、速度・加速度・摩擦・跳ね返りなどの初歩の物理からインバースキネマティクス、三次元まで豊富にあります。ビット演算や行列の演算にも触れているところが非常に参考になりました。
不満な点を上げるとすれば、跳ね返りなど物理の部分で「円」の場合でしか紹介されていないこと。長方形が斜めにぶつかったときにどういった計算になるのかということは教えてくれません。およそここから本格的な物理になってくるからだとは思いますが...。
すこし誤植が多いですが、理論的に再構築したい人にはオススメの1冊です。
ActionScript3.0 アニメーション(株式会社 ボーンデジタル:Keith Peters)7,350円
]]>先のエントリーでやった「水面のようなエフェクト」はその習作だったのですが、クライアントがやっぱり波紋でやりたいということだったので作成することに。
「DisplacementMapFilter」を利用することは変わらないので、いかに置き換えマップを作成するのかがカギなのですが、計算をなるべく省きたい。そこで、検索で見つけた鮭さんのブログのやり方を参考にして、円形グラデーションでマップを作成することにしました。
※枠内クリックで実行
]]> 鮭さんのところでは、ひとつのグラデーション定義で波紋を表現されていたのですが、要望によっては同心円でない場合もあるし、減衰もさせたいとなると波紋ごとの管理がややこしくなりそう...。そこで、グラデーション定義ではひとつの波紋だけを表現し、それを複数枚作成して重ねてしまおうと思い立ちました。これなら簡単に出来そうです。
ソースはこんな感じ
package jp.norisuke {
import flash.display.*;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.filters.DisplacementMapFilter;
import flash.filters.DisplacementMapFilterMode;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.utils.Timer;
public class Ripple extends MovieClip {
//ソースイメージ、ノイズイメージ、ビットマップ
public var sourceImage:BitmapData;
private var ripplesImage:BitmapData;
private var softLightBitmap:Bitmap;
private var bitmap:Bitmap;
//波紋を保持する配列
private var ripples:Array;
//波紋の回数
public var times:uint;
//波紋の間隔
public var interval:Number;
//フェードするか否か?
public var fadeFlag:Boolean;
//置き換えマップの移動強度
public var filterScale:uint;
//全ての波紋を生成したか否かのブール
private var timerCompleteFlag:Boolean = false;
//コンストラクタ
public function Ripple(g:BitmapData, _fs:uint = 20, _t:uint = 8 , _interval:Number = 200 , _fade:Boolean = true, _softlightFlag:Boolean = true )
{
sourceImage = g;
filterScale = _fs;
times = _t;
interval = _interval;
fadeFlag = _fade;
//
ripples = new Array();
bitmap = new Bitmap(sourceImage);
addChild(bitmap);
softLightBitmap = new Bitmap();
if(_softlightFlag) {
softLightBitmap.blendMode = BlendMode.HARDLIGHT;
softLightBitmap.alpha = 0.5;
addChild(softLightBitmap);
}
}
//実行
public function start():void
{
if(!timerCompleteFlag){
//タイマーを設定。引数で与えられた間隔と回数をそのまま定義
var timer:Timer = new Timer(interval, times);
timer.addEventListener(TimerEvent.TIMER, timerCountHandler)
timer.addEventListener(TimerEvent.TIMER_COMPLETE, timerCompleteHandler)
timer.start()
//波紋の進行はENTER_FRAMEでおこなう
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
}
//指定された回数が終われば、フラグをたてる。
private function timerCompleteHandler(e:TimerEvent):void
{
timerCompleteFlag = true;
}
//タイマーがカウントされたらObjectに波紋の中心点と現在のカウントを記録して、波紋管理用の配列へpush。
private function timerCountHandler(e:TimerEvent):void
{
var r:Object = new Object;
r.tx = Math.floor(Math.random() * sourceImage.width - sourceImage.width/2);
r.ty = Math.floor(Math.random() * sourceImage.height - sourceImage.height / 2);
r.r = 0;
r.count = e.target.currentCount;
ripples.push(r);
}
//波紋を更新する。
private function enterFrameHandler(e:Event):void
{
updateRipplesArray()
updateRipples();
updateBitmap();
}
//波紋管理用の配列の更新(規定値を超えたら配列から削除)
private function updateRipplesArray():void
{
var i:uint = 0;
for each(var r:Object in ripples) {
if (r.r > 255) {
ripples.splice(i, 1);
}
i++
}
}
//波紋管理用の配列からオブジェクトを取り出し、波紋をグラデーションで生成
private function updateRipples():void
{
var sprite:Sprite = new Sprite();
if (ripples.length == 0 && timerCompleteFlag) {
removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
timerCompleteFlag = false;
return;
}
for (var i:uint = 0; i < ripples.length; i++) {
var r:Object = ripples[i];
var shape:Shape = new Shape();
var g:Graphics = shape.graphics;
var matrix:Matrix = new Matrix()
matrix.createGradientBox(sourceImage.width, sourceImage.height, 0, r.tx, r.ty);
var _alpha:Number;
if(fadeFlag) {
_alpha = 0.5 * ((255 - r.r) / 255) * ((times - (r.count - 1))/times);
} else {
_alpha = 0.5 * ((255 - r.r) / 255) ;
}
g.beginGradientFill(GradientType.RADIAL, [0xffffff, 0xffffff, 0xffffff], [0,_alpha,0], [r.r, r.r+20, r.r+40], matrix, SpreadMethod.PAD);
g.drawRect(0,0,sourceImage.width,sourceImage.height)
//生成した波紋をスプライトに加えていく。
sprite.addChild(shape);
//半径
r.r += 8;
ripples[i] = r;
}
ripplesImage = new BitmapData(sourceImage.width,sourceImage.height,true,0xff7f7f7f)
//スプライトをBitmapDataにして、置き換えマップの完成。
ripplesImage.draw(sprite);
softLightBitmap.bitmapData = ripplesImage;
}
//ソースイメージにフィルタをかける
private function updateBitmap():void
{
var filter:DisplacementMapFilter = getBitmapFilter();
bitmap.filters = [filter]
}
//置き換えフィルタを得る
private function getBitmapFilter():DisplacementMapFilter {
var mapPoint:Point = new Point(0, 0);
var channels:uint = 2
var componentX:uint = channels;
var componentY:uint = channels;
var scaleX:Number = filterScale;
var scaleY:Number = filterScale;
var mode:String = DisplacementMapFilterMode.CLAMP;
var color:uint = 0;
var alpha:Number = 0;
return new DisplacementMapFilter(ripplesImage,
mapPoint,
componentX,
componentY,
scaleX,
scaleY,
mode,
color,
alpha);
}
}
}
使い方は
obj:WaterSurface = new Ripple(BitmapData, FilterScale, Times, Interval(ms));
addChild(obj);
obj.start()
といった感じ。引数は(ビットマップデータ、エフェクトの強さ、波紋の数、波紋の間隔(ms)、フェードの有無(bool)、水面のテカリの有無(bool))
]]>※枠内クリックで実行
ソースはこんな感じ
]]>package {
import flash.display.*;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.filters.DisplacementMapFilter;
import flash.filters.DisplacementMapFilterMode;
import flash.geom.Point;
import flash.utils.Timer;
public class WaterSurface extends Sprite {
//ソースイメージ、ノイズイメージ、ビットマップ
public var sourceImage:BitmapData;
private var noiseImage:BitmapData;
private var softLightBitmap:Bitmap;
private var bitmap:Bitmap;
//ノイズのパラメータ
public var basex:uint;
public var basey:uint;
public var octaves:uint;
public var seed:uint;
public var offsetArray:Array;
public var speedArray:Array;
//置き換えマップの移動強度
public var filterScale:uint;
private var filterScaleTemp:uint;
//減衰が始まるまでの時間(ms)
public var delayTime:Number;
//減衰の時間(ms)
public var decayTime:Number;
//減衰値
private var decayValue:Number;
private var softLightDecayValue:Number;
//減衰フラグ
private var decayFlag:Boolean;
//コンストラクタ(エフェクトをかけるBitmapData、フィルタの強さ、減衰までの時間、減衰の時間、水面の光を入れるか)
public function WaterSurface(g:BitmapData, _fs:uint = 20, _delay:Number = 1000, _decay:Number = 1000, _softlightFlag:Boolean = true )
{
sourceImage = g;
init(_fs,_delay,_decay);
bitmap = new Bitmap(sourceImage);
addChild(bitmap);
softLightBitmap = new Bitmap();
if (_softlightFlag) {
softLightBitmap.blendMode = BlendMode.HARDLIGHT;
softLightBitmap.alpha = 0.5;
addChild(softLightBitmap);
}
}
//初期化
private function init(_fs,_delay,_decay):void
{
basex = 100;
basey = 40;
octaves = 2;
seed = 0;
filterScale = _fs;
filterScaleTemp = filterScale;
delayTime = _delay;
decayTime = _decay;
decayFlag = false;
initOffsetArray(octaves);
}
//オフセットを初期化
private function initOffsetArray(octaves:int)
{
offsetArray = new Array();
speedArray = new Array();
if ( octaves > 0 )
{
for ( var i:int = 0; i < octaves; i++ )
{
offsetArray.push(new Point(0, 0))
speedArray.push(new Point(
Math.floor(Math.random() * 4 + 4),
Math.floor(Math.random() * 4 + 4) ));
}
}
}
//実行
public function start() {
decayValue = filterScale / (stage.frameRate * decayTime/1000)
softLightDecayValue = softLightBitmap.alpha / (stage.frameRate * decayTime/1000);
var timer:Timer = new Timer(decayTime, 1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE,startDecayHandler)
timer.start();
addEventListener(Event.ENTER_FRAME, enterFrameHandler);
}
//減衰をはじめる関数
private function startDecayHandler(e:TimerEvent):void
{
decayFlag = true;
}
//EnterFrame
private function enterFrameHandler(e:Event):void
{
for (var i:int = 0; i < octaves; i++) {
offsetArray[i].x += speedArray[i].x;
offsetArray[i].y += speedArray[i].y;
}
updatePerlinNoise();
updateBitmap();
if (decayFlag) {
filterScaleTemp -= decayValue;
softLightBitmap.alpha -= softLightDecayValue;
}
if (filterScaleTemp == 0) {
removeEventListener(Event.ENTER_FRAME, enterFrameHandler);
filterScaleTemp = filterScale;
decayFlag = false;
}
}
//ノイズを生成する
private function updatePerlinNoise():void
{
noiseImage = new BitmapData(sourceImage.width, sourceImage.height, false, 0x00000000);
noiseImage.perlinNoise(basex, basey, octaves, seed, false, true, 2, true, offsetArray);
softLightBitmap.bitmapData = noiseImage;
}
//ソースイメージにフィルタをかける
private function updateBitmap():void
{
var filter:DisplacementMapFilter = getBitmapFilter();
bitmap.filters = [filter]
}
//置き換えフィルタを得る
private function getBitmapFilter():DisplacementMapFilter {
var mapPoint:Point = new Point(0, 0);
var channels:uint = 2
var componentX:uint = channels;
var componentY:uint = channels;
var scaleX:Number = filterScaleTemp;
var scaleY:Number = filterScaleTemp;
var mode:String = DisplacementMapFilterMode.CLAMP;
var color:uint = 0;
var alpha:Number = 0;
return new DisplacementMapFilter(noiseImage,
mapPoint,
componentX,
componentY,
scaleX,
scaleY,
mode,
color,
alpha);
}
}
使い方は
obj:WaterSurface = new WaterSurface(BitmapData, FilterScale, DelayTime, DecayTime,SoftlightFlag);
addChild(obj);
obj.start()
といった感じ。引数は(ビットマップデータ、エフェクトの強さ、減衰するまでの時間(ms)、減衰時間(ms)、水面のテカリの有無(bool))
プログラムの流れは
Flash標準のTweenとは順序が違うけど、だいたい概念は一緒なので、あてはめれば簡単です。
var tw:TweenMax = new TweenMax(Object, sec, { x:x, ease:EasingFunction ,runBackwards:Boolean});
基本的にはこんな感じ。第1引数はObject、第2引数secは秒数、第3引数はTweenの内容を指示するオブジェクトで、{}で囲って適宜示せばOK。上の例では、x座標をxまで動かす様になっています。y座標を動かすときは「y:y」を挿入します。x,y同時に動かすことも出来ます。
TweenMaxは基本的に、現在位置から指示した位置へ動かします。標準のTweenのようにStartValueは不要です。
指示オブジェクトの「runBackwards」は現在位置から指示位置へ動かすか、その逆かのブール値で、trueなら指示した位置から現在位置へ動きます。デフォルトはfalseです。
TweenMaxでもカスタムイージング関数が使えます。適宜関数を定義して「ease:EasingFunction」で指示するだけです。先のエントリーでも、砂の飛ばし方のy座標でカスタムイージング関数を使っています。このサイトでカスタムイージング関数を作成できるので、TweenMaxでバリエーションが足りないと思うひとはお試しください。
]]>
※枠内クリックで実行
ソースはこんな感じ
]]>package {
import gs.TweenMax;
import gs.easing.*;
import gs.events.TweenEvent;
import flash.display.*;
import flash.utils.Timer;
import flash.events.TimerEvent;
import flash.geom.Rectangle;
import flash.geom.Point;
public class ReconstructionImage extends MovieClip {
//表示オブジェクト
public var obj:DisplayObject;
//放出位置
public var beginX:Number;
public var beginY:Number;
//まとめて放出する際の個数
public var flocks:uint;
//参照を残すための配列群
private var rects:Array = new Array();
private var coords:Array = new Array();
private var tws:Array = new Array();
//コンストラクタ
public function ReconstructionImage(_o:DisplayObject, _bx:Number = 0, _by:Number = 0, _fl:uint = 4)
{
obj = _o;
beginX = _bx;
beginY = _by;
flocks = _fl;
init(obj)
}
//初期化
private function init(o:DisplayObject):void
{
//与えられたオブジェクトをBitmapDataに変換
var bd:BitmapData = new BitmapData(o.width,o.height,true,0x00000000)
bd.draw(o);
//BitmapDataを(0,0)から枚挙
for (var _x:uint = 0; _x < bd.width; _x++) {
for (var _y:uint = 0; _y < bd.height; _y++) {
var color:uint = bd.getPixel(_x, _y);
//Spriteを作り、該当位置の色の四角形を作成する。
var tbd:BitmapData = new BitmapData(1, 1 , true , bd.getPixel32(_x, _y));
var dot:Bitmap = new Bitmap(tbd);
//目標位置を記録するオブジェクトを作成
var d:Object = new Object();
d._x = _x*1;
d._y = _y * 1;
//それぞれ保管する
rects.push(dot);
coords.push(d);
//ドットを表示しておく
dot.x = beginX;
dot.y = beginY;
}
}
}
//実行
public function start() {
var timer:Timer = new Timer(1, Math.ceil(rects.length/flocks));
timer.addEventListener(TimerEvent.TIMER, moveRects);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, finishReconstruction);
timer.start();
}
//ドットを移動させる関数
private function moveRects(e:TimerEvent):void
{
for (var i:uint = 0; i < flocks;i++){
var count:uint = (e.target.currentCount - 1) * flocks + i;
if (rects[count]) {
var s:DisplayObject = rects[count];
s.x = beginX;
s.y = beginY;
addChild(s);
var ep:Object = coords[count];
var sec:Number = Math.random()/4 + 0.25;
var twx:TweenMax = new TweenMax(s, sec, { x:ep._x, ease:Linear.easeOut ,runBackwards:false});
var twy:TweenMax = new TweenMax(s, sec, { y:ep._y, ease:originEase ,runBackwards:false});
tws.push(twx,twy);
}
}
}
//TIMER_COMPLETEしたら実行
private function finishReconstruction(e:TimerEvent):void
{
//一応1000ミリ秒待ってから
var timer:Timer = new Timer(1000,1);
timer.addEventListener(TimerEvent.TIMER_COMPLETE, finishReconstructionHandler);
timer.start();
}
//イメージの再構成が終わったら実行
private function finishReconstructionHandler(e:TimerEvent):void
{
//全てのドットを削除
for each (var rect in rects) {
removeChild(rect)
}
//保持配列をクリア
rects = new Array();
coords = new Array();
tws = new Array();
//分解前の画像を表示
addChild(obj);
}
//イージング関数
private function originEase(t:Number, b:Number, c:Number, d:Number):Number {
var ts:Number=(t/=d)*t;
var tc:Number=ts*t;
return b+c*(42.29629629629623*tc*ts + -198.76543209876544*ts*ts + 259.13580246913585*tc + -122.96296296296296*ts + 21.296296296296298*t);
}
}
}
カタマリのとは大分違った感じですが、まぁそれなりなハズ(w
使い方は
obj1 = new ReconstructionImage(DisplayObject,x,y,n);
addChild(obj1);
obj1.start()
といった感じで。xとyは砂が飛び出す位置、nは一度に舞う砂の数。
プログラムの流れは
FlashのTweenライブラリではちょっと動作がもたつくので、TweenMaxを使ってみた。速い速いと聞くけど、そんなに大差ないと思っていましたが、使ってみてその速度に驚きました。ただ精度が標準と比べて落ちるようで、飛び方が荒くなりましたが、今回のようなケースでは、精度より速さ。今後もケースに応じて使ってみたいと思います。
]]>ただ繋ぎ換えただけだと、レイアウトは日本語のまま。
IMEの設定からUSレイアウトを追加しても、IME起動時には日本語レイアウトにもどってしまうし、レイアウトを切り替えなければならないのも不便。
そこでいろいろ調べてみると、レジストリをいじることで解決するみたい。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\i8042prt\Parameters\
の「LayerDriver JPN」と「OverrideKeyboardIdentifier」の値をそれぞれ、「KBD101.DLL」とPCAT_101KEY」に書き換えればよいみたいです。
ただコレだけではダメで、同じトコロにある「OverrideKeyboardSubtype」の値を「2」->「0」に変更すればOK♪
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Ketboard Layouts\E0010411
の「Layout File」の値を「kbdusx.dll」に書き換えるという情報もありますが、これをするとIMEを通常のキーバインドでは起動することが出来なくなってしまうので要注意です。