[JSFL]座標の小数点を丸めるJSFL使用時の注意(Windows FlashCS4,CS5で確認)

ステージ上のオブジェクトの座標を整数に丸めてくれる便利JSFLに罠があることに気づきました。
CS5で気づいて、CS4でも同じことになったから既知の現象でしょう。

丸めるJSFLはいろんな方が公開してくれてるのでボクもどこかで拾ったものを使ってます。
↓こんなの

var doc = fl.getDocumentDOM();
if (doc.selection.length) {
	for (var i = 0 ; i < doc.selection.length ; i++){
		var mat = doc.selection[i].matrix;
		mat.tx = Math.round(mat.tx);
		mat.ty = Math.round(mat.ty);
		doc.selection[i].matrix = mat;
	}
}

選択したオブジェクトを一括でバーンと変換してくれて便利なんですが、保存時に結果を変換後の座標を保持してくれないことがあるようだということに気づき、なんとなく原因と対策っぽいこともわかったのでメモしときます。


まず、座標を保持しない再現手順を書きます。
(うちでの再現率:100%)

■手順(準備編)

  • 1.新規flaファイルを作成
  • 2.何でもいいから四角いシェイプを書いてMC化(シンボル1とする)
  • 3.シンボル1をさらにMC化(シンボル2とする)
  • 4.シンボル2の中に入り、シンボル1のx座標を0.5にする(プロパティパネルから数値変更)
  • 5.保存して、ファイルを閉じる。
  • 6.再度ファイルを開き、シンボル2の中のシンボル1の座標を確認するとx座標は0.5となっている。

→ここまでは何の問題もない

■手順(不具合発生編)

  • 7.シンボル1を選択した状態で上記JSFLを実行する。
  • 8.プロパティパネル上では0.5が1となっているはず。
  • 9.ファイルを上書き保存して閉じる。
  • 10.ファイルを開いて、シンボル2の中のシンボル1の座標を確認するとx座標は0.5となっている。

→なにこれ、ばかなの、しぬの


ちなみにJSFLを使わずに手動でプロパティパネルの数値を0.5→1に変更した場合は保存は反映されます。
(当たり前か)

では何が問題か。
ここからは推測ですが、上記JSFLでの結果ではflaファイル的には「変更扱いにされていない」っぽいようです。
ためしに上記手順8まで実行した状態でファイルを保存するまえにシンボル2の中のタイムラインのレイヤーをひとつふやしてから保存して開き直してみると、こんどはちゃんとシンボル1座標変更が反映されているのが確認できます。

ここで注意が必要なのは、シンボル2の中のタイムラインをいじったということ。

シンボル2のタイムラインではなく、メインタイムラインのレイヤーをひとつふやしてもシンボル1の座標変更は反映されません。
つまりはFlashはMC単位で変更があったかなかったかを判断して、状態を保存するかしないかを決めてるっぽいので関係ないタイムラインに変更を加えても意味がない、ということになりそうです。


というわけで、対策
確実に「MCに変更を加えたぞ」と判らせてあげるために、上記JSFLを改造。

var doc = fl.getDocumentDOM();
if (doc.selection.length) {
	for (var i = 0 ; i < doc.selection.length ; i++){
		var mat = doc.selection[i].matrix;
		mat.tx = Math.round(mat.tx);
		mat.ty = Math.round(mat.ty);
		doc.selection[i].matrix = mat;
	}
}
//追加:レイヤーを追加して、追加したレイヤーを消す
doc.getTimeline().addNewLayer();
doc.getTimeline().deleteLayer();

最後に2行追加しただけです。
レイヤーを追加してすぐにその追加したレイヤーを削除する。
結果的には何の変化もない意味のない処理ですが、これで「MCに変更を加えたぞ」とflaに判らせてあげることができるようになります。
このJSFLを用いて上記手順を実行すると小数点丸めは確実に保存時に反映されるようなりました。

かなり力技な感じですが、もっとマシな方法がありました教えてくださいませ。
(果たしてCS5.5では直ってるのか?・・・まぁ直ってないだろうな。。)

[AS]FlashPlayer11で、FMS接続でのNetStatusEvent.NET_STATUSをリスナーしてるときのNetStreamからのdispatchの挙動が変わったっぽい。

FlashPlayer11(以下FP11)とFlashPlayer10(FP10)で、FMSの動画を再生する際に、NetStreamでNetStatusEvent.NET_STATUSイベントをaddEventLinster登録したさいのイベント配信のタイミングがFP11とFP10で異なる現象に遭遇した。

具体的には以下をドキュメントクラスとしてパブリッシュしたswfを再生した場合に、traceされる結果がFP11とFP10で異なった。

package
{
import flash.display.Sprite;

public class FMSTest extends Sprite
{
public function FMSTest()
{
//FMSサーバーへのパス
var dirPath:String = “rtmp://hoge.hoge.hoge.hoge”;
var filePath:String = “mp4:hoge.mp4″;
addChild(new LoadMovie(dirPath, filePath));
}
}
}
import flash.display.MovieClip;
import flash.events.NetStatusEvent;
import flash.media.Video;
import flash.net.NetConnection;
import flash.net.NetStream;

class LoadMovie extends MovieClip
{

private var nsUrl:String
private var nc:NetConnection;
private var video:Video;

public function LoadMovie(ncUrl:String, nsUrl:String, w:uint = 320, h:uint = 320 ) {
this.nsUrl = nsUrl;
//ネットコネクションを作る
nc = new NetConnection();
//ネットコネクションの接続状態を調べるリスナー
nc.addEventListener(NetStatusEvent.NET_STATUS , onNcStatus);
//ネットコネクションを接続する。
nc.connect(ncUrl);
nc.client = new Object();
}

//ネットコネクションの状態でいろいろ出力される
private function onNcStatus(e:NetStatusEvent):void
{
switch (e.info.code)
{
//もし無事に接続されたら、
case “NetConnection.Connect.Success”:
initStream();
break;
}
}

//ネットストリームの初期化処理
private function initStream():void {
//ネットコネクションを作る
var ns:NetStream = new NetStream(nc);
//ネットコネクションの接続状態を調べるリスナー
ns.addEventListener(NetStatusEvent.NET_STATUS, onNsStatus);
//読み込みの時間を設定
ns.bufferTime = .1
//メタデータ取得用のオブジェクトを設定
ns.client = new Object();
//videoインスタンスを作成
video = new Video();
video.attachNetStream(ns);
addChild(video);
//再生開始
ns.play(nsUrl);
}

private function onNsStatus(e:NetStatusEvent):void {
trace(“onNsStatus : “+e.info.code);
}
}

再生した際のtraceの出力結果を以下に示す。
FP10

onNsStatus : NetStream.Play.Reset
onNsStatus : NetStream.Play.Start
onNsStatus : NetStream.Buffer.Full

FP11

onNsStatus : NetStream.Play.Reset
onNsStatus : NetStream.Play.Start
onNsStatus : NetStream.Buffer.Empty
onNsStatus : NetStream.Buffer.Full

FP11では、NetStream.Buffer.Emptyが追加されている。
再現性は100%ではないが、6割~9割位の割合でNetStream.Buffer.Emptyイベントを取得するっぽい。


で、再生開始のタイミングでNetStream.Buffer.Emptyイベントがでることで何が困るかというと、FMSでは動画の終了のタイミングを取るのにNetStream.Buffer.Emptyを使うことがあるからだ。
参考:RTMP接続のランダム再生で最後の数秒が途切れてしまう!


再生開始のタイミングでNetStream.Buffer.Emptyを出したくない、どうしたもんかと思ってたら解決策っぽいのが見つかった。
Netstream.bufferTimeを多めに取ってあげるとよいようだ。
具体的には上記コードの59行目

ns.bufferTime = .1; //0.1秒
//↓0.1秒を2秒にする
ns.bufferTime = 2; //2秒

これでNetStream.Buffer.Emptyはtraceされなくなった。
とりあえず、同じ現象に遭遇してしまった人の参考になれば幸いです。

[iPhone]3GSから4sに機種変更するとき「実質無償機種変更キャンペーン」を利用するメリットとデメリット

以前書いた記事
「[iPhone]契約2年を迎えたときに、2年契約(キャンペーン)を更新する or しない のメリットとデメリット」
のオマケ的なお話。

本日iPhone4sに機種変更してきました。
現在softbankは以下のようなキャンペーンを実施しています。(11/30まで)

「実質無償機種変更キャンペーン」

これは、ざっくり以下の内容。

  • 使用中の3GSの端末価格の支払いが済んでない場合はその分はチャラにするよ
  • 支払いが完了してる人(ボクはここに該当)でも6000円キャッシュバックするよ

普通に考えると利用しない手はないのですが、ボクは今回このキャンペーンをあえて使わなかった。


その理由は、(前回の記事の内容とも関係するけど)
このキャンペーンを利用するといわゆる2年縛り状態になってしまう、ということ。
つまり特定の期間外でsoftbankを解約した場合に約1万円の違約金が発生してしまう。

前回の記事にも書いたようにボクは現在softbankの2年縛りの呪縛から開放されている状態だった。
目先の6000円を追うよりも、いつでも解約できるという精神的な安定を望んだわけだ。
もちろん解約しないでずっと使うよ、って人はキャンペーンを利用したほうが得だろう。
ただ個人的に、電話会社のプランは日々変化しつづけていて、それが消費者にとっては改悪の場合もあるわけで、新規で契約する場合にはそちらしか選べないけど、既存の契約者が旧プランを維持できるんであればそれを利用しつづけるのも手かな、と。
一度プラン変えちゃったら、もう元には戻れないと思うし。


p.s
今回アップルストアで機種変更したのだけど、対応してくれた店員さんはとても親切でボクの過去3ヶ月の通話記録からもっと安くなるようなプランを提案してくれた。
具体的には全然通話してなかったから、Wホワイトよりホワイトの方がお得ですよ、と。
ありがたくその提案に従ったけれども、さすがに上記キャンペーンについての細かい話はなかった。
(ボクが2年縛りのかかってない状態かなんて知らないだろうしね)
こちらから質問することで丁寧に教えてくれた。
なんでも直接聞いてみるのが一番だね。

[AS]AS3での、TextField.htmlTextでつかえる、HTML,CSSのまとめ

以前作ったもの。
ネットで検索できるようにメモ。

[AS]Progressinで「at jp.progression.casts::CastPreloader/set contextMenu()」なエラーがでたときの(とりあえずな)対処法

Progressionを使ってこんなエラーに遭遇。

TypeError: Error #1009: null のオブジェクト参照のプロパティまたはメソッドにアクセスすることはできません
at jp.progression.casts::CastPreloader/set contextMenu()
at com.courservector.flashbug::Profiler/allCompleteHandler()


詳しく検証してないからわかってることだけとりあえず箇条書き

  • FlashPlayerがデバッグプレイヤーのときだけ発生
    (普通のプレイヤーでは発生しない)
  • FireFoxで、かつFireBugとFlashBugが入ってるときに発生
  • FireBugとFlashBugを無効化するとエラーはでなくなる
    (このときPCを再起動する必要があった)
  • 無効化してからもいちど有効化したらエラーがでなくなった
    (わけわかめ)

再現の規則性がよくわからんのでブラウザ(FF)とアドオンのバグなんじゃないかと推測。


とりあえずProgression側での対処法も書いておく
CastPreloader.asの431行目にあるsuper.contextMenu = menu;をコメントアウトすればOKっぽい。
(右クリックでProgressionのライセンス表記もでるし、とりあえず大丈夫っぽい)

抜粋したコードはだいたいこんな感じ

//CastPreloader.asの428~431行目あたり

// ContextMenu を作成する
var menu:ContextMenu = new ContextMenu();
menu.hideBuiltInItems();
//■↓ここをコメントアウトする
//super.contextMenu = menu;

[AS]画像をゆっくり動かす方法 その2

以前にも書いた内容についての補足です。
画像をゆっくり動かす方法

上のリンクを読んでもらうとわかるのですが、
画像をゆっくり動かすにはbeginBitmapFill()の第2引数のMatrixを使って位置を変更しながら毎フレーム描画する、
ということだったのですが、これだとあまり直感的でなくてちょっとめんどくさい。

↓のサイトを観たらもっと簡単にできました。
にゃあプロジェクト|[AS3.0] カルーセルに挑戦! (2)

要はShapeなりSpriteなりにbeginBitmapFill()を使って(smoothing=trueで)描画してしまえば、画像が描画されたShapeなりSpriteは0.1px刻みで動かしてもカクカクすることはないようです。

前回のスクリプトを例に修正すると、

package {
import flash.display.BitmapData;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.geom.Matrix;
/**
* …
* @author 393
*/

//ライブラリに画像を用意し、クラス名Bmpでリンケージ。
//画像サイズは400×300

public class Main extends Sprite{

//private var matrix:Matrix = new Matrix();
private var bmp:BitmapData;
private var sp:Sprite;
//private var mx:Number = 0;
//private var my:Number = 0;
//private var w:Number;
//private var h:Number;

public function Main() {
bmp = new Bmp(0, 0);
sp = new Sprite();
addChild(sp);
buttonMode = true;
this.addEventListener(Event.ENTER_FRAME , xEnterFrame);

//■追加:あらかじめspにBitmapDataを描画する。
sp.graphics.beginBitmapFill(bmp, null, false, true);
sp.graphics.drawRect(0,0,bmp.width,bmp.height);
}
function xEnterFrame (e:Event):void {
//mx += 0.05
//my += 0.05
//matrix.tx = mx;
//matrix.ty = my;
//sp.graphics.clear();
//smoothプロパティをtrueにするのがポイント
//sp.graphics.beginBitmapFill(bmp, matrix,false,true);
//sp.graphics.drawRect(mx, my, 400, 300);
//sp.graphics.endFill();

//直接動かしてもカクカクしない
sp.x += 0.05;
sp.y += 0.05;
}
}
}

こちらの方が直感的に使えていいですね。

[iPhone]契約2年を迎えたときに、2年契約(キャンペーン)を更新する or しない のメリットとデメリット

iPhone(3GS)を契約して丸2年になったこともあり、softbaknkの窓口でタイトルどおりの質問をしてきたのでメモしとく。


まず、「2年契約(キャンペーン)」とは
たぶん最初にsoftbankに契約したときに入ることになるいわゆる2年縛りの契約。
この2年がたたないうちに契約を解除すると違約金を1万円くらい払わなきゃいけない。
これは、どこの携帯電話会社でもあるよね。


で、このまま何もしないと3年目からも「2年契約(キャンペーン)」に加入することになり、また2年縛りが始まり途中解約では違約金が発生する、ということ。

これが「2年契約(キャンペーン)」を更新したときのデメリットとなります。
「2年契約(キャンペーン)」に加入してるときは、2年契約(キャンペーン)の更新可能月以外はsoftbank解約時に違約金を払う必要があるので好きなときに解約しずらいということ。
ちなみに「2年契約(キャンペーン)」の更新可能月は、契約月+12,13,14の3ヶ月間。
たとえばボクの場合は2009年8月にiPhone持ったので、更新可能月は2011年の8,9,10月ということ。


では「2年契約(キャンペーン)」のメリット
パケットの上限が4410円になります。
ちなみに2年契約(キャンペーン)に加入してない場合の上限は5980円

下限はいずれも1029円なので、具体的には

  • 2年契約(キャンペーン)アリ:1029~4410円
  • 2年契約(キャンペーン)ナシ:1029~5980円

という料金形態になります。


こうなると毎月パケット上限まで使い切ってる人(つまりボク)は「2年契約(キャンペーン)」をナシにすると毎月の支払い額が増えてしまって微妙だなぁと思ったら、「パケットし放題フラット」というサービスもあると。
こちらに加入するとパケット使っても使わなくても毎月定額4410円のパケット代になると。


まとめると、
毎月パケットを上限まで使い切ってる人は、契約2年を迎えたときに迷わず「2年契約(キャンペーン)」の更新をとめる。
これで、3年目以降はsoftbank解約時に違約金を払わなくてすむので安心。
そして「パケットし放題フラット」に加入すれば月々の支払いは今までどおり。

毎月パケットを上限まで使い切ったり使い切らなかったりとムラが激しい人で、softbankから解約することはないって人は「2年契約(キャンペーン)」を更新してもいいんじゃないかな。

softbankの前はau使ってたのだけど、auは何年使っても契約月以外での解約は違約金払わされるシステムだった気がする。
そう考えると、softbankは良心的なんじゃないかと思った。


>2011.10.6追記


どうやらsoftbankの2年縛りには2種類あるらしい。

■1つは上にかいた「2年契約(キャンペーン)」
■もうひとつは、2010年4月27日から改定された「ホワイトプラン」(基本料金のプラン)

ボクの場合は2010年4月27日以前(「2年契約(キャンペーン)」に加入してる人はこうなるはず)にホワイトプランを契約してるので、上記に書いたとおり、「2年契約(キャンペーン)」を解除すれば2年縛りの呪縛から解除されて、いつ解約してもよくなるのだけど、2010年4月27日以降に契約した人は「ホワイトプラン」(iPhoneの基本料金プランなので必ず入ってるはず)に2年縛りの条項が追加されたので、2年縛りからの呪縛からは逃れる方法はないみたい。

詳細>>ソフトバンクの新ホワイトプランが“改悪”にしか見えない理由

全然良心的じゃないな。
あとよくよく考えたらauのときは端末代無料で2年縛り的なことがまかりとおってた時代だった。
端末代一括で払ったとしても2年縛りがつきまとう、依然よりも環境悪化した気がする。

[iPhone]UISliderにてvalue値固定でmaximumValueを変更した際にはUISliderの見た目が変化しないみたい。そんなときの無理やりな対処の仕方。

UISliderの挙動に悩みました。

やりたかったこと。
たとえば、UISliderが二つあって(sliderA,sliderBとする)、
初期値はこんな感じで、

sliderA.maximumValue = 200;
sliderA.minimumValue = 100;
sliderA.value = 150;
sliderB.maximumValue = 100;
sliderA.minimumValue = 0;
sliderA.value = 50;
[

sliderAのvalue値をsliderBのmaximumValueに対応させたい

//sliderAに対するValue changedなメソッド
-(IBAction) changeSliderAValue:(UISlider* )slider
{
    sliderB.maximumValue= sliderA.value;
}

sliderBはmaximumValueは変化するがvalueは変化しない。
この状態でsliderBの見た目(つまみの位置)が相対的に変化して欲しい。
が、変化しない。。

sliderBのvalueを変数で保持しておいて、明示的にsilderB.valueに代入してみてもだめ。

float sliderBValue;
//sliderAに対するValue changedなメソッド
-(IBAction) changeSliderAValue:(UISlider* )slider
{
sliderB.maximumValue= sliderA.value;
sliderB.value = _sliderBValue;
}
//sliderBに対するValue changedなメソッド
-(IBAction) changeSliderBValue:(UISlider* )slider
{
_sliderBValue = sliderB.value;
}

どうも挙動を確認してみるとslider.valueには現在地と同じ値を明示的に代入しても見た目の変化は起きないようだった。
現在地と違う値を入れてあげれば、maximumValueに対応した見た目の変化も発生する。

で、考えた苦肉の策はこちら

float sliderBValue;
//sliderAに対するValue changedなメソッド
-(IBAction) changeSliderAValue:(UISlider* )slider
{
sliderB.maximumValue= sliderA.value;
//わざとランダムな数値を一度代入することで現在値を更新する
sliderB.value = arc4random() % 100;
//改めて_sliderBValueを代入することで正しい見た目にする
sliderB.value = _sliderBValue;
}
//sliderBに対するValue changedなメソッド
-(IBAction) changeSliderBValue:(UISlider* )slider
{
_sliderBValue = sliderB.value;
}

もっといい方法がありましたら、教えてくださいませ。。

[AS][iPhone]FlashBuilder4.5のActionScriptモバイルプロジェクトで横向き固定の設定をした場合のステージサイズを正しく取得する方法

前の記事の続き、
FlashBuilder4.5のActionScriptモバイルプロジェクトでの設定のお話。

まず横向き固定にする方向は、hoge-app.xmlに

<!-- hoge-app.xml内のinitialWindow要素に指定 -->
<aspectRatio>landscape</aspectRatio>

を設定するだけでOK。
これでデバッグプレビューすると確かに横向きでプレビューされる。
が、stage.stageWidthは320、stage.stageHeightは480と変更されていない。
(ちなみにFlexモバイルプロジェクトの場合はstage.stageWidthは480、stage.stageHeightは320となり問題ないようす)

ではどうしたらいいか、
結論としては、ドキュメントクラスのコンストラクタに以下の一行を追加
stage.setAspectRatio(StageAspectRatio.PORTRAIT);

//前提で、hoge-app.xmlにlandscapeと設定
stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
trace(stage.stageWidth, stage.stageHeight); //出力:320,480
stage.setAspectRatio(StageAspectRatio.PORTRAIT);
trace(stage.stageWidth, stage.stageHeight); //出力:480,320

解せないのが、なぜPORTRAITなのか。
通常はPORTRAITは縦、LANDSCAPEは横をあらわすので、stage.setAspectRatio(StageAspectRatio.LANDSCAPE);と設定すればいいと思ったのだけど、これだとstage.stageWidthは320、stage.stageHeightは480のままとなった。

//前提で、hoge-app.xmlにlandscapeと設定
stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
trace(stage.stageWidth, stage.stageHeight); //出力:320,480
stage.setAspectRatio(StageAspectRatio.LANDSCAPE);
trace(stage.stageWidth, stage.stageHeight); //出力:320,480

解せぬ。


※2011.8.15追記
上記設定だと実機転送した際に横方向にはならない様子。。。
やはりsetAspectRatio()にはStageAspectRatio.LANDSCAPEを設定しないと横向き固定にはなりませんでした。
上に書いたLANDSCAPE設定での懸念されるステージサイズは、
trace(stage.stageWidth, stage.stageHeight); //出力:320,480
となっているようで実機起動上では特に問題なさげ。
ステージサイズがちゃんと取れないのはデバッグプレビューだけでのバグってことなのか!?

※2011.8.18追記
コメント欄にて教えていただきました。
stage.setOrientation(StageOrientation.DEFAULT)を設定することで想定したstageサイズを取得することができました。

//前提で、hoge-app.xmlにlandscapeと設定
stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;
trace(stage.stageWidth, stage.stageHeight); //出力:320,480
stage.setAspectRatio(StageAspectRatio.LANDSCAPE);
stage.setOrientation(StageOrientation.DEFAULT);
trace(stage.stageWidth, stage.stageHeight); //出力:480,320

[AS][iPhone]FlashBuilder4.5のActionSclriptモバイルプロジェクトにて、iOSでプレビューした際のステージサイズが正常に取れない場合

だいぶはまってネットに情報が見当たらなかったのでメモ。

FlashBuilder4.5でiPhone、Androind等のアプリを作るため、以下2つのプロジェクトが用意されました。

  1. Flexモバイルプロジェクト
  2. ActionScriptモバイルプロジェクト

1.はMXMLベースのプロジェクトで2はASだけで作れるプロジェクト。
ボクはMXMLはさっぱりなのでASだけで作れる2.を選択。
普通のFlashコンテンツを作ると同様にドキュメントクラスからゴリゴリ書いていけばOKですが、
iOS用の書き出しをした際にステージサイズの参照値おかしなことになりました。

こちらの想定は、シミュレートデバイスが、iPhone3GSなら320 × 480、
iPhone4設定なら、640 × 960となってほしいところですが、
stage.stageWidth,stage.stageHeightのtrace結果は常に、500, 375

なんぞこれ、と思えどステージサイズの設定する箇所は見当たらず。
ためしにapp.xmlのwidthとheightに直接値(320 480)を入れてみるも変化無し。
さらにドキュメントクラスにSWFのembedタグを書いてみるも変化無し。


FlashBuilderのHelpを観てみるとこんなページに行き着きました。
http://www.randytroppmann.com/2011/04/12/pure-as3-workflow-with-flex-builder-4-5/

そこに書かれていた見慣れぬ1行を追加してみると。。。

stage.displayState = StageDisplayState.FULL_SCREEN_INTERACTIVE;

これを入れることでstage.stageWidth,stageHeightが想定通りの値となりました。
(シミュレートデバイスを変えることにより値も変化する)
とりあえず、よくわからんけど、上記一行は必須らしい。


P.S.
Retina対応もできるらしいけど、3G/3GSとRetinaの混合設定がよくわからん。。
highを書くだけで、Objective-Cみたいに自動でいい感じに変換してくれるのか、それとも2種類の画角を分けて作らないのいけないのか。。
Retinaの実機がないから検証できんのよね。。