MAMP

前回記事でfacebookアプリを開発するためにXAMPP for macの導入を行いました。
xampp for mac - 武田のつぶや日記

しかし、XAMPP for macに入っているPHPのVer.が5.3.1で、今回フレームワークとして用いるSilexが必要とするVer.が5.3.2以上だと知り、急遽XAMPP for macをアンインストールし、MAMPを導入し直しました。
Ver5.3.1でももしかしたら動いたかもしれませんが、一応。
そしてXAMPPとかに入っているPHPのバージョンアップはどうやってやればいいのでしょうか?色々調べてみましたが、結局イマイチわかりませんでした。

それにしても前回から時間経ち過ぎだろ、みたいなところもあるのですが、本当に動かなくて苦労しました。
ですがとりあえず一通りアプリを動かすところまで来ました。なので記事を書きました。

それでは今回はMAMPの導入です。
また導入か、という感じですが。

MAMPとは前回導入したXAMPPのmac版です。
前回のXはクロスプラットフォームという意味ですが、今回の最初のMはmacのMですね。

では導入して行きましょう。
まずはMAMPの公式サイトにいきアプリケーションをダウンロードしていきましょう。
MAMP & MAMP PRO - your local web development solution for PHP and WordPress development

ただのMAMPMAMP proが用意されていますが、MAMPを選びます。
proの方は有料でバーチャルホストの数が無制限だったりするらしいです。

少し時間がかかりますが、zipファイルを無事ダウンロードできたら解凍してpkgファイルをクリックしてインストールします。
下のような画面が出るので「続ける」をがしがし押してインストールします。

無事インストールが終了すると、アプリケーションフォルダにMAMPMAMP PROというのが出現します。
どうやらMAMPからインストールしてきても両方入るみたいです。
使うのはMAMPなのでMAMPをクリックし、ディレクトリを展開していきます。

その中にMAMP.appがあり、それが本体です。
とりあえず動作確認のためにクリックして起動しましょう。
下のような画面が表示されます。

関係ないですが、個人的にはXAMPPよりMAMPの方がシンプル感があって好きです。
あと像もとっても可愛いですし。

ではapacheサーバを起動してみます。
「サーバを起動」ボタンで起動します。
ApacheサーバとMySQLサーバの文字の左にある緑ランプが点灯すれば起動状態です。
ここで本当に起動しているのかを確認するために「スタートページを開く」を押してみましょう。

このような画面が表示されれば、無事うまくいっている事がわかります。
普通に日本語で表示されると思いますが、されていなければアドレスバーのlanguage=以降をJapaneseにすれば日本語で表示されます。

次にポート番号を変えてみましょう。
MAMP.appの画面に「環境設定」のボタンがあり、ここでPHPのバージョンを変える事ができたり(便利!)、ポート番号を変更したりする事ができます。
今回は練習用なので、ポート番号を標準の80に変えていきます。
本番用はどうした方が良いのかは実はよくわかっていません。
とりあえず「環境設定」のボタンを押し、ポートタグを押してポート番号を設定する画面に変えましょう。

そして「ApacheMySQLの標準ポートに設定」ボタンを押せば、ポート番号等を勝手に変えてくれます。

続いてアクセス制限をかけてセキュリティを高めていきます。
ここからはXAMPPのときとほとんど変わらない?ですかね。

MAMP/conf/apacheディレクトリにあるhttpd.confファイルを編集します。

<Directory "/Applications/MAMP/htdocs">
     〜中略〜
</Directory>

内にある

    Order allow,deny
    Allow from all

を見つけて(237行くらいです)、この二つの冒頭に#を付け加えてコメントアウトします。
その下に次のように書き加えます。

        #Order allow,deny
        #Allow from all
	Order Deny,allow
	Deny from all
	Allow from localhost
	Allow from 127.0.0.1
	Allow from 192.168

これであるアクセス(この場合localhostだったり、IPアドレス127.0.0.1だったり)からのみ受け付ける事になります。

続いてPHPの日本語を有効にしていきます。
現在使用しているPHPのVer.は5.4.4なので(使用しているVer.はMAMP.appの環境設定で確認できます。)、/MAMP/conf/php5.4.4/ディレクトリにあるphp.iniファイルの中にある5つの記述を次のように編集します。
(わかりづらいですが、編集した行の右側に「!!」をつけています)

; As of 4.0b4, PHP always outputs a character encoding by default in
; the Content-type: header.  To disable sending of the charset, simply
; set it to be empty.
;
; PHP's built-in default is text/html
default_mimetype = "text/html"
default_charset = "UTF-8"  !!

だいたい394行目くらい。charsetで検索をかけてしまいましょう。

[mbstring]
; language for internal character representation.
mbstring.language = Japanese  !!

; internal/script encoding.
; Some encoding cannot work as internal encoding.
; (e.g. SJIS, BIG5, ISO-2022-*)
mbstring.internal_encoding = UTF-8  !!

; http input encoding.
mbstring.http_input = auto  !!

; http output encoding. mb_output_handler must be
; registered as output buffer to function
;mbstring.http_output = SJIS

; enable automatic encoding translation accoding to 
; mbstring.internal_encoding setting. Input chars are
; converted to internal encoding by setting this to On.
; Note: Do _not_ use automatic encoding translation for
;       portable libs/applications.
;mbstring.encoding_translation = Off

; automatic encoding detection order.
; auto means 
mbstring.detect_order = SJIS,EUR-JP,JIS,UTF-8,ASCII  !!

だいたい1007行目くらいです。mbstringで検索をかけるといいかな。

では、適当なファイルを作成して、設定がうまくいっているかみてみましょう。
テスト用に次のようなファイルを用意しました。

<html>
<head>
<title>Hello world!</title>
</head>
<body>
<?php
echo "こんにちはーっす。";
echo '現在 ' . date('Y/m/d H:i') . ' です。';
?>
</body>
</html>

このファイルをtest.phpというような名前で、MAMP/htdocs/ディレクトリに保存しましょう。
そして、MAMP.appでapacheサーバを有効にして、http://localhost/test.phpとブラウザでアクセスしたときに次のような画面が出れば成功です。

この際PHPの文法は省きますが、現在日時刻を表示しています。
ちゃんと漢字も表示されていますね。
文字化けしていたらtest.phputf-8で保存し直すといいかもしれないです。
きちんと確認できたらもう使用しないので、test.phpは削除してもいいでしょう。

では最後にバーチャルホストを有効にします。
先ほど編集したhttpd.confファイルをもう一度編集します。
Includeで検索をかけるといくつかヒットすると思いますが、そのうちの530行目くらいにあるバーチャルホストの項目を編集します。
これは簡単で、

# Virtual hosts
#Include /Applications/MAMP/conf/apache/extra/httpd-vhosts.conf

のIncludeの左にある#を外すだけです。

これでバーチャルホストが有効になりました。


という感じでMAMPの導入でした。
次回はfacebookアプリの開発に入ります。

facebookアプリ 開発環境構築編

では、前回facebookアプリ アプリ登録編 - 武田のつぶや日記に続いてフレームワークであるSilexをダウンロードします。
Homepage - Silex - The PHP micro-framework based on the Symfony Components

次のような画面が出ます。

このinstall nowの方ではなくdownloadを選択します(別にinstall nowでも良いですが)。
すると次のような画面に切り替わります。

そこからas a "slim"と書いてある軽量版の方のファイルをクリックしてインストールします。
自分はzipで落としました。
これを解凍するとsilexフォルダができるので、これを/MAMP/htdocs/フォルダにコピーして、skillshindan.localhostという名前にリネームします。(これで/MAMP/htdocs/skillshindan.localhost/というディレクトリ構成になります)
このskillshindan.localhostは上でURLとして登録した名前です。

ついでに公式サイトでsilexに関するドキュメントを読むといいです。
Introduction - Documentation - Silex - The PHP micro-framework based on the Symfony Componentsとか
Usage - Documentation - Silex - The PHP micro-framework based on the Symfony Componentsとか
Twig - Documentation - Silex - The PHP micro-framework based on the Symfony Componentsとか。

日本語訳のドキュメントもありましたが、特にtwigに関する記述が少し違っていたので公式サイトの方がいいかもしれません。
自分の知識不足なだけで実は同じ事が書いてあるのかもしれませんが。。

続いてテンプレートエンジンであるtwigをダウンロードします。
公式サイトはこちらHome - Twig - The flexible, fast, and secure PHP template engineになりますが、最新stable版とされているver.1.9.2のディレクトリ構成が勉強した本や各サイトと微妙に違っていてびびってしまったので以下のサイトからver.1.9.0をダウンロードしました。
Tags · fabpot/Twig · GitHub

ここからver1.9.0の.zipファイルをダウンロードします。
落とした.zipファイルを解凍してできたファイルをtwigという名前にリネームして/MAMP/htdocs/skillshindan.localhost/vendor/に保存します。(これでディレクトリ構成は/MAMP/htdocs/skillshindan.localhost/vendor/twig/です。)

次はfacebookとの連携をとるためにfacebook skdをダウンロードします。
以下のサイトからsdkの.zipファイルをおとします。
GitHub - facebookarchive/facebook-php-sdk: This SDK is deprecated. Find the new SDK here: https://github.com/facebook/facebook-php-sdk-v4

右上のDownloadsから.zipファイルをダウンロードします。
これも同様に解凍してできたファイルをfacebook-php-sdkという名前にリネームして、vendorフォルダにいれます。
最後にサイトの体裁を整えるtwitter bootstrapをダウンロードします。
Bootstrap

これはすごく単純でdownload bootstrapすればいいですね。
少し脱線しますが、新しいver.が出て話題にあがったbootstrapですがどんな風に変わったのでしょうか。
これもダウンロードした.zipファイルを解凍して、/MAMP/htdocs/skillshindan.localhost/web/にassetsというディレクトリを作りその中にいれましょう。

これで全てのライブラリが揃いました。
ディレクトリ構成としては

/htdocs/skillshindan.localhost/vendor/silex
                                                           /twig
                                                           /facebook-php-sdk
                                               /web/assets/bootstrap
                                                       /index.php

のようになっているでしょうか。諸々のファイルは省略してありますが。

続いてバーチャルホストの設定を行います。
以前MAMPの導入を行った際にMAMP - 武田のつぶや日記、バーチャルホストを有効にしていますので、次は今回に合わせた設定に変えます。
まず、/MAMP/conf/apache/extra/httpd-vhosts.confファイルを編集します。

<VirtualHost *:80>
    ServerAdmin webmaster@dummy-host.example.com
    DocumentRoot "/Applications/MAMP/Library/docs/dummy-host.example.com"
    ServerName dummy-host.example.com
    ServerAlias www.dummy-host.example.com
    ErrorLog "logs/dummy-host.example.com-error_log"
    CustomLog "logs/dummy-host.example.com-access_log" common
</VirtualHost>

<VirtualHost *:80>
    ServerAdmin webmaster@dummy-host2.example.com
    DocumentRoot "/Applications/MAMP/Library/docs/dummy-host2.example.com"
    ServerName dummy-host2.example.com
    ErrorLog "logs/dummy-host2.example.com-error_log"
    CustomLog "logs/dummy-host2.example.com-access_log" common
</VirtualHost>

と27行目あたりがなっていると思うので、これを全部冒頭に#をつけてコメントアウトしてその下に、次のコードを加えます。

<VirtualHost *:80>
    ServerName skillshindan.localhost 
    DocumentRoot /Applications/MAMP/htdocs/skillshindan.localhost/web
	DirectoryIndex index.php
	<Directory "/Applications/MAMP/htdocs/skillshindan.localhost/web">
		AllowOverride All
		Allow from All
	</Directory>
</VirtualHost>

これで、http://skillshindan.localhost/でアクセスした際に/MAMP/htdocs/skillshindan.localhost/web/というディレクトリをルートディレクトリとして、その中のindex.phpを真っ先に参照する事になります。

続けて/MAMP/htdocs/skillshindan.localhost/web/フォルダの中に.htaccessというファイルネームで次のコードを保存します。

<IfModule mod_rewrite.c>
	RewriteEngine On
	RewriteBase /
	RewriteCond %{REQUEST_FILENAME} !-f
	RewriteRule ^(.*)$ index.php/$1 [QSA,L]
</IfModule>

このdotから始まるファイルは隠しファイルになるので、探すときはターミナル等でls -aコマンドを用います。
最後にドメインの設定を行います。
macなら、というか自分の場合はhosterというアプリケーションを使いました。
無料等なのでいいと思います。

hosterをインストールし、起動したら、下のような画面が出ます。

そしたら緑色バックのプラスボタンを押して設定を追加します。

セット名はなんでもいいのでわかりやすい名前にしましょう。
IPは127.0.0.1です。
ホスト名はskillshindan.localhost
にしましょう。

これで概ね準備は完了です。
最後にテストをしてみます。
MAMP.appでサーバを起動し、hoster.appでセット名の左にあるくらい部分を押すとそこが緑に光ってホストが反映されます。
その状態でhttp://skillshindan.localhost/helloとアドレスバーに打ち込むと下のような画面が表示されるはずです。
そうなれば成功です。

長くなるので、とりあえず今回はこれまでで。
次回はいよいようアプリ開発に入ります。

CAAT::Actor(transformation)

今回はactorのtransformation、つまりactorのビジュアル的変化です。
公式チュートリアルでは次のような記述となっています。
http://hyperandroid.github.com/CAAT/documentation/tutorials/t2-3.html

Transformations

transformationとはactorが自身のアピアランスを装飾したり、同じようなactorに同様の処理を施すもの。
例えば、開発者が横幅のスケールを変更した際に見た目は変更されるが、実際には同じサイズのままです。
(つまりビジュアル的変化を引き起こすが、データ的には値は変わっていないという事?イラレベクターデータみたいなものですかね)
少しodd bit(これはどういう意味なんだろう。。)に思えるかもしれないが、actorのプロパティの一つはそのディメンションに関するもの。
(setSizeやsetBoundsを使ったとしても、直接高さや幅、attributeを代入しても)
そしてもうひとつはどのように見えるかや、Directorを通してアフィン変換を行うもの。
(アフィン変換とは座標をずらしたり、倍率を変えたり、回転させたりするベクトル変換)

actorは三つの異なるプロパティを持つ。

  • translation

これはほとんど見た目に影響を与えないが、描画の際の位置に影響を与えるプロパティ。
あるレンダリングでCAATが正しい値をセットするのを妨げてしまう事があるため、Actor.xやActor.yに値を直接セットすることは推奨されていない。
守るべきルールの一つとしては、actorのインスタンスプロパティをgetしたいのならaccessメソッドを、setしたいのならmutatorメソッドを使用しなくてはいけない。

  • rotation

これはactorをある角度(ラジアン単位)回転させるもの。rotationを適応するために二つのメソッドがある。

    • function setRotation(angle_in_radians)
    • function setRotationAnchored(angle_in_radians, center_x, center_y)

setRotationはactorをactorの中心を軸にして回転させたいときに使用する関数で、setRotationAnchoredの補助的関数です。
デフォルトではradiansの値は0でセットされていて、回転されずに描画される。
center_xとcenter_yの値はactorの左上を(0, 0)として、ピクセル単位で指定する回転の中心となる点。

  • scale

これはactorの幅や高さの値を変更するもの。
開発者は幅と高さとしてそれぞれ別の値を指定する事ができる。
この値というのはactorのディメンションを何倍かするものです。
デフォルトではこの値はそれぞれ1となっていて、つまり等倍で描画される。
scaleを扱うためのメソッドは以下の二つである。

    • function setScale(scale_x, scale_y)
    • function setScaleAnchored(scale_x, scale_y, anchor_x, anchor_y)

rotationと同じようにsetScaleはsetScaleAnchoredの助けとなる。また、このanchorという二つの引数も同様に作用する。
大事なのはrotationAnchoredとscaleAnchoredは違うという事。


とまぁ色々書いてありましたが恐らく意識しなくてはいけないのは、
scaleを変更しようがしまいが、回転させようがさせまいが、最初からactorはこれらの値を持っており、必要に応じてこの値を変えていくという事でしょうか。

では次にサンプルを見ていきます。

Sample

とはいえ今回はゲームっぽい要素が無いように思えたので、サンプルそのままです。
ですがこのサンプル、緑の四角にカーソルを合わせると各位置情報を取得できるのですが、カーソルが緑の四角から外れてもこの情報が表示されたままだったのですが、それがあまり気に入らなかったのでそこだけ直しました。

緑の四角にカーソルを合わせると、、

各位置情報が表示される。
緑の四角からカーソルを外すと、、

位置情報はなくなる。
とはいえ、キャプチャの関係上カーソルが乗っかっているように見えないんですけど。

ソースコード

<!DOCTYPE HTML PUBLIC "-//W3c//DTD HTML 4.01 Transitiional//EN"
"http://www.w3.org/TR/html4/loose,dtd">
<html>
	<head>
		<title></title>
	</head>

	<body>
		<div><canvas id="_c3"></canvas></div>
		<div><span id="_c3_text"></span></div>
		<script type="text/javascript" src="../../../hyperandroid-CAAT-f7d1a87/build/caat.js"></script>
		<script type="text/javascript">
			(function( ){
			 var _director_3 = new CAAT.Director().initialize(
				 400,
				 120,
				 document.getElementById('_c3'));

			 var _scene_3 = _director_3.createScene();

			 var _pulsating_actor_3_0 = new CAAT.Actor().
			 setBounds(10, 20, 80, 80).
			 setFillStyle('#00ff00');
			 _pulsating_actor_3_0.name = 'no transformation';

			 var _pulsating_actor_3_1 = new CAAT.Actor().
			 setBounds(120, 20, 80, 80).
			 setFillStyle('#00ff00').
			 setRotation(Math.PI/6);
			 _pulsating_actor_3_1.name = 'rotated 30 degrees';

			 var _pulsating_actor_3_2 = new CAAT.Actor().
			 setBounds(200, 20, 80, 80).
			 setFillStyle('#00ff00').
			 setScale(.5, 1);
			 _pulsating_actor_3_2.name = 'scaled(.5, 1)';

			 var _pulsating_actor_3_3 = new CAAT.Actor().
				 setBounds(300, 20, 80, 80).
				 setFillStyle('#00ff00').
				 setScale(1.2, .4);
			 _pulsating_actor_3_3.name = 'scaled(1.2, .4)';

			 var mouseMoveHandler = function(mouseEvent){
				 var actor = mouseEvent.source;

				 document.getElementById('_c3_text').innerHTML =
					 "<b>Actor:</b>" + actor.name + " " +
					 "<b>Local Coord:</b> (" +
					 ((mouseEvent.point.x*100)>>0)/100 + ", " +
					 ((mouseEvent.point.y*100)>>0)/100 + ") " +
					 "<b>ScreenCoord:</b> (" +
					 mouseEvent.screenPoint.x + ", " +
					 mouseEvent.screenPoint.y + ") ";
			 };

			 var mouseExitHandler = function(mouseEvent){
				var actor = mouseEvent.source;

				document.getElementById('_c3_text').innerHTML = " ";
			 };

			 _pulsating_actor_3_0.mouseMove = mouseMoveHandler;
			 _pulsating_actor_3_1.mouseMove = mouseMoveHandler;
			 _pulsating_actor_3_2.mouseMove = mouseMoveHandler;
			 _pulsating_actor_3_3.mouseMove = mouseMoveHandler;

			 _pulsating_actor_3_0.mouseExit = mouseExitHandler;
			 _pulsating_actor_3_1.mouseExit = mouseExitHandler;
			 _pulsating_actor_3_2.mouseExit = mouseExitHandler;
			 _pulsating_actor_3_3.mouseExit = mouseExitHandler;

			 _scene_3.addChild(_pulsating_actor_3_0);
			 _scene_3.addChild(_pulsating_actor_3_1);
			 _scene_3.addChild(_pulsating_actor_3_2);
			 _scene_3.addChild(_pulsating_actor_3_3);

			 CAAT.loop(20);
			})();
</script>
	</body>
</html>

わりとお馴染みのコードです。このscaleやrotationも今まで使ったものですし。
ですが、各actorに同じようなマウスイベント処理を施したいときに、関数を定義して、その定義した関数を各actorのイベントにaddするというのは初めてだった気がするのでなるほどと思いました。
いや、よく考えれば普通の事なのですが。

これなら前回のクリックゲームももう少しスマートに書きなおせそうですね。

どうやったらイベントの発生したアクターを特定するのかと思っていたのですが、
mouseEvent.source
でイベントの発生したactorを特定しています。
mouseExitも同様に処理を行なっています。

今回は特に目新しいものはないですのでこんなところでしょうか。


それよりも(というと良くないかもしれませんが)、Vimで便利そうなコマンドを学習したのでメモ。
(既存の記事に追記)
[MacVim] - 武田のつぶや日記

xampp for mac

facebookアプリ開発の記事を雑誌で見て面白そうだと思ったので、折角phpも少し勉強してみたという事で自分でも何かしらを作ってみようと思ったのですが、ローカル開発環境(特にローカルである必要もないですがこの場合公開する予定がないので)が必要という事でとりあえずローカル開発環境を構築しました。
windowsでは作っていましたが、macに作るのは初めてだったので色々調べながらやったのでそのメモという事で。

色々手段はあるみたいですが、今回はwindowsで一度した事があったxamppのmac版、xampp for macというのを使っていきます。
このxamppというのはwebアプリ開発に必要となるフリーソフトを集めたもので、x(クロスプラットフォーム)a(apache:webサーバソフトウェア)m(mysql:データベース)p(php:プログラム言語)p(perl:プログラム言語)という略です。

他にもmamp等もあるそうです。

インストール

何はともあれxamppを手元のマシンにインストールします。
googleにてxampp for macで検索して一番最初に出るページにアクセスします。
http://www.apachefriends.org/jp/xampp-macosx.html

少し下に行くと、ダウンロードリンクがあるのでそこからダウンロードします。

9/10現在、verは1.7.3のようです。
インストールしたzipファイルを解凍するとdmgファイルを得るのでそれをクリックしてインストールします。
インストール法はお馴染みのドラッグでapplicationフォルダにうつすだけです。

これでインストール完了です。
実際に動作させてみます。

アプリケーションフォルダの中のxamppフォルダ内の.appをクリックして起動すると下のような画面が出ます。

画像にも書いてある通り、apacheの横にあるstartボタンを押してapacheを起動します。
すると、apacheの横の赤いランプが緑になり、startボタンがstopボタンに変わります。

この状態で、ブラウザを立ち上げ「http://localhost」とurl欄に打ち込んだら次のような画面が出れば成功です。

セキュリティ

この状態だとセキュリティが不安なのでいくつかセキュリティ設定を行います。
まずrootユーザーに変更するために
Macintosh HD/System/Library/CoreServices/ディレクトリユーティリティ.app
をクリックします。

そしてメニューバーの編集からルートユーザーを有効化するを選び、さらにパスワードを変更からパスワードを設定してください。
これでルートユーザーになったのでセキュリティを強化していきます。

まず、ターミナルを立ち上げ「su -」としてルートユーザーになります。パスワードを聞かれると思うので、先ほど設定したパスワードを入力します。
次のコードをターミナルに入力します。
/Applications/XAMPP/xamppfiles/xampp security
すると、
XAMPP: Your XAMPP pages are NOT secured by a password.
XAMPP: Do you want to set a password? [ja]
というような表示が出るので、enterでパスワードを二回入力します。
このパスワードは後ほどlocalhostにアクセスするために必要になるので忘れてはいけないようです。

さらにその後、いくつかエンターを求められるのでとりあえずエンターを押しておきます。
Doneの表示が出れば全て終了なので、exitコマンドでルートユーザーを脱出し、さらにexitコマンドでプロセスを終了します。
その後、ルートユーザーを無効化しておきます。

次にmySQLのセキュリティ設定を行うので、先ほどapacheを立ち上げたようにmySQLもたちあげておきます。
そして、ターミナルを立ち上げ、次のコマンドを入力します。
/Applications/XAMPP/xamppfiles/bin/mysqladmin -u root -p password 設定するパスワード
その後、enterを求められるのでenterしておきます。

最後にphpMyAdminのルートユーザーのパスワード設定を行なっておきます。
/Applications/XAMPP/xamppfiles/phpmyadmin/config.inc.phpファイルを設定し直します。
ここでもターミナルを立ち上げ、/Applications/XAMPP/xamppfiles/phpmyadmin/ディレクトリに移動します。
入力が面倒であれば、cd (cd+space)と打った後に上記のディレクトリをFinderあたりで探してきてターミナル内にドラッグすれば大丈夫です。
ディレクトリに移動したら
sudo vim config.inc.php
と打ちます。sudoはsuperuserでdoする、的な意味でしょうか。

$cfg['Servers'][$i]['password'] = ' ';

$cfg['Servers'][$i]['password'] = '設定したパスワード';

というように書き換えます。

折角なのでvimコマンドを使うといいですね。
ノーマルモードで/$cfgで検索をかければ早いです。
:wqで保存、終了して設定終了です。

もう一度localhostにアクセスしてみましょう。
今度はユーザーとパスワードの入力が求められるでしょうか?
ユーザーにはxampp、パスワードには設定したパスワードを入力します。

無事にアクセスできたら左の一覧からセキュリティを選びステータスを確認します。
全て安全であればよいでしょう。

バーチャルホスト

xamppではルートフォルダ(最初にアクセスされるフォルダ)がデフォルトではxamppディレクトリのhtdocsディレクトリとなっていて、このhtdocs内に色々とファイルを構成してwebを構築していくようなのですが、いくつか同時にwebを制作するとき等はいちいちhtdocsの中身を入れ替えないといけないので少し面倒になります。
なので、バーチャルホストを設定する事によりルートフォルダを変更してアクセスする事ができるようになるらしいです。

今回はfacebookのwebアプリを作成するだけなので必要ないかと思っていましたが、silexというフレームワークを使用するにあたってルートフォルダを変更しなければならない?ようなので、バーチャルホストを設定していく事にします。

実際のバーチャルホストの設定はfacebookアプリの作成に合わせるので次回に説明するとして、今回はバーチャルホストを有効化するところまでにします。

これは/Applications/XAMPP/xamppfiles/etc/httpd.confというファイルをいじるようです。

# Virtual hosts
# Include /Applications/XAMPP/etc/extra/httpd-vhosts.conf

この二行目の最初の#を外す事によりコメントアウトが解けて、この設定が有効化されるようです。
ようするにhttpd-vhosts.confというファイルにバーチャルホストに関する色々な設定があって、これを読み込むようになるという事ですね。
このファイルを開く際は先程と同様にsudoコマンドをつけて開かないと書き込みができないので気をつけます。
これもさくっと/#Includeとか入力して検索をかけて見つけてしまいます。


こんな感じでざっくりと設定を終える事ができました。
次はfacebookアプリケーションに取り組んでみたいとおもいます。
次回は違う記事になるかもしれませんが。

CAAT::Actor(Life Cycle)

今回は次のページを参考にCAATのlife cycleについて学習してみます。
http://hyperandroid.github.com/CAAT/documentation/tutorials/t2-2.html

life cycleとはActorが生成されたり、消えたりする一連の流れのようなものですかね。
それでは見ていきます。

life cycle

デフォルトではActorというのはSceneが表示されると同時に描画され、ずっと消える事はない。
しかし、life cycleを用いてある時間でSceneのtime lineをコントロールする事ができる。
setFrameTime(start_time, duration)という関数を用いて、actorのlife cycleをコントロールする事ができます。
scene timeはactorのstart_timeよりも小さいか、start_time + durationより大きくなければいけないのでactorはframe timeの外側にあるべきです。
そうでなければactorはframe timeの内側にいるものとされ、与えられた振る舞いを持ち、描画されてしまう。
start_time + durationより大きいactorがframe timeより外側に置かれた場合、actorの有効期限は切れる。
これはisExpired()と呼ばれるメソッドを呼び出す事によって呼ばれる読み込み専用のプロパティです。
(=この読み込み専用プロパティによりactorの有効期限内か、外かを判別している??)

actorはExpiredを一度だけセットされ、このExpiredがセットされている間は登録されているlife cycle listenerを読み込む。
三つのリスナーのうち一つはactorをもう一度frame timeにセットできるように、frame timeをリセットするもの。
actorの消去処理はsetDiscardable(true)というメソッドを用いてdiscardableというactorのフラグを立てる事により行う。
デフォルトではactorのdiscardableフラグは立っていない。
これはどういう事かというと、directorのframe cycleの終わり、frameレンダリング処理の終了時に有効期限の切れているactorやdiscardableフラグのたっているactorはシーンの外に出されて消去されます。
壊されたactorは親要素からも消去されます。

life cycle listener

actorは自身のlife cycleをentity(何らかの物体)に関係するthird partyに触れさせる次のようなメソッドを持つ。

  • addListener(actor_life_cycle_listener)
  • removeListener(actor_life_cycle_listener)
  • fireEvent(event_time, time)

開発者はadd/removeメソッドをコントロールしてfireEventを呼び出し、関係するdirector/sceneアニメーションを変化させる。
actor_life_cycle_listenerは{actorLifeCycleEvent : function(actor_ref, event_type, time){処理}}というような形をしていなくてはいけない。

  • actor_ref

自身のlife cycle eventを通知するactorへの参照。開発者は同じリスナーを異なるactorに参照する事ができる。

  • event_type

expired、destroyといったString型のvalue

  • time

actorがデストロイされてからの時間


んー、あまり何を言っているかわかりませんでした。
サンプルコードを実行する事によって少し見えてくるのでサンプルコードを実行して確かめるといいでしょう。

sample game

という事で、サンプルを実行してみます。
とはいえただ丸写しはあまり面白くないので今回もまた簡単なゲームのようなものを作ってみます。

例によって例の如く実行結果からいきます。
今回公式のサンプルは緑の四角が消えたり描画されたりするもの、という感じだったので作成するものはある範囲内の適当な位置に表示される四角をクリックしてポイントを貯めていくというゲームにしましょう。

起動画面は次の通りです。

真っ白い何も表示されていない画面が描画されます。
数秒立つと、小さい四角が画面内に表示されます。

この四角は一定時間を過ぎると消えてしまうので消える前にクリックしていきます。クリックを失敗した場合画面左下にbad!!的なメッセージが表示され、bad数が1増えます。

きちんと、クリックできればgreat!!と表示され、great数が増加します。

この小さい四角は一定good数を超える事により四角が消えてから次の四角が現れるまでの時間と、四角が現れている時間が短くなっていきます。
僕の作った設定だとgood数が5の倍数になる度に、次の四角が現れる時間が500[ms]ずつ、四角が現れている時間が200[ms]ずつ短くなっていきます。

また、good数が20に達すると左下に「new Square will appear!!」みたいなメッセージが現れ、出現する四角の数が二つに増えます。


(画像だと時間節約にするために発動するgreat数を変えて実行しています)

さらにgood数が40に達すると「more newer square will appear!!」みたいなメッセージとともに出現する四角の数が三つになります。

そしてbad数が5に達するとゲームは終了し、左下に結果が表示されます。

(キャプチャを失敗して全部左下がbadになっています)

一応動画でも。

画面収録時間の関係でスーパーイージーモードの時ですが。
実際に試してみたい方は
https://github.com/takedai0313/lifecycle
の画面真ん中あたりの右側にありますdownloadsからお試しください。

ダウンロードした.zipファイルを解凍して中にあります、sample.htmlをクリックするだけです。
ただし、ブラウザはgoogle chromeでしか試していないので他のブラウザで予期せぬ動作をした場合すみません。
いずれこのgithubの使い方もまとめてみます。
まだ、dotinstallでgitの使い方とgithub for macを使ったくらいですが。

それからcaat.jsは恐らくオープンソースだと思ったので、公開していますがもしこういったことがダメだった場合は教えていただければ幸いです。すぐに対処いたします。

ソースコード

とまぁ横道にそれてしまいましたが、ソースコードは次のようになっています。

<!DOCTYPE HTML PUBLIC "-//W3c//DTD HTML 4.01 Transitiional//EN"
"http://www.w3.org/TR/html4/loose,dtd">
<html>
	<head>
		<title>click game</title>
		<style type="text/css">
			result{font-size: 1.25em}
		</style>
	</head>

	<body>
		<div><canvas id="_c2"></canvas></div>
		<div><span id="_c2_text"></span></div>
		<div><result><span id="message"></span></result></div>
		<script type="text/javascript" src="../../../hyperandroid-CAAT-f7d1a87/build/caat.js"></script>
		<script type="text/javascript">
			(function( ){

			 var _director_2 = new CAAT.Director().initialize(
				 400,
				 400,
				 document.getElementById('_c2'));

			 var _scene_2 = _director_2.createScene();
			 _scene_2.paint = function(director, time){
				var ctx = director.ctx;
				ctx.stokeStyle = 'balck';
				ctx.strokeRect(0, 0, this.width, this.height);
			}
			 
			 var span = document.getElementById('_c2_text');
			 var message = document.getElementById('message');

			 var _pulsating_actor_2 = new CAAT.ActorContainer().
			 create().
			 setBounds(10, 10, 80, 80).
			 setFillStyle('white').
			 setFrameTime(0, 200);

			 var _pulsating_actor_3 = new CAAT.ActorContainer().
				 create().
				 setBounds(10, 10, 80, 80).
				 setFillStyle('white');

			 var _pulsating_actor_4 = new CAAT.ActorContainer().
				 create().
				 setBounds(10, 10, 80, 80).
				 setFillStyle('white');
			 
			 var flag = 1;
			 var flag_add = 1;
			 var good = 0;
			 var bad = 0;
			 var setTime = 2700;
			 var visibleTime = 2700;
				
			 var colors= [ 'blue', 'red', 'yellow', 'green', 'gray' ,'orange' ];
			 var color_index = 0;
			 
			 _pulsating_actor_2.addListener({
				actorLifeCycleEvent : function(actor, event_type, time){
					if(event_type == 'expired'){
						actor.setFillStyle(colors[(color_index++)%colors.length]);
						if(flag == 0){
							bad++;
							if(bad == 5){
								_pulsating_actor_2.destroy(time);
								_pulsating_actor_3.destroy(time);
								_pulsating_actor_4.destroy(time);
								message.innerText = '[game finish] ' + good + ' good!!!';
							}
							span.innerText = '[ bad!! ]' + ' good: ' + good + ' bad: ' + bad;
						}else{
						}
						actor.setFrameTime(time + setTime, visibleTime);
						var s = 20 + 20 * Math.random();
						actor.setBounds(360*Math.random(), 360*Math.random(), s, s);
						flag = 0;
					}
					_pulsating_actor_2.mouseClick = function(mouseEvent){
						actor.setFrameTime(time, 10);
						flag = 1;
						good++;
						span.innerText = '[ good!! ]' + ' good: ' + good + ' bad: ' + bad;
						
						if(good % 5 == 0 && good != 0 ){
							if(setTime != 200){
								setTime = setTime - 500;
							}
							if(visibleTime != 500){
								visibleTime = visibleTime - 200;
							}
						}
					}
					if(good == 20){
						if(flag_add == 1){
							_scene_2.addChild(_pulsating_actor_3);
							_pulsating_actor_3.setFrameTime(time, 2700);
							message.innerText = 'New Square will appear!!'
							flag_add = 0;
						}
					}
					if(good == 40){
						if(flag_add2 == 1){
							_scene_2.addChild(_pulsating_actor_4);
							_pulsating_actor_4.setFrameTime(time, 2700);
							message.innerText = 'More Newer Square will appear!!'
							flag_add2 = 0;
						}
					}
				}
			 });

			 var flag2 = 1;
			 var flag_add2 = 1;
			 var setTime2 = 2700;
			 var visibleTime2 = 2700;
			 var color_index2 = 0;

			 _pulsating_actor_3.addListener({
				actorLifeCycleEvent : function(actor, event_type, time){
					if(event_type == 'expired'){
						actor.setFillStyle(colors[(color_index2++)%colors.length]);
						if(flag2 == 0){
							bad++;
							if(bad == 5){
								_pulsating_actor_2.destroy(time);
								_pulsating_actor_3.destroy(time);
								_pulsating_actor_4.destroy(time);
								message.innerText = '[game finish] ' + good + ' good!!!';
							}
							span.innerText = '[ bad!! ]' + ' good: ' + good + ' bad: ' + bad;
						}else{
						}
						actor.setFrameTime(time + setTime2, visibleTime2);
						var s = 20 + 20 * Math.random();
						actor.setBounds(360*Math.random(), 360*Math.random(), s, s);
						flag2 = 0;
					}
					_pulsating_actor_3.mouseClick = function(mouseEvent){
						actor.setFrameTime(time, 10);
						flag2 = 1;
						good++;
						span.innerText = '[ good!! ]' + ' good: ' + good + ' bad: ' + bad;
						
						if(good % 30 == 0 && good != 0){
							if(setTime2 != 200){
								setTime2 = setTime2 - 500;
							}
							if(visibleTime2 != 500){
								visibleTime2 = visibleTime2 - 200;
							}
						}
					}
					if(good == 40){
						if(flag_add2 == 1){
							_scene_2.addChild(_pulsating_actor_4);
							_pulsating_actor_4.setFrameTime(time, 2700);
							message.innerText = 'More Newer Square will appear!!'
							flag_add2 = 0;
						}
					}

				}
			 });

			 var flag3 = 1;
			 var setTime3 = 2700;
			 var visibleTime3 = 2700;
			 var color_index3 = 0;

			 _pulsating_actor_4.addListener({
				actorLifeCycleEvent : function(actor, event_type, time){
					if(event_type == 'expired'){
						actor.setFillStyle(colors[(color_index3++)%colors.length]);
						if(flag3 == 0){
							bad++;
							if(bad == 5){
								_pulsating_actor_2.destroy(time);
								_pulsating_actor_3.destroy(time);
								_pulsating_actor_4.destroy(time);
								message.innerText = '[game finish] ' + good + ' good!!!';
							}
							span.innerText = '[ bad!! ]' + ' good: ' + good + ' bad: ' + bad;
						}else{
						}
						actor.setFrameTime(time + setTime3, visibleTime3);
						var s = 20 + 20 * Math.random();
						actor.setBounds(360*Math.random(), 360*Math.random(), s, s);
						flag3 = 0;
					}
					_pulsating_actor_4.mouseClick = function(mouseEvent){
						actor.setFrameTime(time, 10);
						flag3 = 1;
						good++;
						span.innerText = '[ good!! ]' + ' good: ' + good + ' bad: ' + bad;
						
						if(good % 5 == 0 && good != 0){
							if(setTime3 != 200){
								setTime3 = setTime2 - 500;
							}
							if(visibleTime3 != 500){
								visibleTime3 = visibleTime3 - 200;
							}
						}
					}
				}
			 });

			_scene_2.addChild(_pulsating_actor_2);

			CAAT.loop(20);

			})();
			</script>
	</body>
</html>


いつにもましてひどいコードですが、こうすればいいのにというのがあればgithubの方から更新等していただけましたら幸いです。
それではコードを見ていきます。

headタグ内はいいとして、bodyタグの最初に例の如くdiv要素で三つ程描画領域を定義しています。
今回は実際に四角形等を描画するものを一つ、good数やらbad数やらを表示するものが一つ、gameoverメッセージやらなんやらを表示するものが一つということです。

そしていつものようにdirectorを作り、sceneを作り、四角を表示するためのActorを作ります。公式サイトのサンプルではCAAT.Actor()でしたが、ここではクリック処理を行いたいのでCAAT.ActorContainer()に変えています。
変数名が_2から始まっているので少し気持ち悪いですが、この_2から始まっている変数名が最初に描画される四角形です。
その後に_3、_4と二番目に描画される四角形、三番目に描画される四角形のActorContainerを用意しています。
最初にsetFillStyle('white')で白い色で描画しているのは、いきなり描画されると良くないかなと思ったので最初は白い四角で見えないように描画して、その後lifecycle内で別の見える色で描画していけばいいかなという感じです。
(よくよく考えれば、setFrameTimeの引数を0でなく、適当な秒数にすればよかっただけな気もします)

また_3、_4のActorContainerにはsetFrameTimeがこの時点では記述されていないのは、この二つは最初から描画をするわけではなく、life cycle内のある適当なタイミングで描画をしたかったので、life cycleの時間が引数に必要となり現時点ではそのtimeが使用できないので、実際にsceneにaddするタイミングでsetFrameTimeを行なっています。


続いては各種変数です。
javascriptはどこで変数を定義しても良いので、こんなところで定義していたりしますがやっぱり最初に書いた方がいいのでしょうか。
変数は上から順番に
各ActorContainerがクリックされたかどうかを判断するflag変数、新しい四角(新しいActorContainer)をsceneにaddするかどうかを判別するflag_add変数(なぜこれが必要かは以下に記載)、good数bad数を管理するgood変数bad変数、四角が消えてから次の四角が描画されるまでの時間を示すsetTime変数と描画された四角形が消えるまでの時間を示すvisibleTime変数、といった感じです。
その下にはcolorを管理する各種変数が二種類用意していますがこれはいいでしょう。


で、ここからがいよいよlife cycleを管理する関数です。
今回はリスナーを登録したいのでaddListenerです。その引数?を公式リファレンスに書いてあった通りにactorLifeCycleEventとして登録していきます。

まずif文でactorがexpiredの状態時(つまり有効期限切れだったら?)の処理を記載致します。
expiredの状態だった場合、何秒か後に異なる色で表示したいので、setFillStyleを再度用いて違う色に変えます。
その後、flagが0だった場合は、つまりクリック失敗だった場合はbad数を増やします。そして、お馴染みのinnerTextでメッセージを表示します。
さてその間の処理ですが、これはbad数が5だった場合game overにするための処理です。
actorのlife cycleを終了させるためにリファレンス通りremoveListenerだったり色々試してみましたがうまくいかず(恐らく自分の使い方が間違っているのですが)、caat.jsファイルを見てdestroy(time)メソッドを用いています。このtimeを色々いじれば恐らくdestroyするタイミングをコントロールする事ができるのではないかと思います。
ちなみにこの処理(だけではないですが)、他のactorでも同様にそれぞれ3つ分のdestroy処理を行なっていますが、これはどのactorのlifeCycleでbadが5に達するか判別できないと思ったので力技で全てに同じ処理を施しています。
もっといいやり方があるに違いありません。

flagが1だった場合(クリック成功の場合)には特に何もせずに次の四角形を表示するための準備を行なっています。
flagが1の場合何故何もしないかというと、click時の処理はmouseClickメソッドで定義しているからです。
flag変数に何故最初に1を代入していたかというとこういった理由です。これにより、最初に白(見えないように)で描画された四角形が消滅してもbad数が増えないようにするためです。

肝心のその処理ですが、
setFrameTimeでtime(現時刻)からsetTime[ms]後に、visibleTime[ms]まで描画し続けなさい、としています。
また四角形の大きさもランダムに変えたいので20〜40[px]の大きさになるように設定しています。
さらにsetBoundsでランダムな位置にactorを表示できるようにしています。
最後にflagを0に設定し直す事で、一度クリックしても次にクリックを失敗すればbad数が増えるようにしています。

さらにその下ではmouseClick処理を記述しています。
まず、setFrameTimeで現在時刻から10[ms]でexpiredの状態にしています。こうすれば各actorをクリックした時点でactorを消去でき、さらにlife cycleにより次のactorが再描画されます。
そしてflagを1にセットして、good数を増やし、innerTextで結果を表示しています。

その後、if文を用いた各種分岐処理を行なっています。
今回はgood五回毎にsetTimeとvisibleTimeを短くしたいのでそのように記載しています。それぞれ、500[ms]と200[ms]ずつ短くし、ある適当な値で止まるようにしています。
if文の条件の0でないなら、というのは例えばgood数が0でも0 ÷ 5は余り0になるんじゃね?と思ったので、それを回避するために記載しています。いらないかもしれません。

次にgood数20で_3のactorをsceneに登録できるようにしています。
ここで、上記のflag_addを使います。
例えばgood数20で_3のactorをaddするのはいいのですが、ここでクリックを失敗した場合good数が増えずに、if文の条件が再度満たされてしまい、もう一度addされてしまいます。
しかし、もう既にaddされているのでこれはエラーになるようです。
なのでこれを回避するためにflag_addを用いて、二度同じ処理を繰り返さないようにしています。
追加と同時にsetFrameTimeでlife cycleをコントロールします。

_4のactorも同様に処理します。
この_4のactorの追加処理は_3のlife cycleも記載していますが、これはdestroyの処理と同様にどちらのlife cycleでgood数が40に達するかわからないので、両方に処理を記載しています。
_3追加処理が_2にしかないのかというと、_3の追加は_2のlife cycleでしか起こり得ないからです。

そしてここからは同じような処理を_3と_4に加えています。


で、何故このような同じ処理を三回も繰り返しているのかというと、、自分の知識不足です。
オブジェクト指向のクラスのようにクラスを作成してあげればよかったのかもしれませんが、javascriptでの記述の仕方がよくわからずにこんな感じになってしまいました。
もう少し勉強してスマートな書き方を学習してみようと思います。
javaなら書けるような気がするけど同じ感じでいいのでしょうか。。

学習しよう。



こんな感じでlife cycleの学習は終わりです。
次にCAATについて勉強するとしたら、恐らくtransform、つまり各actorの変化について学習する事になると思います。


最後にcaat作成者の方に感謝致します。
http://hyperandroid.github.com/CAAT/documentation/tutorials/t0.html

CAAT::Actor(Events){練習編}

前回、折角Actorの各Eventsについて学習してみたので、なにかしら作ってみたいと思います。
前回記事↓
CAAT::Actor(Events) - 武田のつぶや日記

しかし前回学習した事だけで何ができるのかと考えていましたが、、ありました。
というわけで今回は脳トレっぽいゲームを作ってみたいと思います。

今回は実行結果から。
初期画面はこんな感じです。

大きい四角の中の左側に水色っぽい色のゾーンと、右側に赤っぽい色のゾーンを用意し、真ん中の白いゾーンに様々な色の小さい四角を30個描画しています。
小さい四角の中にはそれぞれに矢印を描画しています。

さて、ゲームですがこの小さい四角をあるルールに従って左側の水色っぽいゾーンと右側の赤っぽいゾーンに分けるという単純なものです。
そのルールというのは次のようなものです。

まず、この小さい四角は実は二種類に分ける事ができます。
30個それぞれを適当な角度で回転させていますが、この回転をなくすと次のような二種類になります。

つまり、矢印が四角形の左上に来るようにしたとき、左向きの矢印が描かれた四角形と右向きの矢印が描かれた四角形の二種類です。
色は関係ありません。
この左向きの矢印が描かれた四角形は水色っぽいゾーンに、右向きの矢印が描かれた四角形は赤っぽいゾーンに持っていくというものです。
この小さい四角形達は色のついたどちかのゾーンに持っていかれる事によって、ドラッグが不可能となります。
前回学んだ事を生かして説明すると、親要素から出てしまうためです。

なにはともかく一つ四角形を動かしてみましょう。

矢印が右向きだったので、右側のゾーンに持って行きました。
その判断が正しい場合、左下に「great!!」と出ます。

他の四角形を触るとgreat!!の文字は消えます。
こんな感じになります。

きちんと消えていますね。
次は正しくないver.を見てましょう。

本当は右向きの矢印なのに左側に置いたために、今度は左下に「bad!!」の文字が出ています。
こんな感じで30個延々と繰り返していきます。
正直別段楽しい作業ではないですが、いいでしょう。頑張って繰り返します。最後の一つをどちらかのゾーンに置くと左下に結果が表示されます。

こんな感じです。
この小さい四角が最初に描画される位置とどの程度回転するかはランダムに決定されるので、まぁ一応毎回違ったものを楽しめます。


本当は制限時間を付けたり、メニュー画面を作ったり、説明画面を作ったりしたかったのですが、まだ学習していないのでまたの機会にという事にしてみます。
静止画だけだとイメージがつきにくいと思うので、小さい四角の数を3つにして動画を以下に貼り付けておきます。

公開する方法がよくわかっていないので、公開できそうだったら自分以外も遊べるようにしてみたいです。
それでは最後にソースコードと、コード解説を。

<!DOCTYPE HTML PUBLIC "-//W3c//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
	<head>
		<title>sample</title>
		<style type="text/css">
			result {font-size: 1.25em}
		</style>
	</head>

	<body>
		<script type="text/javascript" src="../../../hyperandroid-CAAT-f7d1a87/build/caat.js"></script>
		<div><canvas id="_c1"></canvas></div>
		<div><result><span id="_c1_text"></result></span></div>

		<script type="text/javascript">
			(function( ){
				
				var boxNumber = 30;
				var boxCount = boxNumber;
				var great = 0;
				var bad = 0;
				var director_1 = new CAAT.Director().initialize(
					600,
					400,
					document.getElementById('_c1'));

				var span = document.getElementById('_c1_text');

				var scene_1 = director_1.createScene().setFillStyle('#fff');

				scene_1.paint = function(director, time){
					var ctx = director.ctx;
					ctx.fillStyle = '#0fc';
					ctx.fillRect(0, 0, 100, this.height);
					ctx.fillStyle = '#c06';
					ctx.fillRect(500, 0, 600, this.height);
					ctx.strokeStyle = '#000';
					ctx.strokeRect(0, 0, this.width-1, this.height-1);
					}

				var _c1_container = new CAAT.ActorContainer().
					setBounds(100, 0, 400, scene_1.height).
					setFillStyle('white');
				
				_c1_container.paint = function(director, time){
					var crx = director.ctx;

					crx.fillStyle = this.fillStyle;
					crx.fillRect(0, 0, this.width, this.height);

					crx.strokeStyle = 'black';
					crx.strokeRect(0, 0, this.width, this.height);
				};

				scene_1.addChild(_c1_container);
				
				var colors= [ 'blue', 'red', 'yellow', 'white', 'gray' ,'orange' ];
				var color_index = 0;

				for(var i=0;i<boxNumber;i++){
					var rdm_number = Math.random();

					if(rdm_number > 0.5){
						var _c1_container_child_left = new CAAT.ActorContainer().
							setBounds(370 * Math.random(), 370 * Math.random(), 30, 30).
							setRotation(Math.PI * 2 * Math.random()).
							setFillStyle(colors[(color_index++)%colors.length]).
							enableDrag();

						_c1_container_child_left.mouseDown = function(mouseEvent){
							span.innerText = '     ';
						}
						
						_c1_container_child_left.mouseUp = function(mouseEvent){
							if(mouseEvent.screenPoint.x < 100){
								span.innerText = 'great!!';
								great++;
								boxCount --;
								if(boxCount == 0){
									resultReport(span, great, bad);
								}
							}else if(mouseEvent.screenPoint.x > 500){
								span.innerText = 'bad!!';
								bad++;
								boxCount --;
								if(boxCount == 0){
									resultReport(span, great, bad);
								}
							}
						}
						_c1_container_child_left.paint = function(director, time){
							CAAT.ActorContainer.superclass.paint.call(this, director, time);
							var ctx = director.ctx;

							ctx.fillStyle = 'white';

							ctx.strokeStyle = 'black';
							ctx.strokeRect(0, 0, this.width, this.height);

							ctx.beginPath();
							ctx.moveTo(20, 10);
							ctx.lineTo(5, 10);
							ctx.lineTo(10, 5);
							ctx.moveTo(5, 10);
							ctx.lineTo(10, 15);
							ctx.stroke();
						}

						_c1_container.addChild(_c1_container_child_left);
					}else{
						var _c1_container_child_right = new CAAT.ActorContainer().
							setBounds(370 * Math.random(), 370 * Math.random(), 30, 30).
							setRotation(Math.PI * 2 * Math.random()).
							setFillStyle(colors[(color_index++)%colors.length]).
							enableDrag();

						_c1_container_child_right.mouseDown = function(mouseEvent){
							span.innerText = '     ';
						}
						_c1_container_child_right.mouseUp = function(mouseEvent){
							if(mouseEvent.screenPoint.x < 100){
								span.innerText = 'bad!!';
								bad++;
								boxCount --;
								if(boxCount == 0){
									resultReport(span, great, bad);
								}
							}else if(mouseEvent.screenPoint.x > 500){
								span.innerText = 'great!!';
								great++;
								boxCount --;
								if(boxCount == 0){
									resultReport(span, great, bad);
								}
							}
						}
						_c1_container_child_right.paint = function(director, time){
							CAAT.ActorContainer.superclass.paint.call(this, director, time);
							var ctx = director.ctx;

							ctx.fillStyle = 'white';

							ctx.strokeStyle = 'black';
							ctx.strokeRect(0, 0, this.width, this.height);

							ctx.beginPath();
							ctx.moveTo(5, 10);
							ctx.lineTo(20, 10);
							ctx.lineTo(15, 5);
							ctx.moveTo(20, 10);
							ctx.lineTo(15, 15);
							ctx.stroke();
						}

						_c1_container.addChild(_c1_container_child_right);
					}

				}
				CAAT.loop(10);

			})( );

			function resultReport(span, great, bad){
				span.innerText = '[GAME FINISH]  great: ' + great + '  bad: ' + bad;
			};
		</script>
	</body>
</html>

とはいえ、サンプルコードを大きくは変えていません。
まず、headタグ内で結果表示の文字の大きさを変えたかったので、stylesheetで定義しています。
次にbodyタグ内の最初で、実際に画面を描画する場所と結果を表示する場所をdivタグで定義しています。
結果表示のところはタグ(これは適当に名前つけただけ)を用いてstylesheetを適応しています。

いよいよ画面描画の関数ですが、最初に小さい四角の数・ドラッグ可能な残り四角の数・great数・bad数といった変数を定義しています。
ディレクターやシーンを作るところは一緒なので良いとして、実際に色を塗る際にx座標が0〜100、500〜600で色を分けています。
続いて親要素となるActorContainerを画面のx座標が100〜500のところにセットしていきます。
この親要素はドラッグする必要がないので、enableDrag()をつけていません。

このアクターをシーンに組み込み終わったら、次に小さい四角を描画する準備にとりかかります。
このcolorsという配列とcolor_indexは
CAAT::ShapeActor - 武田のつぶや日記
でも用いました。

そしてforループで四角を複数生成します。
ランダムな0〜1までの数を作り、0.5より大きければ左向き矢印の四角形、それ以外なら右向き矢印の四角形を作ります。
それぞれ、setBoundsで真ん中の白い範囲内のランダムな位置に四角形が生成されるようにして、mouseDownで他の四角形を触ったときに結果表示を消す処理を定義し、mouseUpでドラッグしていき手を離した際の処理を書いています。
mouseUp内では、クリックを離された場所を検知し、水色っぽいゾーンなら何をする、赤っぽいゾーンなら何をする、というように書いています。
mouseEvent.screenPoint.xでx座標を取得できるみたいです。

あとは大体サンプルと一緒で、最後に結果を表示するための関数を作成しています。
本当は小さい四角である子要素を二つに分けずに一つしか作らず、中に持つ変数で処理を分けていきたかったのですがやり方がいまいちわからなかったので、泥臭い方法でゴリ押ししました。
javaとかなら中に変数追加できるんだけど、、

まぁとりあえず自分で考えてできたので概ね満足です。
コードの書き方ひどいけど、、

どうやって勉強しようか。。

CAAT::Actor(Events)

今回はActorにおけるイベントの発生。
適当な範囲においてマウスを動かしたり、クリックする事によってイベントを発生させる方法のようです。

今回はこのページを見ながらやっていきます。
http://hyperandroid.github.com/CAAT/documentation/tutorials/t2-1.html


入力システムについてざっくりと概要が書いてあります。

Input Systemについて

CAATの入力システムは二つの方法で動作するようです。
デフォルトでは全てのscene graph actorはマウスやタッチといったインプットシステムを利用する事ができます。
入力システムはActorがどんなInput Eventを持っているのかを探すためにシーン上で動作する。
ここで最も大事な事は、親要素の領域を出た子要素はinputイベントを受け取る事ができなくなるという事。
これを防ぐためにCAAT.ActorContainerはCAAT.ActorContainer.AddHint.CONFORMという要素を持って作られる事ができ、そうする事によってCAAT.ActorContainerはバウンディングボックスを計算して自身のサイズを適応する事ができる。

Input List

入力システムのもう一つの方法としてInputListが紹介されていましたが、このInputListがなんなのかいまいちわかりませんでした。
InputListは次のようなメッソドを持つようです。

  • enableInputList(number)

sceneにセットするためのpriorityListの数を返す?priorityListというのは最初に入力を受け取るのに適しているActorのリストの事。
もしpriorityList上にActorが存在しない場合全てのsceneがトラバースされる。このトラバースが何と訳されるのかがわからず、結局全体像もつかめませんでした。
caat.jsファイルを見てみるとinputListというのは開発者が指定されたActorを見つけるためのグラフシーンをトラバースしたくないときにセットします。と書いてありますがどういう事やら、、。

        /**
         * Enable a number of input lists.
         * These lists are set in case the developer doesn't want the to traverse the scene graph to find the pointed
         * actor. The lists are a shortcut whete the developer can set what actors to look for input at first instance.
         * The system will traverse the whole lists in order trying to find a pointed actor.
         *
         * Elements are added to each list either in head or tail.
         *
         * @param size <number> number of lists.
         */
        enableInputList : function( size ) {
            this.inputList= [];
            for( var i=0; i<size; i++ ) {
                this.inputList.push([]);
            }

            return this;
        },

こんな感じのコードなのですが、あまりに知識不足でつかめませんでした。残念。

  • addActorToInputList( actor, index, position )

適当な位置にActorをprioryListに加える。

  • emptyInputList(index)

リストの中から全ての要素を削除する。

  • removeActorFromInputList( actor, index)

インデックスによって定義されたActorをリストから削除する。

全てのSceneActorで入力を無効にするにはCAAT.Actor.protoype.mouseEnabled = flaseをセットしてactor.enableEvents(true)メソッドを呼び出す必要がある。

Input Events

Actorインスタンスはデフォルトで利用できる次のようなイベントがある。

  • function mouseEnter(mouseEvent)

Actorの四角いエリアにマウスが入ったかどうかがトリガーとなる。そのActor自体はscaleやrotationで形等を変える事ができる。
CAATはピクセル単位での衝突を感知する事ができるので、変化がidに適応されているいないに関わらずマウスの矢印がActorの中に入る事ができる。

  • function mouseExit(mouseEvent)

mouseEnterと一緒だがこちらはActorから出たらイベントが発生する。

  • function mouseMove(mouseEvent)

マウスがActorの中を横切ったらイベントが発生する。

  • function mouseDown(mouseEvnet)

マウスがクリックされたときにイベントが発生する。

  • function mouseUp(mouseEvent)

マウスがクリックされ、離されたらイベントが発生する。

  • function mouseClick(mouseEvent)

マウスがクリックされたときにイベントが発生する。ただし、mouseDownの方が優先度が高い。

  • function mouseDbClick(mouseEvent)

mouseClickと一緒だが、こちらはダブルクリック時にイベントが発生する。

  • function mouseDrag(mouseEvent)

マウスドラッグ時にイベントが発生する。

これら全てのメソッドはmouseEventというユニークな値をを受け取る。
mouseEventは次のような情報を含む。

  • screenPoint

mouseEventが発生したスクリーン上の二次元座標

  • x,y

screenPointと一緒ではあるが、オブジェクトに含まれるw/o。
このw/oが何なのかわかりませんでした。

  • modifiers

modifiersはマウス入力が行われている間に特別なキーが押されているかどうかを教えてくれるもの。
CAAT.mouseEventクラスは特別なキーを調べるメソッドがいくつかあり、caat.jsファイルの12647行目あたりを見てみると特別なキーというのは「alt」だったり「contorl」だったり「shift」だったりといったキーの事らしい。

  • time

イベントが発生した時間。

  • source

イベントが発生しているActor。

特別なマウスハンドリング

CAAT.Actorインスタンスがデフォルトのマウスハンドリングを変えるようなメソッドが二つある。

  • function enableDrag()

Actorインスタンスのドラッグを許可するメソッドをセットする。
shiftキーやaltキー、controlキーとドラッグ操作でActorのrotationやscaleを変更する。
caat.jsファイルの6887行目くらいのコメントにshift+dragでscaleを変え、control+dragでrotationを変える。と書いてあります。

  • function setAsButton()

Actorにボタンとしての役割を与える。

他のインプットCAAT.directorにあるので、また別の機会に見ていきます。

sample

今回はチュートリアルのsampleコードをそのまま使っていきます。
ですので、実際に使用してみたのは次のようなコードです。

<!DOCTYPE HTML PUBLIC "-//W3c//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
	<head>
		<title>sample</title>
	</head>

	<body>
		<script type="text/javascript" src="../../../hyperandroid-CAAT-f7d1a87/build/caat.js"></script>
		<div><canvas id="_c1"></canvas></div>

		<script type="text/javascript">
			(function( ){
				var director_1 = new CAAT.Director().initialize(
					600,
					120,
					document.getElementById('_c1'));

				var scene_1 = director_1.createScene().setFillStyle('#fff');

				scene_1.paint = function(director, time){
					var ctx = director.ctx;
					ctx.fillStyle = this.fillStyle;
					ctx.fillRect(0, 0, this.width, this.height);
					ctx.strokeStyle = '#000';
					ctx.strokeRect(0, 0, this.width-1, this.height-1);
					}

				for(var i=0;i<6;i++){
					var s = 80; // 四角形の一辺の長さ

					var _c1_container = new CAAT.ActorContainer().
						setBounds(i*100+10, 20, s, s).
						setFillStyle('#ff3fff').
						setRotation(Math.PI * 2 * Math.random()).
						enableDrag();	// 引数をとらない
					
					_c1_container.name = 'rectangle' + i;

					_c1_container.paint = function(director, time){
						var crx = director.ctx;

						crx.fillStyle = this.fillStyle;
						crx.fillRect(0, 0, this.width, this.height);

						crx.strokeStyle = 'black';
						crx.strokeRect(0, 0, this.width, this.height);

						crx.strokeStyle = 'white';
						crx.beginPath();
						crx.moveTo(5, 10);	// 四角形の左上からの移動
						crx.lineTo(20, 10);
						crx.lineTo(15, 5);

						crx.moveTo(20, 10);
						crx.lineTo(15, 15);

						crx.lineWidth = 2;
						crx.lineJoin = 'round';	// round|bevel|miter
						crx.lineCap = 'round';	// round|butt|square

						crx.stroke();
					};

					scene_1.addChild(_c1_container);

					var _c1_container_child = new CAAT.ActorContainer().
						setBounds(s/2, s/2, s/4, s/4).
						setFillStyle('#00ff00').
						setRotation(Math.PI * 2 * Math.random()).
						enableDrag();

					_c1_container_child.paint = function(director, time){
						CAAT.ActorContainer.superclass.paint.call(this, director, time);
						var ctx = director.ctx;

						ctx.fillStyle = 'white';
						ctx.beginPath();
						ctx.arc(7, 7, 5, 0, 2*Math.PI, false);
						ctx.fill();
					}

					_c1_container.addChild(_c1_container_child);
				}
				
				CAAT.loop(10);

			})( );
		</script>
	</body>
</html>


少しずつコードを読んでいきます。
まず、directorインスタンスを横幅600px、縦幅120pxで初期化して、_c1要素に埋め込んでいます。
作ったdirectorインスタンスからSceneインスタンスを作成して、#fffで色を塗っています。
setFillStyleはRGBを16進数二桁で表すものかと思っていたのですが、16進数一桁でも利用する事ができるのですね。
その後、paintメソッドを作成します。paintメソッドではfillStyleを使い、strokeStyleで枠線を決めています。
ここでfillStyleをもう一度利用する必要はあるのでしょうか??

そしてここから実際にマウスイベントに対応した四角形を描いていきます。
四角形の個数が6個なので、forループを用いて同様の処理を六回繰り返します。

まず、ドラッグ可能な大きい四角を生成するためにActorContainerを用いて、インスタンスを作成します。
setBoundsで原点となる座標と実際の大きさを指定して、色を塗り、setRotationで適当な角度回転させます。
上で記載した、shift+dragの処理等も使えるようにしたいので、enableDrag( )を加えます。
caat.jsファイルを確認した限り引数は必要ない、、みたいです。
そして先程と同様に.paintで実際に色をつけていきます。
fillStyleもstrokeStyleも一緒ですが、矢印を描く際にパスを利用しています。イラレ等で用いるあのパスです。
まずbeginPath( )でパスを用いる事を宣言し(?)、先ほどsetBoundsで宣言した原点からmoveTo( )で(x, y)=(5px、10px)に移動してそこから(x, y)=(20px、10px)まで線を引きます。さらにそこから(つまり(x, y)=(20px、10px)の位置)、(x, y)=(15px、5px)の位置まで線を引き、もう一度(x, y)=(20px、10px)の位置まで戻り、今度は(x, y)=(15px、15px)の位置まで線を引きます。

ここで大事なのは、原点をsetBoundsで指定したところという事であり、またsetRotationはここよりも前に記載されていますが、こういった変化を与えるメソッドに影響を受けずに位置を指定する事ができるという事です。

そして線の太さを2pxにして、lineJoinやlineCapをroundに指定します。これはパスからパスへと線を繋ぐ際のつなぎ方です。
lineJoinにはroundやbevel、miterといった指定法があり、lineCapにはroundやbutt、squareといった指定法があるそうです。

そして描いたものを_c1_containerに加えています。

同様にして小さい四角形も描いていきます。
違うのは四角形内にarcを用いて円を描いている点と、先ほど作った四角形_c1_container_childを親要素としているという点です。

arcは引数に(中心のx座標、中心のy座標、半径、始点[度数指定]、終点[度数指定])をとります。


実際に実行した結果が次のようなものです。

左から二番目はshift+dragでスケールを変えています。
右から二番目は子要素の小さい四角形が親要素である大きい四角形をはみ出しているので、ドラッグする事ができません。
ざっくりとですが、inputについてはこのような感じでしょうか。

追記

色の指定法に16進数一桁でRGBそれぞれを表す事ができるのか、と思いましたが、普通にそういう指定法があるみたいですね。
参考までに。
Web Safe Color一覧表/カラーチャート