はい、ということで、例によって作ってみようシリーズです。
今回作るのはこれ
今回は「トップページでPRアイテムを右から左へ流すFLASH」です。
サイトトップやカテゴリトップで新着アイテムを右から左へ流すようなアレを作ってみます。
レイアウト・動作仕様案を考える
サイトの一部として入る部品なので、全体のデザインに合わせてレイアウトや仕様を考えます。
今回は本サイトの本文横幅に合わせてこんなんなりました。

動作仕様
- 画面上には6個のアイテムが表示される
- 常に右から左へアイテムが等速で流れていく
- 各アイテムをクリックすると該当ページへ飛ぶ
- アイテム情報はXML管理
ステージとライブラリの準備
今回はライブラリに登録するアイテムはありませんでした。全部スクリプトでいきます。(てか、デザイン要素ないもんな、枠線くらい?)
なので、FLASH側でオーサリングしたのはステージサイズの設定とドキュメントクラスをAppってしただけです。
XMLファイルを作る
シンプルな構成です。画像のパスとリンク先、ウィンドウの開き方、アイテムタイトルを入れました。
<?xml version="1.0" encoding="utf-8" ?> <items> <item src="/photos/thumb/20100306.jpg" href="/2010/03/post-721.html" target="_blank"> 休みの日に限って早起きの法則 </item> <item src="/photos/thumb/20100305.jpg" href="/2010/03/post-720.html" target="_blank"> もし雨が降らなかったら </item> <item src="/photos/thumb/20100304.jpg" href="/2010/03/post-718.html" target="_blank"> 例えばの話の翌日の話 </item> <item src="/photos/thumb/20100303.jpg" href="/2010/03/post-718.html" target="_blank"> 例えばの話 </item> <item src="/photos/thumb/20100228.jpg" href="/2010/03/post-717.html" target="_blank"> 血の味がする </item> <item src="/photos/thumb/20100227.jpg" href="/2010/02/post-716.html" target="_blank"> グラスの中の水に溶かす </item> <item src="/photos/thumb/20100226.jpg" href="/2010/02/post-715.html" target="_blank"> 色々な部分 </item> <item src="/photos/thumb/20100225.jpg" href="/2010/02/post-714.html" target="_blank"> いろいろ読めない男 </item> <item src="/photos/thumb/20100224.jpg" href="/2010/02/post-714.html" target="_blank"> 元気があって大変よろしい </item> <item src="/photos/thumb/20100221.jpg" href="/2010/02/post-712.html" target="_blank"> シャンプーは無いけれどコンディショナーがダブルでエクストラダメージケア </item> </items>
お待ちかねのActionScript
スクリプト部分を作ります。
今回も前回同様、ドキュメントクラスに指定したApp.asといつも使っている 大重本 のXMLloaderクラスのみです。
なお、オンマウス時のコンテトラスト変化用にTweenerのColorShortcutsを使っています。
処理の流れ
- コンストラクタでXMLをロード
- XML読み込み完了後、XMLの中身を分解して格納
- 最初に配置するアイテムを定義
- 個々のアイテムを作成
- アイテム自身がステージの外へ出たら自分で消えて次を呼び出す
- 以下ループ
今回のスクリプトでキモとなるのがアイテム生成の所、function createItem(num:int, position:int)です。
以下のような動きをします。
- 自分の画像・リンク先URLとタイトル名をXMLListから取ってくる
- コンテナMCを作る
- マウスアクションを設定する
- 画像を読み込む
- 画像にマスクをつける(大きい画像を読み込んだ時用)
- 枠線を描く
- タイトル表示用のテキストフィールドを生成する
- 所定の場所に自分を置く
- 横移動をイベントリスナーで設定(Event.ENTER_FRAME)
また、横移動する部分(function move(event:Event):void)では、自分がステージの外に出たら自分を消して次のアイテムを呼ぶ処理を行っています。
新しく覚えたこと
ソースにもコメントを入れましたが、自分を消す処理(removeChild())のところで嵌りました。
イベントリスナーで呼ばれたfunctionが、一緒にくっついてくるevent.currentTargetを使ってremoveChild()しようとしたら何やらエラーが出ます。
静的型 Object の値が、関連しない可能性が高い型 flash.display:DisplayObject に暗黙で型変換されています。
でも最近少し賢くなったので、この手のエラーは大抵キャストすればいけるっちゅー事でDisplayObjectでキャストして無事解決です。なお、これはStrictモードでの話。FLASHの設定でStrictモードのチェックを外しておけばエラーは出ないようです。
ってか、なんでキャストせないかんの。そもそもevent.currentTargetって何型?という素朴な疑問が。
リファレンスによると・・・
currentTarget:Object [read-only]
Object型なんですね。
それでremoveChildはというと・・・
removeChild(child:DisplayObject):DisplayObject
ここにエラーの原因がある模様です。ってか、ちょっとくらい見逃してよ!って思いますが、それならStrictモード外せよってことなんでしょうね。
ということで、以下ソースコードです。
package
{
import caurina.transitions.SpecialProperty;
import flash.display.*;
import flash.events.*;
import flash.net.URLRequest;
import flash.net.navigateToURL;
import caurina.transitions.Tweener;
import caurina.transitions.properties.ColorShortcuts;
import flash.text.TextField;
import flash.text.TextFormat;
import XMLloader;
public class App extends Sprite
{
private static const XMLURL:String = "top_newItem.xml";
private static const setItemNum:int = 10; //ステージに設置するアイテム数
private static const speed:Number = 1; //1フレームあたりの移動距離
private var xmlLoader:XMLloader;
private var xmlData:XML;
private var itemList:XMLList;
private var maxItemNum:int; //XMLのアイテム数
private var itemCount:int; //カウンター
//コンストラクタ
public function App()
{
ColorShortcuts.init();
//XMLloaderクラスを呼んでXMLを読み込む
xmlLoader = new XMLloader(XMLURL, true);
//読み込み終わったらonXMLloadedに行く
xmlLoader.addEventListener(XMLloader.LOAD_COMPLETE, onXMLloaded);
}
//XML読み込み完了
private function onXMLloaded(event:Event):void
{
//XMLを格納
xmlData = xmlLoader.getXML();
//XMLの中からitemを取り出す
itemList = xmlData.item;
//itemの個数を数える
maxItemNum = itemList.length();
//設定開始
setting();
}
//設定
private function setting():void
{
//ここで最初に表示しておく分を並べる
for (var i:int = 0; i < setItemNum; i++)
{
//全アイテム出し切ったらまた最初から
if (itemCount > maxItemNum - 1 )
{
itemCount = 0;
}
createItem(itemCount, i);
itemCount++;
}
}
//アイテム作成
private function createItem(num:int, position:int)
{
//読み込む画像のURLを定義
var urlStr:String = itemList[num].@src;
var linkStr:String = itemList[num].@href;
var linkTarget:String = itemList[num].@target;
var titleStr:String = itemList[num];
//アイテムコンテナ
var itemBox:Sprite = new Sprite();
//画像コンテナ
var container:Sprite = new Sprite();
//画像コンテナマウスアクション
container.buttonMode = true;
container.addEventListener(MouseEvent.CLICK, itemClick(linkStr, linkTarget));
container.addEventListener(MouseEvent.ROLL_OVER, itemOver);
container.addEventListener(MouseEvent.ROLL_OUT, itemOut);
//写真を画像コンテナに読み込む
container.addChild(imgLoader(urlStr));
//矩形マスクを画像コンテナに適用
var maskSquare:Shape = new Shape();
maskSquare.graphics.lineStyle(1, 0x000000);
maskSquare.graphics.beginFill(0xff0000);
maskSquare.graphics.drawRect(0, 0, 96, 96);
maskSquare.graphics.endFill();
itemBox.addChild(maskSquare);
container.mask = maskSquare;
//枠線
var frame:Shape = new Shape();
frame.graphics.lineStyle(1, 0xCCCCCC);
frame.graphics.lineTo(0, 96);
frame.graphics.lineTo(96, 96);
frame.graphics.lineTo(96, 0);
frame.graphics.lineTo(0, 0);
//テキストフィールド
var label:TextField = new TextField();
label.text = titleStr;
label.width = 96;
label.height = 24;
label.y = 96;
label.wordWrap = true;
label.selectable = false;
//テキストフォーマット
var format:TextFormat = new TextFormat();
format.font = "_ゴシック";
format.size = 10;
label.setTextFormat(format);
//配置
itemBox.addChild(container);
itemBox.addChild(frame);
itemBox.addChild(label);
//アイテムの配置位置を設定
itemBox.x = position * (96 + 10);
addChild(itemBox);
//移動する動きをonEnterFrameで
itemBox.name = "t" + position;
itemBox.addEventListener(Event.ENTER_FRAME, move);
}
//画像を読み込む関数
private function imgLoader(urlStr:String):Loader
{
//URL定義
var url:URLRequest = new URLRequest(urlStr);
//ロード用オブジェクトのインスタンスをnewする
var loader:Loader = new Loader();
loader.load(url);
return loader;
}
//移動する動き
private function move(event:Event):void
{
//ステージの外に出たら消し、新しいのを出す
if ( event.currentTarget.x < -106 )
{
event.currentTarget.removeEventListener(Event.ENTER_FRAME, move);
/**
* 下の一行で少しはまった。addEventListenerとremoveChildの階層をきちんと理解しておかないと
* event.currentTargetの中身が変わってしまうので、矛盾が発生してエラーが出てしまう。
* あと、DisplayObject()でキャストしてあげないとStrictモードではエラーが出るのも落とし穴。
*/
removeChild(DisplayObject(event.currentTarget));
/**
* 一つ消えたので、新しいのを追加する
*/
if (itemCount > maxItemNum - 1 )
{
//全アイテム出し切ったらまた最初から
itemCount = 0;
}
createItem(itemCount++, setItemNum-1);
}
event.target.x -= speed;
}
//メインイメージがクリックされたときの動作
private function itemClick(linkStr:String, linkTarget:String):Function
{
return function(event:MouseEvent):void
{
var url:URLRequest = new URLRequest(linkStr);
navigateToURL(url, linkTarget);
}
}
//メインイメージロールオーバー
private function itemOver(event:MouseEvent):void
{
Tweener.addTween(event.target,{_contrast:1, time:0.5});
}
//メインイメージロールオーバー
private function itemOut(event:MouseEvent):void
{
Tweener.addTween(event.target,{_color:null, time:1});
}
}
}これで完成!

THE BACK HORN、GRAPEVINEを聞いていたと言うだけあって、そのテイストが感じられる曲調。3ピースでも音にしっかりとした厚みがあって、バランスが良いと思った。
その名の通り、切なくて冷たい雨が降る。TK(男性Vo)のハイトーンは好みが分かれるところだが、345(女性Vo)とのツインボーカルが生み出す緊迫感はとても狂おしく、破滅的で情緒に溢れている。
でもね、曲はめっちゃカッコイイス。そういう細かいところを気にするアホウは僕くらいなもんで、良いアルバムに仕上がってますよ。
いやはや、凄いの見てもーた。基本はスクリーモなんですが、エモが来たと思ったらいきなりエレクトロニカなん?4つ打ちなん?っていう最高の一品です。
1曲目の「insurance?」からいきなり「It's Only Natural」と似たテイストのノリノリナンバーで、一気に持ってかれてしまいました。全体的に気持ちよく聴けるアルバムに仕上がっています。
埼玉産インディーズバンドLooking For。同郷なら応援しないわけにはいかない。とにかくメロディック・メロディックなのであります。まさしく僕好み。ありがとうございます。
初めて聴いた感想はズバリ「つまらん」。
で、封印しようかと思いつつ、他に聴くものもないし・・・などとループ再生していたところ・・・4,5回目くらいから良くなってきました。
僕のファーストインプレッションは、
「んー、フライングキッズ?いや、オリジナルラヴ?」
でした。
前作 rapture が割とアップテンポで勢いのある印象だったので、アップテンポ好きな僕には少し物足りないというか、お子ちゃまな僕の好きな路線とはちょっと違うかなぁという感想。
女性Vo.なんですが、彼女の声と曲の世界観が絶妙です。彼女の声を聴いていると、切なくなるような、苦しくなるような、かと思えば一気に解放されるような、フワフワ浮かんでいるような。
クラムボンが好きな人とかすんなり聴けるんじゃないかと思います。
正統派J-popとでもいうべき非常に聴きやすい作品。メロディーも心地よく耳に残る感じ。無意識のうちに結構気に入っていたらしく、このまえ気付いたら4曲目のサビをひたすら口ずさんでました。
コメントする