自分は最近Flashでの制作はしてないんですが、以前同僚の方に「Flashで入れ子(親子関係)を使ってアニメーションさせて、最終的に親の動きを継承した状態でその子のレイヤーを親と同じ階層にできないか」という相談を受けました。
まぁ、なんでそういう相談を受けたかというと、うちの場合はFlashで動きをつけたあとにそれをプログラマーさんが作られたJSFLコマンド使ってXML形式でエクスポートするんですが、そのエクスポートのスクリプトが入れ子の階層に対応してないんですね・・・(^^;)
(他社さんはたぶんこういうのも対応しているんだろうなぁ…)
ということで、おもしろそうだったので勉強も兼ねてプライベートで
親子関係を利用したアニメーションを持つシンボルを分解するJSFLを作っていたのを公開してみます。
使い方としては入れ子があるレイヤーを選択してコマンドから実行するだけです。
【注意点】
●今のところ1階層分しか対応させていません。
●継承する情報はとりあえずAlpha、Translation、Rotation(Skew)、Scaleです。
●キーフレームのある位置が親と子で異なると思うのでプロット(全部キーフレームに変換)しています。
●プロットしたりしちゃうので元のデータを汚さないように実行時にコピーファイルを作って行います。(実行したFlaファイル名の末尾に_copyがついたものが作られます)
●トライアンドエラーがしやすいように(?)、実行時にできたコピーファイルが開かれている場合は自動で閉じてから実行されます。
もしご興味あれば使ってみてください。
コピーファイルを作って実行するのでたぶん大丈夫だと思いますが、
利用に際して何らかの損害が発生しても作者は責任を負いませんので自己責任でお願いします。
実行される場合は念のため保存してから、もしくはテストデータで試してもらってからが良いかもしれません。
zxpファイルのDLはこちらから
//fl.trace("Flashのバージョン " + fl.version); //CS5 =WIN 11,0,2,489 var doc = fl.getDocumentDOM(); var P_TL = doc.getTimeline(); var selectedLayers = P_TL.getSelectedLayers(); //fl.trace("selectedLayers.lengthは " + selectedLayers.length); //fl.trace("Doc" + fl.findDocumentIndex(fl.documents[0].name)); var openDocs = fl.documents; for(a=0; a < openDocs.length; a++){ //fl.trace(i + " " + openDocs[a].name +"\n"); if (openDocs[a].name.indexOf ("_copy") != -1){ var copyDocIdx = fl.findDocumentIndex(openDocs[a].name); fl.closeDocument(fl.documents[copyDocIdx ] , false); fl.trace("開かれていたコピーを閉じました"); } } if (selectedLayers.length == 0) { alert("何も選択されていません"); }else{ //-----念の為、ファイルをコピーしておく fileCopy (); //-----選択している親レイヤーの名前を入れていく配列 var P_LayerNameArr = []; for (g = 0; g < selectedLayers.length ; g++ ){ var P_LayerName = P_TL.layers[ selectedLayers[ g ] ].name; P_LayerNameArr.push( P_LayerName ); } //fl.trace("選択したレイヤーの名前の配列は " + P_LayerNameArr); for (h = 0; h < selectedLayers.length ; h++){ //-----選択しているシンボルを解除しておく doc.selectNone(); var P_LayerIdx= P_TL.findLayerIndex( P_LayerNameArr[ h ] ); //fl.trace("P_LayerIdxは " + P_LayerIdx[ 0 ] + " : 現在のレイヤーネームは " + P_TL.layers[ P_LayerIdx[ 0 ] ].name); P_TL.setSelectedLayers( P_LayerIdx[ 0 ] ,true); //-----選択したレイヤーがロックされていたらエラーになるのでロック外す P_TL.setLayerProperty('locked', false); var P_FrameArray = P_TL.layers[ P_LayerIdx[ 0 ] ].frames; var P_LastFrame = P_FrameArray.length; //P_TL.frameCount; //fl.trace("P_LastFrameは " + P_LastFrame); //-----コンバート前に初期のキーフレームを配列に入れておく var P_keyframeArry = []; for (k = 0; k < P_LastFrame; k++){ var frame = P_FrameArray[ k ]; var firstFrameElement = P_TL.layers[ P_LayerIdx[ 0 ] ].frames[ k ].elements; if (k == frame.startFrame && firstFrameElement.length != 0 ) { P_keyframeArry.push( k ); } } //-----キーフレームのある配列の最大値(一番最後のフレーム)を取得して、タイムラインのカウント数より小さい場合書き換える var P_maxKeyFrame = Math.max.apply( null, P_keyframeArry ); if ( P_maxKeyFrame < P_LastFrame){ P_LastFrame = P_maxKeyFrame; } //fl.trace("キーフレーム配列(P_keyframeArry)" + P_keyframeArry); //fl.trace("P_keyframeArry.lengthは" + P_keyframeArry.length); //-----最初のキーフレームから最後のキーフレームまでのフレーム選択して、キーフレーム変換 var P_minKeyFrame = Math.min.apply( null, P_keyframeArry ); P_TL.setSelectedFrames( P_minKeyFrame , P_LastFrame ); P_TL.convertToKeyframes(); //-----各フレームの情報を入れていく配列を用意 var arrP_Alp = new Array(); var arrP_Rot = new Array(); var arrP_SclX = new Array(); var arrP_SclY = new Array(); var arrP_SkwX = new Array(); var arrP_SkwY = new Array(); var arrP_PosX = new Array(); var arrP_PosY = new Array(); var blankFrames = new Array(); for (i=0 ; i < P_LastFrame; i++) { P_TL.currentFrame = i; var frame1 = P_TL.layers[ P_LayerIdx[ 0 ] ].frames[ i ]; var curFrameElement1 = P_TL.layers[ P_LayerIdx[ 0 ] ].frames[ i ].elements; //fl.trace("curFrameElement1.lengthは " + curFrameElement1.length); //-----各フレームをまわしていき、空のフレームじゃなかったら親の回転・スケール・スキュー・移動を格納していく if ( !frame1.isEmpty && curFrameElement1.length != 0){ //fl.trace("i = " + i); var elm1 = P_TL.layers[ P_LayerIdx[ 0 ] ].frames[ i ].elements[ 0 ]; elm1.selected = true; arrP_Alp.push( elm1.colorAlphaPercent ); arrP_Rot.push( elm1.rotation ); arrP_SclX.push( elm1.scaleX ); arrP_SclY.push( elm1.scaleY ); arrP_SkwX.push( elm1.skewX ); arrP_SkwY.push( elm1.skewY ); arrP_PosX.push( elm1.x ); arrP_PosY.push( elm1.y ); }else { //空のフレームの場所をいれていく blankFrames.push( i ); arrP_Alp.push( 0 ); arrP_Rot.push( 0 ); arrP_SclX.push( 1 ); arrP_SclY.push( 1 ); arrP_SkwX.push( 0 ); arrP_SkwY.push( 0 ); arrP_PosX.push( 0 ); arrP_PosY.push( 0 ); } } //fl.trace("blankFramesは " + blankFrames); //-----現在のレイヤーの最初のキーフレームにあるエレメントを選択状態にしておく P_TL.currentFrame = P_minKeyFrame; var elm = P_TL.layers[ P_LayerIdx[ 0 ] ].frames[ P_minKeyFrame ].elements; //fl.trace("elm.lengthは " + elm.length + ": エレメントタイプは" + elm[ 0 ].elementType + " , ネームは " + elm[ 0 ].libraryItem.name); elm[ 0 ].selected = true; //------------------------------------------------------------------子の階層に入る---------------------------------------------------------------------------------------- doc.enterEditMode('inPlace'); //-----子の階層のタイムラインを取得しておく var C_TL = doc.getTimeline(); var C_layerCount = C_TL.layerCount; //fl.trace("C_Countは " + C_Count); //-----インスタンスのタイプがシンボルのレイヤーのインデックスを入れていく配列 var C_LayerArray = new Array(); //-----子どものフレームの配列を入れておく var C_keyframeArry = new Array(); //-----子どものレイヤーの名前を入れていく配列 var C_LayerNameArr = new Array(); for (f = 0; f < C_layerCount ; f++ ){ C_keyframeArry[ f ] = new Array(); var C_FrameArray1 = C_TL.layers[ f ].frames; var C_LayerName = C_TL.layers[ f ].name; //fl.trace("C_FrameArray1.lengthは " + C_FrameArray1.length); //-----キーフレームのあるフレームをC_keyframeArryに入れていく for (j = 0; j < C_FrameArray1.length; j++){ var frame2 = C_FrameArray1[ j ]; var firstFrame = C_TL.layers[ f ].frames[ j ]; if (j == frame2.startFrame && firstFrame.elements.length != 0 ){ C_keyframeArry[ f ] .push( j ); //fl.trace("jは " + j); } } //-----シンボルのあるレイヤーの名前を if (C_keyframeArry[ f ] .length > 1) { var C_minKeyFrame = Math.min.apply( null, C_keyframeArry [ f ] ); var insType = C_TL.layers[ f ].frames[ C_minKeyFrame ].elements[ 0 ].instanceType; if (insType == "symbol" ){ C_LayerNameArr.push( C_LayerName ); } } //fl.trace(" f は " + f + " : " + " C_keyframeArry[ f ] は " + C_keyframeArry[ f ] + " : " + "C_keyframeArry[ f ].lengthは " +C_keyframeArry[ f ].length); } //fl.trace("子どものレイヤーの名前の配列は " + C_LayerNameArr); //-----各フレームの情報を入れていく配列を用意 var arrC_Alp = new Array(); var arrC_Rot = new Array(); var arrC_SclX = new Array(); var arrC_SclY = new Array(); var arrC_SkwX = new Array(); var arrC_SkwY = new Array(); var arrC_PosX = new Array(); var arrC_PosY = new Array(); for (b=0; b < P_LastFrame * 2 ){ //-----毎回ラストのフレームを取得する C_LastFrame2 = C_TL.layers[ C_LayerIdx[ 0 ] ].frames.length; //fl.trace("C_LastFrame2(ペースト前)は " + C_LastFrame2 ); //-----後ろにペーストしてしていく C_TL.pasteFrames( C_LastFrame2 , C_LastFrame1 + C_LastFrame2 ); C_LastFrame2 = C_TL.layers[ C_LayerIdx[ 0 ] ].frames.length; //fl.trace("C_LastFrame2(ペースト後)は " + C_LastFrame2 ); } C_LastFrame2 = C_TL.layers[ C_LayerIdx[ 0 ] ].frames.length ; //fl.trace(C_TL.layers[ C_LayerIdx[ 0 ] ].name + "のwhile後のC_LastFrame2は " + C_LastFrame2 + ": P_LastFrameは " + P_LastFrame); //fl.trace("C_TL.frameCountは "+ C_TL.frameCount ); //-----親のフレーム数と合わせるために親のフレーム数以上の部分は削除する C_TL.removeFrames( P_LastFrame + 1 , C_LastFrame2 ); //var C_FrameArray2 = C_TL.layers[ C_LayerIdx ].frames; C_LastFrame2 = C_TL.layers[ C_LayerIdx[ 0 ] ].frames.length ; //fl.trace("Remove後のC_LastFrame2は "+ C_LastFrame2 ); for (c = 0; c < C_LastFrame2; c++) { C_TL.currentFrame = c ; var frame2 = C_TL.layers[ C_LayerIdx[ 0 ] ].frames[ c ]; var curFrameElement2 = C_TL.layers[ C_LayerIdx[ 0 ] ].frames[ c ].elements; //fl.trace( c + " : curFrameElement2は " + curFrameElement2.length); //-----各フレームをまわしていき、空白キーフレームじゃなければ、回転・スケール・スキュー・移動を配列に入れていく if ( !frame2.isEmpty && curFrameElement2.length != 0 ){ var elm2 = C_TL.layers[ C_LayerIdx[ 0 ] ].frames[ c ].elements[ 0 ]; elm2.selected = true; arrC_Alp.push( elm2.colorAlphaPercent ); arrC_Rot.push( elm2.rotation ); arrC_SclX.push( elm2.scaleX ); arrC_SclY.push( elm2.scaleY ); arrC_SkwX.push( elm2.skewX ); arrC_SkwY.push( elm2.skewY ); arrC_PosX.push( elm2.x ); arrC_PosY.push( elm2.y ); }else{ arrC_Alp.push( 0 ); arrC_Rot.push( 0 ); arrC_SclX.push( 1 ); arrC_SclY.push( 1 ); arrC_SkwX.push( 0 ); arrC_SkwY.push( 0 ); arrC_PosX.push( 0 ); arrC_PosY.push( 0 ); } } //-----再度現在のラストフレームを取得 C_LastFrame2 = C_TL.layers[ C_LayerIdx[ 0 ] ].frames.length ; //var C_LastFrame3 = C_TL.frameCount; C_TL.cutFrames( 0 , C_LastFrame2 ); //-----レイヤーを削除しておく C_TL.deleteLayer(); //------------------------------------------------------------------親の階層に戻る---------------------------------------------------------------------------------------- doc.exitEditMode(); //-----同じ名前の新しいレイヤーを作る P_TL.addNewLayer( C_LayerName , "normal" , false ); //fl.trace("C_LayerName : " + C_LayerName); P_TL.pasteFrames( 0 , C_LastFrame2 ); for (d = 0; d < P_LastFrame; d++){ P_TL.currentFrame = d ; //fl.trace("d → " + d + " : 今のレイヤー名は " + P_TL.layers[ P_TL.currentLayer ].name ); var elm3 = P_TL.layers[ P_TL.currentLayer ].frames[ d ].elements[ 0 ]; elm3.selected = true; //fl.trace("ブランクインデックス " + blankFrames.indexOf( c ) ); //-----親の方で空白だったフレームは子どもも空白キーフレームに変換 if ( blankFrames.indexOf( d ) != -1 ){ //-----エレメントがあると空白キーフレームに変換が使えない・・・ なのでトゥイーン削除&エレメント削除する //C_TL.convertToBlankKeyframes( c ); P_TL.setFrameProperty('tweenType', 'none' , d); doc.deleteSelection(); //fl.trace("親がBlank "); }else{ elm3.colorAlphaPercent = ( arrP_Alp[ d ] * arrC_Alp[ d ] ) / 100; elm3.rotation = arrC_Rot[ d ] + arrP_Rot[ d ] ; elm3.scaleX = arrC_SclX[ d ] * arrP_SclX[ d ] ; elm3.scaleY = arrC_SclY[ d ] * arrP_SclY[ d ] ; elm3.skewX = arrC_SkwX[ d ] + arrP_SkwX[ d ] ; elm3.skewY = arrC_SkwY[ d ] + arrP_SkwY[ d ] ; elm3.x = arrC_PosX[ d ] + arrP_PosX[ d ] ; elm3.y = arrC_PosY[ d ] + arrP_PosY[ d ]; /* fl.trace( "加算前のarrP_Alpは " + arrP_Alp[ d ] + " arrC_Alpは "+ arrC_Alp[ d ] ); fl.trace( "加算後のelm3.rotationは " + elm3.rotation); fl.trace( "加算後のelm3.scaleXは " + elm3.scaleX ); fl.trace( "加算後のelm3.scaleYは " + elm3.scaleY); fl.trace( "加算後のelm3.skewXは " + elm3.skewX); fl.trace( "加算後のelm3.skewYは " + elm3.skewY); fl.trace( "加算後のelm3.xは " + elm3.x); fl.trace( "加算後のelm3.yは " + elm3.y); fl.trace( "加算後のAlphaは " + elm3.colorAlphaPercent ); */ } } //fl.trace("今の選択してるレイヤーは " + P_TL.currentLayer + " : " + P_TL.layers[ P_TL.currentLayer ].name); //P_TL.layers[selectedLayers[h]].name P_TL.setSelectedLayers( P_LayerIdx[ 0 ] ); //fl.trace("そして今のレイヤーは " + P_TL.currentLayer + " : " + P_TL.layers[ P_TL.currentLayer ].name); P_TL.currentFrame = P_minKeyFrame; //fl.trace( " P_LayerIdx[ 0 ]は " + P_LayerIdx[ 0 ] + " : P_minKeyFrameは" + P_minKeyFrame ); doc.selectNone(); P_TL.layers[ P_LayerIdx[ 0 ] ].frames[ P_minKeyFrame ].elements[ 0 ].selected = true; //fl.trace("せれくしょん " + doc.selection.length); //------------------------------------------------------------------また子の階層に入る---------------------------------------------------------------------------------------- doc.enterEditMode('inPlace'); //-----配列を初期化する arrC_Alp = []; arrC_Rot = []; arrC_SclX = []; arrC_SclY = []; arrC_SkwX = []; arrC_SkwY = []; arrC_PosX = []; arrC_PosY = []; } //------------------------------------------------------------------最後に親の階層に戻る---------------------------------------------------------------------------------------- doc.exitEditMode(); //-----配列を初期化する arrP_Alp = []; arrP_Rot = []; arrP_SclX = []; arrP_SclY = []; arrP_SkwX = []; arrP_SkwY = []; arrP_PosX = []; arrP_PosY = []; } //fl.trace("完了しました"); alert("完了しました"); } function fileCopy (){ var filePath1 = doc.pathURI; //fl.trace ("filePath1は " + filePath1 ); //-----後ろの.flaを取り除く var filePath2 = filePath1.substr ( 0 , ( filePath1.length - 4 ) ); //fl.trace ("filePath2は " + filePath2 ); if (filePath1.indexOf("_copy") != -1 ){ fl.saveDocument("", filePath1 ); fl.trace("コピーを上書きしました"); }else{ fl.saveDocument("", filePath2 + "_copy.fla"); fl.trace("コピーとして保存しました"); } }
コメントをお書きください