スターウォーズのオープニングクロールを作る
「2015年は映画の年」と言われるくらい、注目作品が上映予定となっております。
    その中でも、スターウォーズの存在は大きいと思います。
    
    ここでは、スターウォーズのオープニングクロールを作ってみようと思います。
  	スターウォーズを見たことがなくても、知ってる人が多いあれです。
    
	
動きのイメージを固める
スターウォーズのオープニングクロールは、誰でも知っているくらい有名ですが、ホーム画面とどのように繋げばいいのでしょうか?
    画面の外から入ってきて、奥へと消えていくのですが、もともと画面にあるアイコンで表現するには、工夫や妥協が必要になります。
    
    そんな訳で、以下のような動作にしようと思います。
    ・現在のページを奥へ傾ける。
    ・現在のページを縮小しながら遠ざける。
    ・次のページを画面外から入り込ませる。
    ・傾いた次のページを起こす。
    こんな感じですが、スターウォーズのオープニングクロールをイメージすると、現在のページと次のページは、同時に表示させるべきですね。
    
    では、1つ1つイメージに近づけていきましょう。
  
現在のページを傾ける
スターウォーズのオープニングクロールは、ご存知の通り、手前から奥へと消えて行きます。
    そのイメージを実現させるには、もともと平面であるページを傾けて、奥行き感を演出する必要があります。
    とりあえず、次のページは後回しにして、現在のページを傾けるところまで作ってみましょう。
    
    ここでは、以下のサンプルを流用します。
    ・動きを止める(effect1_1)
    ・ページ回転のいろいろ(effect4_3)
    この2つで十分かと思います。
    
    最初に、エフェクト的にページ移動を無効にしなければなりませんので、以下の1行を入れておきます。
    
    page:translate( offset )
    
    2ページ目は、とりあえず消えていてもらうので、以下を入れておきます。
    
    if( percent < 0 ) then page:scale(0)
    
    ページを傾けるのですが、どれくらい傾けるのが妥当なのでしょうか???
    しばらく決まりそうにないので、変数に登場してもらいましょう。
    それでも初期値は必要ですので、0.9とします。
    これは、90°に対してどれくらい傾けるのかというものですが、ほとんど寝てるくらい傾けるイメージが強いので、0.9としました。
    
では、この初期値でどれくらい傾くのか確認してみましょう。
  	プログラムは以下の通りです。
  
local percent = offset/page.width
local angle = percent*math.pi/2
local rr = 0.9
page:translate( offset )
if( percent < 0 ) then
page:scale(0)
else
page:rotate(rr * angle, 1, 0, 0)
end
end
effect34_1
  	変数rrが、ページの傾き具合を表し、90°に対する割合を格納します。
  	実際に動かしてみると、こんな感じです。
  
    	画面を傾ける
    
いきなり問題発生ですね。
    画面を傾けるだけのはずが、妙なひねりも入ってしまいました。
    
    これが、「3Dエフェクトにおける予想外の動作」と言われるもので、予想外だからこそ面白いということで使われています。
    しかし、プログラミング的には「バグ」扱いになりますので、対応しなければなりません。
    
    これまでと同様のやりかたで横移動を止めたはずなのですが、どうしてこんな動きになってしまったのでしょうか?
    ページの移動を止めるために、translateを使ったのですが、translateは行列変換ですので、この「行列」がイタズラしているものと考えられます。
    では、行列(translate)を使わずに、横方向の移動を止めてみましょう。
    やり方は単純で、横方向への移動を打ち消すだけです。
    横方向は、page.layer.xで取得&指定できますので、以下のように書き換えます。
  
local percent = offset/page.width
local angle = percent*math.pi/2
local rr = 0.9
page.layer.x = page.layer.x + offset
if( percent < 0 ) then
page:scale(0)
else
page:rotate(rr * angle, 1, 0, 0)
end
end
effect34_1_2
このやり方が、本来のやり方なのでしょうね。
  	このやり方で動かしてみると、こんな感じです。
  
    	画面を傾ける(対策後)
    
イメージ通りの動きになりました。
    これで、スタートできますね。
  
動きを2段階にする
ページを傾けることができましたので、傾いたページを奥へ移動させるのですが、その前に、動きを2段階にしておきます。
    
    ここでは、以下のサンプルを追加流用します。
    ・エフェクトを段階的にする(effect26_1)
    
    動作をどのタイミングで変更するかを表す変数をerとし、その初期値を0.5とします。
    動きに関しては、動作全体の真ん中で動作を止めることにします。
    
  	では、実際にプログラムを記述してみましょう。
  
local percent = offset/page.width
local angle = percent*math.pi/2
local rr = 0.9
local er = 0.5
page.layer.x = page.layer.x + offset
if( percent < 0 ) then
page:scale(0)
else
if( percent < er ) then
page:rotate(percent*rr*math.pi/2, 1, 0, 0)
else
page:rotate(er*rr*math.pi/2, 1, 0, 0)
end
end
end
effect34_2
  	erの前後で動作を変えています。
  	erまではpercentに応じて動作し、その後はerで固定するという内容です。
  	変数angleの宣言が残っていますが、angleの式の中にpercentがあるため、angle自体使っていません。
  	
  	実際に動かしてみると、こんな感じです。
  
    	途中で止める
    
    ページ移動の5割の段階で、90°の9割傾くというのが、ここで目的としている動作なのですが、見た感じ45°くらいで止まってしまっていますね。
    少し眺めていたら分かったのですが、5割と9割を掛け算しているので、45°も傾いていないんですね。
    
    ページ移動の5割の段階で、90°の9割傾かせるには、「エフェクトを段階的にする」の「修正2」のように、工夫しなければなりません。
    
    簡単ですが、以下のように対策しました。
  
local percent = offset/page.width
local angle = percent*math.pi/2
local rr = 0.9
local er = 0.5
page.layer.x = page.layer.x + offset
if( percent < 0 ) then
page:scale(0)
else
if( percent < er ) then
page:rotate(percent*rr*math.pi/2/er, 1, 0, 0)
else
page:rotate(er*rr*math.pi/2/er, 1, 0, 0)
end
end
end
effect34_2_2
  	erで割っただけです。
  	プログラム的には無駄が残ったままですが、以下のような動きになります。
  
    	途中で止める2
    
    きとんと、ページ移動の5割の段階で、90°の9割傾きました。
    9割傾いたからこそ分かったのですが、傾き過ぎていますね。
    ここで、傾きを8割にして、様子を見てみましょう。
    ついでに、プログラムの無駄を削いで仕上げます。
    
    変数epを導入し、if文内のページ回転を1つにまとめることにします。
  
local percent = offset/page.width
local rr = 0.8
local er = 0.5
local ep
page.layer.x = page.layer.x + offset
if( percent < 0 ) then
page:scale(0)
else
if( percent < er ) then
ep = percent
else
ep = er
end
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
end
effect34_2_3
  	プログラムも、少しはシンプルになりましたね。
  	このタイミングで、angleの行も削除しました。
  
    	途中で止める3
    
    きとんと、ページ移動の5割の段階で、90°の8割傾きました。
  	良い感じの傾きかと思います。
  
画面奥へ消えるようにする
  	画面を傾けることができましたが、これはまだまだ「お膳立て」の段階です。
  	スターウォーズのオープニングクロールは、ここから奥へと消えていくので、奥へ消えてもらいましょう。
  	
    では、どうすれば奥へ消えていく感じを演出できるのでしょうか?
    ここが今回のメインなので、じっくり時間をかけて考えたほうが良さそうなのですが、問題発生を待っている自分もいるので、単純に縮小するところから始めていきましょう。
    
    ホントに縮小しただけのサンプルは以下の通りです。
  
local percent = offset/page.width
local rr = 0.8
local er = 0.5
local ep
page.layer.x = page.layer.x + offset
if( percent < 0 ) then
page:scale(0)
else
if( percent < er ) then
ep = percent
else
do
ep = er
page:scale(1-((percent-er)/(1-er)))
end
end
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
end
effect34_3
  	実際に動かしてみると、こんな感じです。
  
    	画面縮小
    
  	想定内ではありますが、考えれば考えるほど、大きな問題に感じます。
  	傾きの方向に消えて行くって・・・
  
  	まぁ、解決策を見出してからだと面白くないので、とりあえず、縮小しながら上に移動させてみましょう。
  	これで、それっぽく見えたら良いのですが・・・
    
    縮小しながら上に移動ということは、縮小率と移動量に何らかの関係性を持たせた方が良さそうですね。
    とりあえず、縮小率と移動量を変数にし、その関係性に重点を置くことにします。
    まずは変数ですが、縮小率をsp、移動量をdyとしましょう。
    移動量は、画面のどこを目指すかが問題になってきますが、デバイスによって違うので、page.heightを使って、画面高さと縮小率で決定すべきかと思います。
    とりあえず、縮小率に画面高さを掛け合わせて、様子を見てみようと思います。
    
    以下が、そのサンプルです。
  
local percent = offset/page.width
local rr = 0.8
local er = 0.5
local ep, sp, dy
page.layer.x = page.layer.x + offset
if( percent < 0 ) then
page:scale(0)
else
if( percent < er ) then
ep = percent
else
do
ep = er
sp = 1-((percent-er)/(1-er))
dy = (1-sp) * page.height / 4
page:scale( sp )
page:translate(0, -dy, 0)
end
end
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
end
effect34_3_2
  	画面高さ分だけ移動すると、さすがに移動し過ぎですので、画面高さの1/4にしてみました。
    
  	実際に動かしてみると、こんな感じです。
  
    	画面縮小 & 縦移動
    
おっと・・・
    良い感じに移動したかと思いきや、下がってしまいました。
    失速して落ちていく感じが出て面白いのですが、望んだものと違うので、これは「バグ」と判断します。
    単なる平行移動のはずなのに、どうしてこんな動きになってしまうのでしょうか?
    これも行列の影響なのでしょうか?
    行列!?!?
    ということは・・・
    page:translateによる移動をやめれば良いのかもしれませんね。
    そうとなれば、早速試してみましょう。。
    
    書き換えたサンプルが、以下になります。
  
local percent = offset/page.width
local rr = 0.8
local er = 0.5
local ep, sp, dy
page.layer.x = page.layer.x + offset
if( percent < 0 ) then
page:scale(0)
else
if( percent < er ) then
ep = percent
else
do
ep = er
sp = 1-((percent-er)/(1-er))
dy = (1-sp) * page.height / 4
page:scale( sp )
page.layer.y = page.layer.y - dy
end
end
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
end
effect34_3_3
  	実際に動かしてみると、こんな感じです。
  
    	画面縮小 & 縦移動2
    
良い感じぢゃないですか〜!?
    微調整も要らないほどに感じます。
    
    やはり、行列が原因だったようですね。
    予期しない動作があるので、少し変更したら即確認という流れは必要な作業ですね。
  
次のページを出現させる
  	ここからが、今回の醍醐味の部分となります。
  	現在のページが消えていく様ができましたので、次のページも同じようにやれば良さそうです。
  	もちろん、かなり大きい状態で出現し、小さくなりながら進んで行くという流れになるかと思います。
  	
  	手始めとして、お膳立てとなる画面の傾きにかかる時間を短くしましょう。
  	時間という言い方も変なのですが、ページ移動の5割も使って画面を傾けていたので、これを1割にします。
    
    手始めのサンプルが、以下になります。
  
local percent = offset/page.width
local rr = 0.8
local er = 0.1
local ep, sp, dy
page.layer.x = page.layer.x + offset
if( percent < 0 ) then
page:scale(0)
else
if( percent < er ) then
ep = percent
else
do
ep = er
sp = 1-((percent-er)/(1-er))
dy = (1-sp) * page.height / 4
page:scale( sp )
page.layer.y = page.layer.y - dy
end
end
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
end
effect34_4
ホントに1割にしただけです。
    
  	こんな感じの動作になります。
  
動作全体の1割で傾く
    
5割で見慣れていたので、1割になると急に速く感じます。
    まぁ、ざっと5倍のスピードですので、速いのでしょうね。
    速すぎかとも思うのですが、画面を傾けることがメインではないので、このまま進みます。
    
    では、次のページに出てきてもらいましょう。
    その登場方法は、もちろん言うまでもありませんが、同じような処理で代用するところから始めます。
    代用したサンプルが、以下になります。
  
local percent = offset/page.width
local rr = 0.8
local er = 0.1
local ep, sp, dy
page.layer.x = page.layer.x + offset
if( percent < 0 ) then
do
ep = er
sp = 1-((percent+er)/(1-er))
dy = (1-sp) * page.height / 4
page:scale( sp )
page.layer.y = page.layer.y - dy
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
else
if( percent < er ) then
ep = percent
else
do
ep = er
sp = 1-((percent-er)/(1-er))
dy = (1-sp) * page.height / 4
page:scale( sp )
page.layer.y = page.layer.y - dy
end
end
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
end
effect34_4_2
縮小率spの内容が違う程度で、あとは全く同じ内容の処理で代用しました。
    
  	こんな感じの動作になります。
  
次ページの出現
    
  	いきなり出現したので、これには私もビックリしました。
    縮小率が、1より大きい数字から始まっているはずなので、大きい状態で始まることは想定していたのですが、大きくなった分だけ画面の外にはみ出すと思っていたため、「想定外」となってしまいました。
    
はみ出させるならdyを大きくすれば良いと思ったのですが、dyはspに依存しているため、spを変更して様子を見ようと思います。
dyでは4で割っているため、spでは4を掛けて見ようと思います。
4倍お試しのサンプルは、以下の通りです。
  
local percent = offset/page.width
local rr = 0.8
local er = 0.1
local ep, sp, dy
page.layer.x = page.layer.x + offset
if( percent < 0 ) then
do
ep = er
sp = 1-((percent+er)/(1-er)) * 4
dy = (1-sp) * page.height / 4
page:scale( sp )
page.layer.y = page.layer.y - dy
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
else
if( percent < er ) then
ep = percent
else
do
ep = er
sp = 1-((percent-er)/(1-er))
dy = (1-sp) * page.height / 4
page:scale( sp )
page.layer.y = page.layer.y - dy
end
end
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
end
effect34_4_3
全体を4倍すると都合が悪いので、部分的に4倍しています。
    
  	こんな感じの動作になります。
  
4倍お試し
    
いい感じではないでしょうか?
    イメージに近づいているのが実感できると思います。
    しかし、実際には「もうちょい」といった感じですので、6倍で試してみます。
6倍お試しのサンプルは、以下の通りです。
  
local percent = offset/page.width
local rr = 0.8
local er = 0.1
local ep, sp, dy
page.layer.x = page.layer.x + offset
if( percent < 0 ) then
do
ep = er
sp = 1-((percent+er)/(1-er)) * 6
dy = (1-sp) * page.height / 4
page:scale( sp )
page.layer.y = page.layer.y - dy
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
else
if( percent < er ) then
ep = percent
else
do
ep = er
sp = 1-((percent-er)/(1-er))
dy = (1-sp) * page.height / 4
page:scale( sp )
page.layer.y = page.layer.y - dy
end
end
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
end
effect34_4_4
全体を6倍すると都合が悪いので、部分的に6倍しています。
    
  	こんな感じの動作になります。
  
6倍お試し
    
これこれ!!
    これぞ!!って感じの動きになったではありませんか!?
良い感じの動きになったところで、区切りとします。
  
次のページも2段階にする
次のページが良い感じで登場したので、次のページも2段階にして、傾きを元に戻しましょう。
  	
  	では、どのタイミングで動きを変えれば良いのでしょうか?
  	これは、1ページ目と同様に、erの値を流用することにします。
  
    2ページ目も2段階にしたサンプルが、以下になります。
  
local percent = offset/page.width
local rr = 0.8
local er = 0.1
local ep, sp, dy
page.layer.x = page.layer.x + offset
if( percent < 0 ) then
if( percent < -er ) then
do
ep = er
sp = 1-((percent+er)/(1-er)) * 6
dy = (1-sp) * page.height / 4
page:scale( sp )
page.layer.y = page.layer.y - dy
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
else
ep = percent
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
else
if( percent < er ) then
ep = percent
else
do
ep = er
sp = 1-((percent-er)/(1-er))
dy = (1-sp) * page.height / 4
page:scale( sp )
page.layer.y = page.layer.y - dy
end
end
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
end
effect34_5
2ページ目の部分にif文を追加し、動作終了側のerに傾きを戻すためのep=percentを入れています。
    
  	2ページ目も2段階にしたサンプルは、こんな感じです。
  
    	2ページ目も2段階
    
2ページ目も2段階になりましたが、傾きを戻す段階で、傾きが逆になっていますね。
    
    傾きを逆にするには、page:rotate内の該当する回転方向を-1にすれば良いのですが、最終的に仕上げる段階で、page:rotateも1つにまとめたいので、ここではep=-percentとして対応しておきます。
    
    対応後のサンプルは、以下の通りです。
  
local percent = offset/page.width
local rr = 0.8
local er = 0.1
local ep, sp, dy
page.layer.x = page.layer.x + offset
if( percent < 0 ) then
if( percent < -er ) then
do
ep = er
sp = 1-((percent+er)/(1-er)) * 6
dy = (1-sp) * page.height / 4
page:scale( sp )
page.layer.y = page.layer.y - dy
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
else
ep = - percent
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
else
if( percent < er ) then
ep = percent
else
do
ep = er
sp = 1-((percent-er)/(1-er))
dy = (1-sp) * page.height / 4
page:scale( sp )
page.layer.y = page.layer.y - dy
end
end
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
end
effect34_5_2
2ページ目の部分にif文を追加し、動作終了側のerに傾きを戻すためのep=percentを入れています。
    
  	2ページ目も2段階にしたサンプルは、こんな感じです。
  
傾き修正
    
できてる?
    できてますよね?
    
    思いっきり完成ですね!?
  
仕上げる
  	動きは出来上がりましたので、プログラムを仕上げましょう。
  	ここで言う「仕上げ」は、無駄を省くという作業を指します。
  	具体的には、if文の中にあるpageの動作をif文の外にひとまとめにし、if文には、ep, sp, dyを求める式だけにすることにします。
  	そうすることで、とてもスッキリするはずです。
    無駄を省いたサンプルが、以下になります。
  
local percent = offset/page.width
local rr = 0.8
local er = 0.1
local ep, sp, dy
page.layer.x = page.layer.x + offset
if( percent < 0 ) then
if( percent < -er ) then
do
ep = er
sp = 1-((percent+er)/(1-er)) * 6
dy = (1-sp) * page.height / 4
end
else
do
ep = - percent
sp = 1
dy = 0
end
end
else
if( percent < er ) then
do
ep = percent
sp = 1
dy = 0
end
else
do
ep = er
sp = 1-((percent-er)/(1-er))
dy = (1-sp) * page.height / 4
end
end
end
page:scale( sp )
page.layer.y = page.layer.y - dy
page:rotate(ep*rr*math.pi/2/er, 1, 0, 0)
end
effect34_6
ep, sp, dyは3つで1セットとしますので、抜けている部分に追加しています。
    
    動作は、こんな感じです。
  
    	完成エフェクト
    
書き換えただけなので、同じ動きかどうかの確認ですね。
  
				当サイトの更新状況を、アラートで表示するかどうかの設定をします。
			
保存する
 
         
        