「AS3.0」カテゴリーアーカイブ

外部swfからクラスを呼び出す

画像が固定(更新なし)のスライドショー的なものを作っていて、外部swfにひとまとめにして、そこから画像を取り出そうと考えてみた。

画像はphoto.swfに入れて、そのライブラリのプロパティでリンケージを設定して「photo0」のようにクラス名をつけておく。それで書き出すだけ。
で、取り出しはSWFをロードするクラスに書きます。
package {
import flash.events.EventDispatcher;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.MovieClip;
import flash.net.URLRequest;
import flash.events.Event;
import flash.system.LoaderContext;
import flash.system.ApplicationDomain;
import flash.events.ProgressEvent;
public class SwfLoader extends Loader {
var flg_play:Boolean;
var func_complete:Function;
private var cont:LoaderContext;
//コンストラクタ
function SwfLoader(url:String,isPlay:Boolean,func_comp:Function = null) {
flg_play = isPlay;
func_complete = func_comp;
//各種イベント定義
this.contentLoaderInfo.addEventListener(Event.INIT,onInit_swf);
this.contentLoaderInfo.addEventListener(Event.COMPLETE,onLoaded_swf);
this.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoadProgress_swf);
//for URL
var urlReq:URLRequest = new URLRequest(url);
cont = new LoaderContext();
cont.applicationDomain = ApplicationDomain.currentDomain;
this.load( urlReq, cont);
}
//—–Event.INIT
function onInit_swf(evt:Event):void {
//ロード中は再生しないよう停止
var info:LoaderInfo = LoaderInfo(evt.target);
var mc:MovieClip = info.content as MovieClip;
mc.stop();
}
//swf:ロード継続
private function onLoadProgress_swf(e:ProgressEvent):void {
//継続イベント:送信(ProgressEvent.PROGRESSを引き継ぐ)
dispatchEvent(e);
}
//—–Event.COMPLETE
function onLoaded_swf(evt:Event):void {
try {
//指定関数の呼び出し(LoaderInfo.contentを渡す)
var info:LoaderInfo = LoaderInfo(evt.target);
var mc:MovieClip = info.content as MovieClip;
//再生の有無
if (flg_play) {
mc.play();
} else {
mc.stop();
}
if (func_complete != null) {
func_complete(mc);
}
} catch (err:TypeError) {
trace(err.message);
}
}
public function getImage():Loader {
return this;
}
public function checkClass(ClassName:String):Class {
var cl:Class;
//アプリケーションドメインに指定したクラスがあるか
if (cont.applicationDomain.hasDefinition(ClassName)) {
//取得したクラスをClass型変数に代入
cl = cont.applicationDomain.getDefinition(ClassName) as Class;
trace(“外部SWFファイルから”+ClassName+”クラスをインポートしました”);
} else {
trace(“外部SWFファイルには”+ClassName+”クラスは存在しません”);
}
return cl;
}
}
}

本体側では、こんな感じにswfをロードして・・・

import SwfLoader;
var swf_content:SwfLoader;
//画像用swf:ロード
function loadContent_img():void {
var url:String = “photo.swf”;
var flg_play:Boolean = false;
swf_content = new SwfLoader(url,flg_play);
swf_content.addEventListener(ProgressEvent.PROGRESS, checkLoad_font);
this.addChildAt(swf_content,1);
}
SwfLoaderのcheckClass()という関数を使って、外部swfからBitmapDataを取得します。
//ビットマップ取得
function getBitmap_img(no:int):Bitmap {
var name_bmp:String = “photo” + String(no);
var imgClass:Class = swf_content.checkClass(name_bmp);
if (imgClass != null) {
var img:BitmapData = new imgClass(stage.stageWidth,stage.stageHeight);
var bmp:Bitmap = new Bitmap(img);
}
return bmp;
}

納品先での画像差し替えが不要で、定期的に一括更新かけるような場合は便利かも。作例はこちら

下記のサイトを参考にさせていただきました。
 

フレームラベルに数値を使ってはいけない

たまたま仕事でもらったflaファイルに”00″〜”09″までのフレームラベルがついていたので、何気なく単純にフレーム制御しようとしたらフレーム番号に移動してしまった。例えば・・・
this.gotoAndStop(“07”)
と書くと、フレーム番号7に移動するといった具合。
でテストしてみました。1フレーム目に・・・
this.stop();
goFrame(“07”)
function goFrame(st:String):void {
this.gotoAndStop(st);
}
と書き、任意(フレーム番号7以外)のフレームラベルを”07″にして、1〜100フレームのライムラインに
this.stop();
trace(“—“,this.currentFrame);
と書いて実行。
結果は、やはりフレーム番号に移動。どうも数字のみのフレームラベルは数値として見なされてしまう模様。”7″でも”007″でも結果は一緒でした。AS2でも確認しましたが、結果は同じです。
ちなみに”00″の場合はフレーム移動せず、エラーにもなりませんでした(AS3.0ではフレームラベルが存在しないとエラーが出る)。
普段は必ず「英字」又は「英字+数字」のフレームラベルをつけるクセがついてるので、こんなことにはならないのですが、一応メモとして残しておきます。

Tweenerでフィルタ効果を使う

つい最近知りました。Tweenerでフィルタ効果が使えるんですねえ(笑)。
フィルタ用のライブラリ(caurina.transitions.properties.FilterShortcuts)をimportして初期化してやるだけ。もっと早く知ってれば、自前でちくちく書かなくてもよかったのに。よく見ればTweenerのヘルプに載ってるし…。
this.stop();
import caurina.transitions.Tweener;
import caurina.transitions.properties.FilterShortcuts;
FilterShortcuts.init();
//title_mc:ブレで登場
Tweener.addTween( title_mc, 
{_Blur_blurX:100,_Blur_blurY:0, 
_Blur_quality:2,time:0, transition:”linear”});
Tweener.addTween( title_mc, 
{_Blur_blurX:0,_Blur_blurY:0, 
_Blur_quality:2,time:1.5, transition:”easeOutCubic”,onComplete:goNext});
//次のフレームへ
function goNext():void {

this.gotoAndPlay(this.currentFrame+1);

}

ちなみにカラーをいじる場合は、ColorShortcutsを同じように使います。
this.stop();
import caurina.transitions.Tweener;
import caurina.transitions.properties.ColorShortcuts;
ColorShortcuts.init();
Tweener.addTween(BG_mc,
 {_tintBrightness:0,time:2,transition:”easeOutQuad”,onComplete:goNext});

下記のサイトを参考にさせていただきました。

半角相当での文字数を調べる

今更だけど「全角●●文字まで」って入力制限があって、単に文字数だと全角も半角も1文字になってしまうので、関数を書いてみました。
文字をエンコードしてみて1文字なら半角、2文字以上なら全角3文字を越えたら全角・・・っていう判断です。String.length()は改行コードも1文字にカウントするので、改行コードは統一した上で除外(半角カナが3文字の場合があるので修正)。
これが最善かはわかりませんが…。みんなどうやってるんだろう?
//半角相当での文字数を調べる(改行コードは除外)
function xGetCharLength(str:String):int {
//改行コード統一
var val:String = str.replace(“\r\n”,”\r”).replace(“\n”,”\r”);
var array:Array = new Array();
var count_char:int = 0;
for (var i:int = 0; i<val.length; i++) {
//改行コードは除外
if (val.charCodeAt(i) != 13) {
                        if (escapeMultiByte(val.charAt(i)).length > 1) {
if (escapeMultiByte(val.charAt(i)).length > 3) {
count_char += 2;
} else {
count_char+=1;
}
}
}
return count_char;
}
[2010.12.16 訂正]

野中さんのご指摘を受けて、訂正しました。野中さんが書かれた文字数チェックはこちら。

文字列の有無によるテキストフォーマット設定方法の違い

ずっと前に個人的にメモってたんだけど、今日「あれ?」となったので改めてココに書いておきます。

———————————————

TextFieldのフォーマットを設定するときに、getTextFormat,setTextFormatを使う。

でもテキストがないTextFieldだとフォーマットが適用されない。その場合は、defaultTextFormatを使う。

要は・・・

・setTextFormat>テキストがある場合

・defaultTextFormat>テキストがない場合

ということらしい。

//テキストフォーマット:設定(テキストあり)
function xSetTextFormat(txt:TextField):void {
var tf:TextFormat = txt.getTextFormat();
tf.color = “0xff0000”
//空のテキストに対しては、
//defaultTextFormatを使うこと。
txt.defaultTextFormat = tf;
}
//テキストフォーマット:設定(テキストなし)
function xSetTextFormat2(txt:TextField):void {
var tf:TextFormat = txt.getTextFormat();
tf.color = “0xff0000”
//入力済みテキストに対しては、
//setTextFormatを使うこと。
txt.setTextFormat(tf);
}

Soundクラスでのシーク対応

Soundクラスによるサウンド再生でシークバーをつけたんだけど、Sound,SoundChannelクラスにはseek()がない。基本的にはSound.play(time)で時間指定をすればいいのだけれど、再生停止中に

sndCh = Sound.play(n);
snfCh.stop();
とやっても、SoundChannel.positionの値が更新されない。なので、再生停止中は、volumeを0にした状態で最小時間(1ms)再生してからSoundChannel.stop()することで対応してみた。他にいいやり方あるのかしらん?
以下、シーク対応を含むクラスです。
package {
import flash.media.Sound;
import flash.media.SoundChannel;
import flash.media.SoundTransform;
import flash.events.EventDispatcher;
import flash.display.Loader;
import flash.display.LoaderInfo;
import flash.display.MovieClip;
import flash.events.Event;
import flash.net.URLRequest;
import flash.utils.Timer;
import flash.events.TimerEvent;
public class SoundLoader extends Loader {
var snd:Sound;
var sndCh:SoundChannel;
var sndTF:SoundTransform = new SoundTransform();
var sndVol:Number;
var flg_play:Boolean;
var flg_repaet:Boolean;
var isNowPlaying:Boolean;
var fn_sndComplete:Function;
var timer:Timer;
const time_interval:Number = 1;
function SoundLoader(url:String,isPlay:Boolean,
isRepeat:Boolean,fn:Function=null) {
flg_play = isPlay;
flg_repaet = isRepeat;
fn_sndComplete = fn;
//再生中フラグ:初期化
isNowPlaying = false;
//サウンド:ロード
snd = new Sound();
snd.addEventListener(Event.COMPLETE,loadCompleteHandler);
var urlReq:URLRequest = new URLRequest(url);
snd.load(urlReq);
}
//sound:ロード完了時の処理
function loadCompleteHandler(evt:Event):void {
if (flg_play) {
sndCh = snd.play(0);
sndCh.addEventListener(Event.SOUND_COMPLETE,
  soundCompleteHandler);
isNowPlaying = true;
}
}
//sound:再生終了時の処理
function soundCompleteHandler(evt:Event):void {
trace(“再生終了!”);
if (flg_repaet) {
//repeat:あり
sndCh = snd.play(0);
sndCh.addEventListener(Event.SOUND_COMPLETE,
  soundCompleteHandler);
} else {
//repeat:なし
isNowPlaying = false;
//再生後の処理が指定されている場合:実行
if (fn_sndComplete != null) {
fn_sndComplete();
}
}
}
//sound:再生
public function playSound():void {
var pausePosition:int;
if (sndCh == null) {
//初回再生の場合
pausePosition = 0;
} else if (sndCh.position == snd.length) {
//最後まで再生した場合
pausePosition = 0;
} else {
//それ以外
pausePosition = sndCh.position;
}
sndCh = snd.play(pausePosition);
sndCh.soundTransform = sndTF;
sndCh.addEventListener(Event.SOUND_COMPLETE,
  soundCompleteHandler);
isNowPlaying = true;
}
//sound:一時停止
public function stopSound():void {
sndCh.stop();
sndCh.removeEventListener(Event.SOUND_COMPLETE,
 soundCompleteHandler);
isNowPlaying = false;
}
//sound:巻き戻し
public function rewSound():void {
if (isNowPlaying) {
//再生中
sndCh.stop();
sndCh = snd.play(0);
sndCh.removeEventListener(Event.SOUND_COMPLETE,
 soundCompleteHandler);
} else {
//停止中
//sndCh.stop();
sndCh = snd.play(0);
sndCh.stop();
}
}
//sound:リピート切替
public function repeatSound(isRepeat:Boolean):void {
flg_repaet = isRepeat;
}
//sound:再生位置取得
public function getPosition():Number {
var pos_return:Number;
if (sndCh == null) {
//一度も再生していない場合
pos_return = 0;
} else {
//再生済みの場合
pos_return = sndCh.position;
}
return pos_return;
}
//sound:長さ取得
public function getLength():Number {
return snd.length;
}
//sound:再生位置合わせ
public function setPosition(position_sound:Number,
flg_play:Boolean):void {
//再生位置:指定
sndCh = snd.play(position_sound);
if (flg_play) {
//—再生
sndCh.addEventListener(Event.SOUND_COMPLETE,
  soundCompleteHandler);
isNowPlaying = true;
} else {
//—再生しない
//現在のボリューム:保存
sndVol = sndTF.volume;
//位置移動用にvolumeをゼロにする
var tf:SoundTransform = new SoundTransform(0);
sndCh.soundTransform = tf;
//サウンド位置合わせタイマー:起動
setIntervalTimer_sound();
}
}
//—————————————————
// sound.play()>SoundChannel.stop()を連続させても、
// SoundChannel.positionの値が変更されないので、
// 最小時間(1ms)だけ無音で再生してから停止する。
//—————————————————
//サウンド位置合わせタイマー:起動

function setIntervalTimer_sound():void {
timer = new Timer(time_interval,1);
timer.addEventListener(TimerEvent.TIMER, onStopSound_timer);
timer.start();
}
//サウンド位置合わせタイマー:サウンド停止
function onStopSound_timer(event:TimerEvent):void {
//再生停止
sndCh.stop();
//volume:元に戻す
var tf:SoundTransform = new SoundTransform(sndVol);
sndCh.soundTransform = tf;
}
}
}

FlashDevelop導入記

仕事でFlashDevelopを使う必要が出てきて、セットアップすることに。ずっとFlashのアプリケーションでの作業に慣れているし、Mac版がないってコトでスルーだったけど、導入してみたら色々トラブルもあったので、備忘録としてまとめておきます。

環境:MacBookPro15inch(Core 2 Duo 2.6GHz+メモリ4GB)
インストール先:BootCampにあるWindowsXP SP2です。
1.FlashDevelop.jpのインストール方法に従ってインストール。Java6、.NET Framework 3.5、Flex SDK 3とFlashDevelop 3.2.2 RTM。

2.インストールページのサンプルは動くものの、「メソッドが見つかりません:’Boolean System.Threading.WaitHandle.WaitOne(Int32)’」のポップアップが出てしまう。いろいろググってみて、やっと見つけたページに「net framework2 sp2を入れると直る」と書いてあったので、早速インストール。ポップアップは出なくなった。ふう。

3.仕事で使うプロジェクトファイルをFlashDevelopで起動。プレビューすると今度は「Error: Java heap space」と出てプレビューできず。これまた調べてみると、本家のページで「Flex SDKのメモリ割り当てが足りないらしい」との記述を発見。Flex SDKのbinフォルダにある「jmv.config」ファイルを下記のように書き換え(上のコメント行は元の記述)。

#java.args=-Xmx384m -Dsun.io.useCanonCaches=false -Duser.language=en -Duser.region=JP
java.args=-Xmx512m -Dsun.io.useCanonCaches=false -Duser.language=en -Duser.region=JP


これでやっとプレビューが出来るようになりました。やれやれ。


ちなみにVM Fusion2で動かす場合、Fusionの仮想マシン>設定で、プロセッサ>2仮想プロセッサ、RAM>1024MBに変更したら、XPの起動は速くなりました。ただパブリッシュは遅いので、コード読むぐらいならいいけど、ちゃんと使うときにはBootCampで切替が必要かなという印象です。

子から見た親の有無判定

外部swfをロードするタイプのコンテンツを作っていて、親は自分、子(外部swf)はデザイナーさん担当でASだけこちらで書くというスタイルで作業してます。

で、子のボタン動作は下記のように親から参照するように共通化したのだけど、これだと子だけでテストしたときに、親がなのでエラーが出てしまう。
//btn_next:ボタンイベント設定
var parentObj:Object = this.parent.parent.parent
var func_btn:Function = parentObj.xGetBtnFunction_next()
btn_next.addEventListener(MouseEvent.CLICK,func_btn)

(※this.parent.parent.parentが親に当たる)

実害はないもののデザイナーさんにエラーを見せるのもイヤなので、回避を考えてみた。
//btn_next:ボタンイベント設定

if (this.parent is Stage) {

//単体動作時のエラー回避
trace(“parentObj is null”);
} else {
trace(“parentObj is not null”);
//btn_next:ボタンイベント設定
var parentObj:Object = this.parent.parent.parent;
var func_btn:Function = parentObj.xGetBtnFunction_next();
btn_next.addEventListener(MouseEvent.CLICK,func_btn);
}

このスクリプトは、メインのタイムラインに書いてあるので、[object MainTimeline]の上(this.parent)が、[object Stage]だったら単体動作、そうでなければ外部読み込みされているという判断です(ちなみに外部読み込みの場合は[object SwfLoader]になります)。

コレで問題ないんだけど、もっとカンタンだったり定番的な方法があったら教えて下さい。

配下のMovieClipを検索する方法

AS2.0までは、MovieClipを一括で取得するのに、for 〜 in を使ってたんだけど、AS3.0では使えない。コレの代替案を発見。発見は大げさか・・・(^^;。
下記のように表示リストから検索すればいいわけです。
//mcリスト作成
var array_mc:Array = new Array();
for (var i:int = 0; i<this.numChildren; i++) {
 var target:MovieClip = this.getChildAt(i) as MovieClip;
 array_mc.push(target);
}

もう以前から使っている方法なんだけど、ついAS2.0のクセで「for 〜 in」を使って「アレ?」ってことになるので、改めて備忘録として書いておきます。

クラスをストリングで参照

クラスをストリングで参照する方法をつぶやいたら、早速野中さん@FumioNonaka)からご教授いただいたのでメモ。感謝。

var myClass:Class = getDefinitionByName(“flash.display.Sprite”) as Class;
trace(new myClass());
getDefinitionByName() が、Stringで指定したクラスのクラスオブジェクトへの参照を返してくれるのですね。
 
何をしたかったかというと、ライブラリのリンケージで指定したクラスを場合によって差し替えたかった…ということです。例えば、ライブラリにbtn0,btn1,btn2,…と複数のボタンがあったとして、下記のような関数で…
function xGetCurrentBtn(num:int):SimpleButton {
//クラスをストリングで参照
var myClass:Class = getDefinitionByName(“btn” + num) as Class;
var btn:SimpleButton = new myClass();
return btn;
}
みたいな感じです。