はじめに
最近Androidアプリ作りました
FLASH CS5.5 で「
かわいいねこちゃん」というちょうおもしろいゲームアプリを作ってAndroid Marketにリリースしました。(
AIRで出力したのでPCでも遊べます)
FLASH自体は作り易かったのですが、とても情報が少なく苦労したところが結構ありましたので
備忘録およびこれからFLASHでアプリ作ってみようと思っている方向けに記事を書こうと思いました。
この記事の想定対象外読者
「Android!うん知ってる!CMでやってた!AUの新しい携帯電話のことだよね!」って言う人
Androidアプリ作ろうぜ!
全国1億人のプログラマ以外の方々こんにちは。
そしてプログラマの方々こんな記事みなくても大丈夫なのでさようなら!!
現在、Androidのアプリを作ろうとする場合、選択肢は大きく2つです。
@全てはGoogle様の御心のままに・・・Eclipse+JAVAで開発する!
⇒これは最もスタンダードなやり方ですね。スタンダードってサイコウだよ!
だってドキュメントとか情報が充実してるし、大手ソーシャルメディア(○REEとか)のSDK組み込めるし、他社の広告配信プラットフォーム使いたい時だってちゃんとSDKとかライブラリが用意されてるから、すごく安心感がありますね!
しかし、プログラマのように困難を快感に感じることのできる
変態新人類でないと、Eclipseの環境構築するだけで途中で投げ出してしまいそうもし投げ出さなかったらプログラマになれ!プロかつグラマーになれ!
AJAVAってJavascriptのことですか?HTML5+Javascriptで作ったものをアプリの形式にコンバートする!
⇒最近かなり注目されてきているアプリの作り方ですね!Windows8ではアプリケーションをHtml5で作れるようになるそうですし、Html書いたことあるしJavascriptもコピペで使ったことありますよ!程度の僕のような技術者でもアプリが作れちゃう敷居の低さも凄い。最近ではDream Weaver CS5.5 が phonegap というフレームワークと連携する機能を備えてます。有名なのは titanium ですかね。簡単さと将来性は最強です!
しかし、HTML5+Javascriptですから、WEB画面のようなページ遷移が頻繁に発生するようなアプリであれば良いのですが、ゲームのようにキャラクターを動かしたり、アニメーションしたり、という仕様を実現するのがちょっと苦手です。ぶっちゃけHTML5で作れる範囲の表現をアプリに固めてなんの意味があるのか、まあ確かに加速度とかアプリじゃないと扱えないものはあるんでしょうけど・・・そのままブラウザでアクセスできる場所にアップロードしたほうがお手軽だしサーバ連携も簡単だし、どうなの?とも思います。
第3の選択肢 Flash CS5.5
プログラムとかよくわかんないんだけど、Androidアプリの簡単なゲームとかアニメとか作ってみたいという方にはFlash CS5.5です。実はFlash builder4.5でも作れるのですが、こちらは完全にAS3.0(パフォーマンスアップ!でもJAVA的な書き方してね!)的な作り方が必要となる点と、iphone用のアプリも出力したい時にiphone SDKとApplication Loaderが必要になるのでMAC(開発には性能的にairではなくproがオススメらしい)を買わないとあかん・・・。(VMWAREで仮想MACOSをWindowsPCに導入するという方法でWindowsのみでのiphoneアプリ開発に成功している方もいるようですが・・・MACOSは価格が¥3,000とかで安いのでやってみる価値はあるのかも)
じゃあFLASH CS5.5はどうなのかというと、iphone SDKがなくてもiphoneアプリを出力するところまではできちゃいます。結局Application Loaderがないとアップロードはできないのですが、アップロードだけは友達のMAC借りてやるとかね!個人であればそんな運用でもよいかと・・・。
かわいいねこちゃんの作り方
企画
何事もまずはじめは企画(やりたいこと)を考えて、妄想をふくらませることですね!
今回は社内の人(2人しかいないけど)に「Andoroidアプリの企画書作ってみて!」という的確な指示を出してみました。
すると5分後、「名称未設定-2.gif」というファイル名の画像がskypeで(無言で)送られてきた!
・・・
・・・
・・・
・・・
・・・
こいつ・・・動くぞ!
やったぞー!企画書の完成だ!
(GIFアニメで企画書提出とは・・・こやつ・・・やりおるわ・・・)
準備
・FLASH CS5.5 起動
・テンプレートから作成「AIR for Android」をクリック
・「800 x 480 空白」を選択してOK
・企画書によると横長画面なので、「修正」⇒「ドキュメント」で幅と高さの数値を入れ替えてOK
・「ファイル」⇒「AIR for Android 設定」クリック
出力ファイル名「cute_cat.apk」
アプリケーション名「かわいいねこちゃん」
アプリケーションID「jp.co.penet.cutecat」
起動時の縦横比「横長モード」
・「デプロイ」タブクリック
証明書「作成」クリック(パスワードとか適当に設定)
証明書「参照」から作った証明書を選択
「パスワード」にさきほどのパスワードを入力して「このセッション中はパスワードを保存する」にチェック
※FLASHを再起動した場合、再度この画面でパスワードを入力する必要があります
・「権限」タブクリック
「アプリケーション記述ファイルへの...」チェックしてOK
※これをやっておかないとxmlの設定ファイルへの修正をFLASHに上書きされてしまいがちになります
制作
AS3.0で作りますが、classとかは使わずに、
フレームに直接actionscriptを書いていく形で
直感的にわかりやすいAS2.0気分で作っていきます。
1フレーム目
var version:Number = 1;
var debug:Boolean;
//デバッグモード
debug = true;
if( debug == true )
{
import net.hires.debug.Stats;
addChild( new Stats() );
}
var webView:StageWebView;
var ADMOB_URL:String = "http://xxx.com/xxx.html";
var ad_width:int = 468;
var ad_height:int = 60;
function view1_initializeHandler():void
{
var target:DisplayObject = this;
while(target.parent){
target = target.parent;
}
var s:Stage = target as Stage;
webView = new StageWebView();
webView.addEventListener(ErrorEvent.ERROR,onIoerror);
webView.stage = s;
webView.viewPort = new Rectangle((s.stageWidth-ad_width)/2,480-ad_height,ad_width,ad_height);
webView.loadURL(ADMOB_URL);
webView.addEventListener(Event.COMPLETE,onComplete);
}
function onIoerror(event:ErrorEvent):void
{
webView.dispose();
}
function onComplete(event:Event):void
{
webView.addEventListener(LocationChangeEvent.LOCATION_CHANGE,update);
}
var update_i:Boolean;
function update(event:LocationChangeEvent):void
{
if(webView.location != ADMOB_URL){
if( update_i == false )
{
event.preventDefault();
navigateToURL(new URLRequest(event.location));
update_i = true;
}
else
{
event.preventDefault();
webView.historyBack();
update_i = false;
}
}
}
view1_initializeHandler();
import be.boulevart.as3.security.Base64;
Multitouch.inputMode = MultitouchInputMode.TOUCH_POINT;
//BGMと効果音
var start_sou:Sound = new start_mp3();
var ue_sou:Sound = new ue_mp3();
var shita_sou:Sound = new shita_mp3();
var bgm_sou:Sound = new bgm_mp3();
var mouse_sou:Sound = new mouse_mp3();
var bird_sou:Sound = new bird_mp3();
var dog_sou:Sound = new dog_mp3();
Global.soundFlag = true;
sou_on_btn.visible = false;
//Twitter連携用date関数
function date14()
{
var now:Date = new Date();
var m:String = "";
var d:String = "";
var H:String = "";
var i:String = "";
var s:String = "";
var Y:int = now.fullYear;
var mp:int = now.month + 1;
if( mp < 10 ){ m += "0";}
m += mp;
var dp:int = now.date;
if( dp < 10 ){ d += "0";}
d += dp;
var Hp:int = now.hours;
if( Hp < 10 ){ H += "0";}
H += Hp;
var ip:int = now.minutes;
if( ip < 10 ){ i += "0";}
i += ip;
var sp:int = now.seconds;
if( sp < 10 ){ s += "0";}
s += sp;
return Y+m+d+H+i+s;
}
//AIR用自動更新
import air.update.ApplicationUpdaterUI;
import flash.filesystem.File;
var appUpdater:ApplicationUpdaterUI;
appUpdater = new ApplicationUpdaterUI ;
appUpdater.configurationFile = new File("app:/config/update-config.xml");
appUpdater.initialize();
var timer_air:Timer = new Timer(1000,1);
timer_air.addEventListener(TimerEvent.TIMER_COMPLETE,function(e:TimerEvent){
appUpdater.checkNow()
});
timer_air.start();
そしてここまで書いて自分のコードの酷さに愕然とした。
えー、まず広告を表示するためにStageWebViewを使ってます。
表示しているのはGoogle Adsenseのスマートフォン用広告です。
広告が表示されるHTMLを作成し適当なサーバにアップロードして、そのURLを指定してください。
ちなみにこの方法で問題がないかどうかわかりませんので、参考にされる場合は自己責任でお願いします。
下記サイトの情報を参考にさせていただきましたが、
http://help.adobe.com/ja_JP/as3/dev/WS901d38e593cd1bac3ef1d28412ac57b094b-8000.htmlhttp://today-only.net/flash_android_admob/AdMobだと広告が表示される頻度が少なかったため、Adsenseにしてみました。
また、ローカルのHTML読み込みではAdsenseだとクロール対象のHTMLではないためか、
広告が表示されなかったため、サーバにアップロードしたものを読み込ませています。
HTML内のテキスト文字列に連動した広告が表示されます。(この場合はタイトルの「かわいいねこちゃん」に連動してペット関係の広告が表示されました)
広告表示用HTMLの内容
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>かわいいねこちゃん</title>
<style type="text/css">
*{margin:0; padding:0; border:0;}
</style>
</head>
<body bgcolor="000000" STYLE="overflow: hidden;">
<script type="text/javascript"><!--
google_ad_client = "ca-pub-xxxxxxxxxxxxxxx";
/* apps_pc */
google_ad_slot = "xxxxxxxxxx";
google_ad_width = 468;
google_ad_height = 60;
//-->
</script>
<script type="text/javascript"
src="http://pagead2.googlesyndication.com/pagead/show_ads.js">
</script>
</body>
</html>
BGMと効果音を一括で読み込んでます。
date14関数はTwitterのoAuth認証でランキングも作ったので、
そのためにアプリから14桁の形式で日時をサーバへ送信するためのものです。
最後にアプリリリース後にバージョンアップしたときに
自動アップデートするための仕組みをいれときます。
app:/config/update-config.xml の内容
http://xxx.com/update-descriptor.xml
1
「ファイル」⇒「AIR for Android 設定」の「含めるファイル」で「config」フォルダを追加しましょう
適当なサーバに update-descriptor.xml を設置
update-descriptor.xml の内容
1.0.0
http://xxx.com/cute_cat.air
これで、サーバに versionNumber の数値を上げた update-descriptor.xml と、
新しく出力した cute_cat.air をアップロードするだけで、アプリが自動更新されます。
(もちろんAndroid Marketのアプリも更新しときましょう)
2フレーム目
import flash.display.MovieClip;
import flash.utils.getDefinitionByName;
Global.stopFlag = false;
Global.resetFlag = false;
if( Global.soundFlag == true )
{
sou_on_btn.visible = false;
sou_off_btn.visible = true;
}
else
{
sou_on_btn.visible = true;
sou_off_btn.visible = false;
}
var cat_timer:Timer = new Timer(500, 0);
cat_timer.addEventListener( TimerEvent.TIMER, cat_timerFunc );
function cat_timerFunc( evt:TimerEvent ):void {
if ( cat_mc.smile == true )
{
cat_mc.gotoAndStop("smile");
cat_mc.smile = false;
}
else if ( cat_mc.currentLabel == "loop" )
{
cat_mc.gotoAndStop("loop2");
}
else
{
cat_mc.gotoAndStop("loop");
}
}
//距離計測
var distance_i:int = 0;
var distance:Timer = new Timer(1000, 0);
distance.addEventListener( TimerEvent.TIMER, distanceCount );
function distanceCount( evt:TimerEvent ):void {
distance_i++;
distance_mc.distance_txt.text = distance_i + " m";
if( Global.stopFlag == true )
{
distance_mc.distance_txt.text = distance_i + " m";
distance.stop();
}
}
//背景移動(=ねこちゃん移動)
var backSpeed:Number = 5;
function backMove(e:Event):void {
back_mc.x += backSpeed;
if( Global.stopFlag == true )
{
back_mc.removeEventListener( Event.ENTER_FRAME , backMove );
}
if( back_mc.x > -100 )
{
back_mc.x = -200;
}
}
//動物出現
var i:int = 0;
var pop:int = 0;
var mcArray:Array = new Array();
var timer:Timer = new Timer(1000, 0);
var mouse_y:int = 0;
var num:int = 0;
var num2:int = 0;
var syu:String;
var dogSpeed:Number = 6;
var mouseSpeed:Number = 7;
var birdSpeed:Number = 9;
timer.addEventListener( TimerEvent.TIMER, mousePop );
function mousePop( evt:TimerEvent ):void {
num = xGetRandomInt(0,9);
if ( distance_i < 20 )//0〜19m
{
switch ( num ) {
case 0: syu = "mouse";break;
case 1: syu = "mouse";break;
case 2: syu = "mouse";break;
case 3: syu = "mouse";break;
case 4: syu = "bird";break;
case 5: syu = "dog";break;
default: syu = "not";
}
}
else if ( distance_i < 50 )//20〜49m
{
switch ( num ) {
case 0: syu = "mouse";break;
case 1: syu = "mouse";break;
case 2: syu = "mouse";break;
case 3: syu = "mouse";break;
case 4: syu = "mouse";break;
case 5: syu = "mouse";break;
case 6: syu = "bird";break;
case 7: syu = "dog";break;
default: syu = "not";
}
}
else if ( distance_i < 100 )//50〜99m
{
switch ( num ) {
case 0: syu = "mouse";break;
case 1: syu = "mouse";break;
case 2: syu = "mouse";break;
case 3: syu = "mouse";break;
case 4: syu = "mouse";break;
case 5: syu = "mouse";break;
case 6: syu = "mouse";break;
case 7: syu = "bird";break;
case 8: syu = "dog";break;
case 9: syu = "dog";break;
default: syu = "not";
}
}
else if ( distance_i < 300 )//100〜299m
{
switch ( num ) {
case 0: syu = "mouse";break;
case 1: syu = "mouse";break;
case 2: syu = "mouse";break;
case 3: syu = "mouse";break;
case 4: syu = "mouse";break;
case 5: syu = "bird";break;
case 6: syu = "bird";break;
case 7: syu = "dog";break;
case 8: syu = "dog";break;
case 9: syu = "dog";break;
default: syu = "not";
}
}
else
{
switch ( num ) {
case 0: syu = "mouse";break;
case 1: syu = "bird";break;
case 2: syu = "bird";break;
case 3: syu = "bird";break;
case 4: syu = "bird";break;
case 5: syu = "bird";break;
case 6: syu = "bird";break;
case 7: syu = "bird";break;
case 8: syu = "bird";break;
case 9: syu = "dog";break;
default: syu = "not";
}
}
if( syu != "not" )
{
i++;
pop++;
var mc_name:Class = getDefinitionByName( syu + "_mc" ) as Class;
var mc = new mc_name();
mc.name = syu;
mcArray[i]= mc;
mcArray[i].x = -200;
num = xGetRandomInt(1,3);
switch ( num ) {
case 1://上に出現
mouse_y = 80;
break;
case 2://真ん中に出現
mouse_y = 190;
break;
case 3://下に出現
mouse_y = 300;
break;
}
mcArray[i].y = mouse_y;
if( syu == "dog" )
{
mcArray[i].speed = dogSpeed;
addChildAt( mcArray[i], 1 );
mcArray[i].addEventListener( Event.ENTER_FRAME , dogAction );
mcArray[i].addEventListener( Event.ENTER_FRAME , dogAction_reset );
}
else if( syu == "mouse" )
{
mcArray[i].speed = mouseSpeed;
addChildAt( mcArray[i], 2 );
mcArray[i].addEventListener( Event.ENTER_FRAME , mouseAction );
mcArray[i].addEventListener( Event.ENTER_FRAME , mouseAction_reset );
}
else
{
mcArray[i].speed = birdSpeed;
addChildAt( mcArray[i], 2 );
mcArray[i].addEventListener( Event.ENTER_FRAME , birdAction );
mcArray[i].addEventListener( Event.ENTER_FRAME , mouseAction_reset );
}
}
else
{
pop = 0;
}
num = xGetRandomInt(1,10);
switch ( num ) {
case 1://花出現
back1Pop();
break;
case 2://空き缶出現
back2Pop();
break;
default://出現しない
}
}
//犬衝突処理&削除
function dogAction(e:Event):void {
var mc:MovieClip = e.target as MovieClip;
mc.x += mc.speed;
if( mc.hitTestPoint( cat_mc.x, cat_mc.y + cat_mc.height/2, true ) && mc.endFlag != true )
{
if( Global.soundFlag == true)
{
dog_sou.play();
}
if( distance.delay >= 100 )
{
mc.gotoAndStop(2);
mc.dog2_mc.gotoAndPlay("up");//犬縮小化&速度UPアニメ
backSpeed *= 1.05;//ねこちゃん&背景移動速度上昇
cat_timer.delay *= 0.95;//ねこちゃんの足の動きも早めたい
timer.delay *= 0.95;//動物出現速度上昇
distance.delay *= 0.95;//距離計測上昇
dogSpeed *= 1.05;
mouseSpeed *= 1.05;
birdSpeed *= 1.05;
zokanum *= 1.05;
}
else
{
mc.gotoAndStop(2);
mc.dog2_mc.gotoAndPlay("max");//犬縮小化&速度MAXアニメ
}
cat_mc.smile = true;
mc.endFlag = true;
}
}
function dogAction_reset(e:Event):void {
var mc:MovieClip = e.target as MovieClip;
if( mc.x > 1000 || Global.resetFlag == true )
{
mc.removeEventListener( Event.ENTER_FRAME , arguments.callee );
this.removeChild( mc );
}
}
//動物衝突処理&削除
function mouseAction(e:Event):void {
var mc:MovieClip = e.target as MovieClip;
mc.x += mc.speed;
if( mc.hitTestPoint( cat_mc.x, cat_mc.y + cat_mc.height/2, true ) && Global.stopFlag == false )
{
if( Global.soundFlag == true)
{
mouse_sou.play();
channel.stop();
}
Global.stopFlag = true;
mc.gotoAndStop(2);//動物巨大化
mc.removeEventListener( Event.ENTER_FRAME , arguments.callee );
}
}
function mouseAction_reset(e:Event):void {
var mc:MovieClip = e.target as MovieClip;
if( mc.x > 1000 || Global.resetFlag == true )
{
mc.removeEventListener( Event.ENTER_FRAME , arguments.callee );
this.removeChild( mc );
}
}
function birdAction(e:Event):void {
var mc:MovieClip = e.target as MovieClip;
mc.x += mc.speed;
if( mc.hitTestPoint( cat_mc.x, cat_mc.y + cat_mc.height/2, true ) && Global.stopFlag == false )
{
if( Global.soundFlag == true)
{
bird_sou.play();
channel.stop();
}
Global.stopFlag = true;
mc.gotoAndStop(2);//動物巨大化
mc.removeEventListener( Event.ENTER_FRAME , arguments.callee );
}
}
function back1Pop():void {
num = xGetRandomInt(1,2);
num2 = xGetRandomInt(0,50);
var mc = new back1_mc();
mc.x = -200;
if( num == 1 )
{
mc.y = num2;
}
else
{
mc.y = 380 + num2;
}
addChildAt( mc, 1 );
mc.addEventListener( Event.ENTER_FRAME , backAction );
mc.addEventListener( Event.ENTER_FRAME , backAction_reset );
}
function back2Pop():void {
num = xGetRandomInt(1,2);
num2 = xGetRandomInt(0,50);
var mc = new back2_mc();
mc.x = -200;
if( num == 1 )
{
mc.y = num2;
}
else
{
mc.y = 380 + num2;
}
addChildAt( mc, 1 );
mc.addEventListener( Event.ENTER_FRAME , backAction );
mc.addEventListener( Event.ENTER_FRAME , backAction_reset );
}
function backAction(e:Event):void {
var back:MovieClip = e.target as MovieClip;
back.x += backSpeed;
if( Global.stopFlag == true )
{
back.removeEventListener( Event.ENTER_FRAME , arguments.callee );
}
}
function backAction_reset(e:Event):void {
var back:MovieClip = e.target as MovieClip;
if( back.x > 1000 || Global.resetFlag == true )
{
back.removeEventListener( Event.ENTER_FRAME , arguments.callee );
this.removeChild( back );
}
}
//ランダム数値生成関数
function xGetRandomInt(n0:int=0, n1:int=1):int {
var nMax:int = Math.max(n0, n1);
var nMin:int = Math.min(n0, n1);
var nRandom:int = Math.floor(Math.random()*(nMax-nMin+1))+nMin;
return nRandom;
}
start_btn.addEventListener(MouseEvent.CLICK, fl_ClickToGoToNextFrame);
function fl_ClickToGoToNextFrame(event:MouseEvent):void
{
gotoAndPlay("main");
}
play_btn.addEventListener(MouseEvent.CLICK, fl_ClickToGoToAndStopAtFrame_4);
function fl_ClickToGoToAndStopAtFrame_4(event:MouseEvent):void
{
gotoAndStop("play");
}
sou_on_btn.addEventListener(MouseEvent.CLICK, fl_ClickToGoToAndStopAtFrame_6);
function fl_ClickToGoToAndStopAtFrame_6(event:MouseEvent):void
{
if( Global.soundFlag == true )
{
Global.soundFlag = false;
sou_on_btn.visible = true;
sou_off_btn.visible = false;
}
else if( Global.soundFlag == false )
{
Global.soundFlag = true;
sou_on_btn.visible = false;
sou_off_btn.visible = true;
}
}
sou_off_btn.addEventListener(MouseEvent.CLICK, fl_ClickToGoToAndStopAtFrame_7);
function fl_ClickToGoToAndStopAtFrame_7(event:MouseEvent):void
{
if( Global.soundFlag == true )
{
Global.soundFlag = false;
sou_on_btn.visible = true;
sou_off_btn.visible = false;
}
else if( Global.soundFlag == false )
{
Global.soundFlag = true;
sou_on_btn.visible = false;
sou_off_btn.visible = true;
}
}
end_btn.addEventListener(MouseEvent.CLICK, fl_ClickToGoToAndStopAtFrame_8);
function fl_ClickToGoToAndStopAtFrame_8(event:MouseEvent):void
{
NativeApplication.nativeApplication.exit();
}
なんかごちゃごちゃ書きました!
MouseEvent.CLICK はタップでも反応するので
別途TOUCHイベントを用意する必要はなさそうです。
いろいろアホな書き方がされていますが
背景の空き缶とかまで無駄に動的に生成しているのが特にアホですね。
背景の無限スクロールとかもすごく適当なのがおわかりいただけるであろうか。
4フレーム目
stop();
なんかこれだけ書いてあった。血迷ったか。
5フレーム目
var cat_mc:cat_base = new cat_base();
cat_mc.x = 563;
cat_mc.y = 200;
addChildAt( cat_mc, 1 );
removeEventListener(Event.ENTER_FRAME, backMove);
var location:String = "center";
//フラグ待機
cat_mc.addEventListener( Event.ENTER_FRAME, catAction );
function catAction( e:Event ):void {
if( Global.stopFlag == true )
{
cat_timer.stop();
removeEventListener( Event.ENTER_FRAME , cursorMoveUp );
removeEventListener( Event.ENTER_FRAME , cursorMoveDown );
removeChild( cursor_top_mc );
removeChild( cursor_bottom_mc );
cat_mc.gotoAndPlay("lose");
cat_mc.removeEventListener( Event.ENTER_FRAME , catAction );
gotoAndStop("end");
}
}
cat_mc.addEventListener( Event.ENTER_FRAME, catAction_reset );
function catAction_reset( e:Event ):void {
if( Global.resetFlag == true )
{
cat_mc.gotoAndStop(1);
cat_mc.y = -200;
cat_mc.removeEventListener( Event.ENTER_FRAME , catAction_reset );
removeChild( cat_mc );
}
}
if( Global.soundFlag == true )
{
start_sou.play();
}
ゲームスタートの瞬間です!!!
なんでこんな風に書いたかは忘れました。
ゲーム中のフレーム
stop();
timer.start();
distance.start();
cat_mc.gotoAndStop("loop2");
cat_timer.start();
addEventListener(Event.ENTER_FRAME, backMove);
if( Global.soundFlag == true )
{
var channel = bgm_sou.play(0,999);
}
var lastIndex1:int = numChildren - 1;
var cursor_top_mc:cursor_top = new cursor_top();
cursor_top_mc.x = 544;
cursor_top_mc.y = 80.80;
addChildAt( cursor_top_mc, lastIndex1 );
var lastIndex2:int = numChildren - 1;
var cursor_bottom_mc:cursor_bottom = new cursor_bottom();
cursor_bottom_mc.x = 544;
cursor_bottom_mc.y = 312.95;
addChildAt( cursor_bottom_mc, lastIndex2 );
var zokanum:Number = 5;
var zokabun:int = 0;
function cursorMoveUp(e:Event):void {
zokabun += zokanum;
cursor_top_mc.y -= zokanum;
cursor_bottom_mc.y -= zokanum;
cat_mc.y -= zokanum;
if( zokabun >= 100 )
{
switch ( location )
{
case "top":
cat_mc.y = 100;
break;
case "center":
cat_mc.y = 200;
break;
case "bottom":
cat_mc.y = 300;
break;
}
zokabun = 0;
cursor_top_mc.visible = true;
cursor_bottom_mc.visible = true;
removeEventListener( Event.ENTER_FRAME , cursorMoveUp );
}
}
function cursorMoveDown(e:Event):void {
zokabun += zokanum;
cursor_top_mc.y += zokanum;
cursor_bottom_mc.y += zokanum;
cat_mc.y += zokanum;
if( zokabun >= 100 )
{
switch ( location )
{
case "top":
cat_mc.y = 100;
break;
case "center":
cat_mc.y = 200;
break;
case "bottom":
cat_mc.y = 300;
break;
}
zokabun = 0;
cursor_top_mc.visible = true;
cursor_bottom_mc.visible = true;
removeEventListener( Event.ENTER_FRAME , cursorMoveDown );
}
}
cursor_top_mc.addEventListener(MouseEvent.CLICK, fl_ClickToGoToAndStopAtFrame);
function fl_ClickToGoToAndStopAtFrame(event:MouseEvent):void
{
if( location == "center" )
{
if( Global.soundFlag == true )
{
ue_sou.play();
}
addEventListener(Event.ENTER_FRAME, cursorMoveUp);
cursor_top_mc.visible = false;
cursor_bottom_mc.visible = false;
location = "top";
}
else if( location == "bottom" )
{
if( Global.soundFlag == true )
{
ue_sou.play();
}
addEventListener(Event.ENTER_FRAME, cursorMoveUp);
cursor_top_mc.visible = false;
cursor_bottom_mc.visible = false;
location = "center";
}
}
cursor_bottom_mc.addEventListener(MouseEvent.CLICK, fl_ClickToGoToAndStopAtFrame_2);
function fl_ClickToGoToAndStopAtFrame_2(event:MouseEvent):void
{
if( location == "top" )
{
if( Global.soundFlag == true )
{
shita_sou.play();
}
addEventListener(Event.ENTER_FRAME, cursorMoveDown);
cursor_top_mc.visible = false;
cursor_bottom_mc.visible = false;
location = "center";
}
else if( location == "center" )
{
if( Global.soundFlag == true )
{
shita_sou.play();
}
addEventListener(Event.ENTER_FRAME, cursorMoveDown);
cursor_top_mc.visible = false;
cursor_bottom_mc.visible = false;
location = "bottom";
}
}
上下矢印をタッチすると移動するという仕組みを書いてます。
ちなみにボタンクリックイベントはボタンMCを選択して、
「ウィンドウ」⇒「コードスニペット」から設定すると簡単です。
ゲーム終了フレーム
stop();
if( Global.httpFlag == false ){
score_btn.visible = false;
retry_btn.y = 245.3;
}
removeEventListener(Event.ENTER_FRAME, backMove);
timer.stop();
distance.stop();
retry_btn.addEventListener(MouseEvent.CLICK, fl_ClickToGoToAndStopAtFrame_3);
function fl_ClickToGoToAndStopAtFrame_3(event:MouseEvent):void
{
gotoAndPlay("init");
}
score_btn.addEventListener(MouseEvent.CLICK, fl_ClickToGoToWebPage);
function fl_ClickToGoToWebPage(event:MouseEvent):void
{
var url:String = "http://xxx.com/twitteroauth/redirect.php";
var request:URLRequest = new URLRequest(url);
var variables:URLVariables = new URLVariables();
var YmdHis:String = date14();
//version_YmdHis_score
variables.s = encrypt(YmdHis+"_"+distance_i,"penetpenet");
request.data = variables;
request.method = URLRequestMethod.POST;
navigateToURL( request );
}
function encrypt(str:String, key:String = '%key&'):String {
var result:String = '';
for (var i:int = 0; i < str.length; i++) {
var char:String = str.substr(i, 1);
var keychar:String = key.substr((i % key.length) - 1, 1);
var ordChar:int = char.charCodeAt(0);
var ordKeychar:int = keychar.charCodeAt(0);
var sum:int = ordChar + ordKeychar;
char = String.fromCharCode(sum);
result = result + char;
}
return Base64.encode(result);
}
function decrypt(str:String, key:String = '%key&'):String {
var result:String = '';
var str:String = Base64.decode(str);
for (var i:int = 0; i < str.length; i++) {
var char:String = str.substr(i, 1);
var keychar:String = key.substr((i % key.length) - 1, 1);
var ordChar:int = char.charCodeAt(0);
var ordKeychar:int = keychar.charCodeAt(0);
var sum:int = ordChar - ordKeychar;
char = String.fromCharCode(sum);
result = result + char;
}
return result;
}
ゲーム終了時にTwitterのアカウントでスコアランキングに登録できるようになってます。
AIRだとPOSTできないのでGET値を暗号化&有効期限設定してサーバへ送信しています。
サーバ側はPHP+twitteroauth+Mysqlで実現しています。
リトライ
Global.resetFlag = true;
これだけで初期化されてもう一度遊べるようになってます。
あっ!Globalは普通はAS3.0では使えませんでした。
こちらのサイト様などを参考にしていただければ。。。
http://clockmaker.jp/blog/2010/05/as3-global/そしてGoogleに$25支払ってGoogleMarketにapkファイルアップロードすればリリース完了。
ほとんど作り方忘れてることもあって力尽きた。
あとはなんか困ったら cute_cat-app.xml をテキストエディタで修正しよう!
cute_cat-app.xmlの内容
jp.co.penet.cutecat
1.0.0
cute_cat
かわいいねこちゃん
cute_cat.swf
standard
false
true
true
landscape
auto
false
false
false
]]>
]]>
ポイントは「<data android:scheme="cutecat"/>」と設定することで、ブラウザで「<a href="cutecat://">アプリ起動</a>」リンクを踏むとアプリを起動させることができるようになるところ。
それと「<manifest android:installLocation="preferExternal"/>」でSDカードにインストール可能になる設定かな!
ね、簡単でしょ?