縦列を特定する
アイコン1つ1つを探索するところまで紹介しましたので、これからは、いろいろな条件でアイコンを振り分けることで、エフェクトの質を高めるテクニックを紹介していきます。
今回は、縦列をグループとしてエフェクトを掛けてみましょう。
最左列のみ回転させる
Cylinderエフェクトを作るために、「アイコン番号」を利用します。
しかし、アイコン番号は横方向の通し番号なので、縦列を特定するには、工夫が必要です。
では、アイコン番号の並び方を確認します。
19コだったので19までしか番号がありませんが、このように横方向に増えていきます。
この縦列を特定しようとしているのです。
ここで、一番左の縦列を見てみましょう。
アイコン番号が、1,5,9,13,17となっております。
等差数列ですので、単純に4n+1で表すことができれば、「一番左の列」を特定できるのではないでしょうか?
しかし、アイコン番号を求める訳ではありません。
プログラミング側から見てみると、アイコン番号が分かっている上で、そのアイコンがどこにあるのかを判断するので、先ほどの等差数列を逆に考えます。
ズバリ!! 4で割った余りを見れば、どの列かが分かります。
つまり、アイコン番号を4で割った余りが「1」であれば、そのアイコンは一番左の縦列に属することが分かります。
では、一番左の縦列を特定したアイコンにエフェクトを掛けたサンプルを紹介します。
local percent = offset/page.width
local angle = percent*math.pi*2
for i, icon in subviews(page) do
if( i % 4 == 1 ) then icon:rotate(-angle) end
end
end
effect11_1
iがアイコン番号です。
for文で、iに順次アイコン番号が格納されます。
そのfor文の中で、そのアイコンが一番左にあるかどうかの判断をします。
判断にはif文を使うのですが、割り算の余りを求めるには、「%」を使います。
i%4が、アイコン番号を4で割った余りを求め、その余りが1かどうかを判断しています。
条件が成立すれば、一番左のアイコンであるということですので、そのアイコンにエフェクトを与えます。
今回は、一番左のアイコンを回転させました。
一番左のアイコンを特定した回転エフェクト
思惑通り、一番左のアイコンが回転しています。
列を交互に上下移動させる
1列の特定方法を紹介しましたが、次は複数列でエフェクトを与えてみましょう。
今回は、交互の列を特定しようと思います。
では、ここでもアイコン番号の並び方を確認します。
単純に、アイコン番号が偶数か奇数かだけの判断でできそうですね。
では、アイコン番号が偶数か奇数か判断してエフェクトを掛けたサンプルを紹介します。
for i, icon in subviews(page) do
if( i % 2 == 0 ) then icon:translate(0, offset*2)
else icon:translate(0, -offset*2)
end
end
end
effect11_2
i%2が、アイコン番号を2で割った余りを求め、その余りが0かどうかを判断しています。
0であれば偶数と判断できますが、奇数の判断はしていません。
これは、偶数か奇数かが分かれば良いだけなので、偶数でなければ、奇数と判断できます。
それを実現するのが、「if」と「else」の組み合わせです。
これにより、偶数と奇数で処理を分けることができます。
今回は、偶数列を下に、奇数列を上に移動させました。
交互の列で上下移動させたエフェクト
これだけの動きでもエフェクトらしさを感じます。
ここで問題発生!!
偶数か奇数かで判断しましたが、それは4列だから成り立っていただけのことです。
5列で試してみると・・・
5列で試したエフェクト
これはこれで良い感じなのですが、思惑と違う動きであればすべて「バグ」です。
では、ここでもアイコン番号の並び方を確認します。
この場合、5で割った余りで処理すれば良いのですが、「じゃぁ横に7コ並んでたら?」ってことになりますよね?
tweakでアイコン数を変更できるので、汎用的に考えなければなりません。
そこで登場するのが、「page.max_columns」です。
これによって、どなたのデバイスでも対応できるようになります。
では、その対応方法ですが、縦1列を特定したやり方と同じです。
横数で割った余りで判別するので、ここでは、アイコン番号をpage.max_columnsで割った余りが偶数か奇数かでを判断することにします。
では、汎用的にしたサンプルを紹介します。
for i, icon in subviews(page) do
if( i % page.max_columns % 2 == 0 ) then
icon:translate(0, offset*2)
else icon:translate(0, -offset*2)
end
end
end
effect11_2_2
アイコン番号をpage.max_columnsで割った余りを求め、さらに2で割った余りが0かどうかを判断しています。
今回は、偶数列を下に、奇数列を上に移動させました。
汎用的にしたエフェクト
今回は、きちんと縦列で移動していますね。
おやっ?
おやおやっ???
右の2列が同じように移動していますね。
「こはいかに!?」って感じです・・・
では、原因を調べてみます。
このような時は、1つ1つ潰していくしかありませんので、アイコン番号1から計算してみます。
1を5で割った余りは1で、奇数です。
2を5で割った余りは2で、偶数です。
3を5で割った余りは3で、奇数です。
4を5で割った余りは4で、偶数です。
5を5で割った余りは0で・・・
あれっ?0って偶数ですよね?
それなら、右2列が同じ動きをしてもおかしくありません。
きちんとプログラム通りに動いていたんですね。
原因が分かりましたので、対策しましょう。
(自称)プログラマーから言わせてもらうと、そもそも1から始まる数字が理解しやすいのは人間だけなんですよね。
プログラミング的には「0から始める」のが都合がいいのです。
ですので、判断する時だけで良いので、アイコン番号を0から始まる数字にします。
アイコン番号はiですので、条件式の中だけi-1にすることにします。
では、対策したサンプルを紹介します。
for i, icon in subviews(page) do
if( (i-1) % page.max_columns % 2 == 0 ) then
icon:translate(0, offset*2)
else icon:translate(0, -offset*2)
end
end
end
effect11_2_3
iをi-1にしたのですが、演算には優先順位がありますので、(i-1)としました。
対策済みの汎用エフェクト
きちんと動いてくれましたね。
左右に分けて移動させる
複数列で終わろうと思いましたが、アイコンが横5つだった場合を考えると、もう1つ紹介した方が良いと考えましたので、今回は、中央から右半分と左半分の縦列を特定しようと思います。
では、ここでもアイコン番号の並び方を確認します。
縦列の特定は、page.max_columnsで割る方法が良さそうなので、今回も同様に進めます。
今回は左右に分けるのですが、単純に、真ん中に対して右か左かの判断で良いと思います。
では、サンプルを紹介します。
for i, icon in subviews(page) do
if( (i-1) % page.max_columns < page.max_columns / 2 ) then
icon:translate(0)
else icon:translate(offset*2)
end
end
end
effect11_3
アイコン番号は、前回と同様に(i-1)としています。
条件式が長くなってしまいましたが、アイコン最大横数で割った余りと、アイコン最大横数の半分をくらべています。
この条件が成り立てば、左半分ということになり、標準のページ移動のままにしています。
成り立たなければ右半分ということですので、右に移動するエフェクトを与えます。
左右に移動させたエフェクト
問題なく動いてくれました。
動きに関しては、きちんと左右に別れてくれたので良いのですが、2ページ目が入ってくるとき、左右の列が交差してしまいます。
ここは交差せず、スマートに入ってきてもらいたいので、手を加えましょう。
アイコンが左右のどちら側なのかを判断するのは変わりないのですが、出て行く時なのか、入ってくる時なのかも判別し、それによって処理を変えることで解決します
。
では、サンプルを紹介します。
for i, icon in subviews(page) do
if( (i-1) % page.max_columns < page.max_columns / 2 ) then
if( offset < 0 ) then
icon:translate(offset*2)
else
icon:translate(0)
end
else
if( offset < 0) then
icon:translate(0)
else
icon:translate(offset*2)
end
end
end
end
effect11_3_2
ページのインとアウトは、offsetの符号で判断しています。
左右判定のifの中に、ページイン・アウトのifが入っています。
「入れ子」と言うのですが、条件を重ねる時に有効です。
それぞれに処理を書きましたので、icon:translateが4つあることを確認してください。
左右に移動させたエフェクト
思った通りの動きをしてくれました。
気づいた方もいらっしゃると思いますが、先ほどのサンプルには、4つのicon:translateがありました。
よく見ると、ページインもページアウトも似たような処理になっております。
ここで1つテクニックを導入します。
Cylinderエフェクトの基本は移動中のページ視点に立つ事なのですが、ページを移動させないことで、プログラミングが楽になり、見やすくなります。
特に今回は、移動ページ視点で作っているので、移動量が0とoffset*2をセットしています。
ページを固定することで、このセットする移動量がoffsetと-offsetとなるのです。
2種類であることには変わりないのですが、「符号が違うだけ」ということが、メリットをもたらしてくれるのです。
さらに、「ページ全体を透過させる」の中で「if文を使わない」技を導入すると、記述量をかなり少なくすることができます。
では、書き直したサンプルを紹介します。
page:translate( offset )
for i, icon in subviews(page) do
if( (i-1) % page.max_columns < page.max_columns / 2 ) then
icon:translate(-math.abs(offset))
else
icon:translate(math.abs(offset))
end
end
end
effect11_3_3
ずいぶんスッキリしましたね。
しかし、符号の違うmath.abs(offset)は何とかならないものでしょうか?
せっかくなので、左右の判別もif文を使わずに書き直してみましょう。
さらに見やすくするために、page.max_columns用の短い変数も用意します。
どうせなら、スピードも変更できるようにしちゃいましょう!
右か左かで符号を分けることができれば良いので、プログラミングテクニックを1つ導入します。
「論理演算子」というものを使うのですが、条件が成り立つか否かで、その挙動が変わることを利用するのです。
では、変数と論理演算子を導入して書き直したサンプルを紹介します。
local max_col = page.max_columns
local speed = 2
local dir
page:translate( offset )
for i, icon in subviews(page) do
dir = (i-1) % max_col < max_col / 2 and -1 or 1
icon:translate(dir * math.abs(offset) * speed)
end
end
effect11_3_4
max_colで条件式が短くなりました。
speedの値を変更することで、移動の速さが変わるようになりました。
dirに向きを入れるのですが、dirの式が今回のポイントです。
論理演算子が「and」と「or」です。
「and」の左側が、書き直した条件式で、この条件が成り立てば、「and」の右側がdirに入ります。
条件が成り立たなければ、「or」の右側がdirに入ります。
つまり、アイコンが左側にあれば、dirは-1となり、アイコンが右側にあれば、dirは1となるのです。
サンプルでは、speed=2としてありますので、倍速移動となります。
書き直した倍速移動エフェクト
では、今回も5列で試してみます。
5列で試したエフェクト
中央の列が、左に移動していますね。
既存エフェクトの「Double Door」も、中央の列が左に移動しますので、これはこれで良いのかもしれませんね。
が、しかし、ここで終わらないのが当サイトの存在意義かと思いますので、続けます。
問題は、中央の列なんですよね。
アイコンを半分にすることは、さすがにできませんので、どちらかに振り分けるしかありません。
ですので、振り分け方を考えます。
テレビで再放送が多い時間帯があり、最近までヤッターマンがやっていました。
ヤッターワンが出動するときに、レンガの壁が左右に開きます。
これを使いましょう!!
では、アイコン番号とともに説明します。
両側2列は、左右に別れれば良いので、省きます。
問題の中央列は、図のように左右に振り分けることにします。
このようにすることで、偏りなく左右に振り分けることができますね。
では、中央列の振り分け方法ですが、中央列だけ見てみると、上から、奇数、偶数、奇数、偶数、・・・となっていますので、この性質を利用しましょう。
今回も、作りやすさと見やすさのために変数を使用しますが、その内容を先に紹介しておきます。
speed:ページ移動のスピードで初期値を2にしています。
center:中央列判別用
(0スタート仕様)
dir:アイコンの移動方向で、1か-1とします。
i_pos:比較用列番号(0スタート)
では、中央列を左右に振り分けたサンプルを紹介します。
local speed = 2
local center = (page.max_columns-1) / 2
local dir, i_pos
page:translate( offset )
for i, icon in subviews(page) do
i_pos = (i-1) % page.max_columns
if ( i_pos < center ) then dir = -1
elseif( i_pos == center ) then
dir = (i%2 == 0) and -1 or 1
elseif( center < i_pos ) then dir = 1
end
icon:translate(math.abs(offset) * dir * speed)
end
end
effect11_3_5
i_posとcenterを比べることで、アイコンの位置を判別し、移動方向を決定します。
特に、i_posとcenterが等しい時は中央のアイコンであるため、実際のアイコン番号が偶数か奇数かで、移動方向を決定します。
中央列を左右に振り分けたエフェクト
良くなくない?
これはこれで完成なのですが、このサンプルも論理演算子を使い、書き換えようと思います。
local speed = 2
local center = (page.max_columns-1) / 2
local dir, i_pos
page:translate( offset )
for i, icon in subviews(page) do
i_pos = (i-1) % page.max_columns
dir = ( i_pos < center ) and -1 or ( i_pos < center ) and 1 or ( i_pos == center ) and ( i%2 == 0 ) and -1 or 1
icon:translate(math.abs(offset) * dir * speed)
end
end
effect11_3_6
論理演算子祭って感じで、if文が1つもなくなってしまいました。
見慣れれば問題ないのですが、if文を無くす必要はありません。
論理演算子を使って、逆に見にくくなるのであれば、if文でスッキリ記述する方が良いと思います。
宮大工は、釘を使わないから素晴らしいのではないですからね。
if文だらけも見にくいのですが、if文を使わないのも考えものです。
必要に応じて使えば良いと思います。
当サイトの更新状況を、アラートで表示するかどうかの設定をします。
保存する