第12回 マウスポインタとスクロールの連動

第12回←教材はこれ!

  • 複数行のコメントアウトは「/*」と「*/」ではさむ。CSSと一緒かな。マウス位置によってスクロールスピードを変える。

// var nNewSpeed:Number; // つぎのステートメントに変更
var nNewSpeed:Number = nStageCenter-stage.mouseX;

/* スクロール方向の判定は不要になる
if (stage.mouseX&nStageCenter) {
nNewSpeed = nSpeed;
} else {
nNewSpeed = -nSpeed;
}
*/

  • ただしこれだとスクロールスピードが速すぎたりするので制限速度をもうける。

// MovieClip: スクロールさせるインスタンス
var nSpeed:Number = 20;  ←制限速度
var nStageLeft:Number = 0;
var nStageRight:Number = stage.stageWidth;
var nStageWidth:Number = nStageRight-nStageLeft;
var nStageCenter:Number = (nStageRight+nStageLeft)/2;
var nSensitivity:Number = 0.2;  ←感度係数
addEventListener(Event.ENTER_FRAME, xScroll);
function xScroll(eventObject:Event):void {
var nNewSpeed:Number = (nStageCenter-stage.mouseX)*nSensitivity;
if (nNewSpeed>nSpeed) {  
←制限速度より大きければ
nNewSpeed = nSpeed;    ←制限速度に置き換え 
} else if (nNewSpeed<-nSpeed) {  ←マイナス方向に制限速度より大きければ
nNewSpeed = -nSpeed;    ←マイナス方向に制限速度置き換え 
}

x += nNewSpeed;

if (x>nStageRight) {
x -= nStageWidth;
} else if (x&nStageLeft) {
x += nStageWidth;
}
}

  • しかし、このやり方でも少し問題があると。
  • DisplayObject.xプロパティに小数点以下の端数がある数値を設定すると、四捨五入で小数点以下第2位までの値に丸められてしまう。
  • なので誤差の累積でインスタンスの位置がずれる可能性がある。
  • ところが変数は最大で小数点以下15桁の値を保持できるので、座標値を変数に入れて扱えば、目に見える誤差が出ない十分な精度で処理できる。なるほどー。
  • そんなわけで最終的にはこうなる。

// MovieClip: スクロールさせるインスタンス
var nSpeed:Number = 20;
var nStageLeft:Number = 0;
var nStageRight:Number = stage.stageWidth;
var nStageWidth:Number = nStageRight-nStageLeft;
var nStageCenter:Number = (nStageRight+nStageLeft)/2;
var nSensitivity:Number = 0.2;
var nX:Number = x;
addEventListener(Event.ENTER_FRAME, xScroll);
function xScroll(eventObject:Event):void {
var nNewSpeed:Number = (nStageCenter-stage.mouseX)*nSensitivity;
if (nNewSpeed>nSpeed) {
nNewSpeed = nSpeed;
} else if (nNewSpeed<-nSpeed) {
nNewSpeed = -nSpeed;
}
nX += nNewSpeed;
if (nX>nStageRight) {
nX -= nStageWidth;
} else if (nX<nStageLeft) {
nX += nStageWidth;
}
x = nX;
}

  • 実際動かしてみたらずれることない感じ。ただ3個だと寂しいね。

第7回 Dateクラスの日付と文字列の操作

第7回←教材はこれ!

  • Dateインスタンスの日付に関するプロパティは以下。ま、ありがちな0スタート。曜日は日曜スタート。西暦は「year」じゃなくて「fullYear」なのがなんか違和感*1。でも4桁なんであと8000年近く大丈夫。
date
Dateインスタンスに設定されたローカル時による日付の日を,1から31までの整数で返す。
day
Dateインスタンスに設定されたローカル時による日付の曜日を,0から6までの整数で返す。0が日曜日で,6は土曜日を示す。
fullYear
Dateインスタンスに設定されたローカル時による日付の年を,4桁の整数で返す。
month
Dateインスタンスに設定されたローカル時による日付の月を,0から11までの整数で返す。0が1月で,11は12月を示す。
  • 取得した日付をTextFieldインスタンスに表示するにはダイナミックテキスト。

[テキストツール]でTextFieldインスタンスを作成する。TextFieldインスタンスには,MovieClipインスタンスと同じように,プロパティインスペクタでインスタンス名を設定する必要がある。ここでは,インスタンス名は"my_txt"としよう。スクリプトでテキストを設定する場合,[テキストの種類]は[ダイナミックテキスト]を選ぶ

  • あくまでTextFieldインスタンスに表示することができるのは文字列なのでデータ型も文字列に変換する必要がある。

var my_date:Date = new Date();
var nYear:Number = my_date.fullYear;
my_txt.text = String(nYear); ←ここでNumber型をString型に変換!

  • 「年」以外のプロパティも表示させたい場合、文字列の連結が必要。「/」で連結したい場合は以下。

my_txt.text = String(nYear)+"/"+String(nMonth)+"/"+String(nDate);

加算演算子+は,式の演算対象となる項の値が数値か文字列かによって機能が変わる。数値のときは算術の加算になり,文字列であれば本文に示したように連結の機能を果たす。

数値と文字列を被演算子オペランド)として加算演算子+を用いると,数値は自動的に文字列に変換されて,文字列を連結する処理が行われる。したがって,前記スクリプト2のTextField.textプロパティへの代入式は,String()関数を使うことなく,以下のステートメントでも同じ結果が得られる。

my_txt.text = nYear+"/"+nMonth+"/"+nDate;

しかし,データ型を意識してString()関数により明示的に文字列への変換を行う方が,万が一の失敗を防ぐ確実なスクリプティングということはできる。

*1:しかも「Y」だけ大文字

第8回 Stringクラスによる文字列の操作と値を返す関数

第8回←教材はこれ!

  • そうそうこっちの方が僕の知ってたイメージ。

文字列の操作には,Stringクラスが利用できる。Stringクラスも,Dateクラスと同じように,インスタンスをターゲットにして,プロパティやメソッドを操作する。しかし,new演算子インスタンスを作成しなくても,ダブルクォーテーション(")で括って記述した文字列は,そのまま Stringクラスのインスタンスとして扱える

  • ただやはりクラスの概念がいまいちー。
  • 文字列から一部を取り出すメソッド「String.substring()メソッド」。引数は開始位置と終了位置。0番目からスタート。使用例は以下。

var year_str:String = "2007";
trace(year_str.substring(2, 4)); // 出力: 07

文字列のインデックス番号は0から始めるので,第1引数の2は(3文字目なので)よいとして,第2引数の4がわかりにくいかと思う。これはヘルプを見ると,第2引数は「抽出するサブストリングの最後の文字のインデックスに1を加えた整数」とされているからである。

  • これまためんどくさい話になってるけど、この続きにあるように文字間に仕切りがあって間の数で考えてるとすると納得できるかな。ただし仕切り0番目は最初の文字の左に来る。間の数を0番目から始めると文字数と最後の番目が一緒になるのも都合が良い!*1
  • さらに大事なことに第2引数を省略すると「String.length」が適用させるとのこと。つまり省略すると最後まで切り抜かれると。
  • 1桁の数字も十の位に0を足して2桁表示にする賢い工夫が以下。

var nDate:Number = 1;
var date_str:String = String(nDate+100).substring(1);
trace(date_str); // 出力: 01

  • だいたいこういう表示ものは値の桁数固定の方が絶対デザイン的に楽。僕のケータイ待ち受け(ドラクエ復活の呪文風時計)はそのあたり間違ってる★
  • ここでこの処理を戻り値ありの関数に定義。戻り値はreturnで指定。書式は以下。

function 関数名(引数:データ型):戻り値のデータ型 {
// 処理内容
return 戻り値;
}

  • 実際はこれ。

function xSetDigits(n:int):String {
var temp_str:String = String(n+100); ←西暦の4桁であっても100を足すけど実は問題なし。
var n_str:String = temp_str.substring(temp_str.length-2); ←何桁であっても下2桁を取り出せる!
return n_str;
}

  • 最後にさりげなく「returnステートメントは,値を返すだけでなく,関数を終了させる。」と記述あり。そういえば「return」の後に何も指定がない関数見たことあるような。。。

*1:植木算の発想ですね。仕切りが「木」で文字が「間」になってしまうけど★

第9回 座標の天動説と地動説

第9回←教材はこれ!

  • いきなりややこしい話だ!!!

x/yやmouseX/mouseYプロパティの定義元には,「DisplayObject」と記されている。つまり,これらのプロパティはDisplayObjectクラスに定義されているのだ。前回まで使っていたrotationもこのDisplayObjectクラスのプロパティである。なぜそれらが,MovieClipインスタンスからアクセスできるのか。

  • アクセスしてたんか!ん?!そもそも「rotation」出てきた時にそんなこと考えてないしな−。
  • そしてすぐに理由が明らかに。

多くのクラスは,階層構造を成している。その場合,ベースとなるクラスのプロパティやメソッド一式を引継ぎ,そこに新たなプロパティやメソッドを追加するかたちで新しいクラスが定義される。ベースとなるクラスは一般に「スーパークラス」と呼ばれ,それを拡張したいわば子どものクラスは「サブクラス」という。

  • つまりスーパークラスであるところの「MovieClip」から、サブクラスであるところの「DisplayObject」へアクセス可能と言うこと?
  • なんか今回から急に話が難しくなった気がする−。*1
  • 今まで割と分かりやすかったのに急にこの日本語難しいよ、野中先生!

mouseXは,MovieClipインスタンスの(継承した)プロパティだった。ということは,インスタンスによって,その値が異なりうることを意味する。マウスポインタは,コンピュータの画面にひとつしか存在しないのに,である。

理由は,mouseXプロパティが,インスタンスの基準点から見た座標を返すためだ。つまりこの値は,マウスポインタインスタンスの右側にあればプラスに,左側にあるとマイナスになる。地球から見て太陽が昇ったり沈んだりしている,と考えるようなものだ。つまり,DisplayObject.mouseX/DisplayObject.mouseYは,「天動説」のプロパティなのである。

  • でも何回も読んだら分かったよ。
  • とりあえず、mouseXプロパティが返す値は相対的なものだっつーことね。だから天動説。うーん無理矢理例え系。
  • 「天動説」「地動説」言わんでも「相対位置」「絶対位置」で通じる気もしますが。
  • ややこしいからまとめてみる。
DisplayObject.mouseX(マウスのx座標)
天動説のプロパティ←インスタンスの基準点から見た座標を返す
DisplayObject.mouseY(マウスのy座標)
天動説のプロパティ←インスタンスの基準点から見た座標を返す
DisplayObject.x(インスタンスのx座標)
地動説のプロパティ←当然親タイムラインから見た座標
DisplayObject.y(インスタンスのy座標)
地動説のプロパティ←当然親タイムラインから見た座標
  • ということで座標空間を地動説に一致させる*2。つーかつまり絶対位置指定ね。当然の流れですね。
  • なにげにインスタンスからメインタイムラインの方を指定するのは初めて。なるほど「parent.」使うのね。

addEventListener(Event.ENTER_FRAME, xFollowMouse);
function xFollowMouse(eventObject:Event):void {
x = parent.mouseX;
}

  • そんなわけで相対指定の方法も教えてくれるって。*3
  • 最後にマウスがウィンドウの外に出た場合についても言及。これについてはなんとなく経験通りの結果かな。
  • マウスが中にあるのか外にあるのかの判定自体は難しそうな予感。

*1:大学の授業でもこういうのよくあったなぁー(´Д⊂

*2:やっぱし地動説・天動説の例え分かりにくい!一瞬だけ迷う(´Д⊂

*3:もう面倒だから天動説・地動説は言い換えて使う!!!

第10回 プロパティのイージング

第10回←教材はこれ!

  • 今回は相対指定で座標を指定するとのこと。

xfunction xFollowMouse(eventObject:Event):void {
x += mouseX;
}

  • これはXの値にマウスの座標を加えると言うことですか。なるほど。
  • でもよく考えたらこっちのほうよく見るし、こっちの方が自然な気がする。
  • さ、そして「イーズアウト」「イーズイン」の話。これは普通にFLASHやってたら知ってる単語。
  • しかしどっちがインでアウトかいまいち覚えられない。フェードイン、フェードアウトは分かるけど*1
  • 「ゆっくり近づく」イーズアウトの公式。

// MovieClip: マウスポインタに追随させるインスタンス
var nDeceleration:Number = 0.2; ←この変数がゆっくり具合を調整するパラメータ。
addEventListener(Event.ENTER_FRAME, xFollowMouse);
function xFollowMouse(eventObject:Event):void {
x += mouseX*nDeceleration; ←係数かけることによってゆっくり近づいていく。
y += mouseY*nDeceleration;
}

  • たしかにこれだとゆっくり近づいていくな−。位置差がつねに0.2倍ということは近づくほど差も小さくなりすすむ距離も短くなる。
  • 減速していくことが「イーズアウト」か。スピードがアウトしていって無くなると覚えればいいのかな。

*1:easeがゆっくりとという意味の英語なら、「ease in=ゆっくり入る」、「ease out=ゆっくり出る」と覚えればいいのかな?←ダメっぽい

第11回 MovieClipをスクロールさせる―条件判定

第11回←教材はこれ!

  • 条件判定っていかにもスクリプトのお勉強っぽくて僕は好きですよ。
  • 野中先生今回は余裕が感じられますね。野中節炸裂。

上級者でも,ひとつのミスもなく,1回で動きを完成することはたやすくない。小分けにして作成と確認を繰返していけば,問題が出たときも,その調査対象を限定できる。事件の早期解決には,何より容疑者の絞り込みが重要なのだ。

  • そして条件文の書式がこちら。

if (条件) {
// 条件が満たされた場合の処理
}

  • 画像を無限ループさせるための条件式。ちょうどスロットマシーンを作りたいと思っててこれやりたいと思ってた!ラッキー。

if (x>stage.stageWidth) { // ステージ右端を超えたら
x = 0; // ステージ左端に移動
}

  • おっとしかしこれでは困るとのこと。なるほどインスタンスがいっぱいあったらずれる可能性があるのね。
  • そんなわけで何ピクセルはみ出してても大丈夫なように「x=0」とせず、「x-=stage.stageWidth」にすると。

// MovieClip: スクロールさせるインスタンス
var nSpeed:Number = 5;
var nStageLeft:Number = 0;
var nStageRight:Number = stage.stageWidth;
var nStageWidth:Number = nStageRight-nStageLeft;
addEventListener(Event.ENTER_FRAME, xScroll);
function xScroll(eventObject:Event):void {
x += nSpeed;
if (x>nStageRight) { // ステージ右端を超えたら
x -= nStageWidth; // ステージ左端に移動
}
}

  • 次は条件分岐の書式。この流れでswitch文も出てくるのかな?

if (条件) {
// 条件の評価がtrueの場合の処理
} else {
// 条件の評価がfalseの場合の処理
}

  • これを利用してマウスポインタの位置からスクロールする方向を変えるのがこれ。

// MovieClip: スクロールさせるインスタンス
var nSpeed:Number = 5;
var nStageLeft:Number = 0;
var nStageRight:Number = stage.stageWidth;
var nStageWidth:Number = nStageRight-nStageLeft;
var nStageCenter:Number = (nStageRight+nStageLeft)/2; // ステージの水平方向中央の座標値
addEventListener(Event.ENTER_FRAME, xScroll);
function xScroll(eventObject:Event):void {
var nNewSpeed:Number;
if (stage.mouseX<nStageCenter) { // マウスポインタがステージ中央より左寄りなら
nNewSpeed = nSpeed; // 移動方向を右(正)に
} else { // マウスポインタがステージ中央もしくは右寄りなら
nNewSpeed = -nSpeed; // 移動方向を左(負)に
}
x += nNewSpeed; // 設定された方向にインスタンスを移動
if (x>nStageRight) {
x -= nStageWidth;
}
}

  • わざわざステージの右と左の座標を取ってる意味が今のところよくわかんない。センターも「stage.stagewidth/2」でいい気がするのに。なぜだ!*1
  • あと変数に「-」つけるだけで絶対値変えられるんかー。やったこと無い気がする。
  • そんで後はステージ左端を越えたら右端に行くという逆の場合の処理も付け加えると最後のif文は以下。

if (x>nStageRight) { ←まず右端を越えてるかチェック
x -= nStageWidth;   ←越えてたら左端へとばす
} else if (x<nStageLeft) { // ステージ左端を超えたら
x += nStageWidth; // ステージ右端に移動
}
}

  • 結局今回はswitch文出てこず。

*1:どーせすぐ種明かしがある。←無かった