Category Archive: ActionScript

[JSFL]シンボル内のオブジェクトの色を一括で変更するコマンド

製作経緯はこんなかんじ。
e-ラーニング系のコンテンツをタイムラインのアニメーションで製作中のこと。
静止テキストのモーショントゥイーンを大量にステージ配置。
あれ。。。よく確認してみたら仕様と違う。。。テキストの色間違ってるじゃん。。。
もう3ファイルくらい作ってて、静止テキストをラップしたMCが大量にあるよ。。。
1個1個MCの中に入って静止テキストの色を変更するのめんどくさい。。。
1ファイルあたりMCが10個以上あるし。。。
!そうだ!これ、JSFLでできるんじゃね!?
とこんな感じ。

そしてできたのはこんなかんじ。
使い方
色を変更したいMCをライブラリで選択し(複数OK)、コマンドを実行。
色を入力するダイアログがでるので色値を入力すればOK。
※MCだけじゃなくて、グラフィックとかボタンでもOK。
※静止テキストだけじゃなくて、シェイプの色も変わります。

var doc = fl.getDocumentDOM();
var items = doc.library.getSelectedItems();
ret = prompt("テキストの文字色を入力", "#000000");
//alert(ret);
for (var i = 0; i < items.length; i++) {
  doc.library.editItem(items[i].name);
  doc.selectAll();
  doc.setFillColor(ret);
  doc.exitEditMode();
}

当初はステージに配置してあるオブジェクトを選択して選択されたMCの中の色を変更しようとしてたのだけど、どうも上手くいかない。
でも良く考えたらこの動作ってライブラリ内のオブジェクトを変更するのと同じことだからこれでいいや、と。

欲しい人いるかはわからんけど一応zipでおいておこう。
シンボル内のオブジェクトの色変更する.jsfl

[AS]TextLayoutFrameworkの簡単なサンプル

TextLayoutFramework(TLF)のメモ

以下に簡単なサンプル

package  {
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.net.*;

	// 使用するText Layout Framework クラスのロード
	//flex SDK 4 に含まれているtextLayout.swcを使用する。
	import flashx.textLayout.container.*;
	import flashx.textLayout.compose.*;
	import flashx.textLayout.conversion.*;
	import flashx.textLayout.edit.*;
	import flashx.undo.*;
	import flashx.textLayout.elements.*;
	import flashx.textLayout.container.ContainerController;

	/**
	 * ...
	 * @author 393
	 */
	public class TextTest2 extends Sprite{
		private var textFlow:TextFlow;
		private var container1:Sprite;
		private var container2:Sprite;
		private var count:int;
		
		public function TextTest2() {

			var text:String="本日確定申告と同時に開業届けも提出してきました。";
			text = [text, text, text, text, text, text, text, text].join("****************");
			
			//テキストフィールドみたいなもの
			textFlow=TextConverter.importToFlow(text,TextConverter.PLAIN_TEXT_FORMAT);
			//テキスト選択とか可能になる
			textFlow.interactionManager = new EditManager();

			//テキストを格納するコンテナーの定義(複数個を連結可能)
			container1 = new Sprite();
			container2 = new Sprite();
			addChild(container1);
			addChild(container2);
			container2.y=150;
			
			//テキストフローにコンテナを追加
			textFlow.flowComposer.addController(new ContainerController(container1, 200, 100));
			textFlow.flowComposer.addController(new ContainerController(container2, 200, 100));
			//テキストフローの更新(コンテナのサイズとか変更したら更新する)
			textFlow.flowComposer.updateAllControllers();
			
			//現在のコンテナの数を取得(出力:2)
			trace("textFlow.flowComposer.numControllers : " + textFlow.flowComposer.numControllers);
			
			//ステージをクリックするごとにテキストフローのコンテナサイズを変化
			stage.addEventListener(MouseEvent.CLICK , clickHandler);
			count = 300;
		}
		
		private function clickHandler (e:*):void {
			//コンテナの数だけループ
			for (var i:int = 0; i < textFlow.flowComposer.numControllers; i++) {
				//コンテナのサイズを変更
				textFlow.flowComposer.getControllerAt(i).setCompositionSize(count,100)
			}
			//テキストフローの更新
			textFlow.flowComposer.updateAllControllers();
			count += 100;
		}	
	}
}

[iP]Objective-Cの文法メモ(self,アクセサ/ミューテーター)

すぐわすれちゃうので気になったところは、とりあえずメモってくことにする。

★プライベートな変数にアクセスするときは、selfを頭につける。
ASでいうところのthisみたいなもんらしい。
ただし記述で省略はしないみたい。
(また、ローカル変数は頭になにもつけないので、頭にselfがあるのはインスタンス変数、なにもなかったらローカル変数という見分け方ができるからわかりやすいかも)

//二つは同じ意味
self.hoge = nil;
[self setHoge:nil]//- (void) setHoge:(id) aHoge{}を実装してあるのが前提

★いわゆるセッターを、Objective-Cではミューテーターと呼ぶ
(インスタンス変数を参照・変更するためのメソッドをアクセサと呼ぶ)

[AS]BetweenAS3でMovieClipのタイムラインのフレームをトゥイーンさせる

ここ最近は、Tweener絶ちをして、BetweenAS3マンセーな感じです。
で、Tweenerみたいにむービークリップのタイムラインのトゥイーンってできるのかなと思い軽くググってもサンプルでてこなかったので、Twitterで呟いてみたらできますよと教えてもらいましたー、
さすがー、すげー

トゥイーン対象がMovieClipの場合は、_frameで操作できるとのこと。
Tweenerと同じ感覚で使えますね。
こんな感じです。

import org.libspark.betweenas3.BetweenAS3;
import org.libspark.betweenas3.easing.*;
import org.libspark.betweenas3.tweens.ITween;

//_mcはタイムラインを持ったMovieClipでステージにおいてあるインスタンス名
BetweenAS3.to(_mc , {_frame:_mc.totalFrames}, 2, Expo.easeOut).play();

[AS]デザインパターン シングルトンパターンの使い方

製作なんてどうせ1人でやるから、Singletonなんて特に決めなくても、自分で覚えてるからいいや、と思ってました。
が、改めて、書籍:ActionScript3.0デザインパターンに書かれているSingletonの基本ソースを見て目からうろこが。。。
Singleton以外のところで感動したのでメモ。
今までのかなり無駄なことをしてたかも。

まずはSingletonクラスの基本ソース

package  {
	/**
	 * ...
	 * @author 393
	 */
	public class SingletonModel{
		//自身をクラスメンバーとすることでどこからでもアクセスできるようにする。
		private static var instance:SingletonModel;
		
		//SingletonEnforcerを引数とすることで外からインスタンス化をできないように。
		//※ただ、引数にnullを設定すれば外からでもインスタンス化できちゃうけど
		public function SingletonModel(enforcer:SingletonEnforcer) {}
		
		//このメソッドでSingletonModelのインスタンス(instance)の参照を取れる
		public static function getInstance():SingletonModel{
			//SingletonModel.instanceが生成されてなければ生成してから、
			if (!SingletonModel.instance){	
				SingletonModel.instance = new SingletonModel(new SingletonEnforcer());
			}
			//returnでインスタンスを返す
			return SingletonModel.instance;
		}
	}
}
class SingletonEnforcer {}

なにが目からうろこだったかって、自分自身をクラスメンバーとして保持するという方法。
これなら、どこのクラスからでも直接参照が取れるから、インスタンスの参照を持ちまわらなくてもいいのよね。
今までは、データモデルとなるようなクラスを、他のクラスに参照渡しても持ちまわってた。
これは一応上記書籍のMVCパターンを参考にしてたのだけど、MをSingletonにしちゃえば、VとかCをインスタンス化するときにわざわざ参照渡さなくてもいいじゃないのかな。
でも全部そうしちゃったらなんか落とし穴もありそうなきもするけど。
とりあえず、こんど使ってみる。

[AS]Vectorで入れ子構造の配列を作るときは宣言でも入れ子構造とする。

2重配列的なことをVectorで実現する場合は最初の宣言時に構造を指定する。
宣言で領域を確保してメモリ消費を抑えるという考え方からすれば当然、か。

//これではだめ
var vec:Vector.<Vector> = new Vector.<Vector>();
vec[0] = new Vector.<Object>();
//こうする
var vec:Vector.<Vector.<Object>> = new Vector.<Vector.<Object>>();
vec[0] = new Vector.<Object>();

※普通の配列の場合は以下のようでOKね。

var array:Array = new Array();
array[0] = new Array()

[AS]progression4 PreloadSWF()を実行するタイミングで「Error: 対象の CastPreloader は準備が完了していないか、すでにコンテンツが読み込まれています。」エラーに注意

タイトルどおりの現象。

※PreloadSWF()については↓の記事がとてもわかりやすいです。
jp.ikekou.blog.Main:Progression 4.0.1 Public Beta 1.3 追加機能① PreloadSWFクラス

で、これを観ながら上記ブログとは少し変えながら試してみたのですが、タイトルのエラー発生。
変更した箇所はatCastLoadStart()の部分で、以下のソース

override protected function atCastLoadStart():void {
	var loaderList:LoaderList = new LoaderList({
		onProgress:function():void{
			trace(this.percent)
		}
	});
	loaderList.addCommand(
        //new PreloadSWF()が遅い
		new LoadSound(new URLRequest("sound/sample.mp3"))
		,new PreloadSWF()
	);
	loaderList.execute();
}

結論から言うと、new PreloadSWF()の書く順番が重要。
↓このように書けばOK

override protected function atCastLoadStart():void {
	var loaderList:LoaderList = new LoaderList({
		onProgress:function():void{
			trace(this.percent)
		}
	});
	loaderList.addCommand(
        //PreloadSWF()が早い
		new PreloadSWF()
		,new LoadSound(new URLRequest("sound/sample.mp3"))
	);
	loaderList.execute();
}

ちなみに参考にしたブログでは、loaderListの処理をatCastLoadStart()のaddCommand()内で行い、そこに追加している。
その際には、new PreloadSWF()の順番は影響はしないようす。

override protected function atCastLoadStart():void {
	addCommand(
		function(){
			var loaderList:LoaderList = new LoaderList({
				onProgress:function():void{
					trace(this.percent)
				}
			});
			loaderList.addCommand(
				//new PreloadSWF()の位置は先でもエラーはでない
				,new PreloadSWF()
				new LoadSound(new URLRequest("sound/sample.mp3"))
			);
			this.parent.addCommand(loaderList);
		}
	);
}

command周りの処理の順番がイマイチちゃんと理解していないから、泥臭く検証しないとわからないのよね。。。
ガッツリ理解しとかないとな。。。

[AS]フォント埋め込みの際のフォント名を取得する方法

以前書いた、
[AS]FlashPlayer10ではTestFieldにアルファ処理可能、あとFlashPlayer9でのフォントの埋め込み方法の詳細
の記事の補足

上の記事では、フォントを指定する際に、TextFormat.fontに指定するフォント名を手動で調べないといけないと書いたけど、ライブラリに登録されたフォントから、さくっと取得することができるようだ。

//フレームアクション
//ライブラリ内のフォントのリンケージ名
var class_name="font1";
var loadedFont:Font = new Font();
var LoadFontClass:Class=ApplicationDomain.currentDomain.getDefinition(class_name) as Class;
Font.registerFont(LoadFontClass);
loadedFont = new LoadFontClass();
//これがTextFormat.fontに指定するフォント名となる。
var font_name=loadedFont.fontName;

//おまけ
//テキストフォーマット
var fmt:TextFormat=new TextFormat();
//フォント名を指定
fmt.font=font_name;
fmt.size = 40;
fmt.bold = false;
//テキストフィールド作成
var tf:TextField=new TextField();
tf.embedFonts=true;
tf.defaultTextFormat=fmt;
tf.text="Test";
//表示
addChild(tf);

教えてくれたサイト:frasio report:[AS3]埋め込みフォントの盲点

[AS]入れ子状態のDisplayObjectの幅/高さをあくまで内容物の大きさによる

あたりまえといっちゃあたりまえのことに躓いた。

var sp:Sprite = new Sprite();
sp.graphics.beginFill(0);
sp.graphics.drawRect(0,0, 10, 100);
var container:Sprite = new Sprite();
container.addChild(sp);
sp.y = 300;
this.addChild(container)
container.addChild(sp)
trace(container.height);//出力は400ではなく、100
//(containerはDisplayObjectContainerの機能しか果たしていないので)

ステージに手動でMCとか作ってるときには直感的に理解していたことだけど、ASで動的に作ってるときにはなぜか上記のようなときは400になるもんだと思ってた。

そんで高さを400にするためには以下のようにすればOK。

var sp:Sprite = new Sprite();
sp.graphics.beginFill(0);
sp.graphics.drawRect(0,0, 10, 100);
var container:Sprite = new Sprite();

container.graphics.drawRect(0,0,0,0);//大きさの無いものをdrawしておくだけでいいらしい

container.addChild(sp);
sp.y = 300;
this.addChild(container)
container.addChild(sp)
trace(container.height);//出力:400

相対的な位置情報も含めて大きさを保持したい場合は単にアルファ0でのものを置こうかと思ったけど、大きさを指定しない状態でdrawするだけでいいようだ。
これは試してみてよかった。

[AS]文字が半角か全角のチェックする方法

厳密にいうとちょっと違うみたいだけどこんな感じ。

//文字列の全角/半角チェック関数。
//(文字列内の文字が全て半角の場合にtrueを返す)
function isAll1ByteChar(str:String):Boolean {
	var countCharCode:Number = 0;
	var isAll1Byte:Boolean = false;
	
	for (var i:int = 0; i < str.length; i++) {
		// 条件分岐
		// 2010/01/27修正:半角カナ対応(のつもり)
		if (str.charCodeAt(i)<=255 || str.charCodeAt(i)>=0xFF61 &amp;amp;amp;&amp;amp;amp; str.charCodeAt(i)<=0xFF9F) {
			countCharCode+=1;
		} else {
			countCharCode+=2;
		}
	}
	if(str.length == countCharCode) {
		isAll1Byte = true;
	} 
	return isAll1Byte;
}
var str1:String = "aaアaaa"
var str2:String = "あああああ";
var str3:String = "aaaaあbcs";
trace(isAll1ByteChar(str1));//出力:true
trace(isAll1ByteChar(str2));//出力:false
trace(isAll1ByteChar(str3));//出力:false

2010/1/27:コード修正:半角カナ対応(のつもり)