スターウォーズのオープニングクロールを作る
「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セットとしますので、抜けている部分に追加しています。
動作は、こんな感じです。
完成エフェクト
書き換えただけなので、同じ動きかどうかの確認ですね。
当サイトの更新状況を、アラートで表示するかどうかの設定をします。
保存する