(メインページへ)
今日のTips

今日のTips

一定時間待つ

ムービークリップの再生を一定時間だけ停止したいってことありますよね。
Flashではムービークリップが停止stop()しても、その中に配置してあるムービークリップは停止しないので、ループアニメーションを一定時間だけ再生したいというときに便利に使えるスクリプトです(言ってる意味わかります?)。

class Navi {
var mc:MovieClip;
var waitTimer:Number;
//コンストラクタ
function Navi(targetMC:MovieClip) {
mc = targetMC;
}
//一定時間待つ
function waitAndPlay(milisec:Number) {
mc.stop();
clearInterval(waitTimer);
waitTimer = setInterval(this, "timeout", milisec);
}
//タイムアウト
function timeout() {
clearInterval(waitTimer);
mc.play();
}
}

使い方は簡単。まず、再生を一旦停止したいムービークリップのタイムラインの最初のフレームアクションで次のようにNaviクラスのインスタンスを作ります。

var naviObj:Navi = new Navi(this);

次に、一旦停止をしたいフレームをキーフレームにし、3秒間止めたいならば次のフレームアクションを書きます。

naviObj.waitAndPlay(3000);

さらに別のフレームで5秒間止めたければ、そのフレームをキーフレームにして次のフレームアクションを書きます。

naviObj.waitAndPlay(5000);

メインのタイムライン、個々のムービークリップのタイムラインごとにNaviクラスのインスタンスを作っておけば、それぞれのムービークリップごとに一定時間停止を自由に指定できるようになりますね。

個別リンク

クラス定義内でのクラスメンバーの参照

クラスメンバーを参照するには、「クラス名. クラスメンバー」の書式を使いますが、クラス定義内では自身のクラスメンバーをクラスメンバー名だけで参照できます。次のサンプルでは3つのボタンがグループ化されています。どのボタンがハイライトになっているかをクラスプロパティで管理しています。







↓解説とサンプルのダウンロード

サンプルファイルのダウンロード

このサンプルでは、ButtonGroupクラスのselectedBtnクラスプロパティでハイライトになっているムービークリップを管理しています。ムービークリップをクリックされたならばselectBtn()メソッドを呼び出し、まず、selectedBtnクラスプロパティにで管理しているそれまで選ばれていたムービークリップをフレーム"off"に移動します。次に、クリックされたムービークリップ自身をフレーム"on"に移動して、さらにselectedBtnクラスプロパティに登録します。

ButtonGroupクラス定義ファイル
class ButtonGroup {
static var selectedBtn:MovieClip;
var mc:MovieClip;
//コンストラクタ関数
function ButtonGroup(targetMC:MovieClip) {
mc = targetMC;
}
//ボタンの選択
function selectBtn() {
if (selectedBtn != undefined) {
selectedBtn.gotoAndStop("off");
}
mc.gotoAndStop("on");
selectedBtn = mc;
}
}

このムービーのメインのタイムラインのフレームアクションでは、グループにするボタンのムービークリップのインスタンスをButtonGroupクラスに登録しています。これにより、ムービークリップがクリックで動作するようになり、クリックによってselectBtn()メソッドが呼び出されるようになります。

//グループ化するムービークリップを登録する
var btn1:ButtonGroup = new ButtonGroup(yamaBtn.tab);
var btn2:ButtonGroup = new ButtonGroup(kawaBtn.tab);
var btn3:ButtonGroup = new ButtonGroup(umiBtn.tab);
//ムービークリップのクリックでButtonGroupクラスのインスタンスのメソッドを呼び出す
yamaBtn.onPress = function() {
btn1.selectBtn();
};
kawaBtn.onPress = function() {
btn2.selectBtn();
};
umiBtn.onPress = function() {
btn3.selectBtn();
};

個別リンク

移動するラベルをリスト管理しよう(その1)

さてさて、次のムービーはどういう作り、スクリプトになっているでしょうか?ちょっと考えてみてください。簡単じゃん?







ヒント1:
ステージにはabcMorphというインスタンスが置いてあり、abcMorphムービークリップのタイムラインの1フレーム目には、次のフレームアクションが書いてあります。"a", "b", "c"...は、アニメーションの区切りとなるキーフレームのフレームラベル名です。

var labels =["a", "b", "c", "d", "e"];

個別リンク

移動するラベルをリスト管理しよう(その2)

「移動するラベルをリスト管理しよう(その1)」に掲載したムービーでは、次のNaviLabelクラスを使っています。このクラスをどのように使えばいいか考えてみてください。

naviLabel.zipのダウンロード


class NaviLabel {
var mc:MovieClip;
var labels:Array;
var loop:Boolean;
var currentPos:Number = 0;
//コンストラクタ
function NaviLabel(targetMC:MovieClip, lbs:Array, loopMode:Boolean) {
mc = targetMC;
labels = lbs;
loop = loopMode;
}
//先頭のラベルへ
function topLabel():Void {
var labelName:String = labels[0];
mc.gotoAndPlay(labelName);
}
//最後のラベルへ
function lastLabel():Void {
var lastPos:Number = labels.length-1;
var labelName:String = labels[lastPos];
mc.gotoAndPlay(labelName);
}
//次のラベルへ
function nextLabel():Void {
var nextPos:Number = currentPos+1;
if (nextPos< labels.length ) {
currentPos = nextPos;
} else if (nextPos == labels.length) {
if (loop) {
currentPos = nextPos=0;
}
}
var labelName:String = labels[nextPos];
mc.gotoAndPlay(labelName);
}
//手前のラベルへ
function prevLabel():Void {
var prevPos:Number = currentPos-1;
if (prevPos>=0) {
currentPos = prevPos;
} else if (prevPos<0) {
if (loop) {
currentPos = prevPos=(labels.length-1);
}
}
var labelName:String = labels[prevPos];
mc.gotoAndPlay(labelName);
}
}

個別リンク

山川海(その2)

クラス定義内でのクラスメンバーの参照」で紹介したButtonGroupクラスですが、これってもっと単純なことだと気付いちゃいませんでしたか?
ButtonGroupクラスを次のように書き換えたらどうでしょうか?

buttongroup2.zipのダウンロード


class ButtonGroup {
static var selectedBtn:MovieClip;
//ボタンの選択
static function selectBtn(mc:MovieClip) {
if (selectedBtn != undefined) {
selectedBtn.gotoAndStop("off");
}
mc.gotoAndStop("on");
selectedBtn = mc;
}
}

そして、yamaKawaUmi.flaのフレームアクションはたったこれだけ。これでよくないかな?

yamaBtn.onPress = function() {
ButtonGroup.selectBtn(this.tab);
};
kawaBtn.onPress = function() {
ButtonGroup.selectBtn(this.tab);
};
umiBtn.onPress = function() {
ButtonGroup.selectBtn(this.tab);
};

ここまで単純化できてうれしいー!クラスメンバー万歳!と感じいったところで新たな不満がむくむくと・・・
このButtonGroupクラスだと1つのグループしか管理できないではないですか。Aグループ、Bグループが必要なときは、A_ButtonGroupクラス、B_ButtonGroupクラスと2つのクラス定義が必要になってしまう。
う〜ん、かっこ悪い。やっぱ、こういうときこそインスタンスメンバーの出番なのでは?どうする?

個別リンク

山川海(その3)

ボタングループといってもボタンをリストで管理するなどしてグループ化する必要はなく、ハイライト情報だけを管理すればいいのです。だったら、これで十分だったのです。

buttongroup3.zipのダウンロード


class ButtonGroup {
var selectedBtn:MovieClip;
//コンストラクタ関数
function ButtonGroup() {
}
//ボタンの選択
function selectBtn(mc:MovieClip) {
if (selectedBtn != undefined) {
selectedBtn.gotoAndStop("off");
}
mc.gotoAndStop("on");
selectedBtn = mc;
}
}

Aグループ、Bグループが必要なときは、それぞれ次のようにButtonGroupクラスのインスタンスを作ればよいわけで、

var groupA: ButtonGroup = new ButtonGroup();
var groupB: ButtonGroup = new ButtonGroup();

そして、次のようにインスタンスのselectBtnメソッドにクリックされたボタンのインスタンスを送ればいいんですね。

yamaBtnA.onPress = function() {
groupA.selectBtn(this.tab);
};
kawaBtnA.onPress = function() {
groupA.selectBtn(this.tab);
};
umiBtnA.onPress = function() {
groupA.selectBtn(this.tab);
};
//
yamaBtnB.onPress = function() {
groupB.selectBtn(this.tab);
};
kawaBtnB.onPress = function() {
groupB.selectBtn(this.tab);
};
umiBtnB.onPress = function() {
groupB.selectBtn(this.tab);
};








個別リンク

playlistという考え方(その1)

好きな曲を3曲入れたプレイリストがあるとします。そして3曲を順に再生します。次のようなメソッドを作ったとしましょう。

function プレイリストを続けて再生(){
プレイリストの1曲目再生開始;
プレイリストの2曲目再生開始;
プレイリストの3曲目再生開始;
}

これでOKのように思えますが、ちょっと考えてみてください。これだと3曲がいっぺんにかかってしまいませんか?本来ならば、1曲目が終わったら2曲目へ、2曲目が終わったら3曲目へと再生しなければならないですよね。
まったくこれと同じことが図を描くときにも言えます。三角形を描くことはさほど難しくないですが、三角形を1辺ずつ描くにはどうすればいいでしょう?やり方はいろいろありそう?

個別リンク

Flash Player 7以降での_global変数の注意点

拙著の「ActonScriptスーパーサンプル集」(ピンク色の本)のp.119「雪が降るアニメーション」がどーしてもちゃんと動かないという質問をいただきました。サンプルファイルはちゃんと動くのになぜ〜というものです。

その原因は、この本がFlash MX対応つまりFlash Player 6対応で書かれているからです。そして、サンプルファイルがうまく動作する理由は、パブリッシュ設定がFlash Player 6になっているからです。Flash Player 7以降の設定でパブリッシュするとうまく動作しない部分があるんです。

Flash Player 7以降で_global変数を使う場合には、次のように_global.depthの初期化が必要になってしまいました。p.120の該当箇所を次のように修正して試してみてください。

function init() {
//擬似的な深度
if (_global.depth == undefined) {
_global.depth = 1;
} else {
myDepth = ++_global.depth;
}
//遠くほど小さく、手前ほど大きくする
this._width = 3+0.5*myDepth;
this._height = 3+0.5*myDepth;
//半透明
this._alpha = 50;
}

※このページ以外にも同様のスクリプトがあります。Flash Player 7以降に対応するためには修正してご利用ください。

個別リンク

Pointクラスを使おう

Flash 8に座標をx,yで管理できるPointクラスが追加されました。x座標、y座標をペアで扱えるので便利ですね。Pointクラスの機能は意外とシンプルなので自分でも作れそうです。実際、ぼくはFlash 7でもPointクラスをカスタム定義して使っています。Pointクラスは次のように定義できますね。
(注意:Flash 8のPointクラスの使い方ではありません)

(訂正:addは予約語でコンパイルできなかったのでplusに変更しました)

class Point {
var x:Number;
var y:Number;
//コンストラクタ
function Point(x:Number, y:Number) {
this.x = x;
this.y = y;
}
//point同士の足し算
function plus(pt:Object):Point {
x += pt.x;
y += pt.y;
return this;
}
//point同士の引き算
function subtract(pt:Object):Point {
x -= pt.x;
y -= pt.y;
return this;
}
}

使うときには、こんな感じ。
var pointA:Point = new Point(5, 50);
var pointB:Point = new Point(100, 200);
var pointC = pointA.plus(pointB);
これで、pointCは{x:105,y:250}の値をもったデータになります。

でも、これだけではいまいち面白くない。Flash8も面白くない。せっかく座標をポイントで指定できるのだから、次のようにムービークリップの座標を指定できると便利だと思いませんか?

myMC.loc = pointA;

あれ?MovieClipクラスにlocプロパティなんてあったっけ?
ありません。なければ作るわけです。次のようにMovieClipクラスを継承するExtMovieClipクラスを定義し、ムービークリップシンボルにリンケージします。
プロパティの値を=で設定・参照できるようにgetter / setterの機能を使ったfunctionを書いちゃいます。


class ExtMovieClip extends MovieClip {
//
//getter / setter
//------ loc
function set loc(pt:Object) {
this._x = pt.x;
this._y = pt.y;
}
//
function get loc():Object {
var pt:Object = new Object();
pt.x = this._x;
pt.y = this._y;
return pt;
}
}

以上です。わかりました?

個別リンク

リングフォーメーションの意味

「日本の伝統音楽『楽器編』」は「インターフェースを懲りすぎ!」という声もありますが、実際ぼくも作りながらにコレでいいのか?と思ってましたが、できあがってみるとなかなか考えられていると思えてきました。

wagakki_ring.jpg
箏(こと)の楽器データ

「楽器図鑑」ではリング状にアイテムが並ぶデザインが使ってあります。リング状になっていることから、
1.ぐるっと回ることがわかる。
2.データの要素の種類と量を一度に俯瞰(ふかん)できる。
3.要素にダイレクトにアクセスできる。
4.マウス操作だけでデータを選べる。

リング状に並んだアイテムは、詳しく観たいアイテムを選ぶインターフェースである以前に、選ばれた楽器の属性データでもあるという点にも着目してください。それが2番の意味です。
これに比較し「演奏図鑑」というコンテンツはアイテムが直線的に並んでいます。リニア状であることから、アイテムの並びには順番があり、1個ずつ順に見てくださいということを示しています。
通常、これぐらい大量のデータをもったデーターベースをブラウジングするには、それなりのコンピュータリテラシーが必要ですが、「楽器図鑑」ではとりあえず興味の向くままに触っているだけで多くのデータに触れることができるかと思います。全体的にボードゲームの感覚(自分の持ちカードをひろげる感じ)で作ってあり、アニメーションのコンセプトは昔のゲームのゼビウスなんですよ。

リングフォーメーションの習作
test-ring1.jpg

リニアフォーメーションの習作
linear.jpg

個別リンク

ロールオーバーで再生と逆再生

この絵を見て「ん?」って思った人もいるでしょうね。ピンク色の表紙「FLASH ActionScriptスーパーサンプル集」の「03-1ロールオーバーで再生と逆再生」のサンプルです。
このサンプルを動作を同じままでスクリプトを書き換えてみました。サンプルは2個あって、1つはムービークリップシンボルにフレームアクションを書き込んだスタイル。もう1つはMovieClipクラスを拡張したPistonクラスをリンケージするスタイルです。

サンプル:
piston.jpg

スクリプトリストとflaファイルのダウンロードのリンクは「続き・・・」にあります↓

Pistonクラス:


class Piston extends MovieClip {
var rollover:Boolean = false;
//
//最初は停止から始める
//
function onLoad() {
stop();
}
//
//マウスカーソルがロールオーバーした
//
function onRollOver() {
//ロールオーバー開始
rollover = true;
onEnterFrame = animation;
}
//
//マウスカーソルがロールアウトした
//
function onRollOut() {
//ロールオーバー終了
rollover = false;
onEnterFrame = animation;
}
//
//フレームが進む度に実行
//
function animation() {
if (rollover) {
//次のフレームへ進む(最終フレームでは無視される)
nextFrame();
} else {
//手前のフレームに戻る(先頭フレームでは無視される)
prevFrame();
}
//先頭または最後のフレームに到達したらアニメーションを終了する
if ((_currentframe == 1) || (_currentframe == _totalframes)) {
//onEnterFrameイベントハンドラを消去する
delete onEnterFrame;
}
}
}

flaファイルとasファイルはココからダウンロードできます。→ダウンロード

個別リンク

雪が降るアニメーション

ピンク本「Flash ActionScriptスーパーサンプル集」の「07-1 雪が降るアニメーション」もFlash 8用に書き換えてみました。ただ、見た目はほとんど同じですが、手法はまったく別のやり方になっています。
雪のインスタンスを[start]ボタンでアタッチし、アタッチした複数のインスタンスを配列で管理する方法に書き換えてあります。カスタムクラスは使っていませんが、ムービークリップのインスタンスをアタッチ・消去する、配列で管理するというサンプルになっています。


サンプル:
snow8.jpg

flaファイルはココからダウンロードできます。→ダウンロード

個別リンク

ホッピングするボール

ボールをクリックすると落下して地面で跳ね返ります。ボールの位置はドラッグできて、どこからでも落とすことができます。傾斜にぶつかったら斜めに跳ね返らないのかよ〜っていうのは、スクリプトを単純化するために省略です。
いったいどうやっているのか考えてみてください? 斜めに跳ね返らせる方法もね。
地面を突き抜けないようにするくふうもポイント。

サンプル:
hopping.jpg

flaファイルはココからダウンロードできます。→ダウンロード

個別リンク

障害物と方向転換

ちょっと変わったサンプルを作ってみました。障害物となるインスタンスの中に入ると進む向きを変更します。動きをよく観察してみてください。

衝突チェックはMovieClip.hitTest()で行います。
var hit:Boolean = hit_mc.hitTest(_x, _y, true);

移動から衝突チェックまでのスクリプト(抜粋)は次のようになります。vx、vyがベクトルの成分です。高校数学を思い出してね。

//移動      
_x += vx;
_y += vy;
//向き
_rotation = d;
//
//衝突チェック
var hit:Boolean = hit_mc.hitTest(_x, _y, true);
if (hit) {
//10度曲がる
d += 10;
vx = speed*Math.cos(d*Math.PI/180);
vy = speed*Math.sin(d*Math.PI/180);
}

サンプル:
slippy.jpg

個別リンク

クリックした位置を中心に回転する

ムービークリップを回転させるには_rotationプロパティの値を少しずつ加算(減算)すればいいですよね。では、次のサンプルのようにクリックした位置を中心点にして回転させるにはどうすればいいでしょう??
ぼくもけっこう試行錯誤したんですが、答えは意外にも簡単でした! さあ、考えてみてください。

サンプル:
clickPt1.jpg

で、これをさらに発展させたのが次のサンプルです。今度はドラッグしてぐるぐる回せます。こっちはちょっと難しいですね。

サンプル:
clickPt2.jpg

個別リンク

クリックした位置を中心に回転する(回答)

先日の「クリックした位置を中心に回転する」はどうやるかを種明かししましょう。写真をクリックするとクリックした点を中心に写真が回転します。そのままドラッグすることもできるというサンプルです。

サンプル:
clickPt1.jpg


ムービークリップのインスタンスを回転させるには、インスタンスの_rotationプロパティを連続的に変更します。_rotationプロパティの単位は度数なので、

this._rotation += 5;

とすれば5度ずつ回転します。このとき、回転の中心はムービークリップの座標の中心点です。ムービークリップには変形の中心点と座標の中心点がありますが、変形の中心点はあくまでもオーサリング時の[自由変形ツール]での変形の中心であって、スクリプトでは座標の中心点が回転や拡大などの中心点になるので誤解しないようにしましょう。

さてここからが種明かしです。(最後にflaファイルのダウンロードのリンクがあります)

回転させるためには写真をムービークリップシンボルにしなければならないというのは予想できると思いますが、実は回転させているのは写真のインスタンスではないのです。ステージに写真のインスタンスを作ったならば、それを選択してもう1回ムービークリップシンボルに変換します。つまり、入れ子になっているムービークリップを作ります。ステージに置いてあるのは、この写真が入れ子になっているインスタンスです。

インスタンスがクリックされたならば、クリックされた座標にインスタンスを移動します。これでマウスの位置にインスタンスの中心点が移動します。しかし、これでは写真の位置が動いてしまうので、インスタンスをマウスの位置に移動しただけ、中に入っている写真のインスタンスを逆方向に動かします。これで写真は元に位置から動いていないように見えます。後はこのままインスタンスを回転させればインスタンスはマウスの位置で回転するので、写真はマウスクリックした位置を中心点にして回転するように見えるのです。


//回転・ドラッグ開始
function onPress() {
//ドラッグ開始
this.startDrag(false);
//クリックした位置に移動
var xm:Number = this._xmouse;
var ym:Number = this._ymouse;
this._x = _root._xmouse;
this._y = _root._ymouse;
//移動した分だけmyMC(写真)の位置を補正
myMC._x -= xm;
myMC._y -= ym;
onEnterFrame = mawasu;
onMouseMove = updateStage;
}
//回転・ドラッグ終了
function onRelease() {
this.stopDrag();
delete this.onEnterFrame;
delete this.onMouseMove;
}
//回転・ドラッグ終了
function onReleaseOutside() {
this.stopDrag();
delete this.onEnterFrame;
delete this.onMouseMove;
}
//画面リフレッシュ
function updateStage() {
updateAfterEvent();
}
//インスタンスを回す
function mawasu() {
this._rotation += 5;
}

マウスクリックの位置を中心として回す方法はほかにも考えられますが、この方法がもっともお手軽なのではないかと思いますよ。発想の転換ですね。この考え方はいろいろなケースで応用できると思うので、研究してみてください。

flaファイルはココからダウンロードできます。→ダウンロード

個別リンク

バトン

バトンを回してみました。

サンプル:
baton.jpg

class Kaiten extends MovieClip {
	var speed:Number;
	var rd:Number = 0;
	//
	//回転開始
	function startRotaSin(s:Number) {
		speed = (typeof s == "number") ? s : 30;
		this.onEnterFrame = rotaSinStep;
	}
	//
	//逆回転あり
	function rotaSinStep() {
		rd += 3;
		//-1〜1
		var a:Number = Math.sin(rd*Math.PI/180);
		this._rotation += speed*a;
	}
	//
	//回転停止
	function stopRotaSin() {
		delete this.onEnterFrame;
	}
}

ダウンロードファイル↓
「FLASH ActionScript スーパーサンプル集 1.0/2.0対応版」サポートページ

個別リンク

ActionScript3搭載Flash9パブリックアルファ

Flash9のパブリックアルファ(英語版)をもう試しましたか?
Flash9ではActionScript3が搭載されています。ActionScript2でさえよくわからんのにーと困惑している人もいるでしょうけど、駅伝の繰り上げスタートと考えればラッキーかもというのは言い過ぎですかね。

パブリックアルファとサンプルは次のサイトからダウンロードできますが、Flash Professional 8がインストールされていないとインストールできないので注意してください。
Flash Professional 9 ActionScript 3.0 Preview

あくまでもアルファ版なのでまだバギーだってことをお忘れなく。
このサイトでもAS3についてもできるだけ紹介しますね。

個別リンク

リングフォーメーションの習作

お待たせしました。リングフォーメーションの習作のダウンロードファイルです。和楽器サイトではこの習作を土台にしています。
説明など用意できないんですが、これを研究してみてください。

flaファイルとASファイルはココからダウンロードできます。→ダウンロード

リングフォーメーションの習作
test-ring1.jpg

個別リンク

ドラッグして振り回す

「クリックした位置を中心に回転する」を応用した「ドラッグして振り回す」のflaファイルをアップしました。どうぞ研究してみてください。

flaファイルはココからダウンロードできます。→ダウンロード

サンプル:
clickPt2.jpg

個別リンク

ベルばら

マウスで乙女チックに描いちゃってください。
ムービークリップを貼っているのではなく、BitmapDataクラスを使ってイメージを描いています。サイズの変形などはMatrixクラスを使っています。

flowerstamp.jpg

flaファイルとクラス定義ファイル↓
「FLASH ActionScript スーパーサンプル集 1.0/2.0対応版」サポートページ

個別リンク

擬似的な回転

六角形のムービークリップをアタッチし、その中にjpegファイルを読み込んでいます。インスタンスが横回転しているように見せるには_xscaleを-100〜100のように変化させる方法がありますが、スケールがマイナスになるとイメージが反転してしまいます。イメージを反転させたくない場合には、_xscaleの値を0〜100で変化させます。同様に_widthプロパティを0〜100で変化させることでも横回転しているように見えます。
このサンプルのようにステージサイズに合わせてインスタンスのサイズを決めて並べたい場合には、スケールよりも_widthを使う方が大きさを扱う上で回りくどくありません。幅の最小値を0ではなく4などにすれば、回転する板に厚みがあるようにも見えます。
なお、MovieClip.setMask()でマスクをかける場合、写真を読み込み終わってから設定しないとうまくいきません。

hexagon.jpg

flaファイルとクラス定義ファイル→ダウンロード

個別リンク

3Dタウン

一見すると普通の単純なアニメーションですが、マウスで押すとグググッと風景の中に入っていけます。こう見えても3次元なんですよ。マウスで上下左右と押したまま動かせば風景の中をウォークスルーできます。キーボードの上下矢印キーで目線の高さを変えることもできますよ。

3d_town.jpg

このサンプルは11月頃に発売予定のサンプル集に収録しています。

個別リンク

メソッドの上書き

次のようなスクリプトを実行するとどうなるでしょうか?
これは使えるかも!と思いませんか?

var myObj:Object = new Object();
myObj.test = function() {
	trace(1);
};
function test2() {
	trace(2);
}
myObj.test = test2;
//
//testを実行してみよう!
myObj.test();

個別リンク

ネコ温度計リリース

ネコ温度計v.2を正式リリースしました。
設置場所のタイムゾーンに合わせた時計、摂氏+華氏の表示など新機能も盛り込みました。設置用のHTMLコードを生成するページもFlashで作っています。

フランス・パリ↓

ネコ温度計を作るための技術的課題と解決

課題1.米国のお天気サーバーからXMLを取得するたにクロスドメイン制限に引っかかる。
課題2.cat.oshige.comのネコ温度計swfに直リンクしてwebページに貼ったとき、ムービークリップに外置きのswfを読み込むとクロスドメイン制限に引っかかる。
課題3.直リンクしているswfをバージョンアップしても、ブラウザのキャッシュがじゃまして更新が反映されない。かと言ってバージョンアップのたびにswfのファイル名を変えるとそれに伴って設置コードも書き換えてもらう必要が出てくる。これは現実的には難しい。

課題1→解決:PHPの簡単proxyを使い、swfはあくまでも同一ドメイン内とやり取りしているように見せかける。
*当初配布していた物にはセキュリティーホールが発覚。さっそく対応。
課題2→解決:cat.oshige.comにクロスドメインポリシィファイルを置き、それをswfで読み込んで他のドメインからのアクセスを許可する。
課題3→解決:ActiveX コントロールをアクティブ化するためのJavaScriptを修正し、HTMLを生成する際にswfのurlにキャッシュ対策用のダミー引数を付加する関数を付け加えた。

*解決策に使ったファイル類はアップロード版のネコ温度計ファイルに同梱しています。
詳しくは、ネコ温度計ホームページのダウンロードへ。

課題3→解決:対応変更しました
コードメーカーで生成する配置コードにキャッシュ対策のJavaScriptを埋め込み、標準のAC_RunActiveContent.jsはそのまま使うことにしました。どのような手法かなのかは配置コードを見るとわかります

個別リンク

アナログクロック

ネコ温度計には時計が付いています。アナログ時計は次のAnalogClockクラスで作ることができます。
ただ、ネコ温度計の時計は設置場所のタイムゾーンを反映する世界時計です。世界時計にするにはどうすればいいでしょうか?ちょっと考えてみてください。

class AnalogClock {
	var choushin:MovieClip;
	var tanshin:MovieClip;
	var clockInterval:Number;
	//コンストラクタ
	function AnalogClock(H_mc:MovieClip, M_mc:MovieClip) {
		choushin = H_mc;
		tanshin = M_mc;
		//現在の時刻にセット
		updateClock();
		//1分間隔で更新
		clockInterval = setInterval(this, "updateClock", 1*60*1000);
	}
	//時針の回転
	function updateClock():Void {
		tanshin._rotation = getTanshin();
		choushin._rotation = getChoushin();
	}
	//短針の角度
	function getTanshin():Number {
		var now:Date = new Date();
		var h:Number = now.getHours()%12;
		var m:Number = now.getMinutes();
		h += m/60;
		var d:Number = Math.floor(360/12*h);
		return d;
	}
	//長針の角度
	function getChoushin():Number {
		var now:Date = new Date();
		var m:Number = now.getMinutes();
		var d:Number = Math.floor(360/60*m);
		return d;
	}
}

個別リンク

フランチャイズ

これまでセミナーなどで、クラスとインスタンスの関係を「工場と車」などいろいろなものに例えて説明してきました。そしてついに最強のたとえを思いつきました。
それは「フランチャイズ」です。牛丼チェーン店とかのことです。本社がクラスであり、契約店はインスタンスです。どうです。わかりやすいでしょ。え?もっと詳しく書いてくれなきゃわからない?
今日は時間がないのでまた今度。

個別リンク

という名前のメソッドはありません。(その1)

**エラー** /Users/yoshi/Documents/(省略)/NextCardDragDrop.as: 行 49:ClearDataPanel' という名前のメソッドはありません。
 PlayListDataPanel.ClearDataPanel();

さて、このエラーの原因はどこにあると推測できるでしょうか?

まず、このエラーメッセージから、エラーの場所がNextCardDragDrop.asファイルの49行目にあることがわかります。49行目には次のように書いてあるようです。
PlayListDataPanel.ClearDataPanel();
このエラーを解決するためにはNextCardDragDrop.asを開いてClearDataPanelを検索します。確かにこの行が見つかるでしょう。でも、これでは解決しません。
ClearDataPanelメソッドが見つからないのは、PlayListDataPanelクラスまたはPlayListDataPanelインスタンスです。通常の命名規則に従っているならばPlayListDataPanelは大文字から始まっているのでクラス名だと思われます。そこでPlayListDataPanel.asファイルを開いてClearDataPanelメソッドを探してみましょう。
すると次のような原因が見つかるでしょう。
1.本当にClearDataPanelという名前のメソッド(function定義)がない。
2. ClearDataPanelと似たメソッドはあったけど、大文字小文字が間違っているなどのスペルの違いがあった。たぶん、先頭小文字のclearDataPanelと定義してあるはず。

1の場合、捜索が完全ではありません。PlayListDataPanelクラス定義が別のクラスを継承していないかどうか確認する必要があります。継承しているクラスがあるならば、そのクラスを調べる必要があります。

*NextCardDragDrop.asの49行目のPlayListDataPanelがクラス名ではなくインスタンス名ならば、PlayListDataPanelインスタンスを作ったクラスを探す必要があります。こんなことがないように、先頭を大文字にするのはクラス名だけにしておくという命名規則を守りましょう。


個別リンク

という名前のメソッドはありません。(その2)

**エラー** /Users/yoshi/Documents/(省略)/NextCardDragDrop.as: 行 103:NextCard' という名前のメソッドはありません。
 NextCard.dropCard(cdObj);

さて、このエラーの原因はどこにあると推測できるでしょうか?

この場合、みつからないメソッドと言われている「NextCard」が本当にメソッドなのか?ということに気付く必要があります。式から推測するとNextCardはクラス名かインスタンス名のほうが自然です。正解はNextCardクラスが見つからないというバグです。
では、なぜNextCardクラスが見つからないのでしょう?原因は2つ考えられます。

1. NextCardのスペルがクラス定義ファイルと一致していない。つまり、NextCard.asという名前のクラスファイルがない。
2. NextCardのクラスパスが間違っている。

原因が2の場合、NextCard .asがflaファイルと別のフォルダに保存してある場合です。importでクラスパスの指定を行えば解決します。次のような式でcommonフォルダに入っているクラスを読み込めるようになります。

import com.oshige.common.*;

これは、flaファイルと同じフォルダにcomフォルダがあり、その中にoshigeフォルダ>commonフォルダと階層があって、commonフォルダにNextCard .asが入っている場合です。importの指定はclass{}より前に書きます。

import com.oshige.common.*;
class com.oshige.edit.EditPlayList extends PlayListSetter {
...
}

個別リンク

関数以外で関数の呼び出しが実行されました。

**エラー** /Users/yoshi/Documents/(省略)/PlayListSelector.as: 行 41:関数以外で関数の呼び出しが実行されました。
 return cardObjList(pos);

さて、このエラーの原因はどこにあるでしょうか?エラーメッセージは何が言いたいのでしょう?

このエラーは、エラーのステートメントをよく見るとわかります。とは言ってもコードを書いた本人でないとわからないんですけどね。cardObjList(pos)は、次の間違いなんですよ。

cardObjList[pos];

どこが違うかというと、カッコが[]の間違いです。そうです。配列の要素を取り出すためのブラケットアクセスです。ちょっとした書き間違いですが、「関数以外で関数の呼び出しが実行されました。」なんていうエラーメッセージが出るわけです。

個別リンク

TextAreaの文字が欠ける

TextAreaコンポーネントの文字の下側がちゃんと表示されずに欠けてしまうという不具合に出会った人はいませんか?次のように見えます。

textarea_bug.jpg

実際のswfを見る

実はこの現象はMacで見てもわかりません。Macで気付かないまま作っていって、最後のテストでWindowsで確認すると「おりょ?!」ってことになるわけです。
どうすれば解決できるのでしょうか?

文字の下が欠けるので行間の高さが不足していると考えられます。ということは、TextAreaコンポーネントのプロパティの・・・と調べていくとハマってしまうのですよ。
このバグの原因は思わぬ所にあります。それは、TextAreaを含んでいるムービークリップにフィルタが掛かっている、この例ではドロップシャドウが付いていることに原因があります。ドロップシャドウの設定を外せば文字の欠けがなくなります。

では、例に示すようなドロップシャドウ付きのムービークリップは諦めるしかないのでしょうか?そんなことはありません。ちょっとした発想の転換で解決します。それはムービークリップ内の背景をムービークリップにしてドロップシャドウを付けるのです。そうすれば、TextAreaを含んでいるムービークリップはフィルタをかけなくてもドロップシャドウ付きで見えます。
背景にドロップシャドウを付けた

個別リンク

印刷するとフィルタ効果が出ない

フィルタ効果のトラブルをもう1つ。(実はまだまだあるんです)
テキストやムービークリップにドロップシャドウなどのフィルタを設定している場合、その画面をPrintJobクラスで印刷してもフィルタ効果が無視されます。ぼくがいろいろ試した限り対処法は見つかりませんでした。
仕様決めのときにクラアイントに納得してもらうしかありません。orz

あ!
BitmapData.draw()でスナップショットを撮る方法で対処できるかもしれませんね。

個別リンク