2010年4月16日金曜日

[Pv3D] Meteor Attack(@wonderfl)の解説

一時的にだけど、[Pv3D] Meteor AttackWonderflでデイリーのPVで一位になったのを記念に解説をこちらのほうでやってみます。


と言ってもこれはそんなに難しいことをしているわけではないんですよね。
やっていることをまとめると、
「球(スフィア)の配置」「カメラ、ライト移動のためのイベント」「画像のロード」「シェーダー、マテリアルの設定」「球(スフィア)のクリックイベント」「アニメーション」「バンプマップの更新」
ぐらいです。

全部説明するのは面倒疲れるので、「球(スフィア)のクリックイベント」「バンプマップの更新」だけ解説します。
該当部はここらへん。
//private function onMapComplete(e:Event):void {
private function onMapComplete():void {
 //var bmpData:BitmapData = new BitmapData(e.target.loader.width, e.target.loader.height);
 var loader1:Loader = imageArray.pop();
 var bmpData:BitmapData = new BitmapData(loader1.width, loader1.height);
 bmpData.draw(loader1);
 moonBmpData = bmpData;
 var loader2:Loader = imageArray.pop();
 bmpData = new BitmapData(loader2.width, loader2.height);
 bmpData.draw(loader2);
 bumpBmpData = bmpData;
 scene.addChild(light);
 
 shader = new PhongShader(light, 0xFFFFFF, 0x666666, 0, bumpBmpData);
 var material:ShadedMaterial = new ShadedMaterial(new BitmapMaterial(moonBmpData), shader);
 material.interactive = true;
 material.smooth = true;
 var sphere:Sphere = new Sphere(material, 100, 15, 15);
 sphere.addEventListener(InteractiveScene3DEvent.OBJECT_CLICK, onObjectClick);
 scene.addChild(sphere);
 
 var particles:ParticleField = new ParticleField(new ParticleMaterial(0xffffff, 1, 1), 200, 2, 500, 500, 500);
 scene.addChild(particles);
}

private function onObjectClick(e:InteractiveScene3DEvent):void {
 var ball:Sphere = new Sphere(new ColorMaterial(0xEEEEEE), 10);
 scene.addChild(ball);
 var tween:ITween = BetweenAS3.tween(ball, {x: e.renderHitData.x * 0.9, y: e.renderHitData.y * 0.9, z: e.renderHitData.z * 0.9}, {x: e.renderHitData.x * 3.5, y: e.renderHitData.y * 3.5, z: e.renderHitData.z * 3.5});
 tween.play();
 tween.onComplete = function():void {
  var sp:Sprite = new Sprite();
  sp.graphics.beginFill(0xFFFFFF);
  sp.graphics.drawCircle(25, 25, 20);
  sp.graphics.endFill();
  sp.graphics.beginFill(0x000000);
  sp.graphics.drawCircle(25, 25, 17);
  sp.graphics.endFill();
  var bmpData:BitmapData = new BitmapData(50, 50, true, 0x00000000);
  bmpData.draw(sp);
  bumpBmpData.draw(bmpData, new Matrix(1, 0, 0, 1, e.x * 1000 - 25, e.y * 500 - 25));
  shader.bumpmap = bumpBmpData;
  scene.removeChild(ball);
 }
}
上のほうはシェーダーの設定です。
sphere.addEventListener(InteractiveScene3DEvent.OBJECT_CLICK, onObjectClick);
でSphereのクリックイベントを設定しています。

で、イベントハンドラで、
(InteractiveScene3DEvent).x及び、(InteractiveScene3DEvent).yは、SphereのマテリアルのUV情報、
(InteractiveScene3DEvent).renderHitData.x(.y, .z)は、クリックしたXYZ座標の値を取ってくることができます。
UVについてはこちらが自分はわかりやすいと思いました。英語だけど。
要するに、UVの値からテクスチャにおける座標を取得したいと思ったら、UVそれぞれにテクスチャの幅と高さを掛けてやれば良いわけです。
(InteractiveScene3DEvent).x * (image).widthという感じで。

上記のプログラムの32行目~は、外側が白で、内側が黒の円を描いて、円の中心がクリックした点になるように移動し、shader.bumpmap = bumpBmpData;でバンプマップを更新しているわけです。

バンプマップを更新したところで、地味で目立たないですね。
というかこれ、以前の記事のプログラムの流用です。

・・・解説下手だなー。

2010年3月21日日曜日

PerlでTwitterAPI使ってみた。

ちょっと前にPerlでつくってみたけどサーバーが無いから公開してなかったやつを紹介。

入力した文字をTwitterで検索して、Google Chart Toolsを使ってどの時間帯に発言されたかを図に示すものを作ってみました。

※時間は世界標準時になってます。+9時間が日本時間です。
「#hanamaru」の結果。
偏ってます。0~1時のは、はなまるマーケット?

「#pandaneko」の結果。
こちらははなまる幼稚園専用っぽいです。上のヤツ以上に偏ってます。
それと、あまり流行ってないのか、結果が500未満です。

「#drrr」の結果。
一部突出してますが、意外と満遍なく発言されてる。

「#haiku」の結果。
発言が多すぎて500件では一日分とってこれてないです。

TwitterのsearchAPIっていろいろと分かってない部分が多くて、検索結果は最大で1500件ぐらいとってこられるみたいなんですが、古いTweetは取ってこられないみたいなんですよね。そんなに精度の高いものではないみたいです。

以下ソースコード。
よくわかってないで書いたのでダメダメです。
use strict;
use warnings;
use Net::Twitter;

print "Content-type: text/html\n\n";
print << 'HERE';
<html>
<head><title>test</title></head>
HERE
my $data;
read(STDIN, $data, $ENV{'CONTENT_LENGTH'});
my($name, $value) = split(/=/, $data);
$value =~ tr/+/ /;
$value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
my $twitter = Net::Twitter->new();
my @times = ();
foreach my $page (0..4) {
 my $results = $twitter->search($value, { rpp=>100, page=>$page+1 });
 foreach my $key (@{ $results->{results} }) {
  push @times, ($key->{ created_at });
 }
}
my %trends = ('0' => 0, '1' => 0, '2' => 0, '3' => 0, '4' => 0, '5' => 0,
'6' => 0, '7' => 0, '8' => 0, '9' => 0, '10' => 0, '11' => 0,
'12' => 0, '13' => 0, '14' => 0, '15' => 0, '16' => 0, '17' => 0,
'18' => 0, '19' => 0, '20' => 0, '21' => 0, '22' => 0, '23' => 0);
for (@times) {
 $_ =~ s/0[0-9]:\d\d:/&count0($_); next;/e;
 $_ =~ s/1[0-9]:\d\d:/&count1($_); next;/e;
 $_ =~ s/2[0-9]:\d\d:/&count2($_)/e;
}
sub count0 {
 $_ =~ s/\d0:\d\d:/$trends{'0'}++/e;
 $_ =~ s/\d1:\d\d:/$trends{'1'}++/e;
 $_ =~ s/\d2:\d\d:/$trends{'2'}++/e;
 $_ =~ s/\d3:\d\d:/$trends{'3'}++/e;
 $_ =~ s/\d4:\d\d:/$trends{'4'}++/e;
 $_ =~ s/\d5:\d\d:/$trends{'5'}++/e;
 $_ =~ s/\d6:\d\d:/$trends{'6'}++/e;
 $_ =~ s/\d7:\d\d:/$trends{'7'}++/e;
 $_ =~ s/\d8:\d\d:/$trends{'8'}++/e;
 $_ =~ s/\d9:\d\d:/$trends{'9'}++/e;
}
sub count1 {
 $_ =~ s/\d0:\d\d:/$trends{'10'}++/e;
 $_ =~ s/\d1:\d\d:/$trends{'11'}++/e;
 $_ =~ s/\d2:\d\d:/$trends{'12'}++/e;
 $_ =~ s/\d3:\d\d:/$trends{'13'}++/e;
 $_ =~ s/\d4:\d\d:/$trends{'14'}++/e;
 $_ =~ s/\d5:\d\d:/$trends{'15'}++/e;
 $_ =~ s/\d6:\d\d:/$trends{'16'}++/e;
 $_ =~ s/\d7:\d\d:/$trends{'17'}++/e;
 $_ =~ s/\d8:\d\d:/$trends{'18'}++/e;
 $_ =~ s/\d9:\d\d:/$trends{'19'}++/e;
}
sub count2 {
 $_ =~ s/\d0:\d\d:/$trends{'20'}++/e;
 $_ =~ s/\d1:\d\d:/$trends{'21'}++/e;
 $_ =~ s/\d2:\d\d:/$trends{'22'}++/e;
 $_ =~ s/\d3:\d\d:/$trends{'23'}++/e;
}
print "<body>\n";
print "<form method='post' action='http://localhost/cgi-bin/twi.cgi'>\n";
print "<input name='tag' type='text' />\n";
print "<dl><dt>word</dt><dd>$value</dd><dt>tweets</dt><dd>";
print my $line = @times, "</dd></dl>\n";
print "<img src=\"http://chart.apis.google.com/chart?cht=bvg&chs=800x300&chxt=x,y&chxl=0:|0:00|1:00|2:00|3:00|4:00|5:00|6:00|7:00|8:00|9:00|10:00|11:00|12:00|13:00|14:00|15:00|16:00|17:00|18:00|19:00|20:00|21:00|22:00|23:00|24:00&chd=t:$trends{'0'},$trends{'1'},$trends{'2'},$trends{'3'},$trends{'4'},$trends{'5'},$trends{'6'},$trends{'7'},$trends{'8'},$trends{'9'},$trends{'10'},$trends{'11'},$trends{'12'},$trends{'13'},$trends{'14'},$trends{'15'},$trends{'16'},$trends{'17'},$trends{'18'},$trends{'19'},$trends{'20'},$trends{'21'},$trends{'22'},$trends{'23'}\" />";
print "</body>\n";
print "</html>";
なんて非効率なコード・・・

参考サイトなど:
Net::Twitter - search.cpan.org
Google Chart Tools - Google Code
Twitter 検索API メモ - 超自己満足プログラミング
Twitter search api - cool_ni_ikouの日記
正規表現 | Perl講座 [Smart]
Perl/CGI研究室 'PERL-LABO'

2010年3月20日土曜日

最近

このブログの駄目なところはジャンルを統一しないところですね。

今回は雑記です。
最近は専ら就職活動をしてます。そのついでに東京観光などをしてみたり。
湯島聖堂明治神宮カンボジア大使館
東京って坂道多いですね。

あと、本屋にも結構寄ります。品揃えが全然違うので。
気になった本をメモ。



最後に東京とは関係ないですが、
これ買いました。「激闘~Battle No.2~」欲しさに。
RPGのボス戦の曲で一番好きな曲だし、Amazonの中古で1000円ぐらいなので1つの曲のために買うのも悪くないかなーと。
ただこの曲聴いてたら他のサントラも欲しくなってしまった。特にOPとED曲は欲しい・・・

2010年3月14日日曜日

Perlのforeachで・・・

先日ちょっとPerlを書く機会があって、その時に次のようなコードを書いてみた。
#!/usr/bin/perl
use strict;
use warnings;

# コピー元の配列作成
my @a = ("One", "Two", "Three", "123");
# コピー先の配列
my @b = ();

foreach my $val (@a) {
 push @b, $val;
 $val = "Change";
}
print @b, "\n";
print @a, "\n";

これ実行結果は、
OneTwoThree123
ChangeChangeChangeChange
となるのですが、なんかこれちょっと不思議な感じがする。個人的に。
$valに代入してるつもりが、@aの要素にも代入されてるのが気持ち悪いのかな?
うっかり元配列まで変更しないように気をつけないといけませんね。

2010年2月9日火曜日

あーくたん

前回のSVG表示するやつを少し変えたものをwonderflに投稿してみました。

回転させる角度を求めるのに、最初Math.atan2メソッドを知らなくて、Math.atanで事象ごとに場合分けをして求めようとしてたら、無駄に苦労して涙目。

というわけでatanの復習。
atanつまりarctan(アークタンジェント)はtan(タンジェント)の逆関数。
直角三角形の2辺から、角度(ラジアン)を求めることができます。

今回のプログラムをatanを使おうとすると、単純にMath.atan(dy / dx)では角度が求められない場合がでてくる。一番わかり易いのだとdxが0の場合とか。
Math.atan2だとそんな問題が解決できる。ActionScriptのatan2がどう実装されているか知りませんが、一般的に、atan2はこのようになっているようです。

atan2(y, x) =
{
atan(y/x) (x>0),

π-atan(|y/x|) (x<0 かつ y>0),

-(π-atan(|y/x|)) (x<0 かつ y<0),

0 (x<=0 かつ y=0),

π/2 (x=0 かつ y>0),

-π/2 (x=0 かつ y<0)
}

ちゃんと0のときも定義されているので使いやすい。