Titanium Mobile でRPG開発進捗36日目

本日もビジュアル的な進捗はナシ。
前回のオブジェクトはTi.includeで利用するものだったのですが
世の中CommonJS準拠でrequire使うのが流行りらしいので
そういった形に乗り換えました。

/*
 * eventloop.js
 * イベントループ
 */
eventloop = {
	// 各種変数
	interval:(1000 / 60),
	count:0,
	funcCount:0,
	funcArray:[],
	timingArray:[],
/*
 * イベントループ開始
 */
	start:function () {
		setInterval(function() {
			eventloop.count++;
			for (var i = 0;i < eventloop.funcCount;i++) {
				var func = eventloop.funcArray[i];
				if(!(eventloop.count % eventloop.timingArray[i]) && func) func();
			}
		}, eventloop.interval);
	},
/*
 * 処理登録
 */
	registFunc:function (func, delay) {
		if (typeof func == "string") func = new Function(func);
		var id;
		for(id = 0;;id++) if (!this.funcArray[id]) break;
		this.timingArray[id] = Math.floor(delay / this.interval) || 1;
		this.funcArray[id] = func;
		if (this.funcCount == id) this.funcCount++;
		return ++id;
	},
/*
 * 処理登録解除
 */
	clearFunc:function (id) {
		id--;
		this.funcArray[id] = undefined;
		if (!((--this.funcCount) == id)) this.funcCount++;
	}
};
exports = {
	start:function() {
		eventloop.start();
	},
	registFunc:function(func, delay) {
		return eventloop.registFunc(func, delay);
	},
	clearFunc:function(id) {
		eventloop.clearFunc(id);
	}
};

利用方法は見れば分かる通りでございます。

var el = require("eventloop");
el.start();
el.registFunc(function() {/*処理1*/}, 100/*実行タイミングmsで指定*/);
el.registFunc(function() {/*処理2*/}, 200/*実行タイミングmsで指定*/);


で、今日書きたかったことはこんなことじゃない。
もっと強烈にドハマリすることがあったのです。


現在のTitanium Mobileではオブジェクトのコピーに対応していない
のではないかという疑惑。
試したところではObject.clone();が動く気配がない。
また当然のごとく、var foo = Object;すれば、参照が渡されるわけで
各マスターデータのオブジェクトからワークへのコピーが出来ないわけです。
今のところfor in でオブジェクトのプロパティ値をシコシココピーしてます。
誰か解決方法教えて...または時間が解決してくれるか。


あくまでもjavascriptでの実装は表面的なものなので
Obj-Cやjavaにっていう場面でcloneって厄介なものなのかもしれない。


そもそもObject.clone();なんてないので、自前で実装しましょう!

追記 2011/10/28

実機で動くように修正しました。
実機で動かない現象が発生し、しかたなく
Xcodeのconsoleからクラッシュ原因をしらべることに。
Parse error / SyntaxError が出ており
これは文法的におかしいところがあるということがわかりました。
で、すごーく簡単なろころが間違っていそうだと
よくよく見なおしたところ、オブジェクトの最後にセミコロンがなかった

eventLoop = {
}; ←ここ!
exports = {
}; ←ここ!


*おお!タイタニウムスタヂオよ!
 みのがしてしまうとは なさけない


としか言いようがない。
こういうのはTitanium Studio側でシンタックスエラー出して欲しいかも。

Titanium Mobile でRPG開発進捗34日目

本日は画面的な変更がないためスクショありません。
進捗としてはログを出力していた割り込み処理
setIntervalをシリアライズする処理を書きました。
これは一昔前に流行った高速化するテクニックですが
Titanium Mobile でも同じことが起きるかはわかりません。
ただ、割り込み処理を何個も創りだすのは
やっぱり厳しいんじゃないかと思いますので
一個の割り込み処理をcallerとして走らせておくのが
きっと良いと思います。


それではソースです。
XXは適当に書き換えてください。

/*
 * lib/eventloop.js
 * イベントループ
 */
XX.lib.eventloop = {
	// 各種変数
	interval:(1000 / 60),
	count:0,
	funcCount:0,
	funcArray:[],
	timingArray:[],
/*
 * イベントループ開始
 */
	start:function () {
		setInterval(function() {
			$EL.count++;
			for (var i = 0;i < $EL.funcCount;i++) {
				var func = $EL.funcArray[i];
				if(!($EL.count % $EL.timingArray[i]) && func) func();
			}
		}, $EL.interval);
	},
/*
 * 処理登録
 */
	registFunc:function (func, delay) {
		if (typeof func == "string") func = new Function(func);
		var id;
		for(id = 0;;id++) if (!this.funcArray[id]) break;
		this.timingArray[id] = Math.floor(delay / this.interval) || 1;
		this.funcArray[id] = func;
		if (this.funcCount == id) this.funcCount++;
		return ++id;
	},
/*
 * 処理登録解除
 */
	clearFunc:function (id) {
		id--;
		this.funcArray[id] = undefined;
		if (!((--this.funcCount) == id)) this.funcCount++;
	}
}
var $EL = XX.lib.eventloop;


使い方はstart呼んで、registFuncで割りこませる処理を登録します。
基本的にはsetIntervalと使用感は同じです。
効率が上がるだけだと思います。

Titanium Mobile でRPG開発進捗30日目


今日で30日、一ヶ月が経ちました。
それなりに遊べるものならすぐ出来ると
甘い気持ちで始めたものの
RPGはやっぱりやることが多いです。


さて、本日の進捗としては

  1. が出るようになったよ
  2. 入力待ち処理

あたりでしょうか。


まず、の出現ですがこちらは出すだけなら
そんなに問題じゃないです。
何故か、ダメージのエフェクト演出を
先に作り始めたんですが、
こいつがなかなか難がある実装となりました。
やってることとしては2つのアニメオブジェクトを
作り出し、交互に呼び出すというもの。
かるーく概要を書くと

var a1 = createAnimation();
var a2 = createAnimation();
a1.addEventListener("complete", function(){
    view.animate(a2);
});
a2.addEventListener("complete", function(){
    view.animate(a1);
});
view.animation(a1);


こんな感じ。これはシンプルな書き方で
これをグローバル変数と絡めると偉いことに。
なんとか逃げ道を付けられたので良かったです。解決。


次に入力待ち処理ですが、こちらも独特な手段を使いました。
Titanium Mobile は基本的にイベントドリブン型なので
イベントが無ければ何も起きないのです。
なので、一旦流れを途切れさせてしまうと、次はイベントが
何らかの形で発生しないと処理できない。
ということで、入力待ち処理の引数にコールバック関数を持ってくことに。
入力待ちには画面サイズのラベルを全面に表示してタップ待ち

// XXはグローバルアクセス用のオブジェクト
inputWait:function (func) {
    var overwrap = Ti.UI.createLabel({text:'▼ タップしてください ▼', width:320, height:480, zIndex:10000});
    overwrap.addEventListener('click', function(){
        XX.view.remove(overwrap);
        (func)();
    });
    this.view.add(overwrap);
},


こんな感じでコールバック関数を実行できるようです。
少し横着な感じですけど、もっと綺麗に書ける方法があるなら教えて欲しいです。

Titanium Mobile でRPG開発進捗24日目


ある程度開発も進んだので製作日記タイトルを
具体的な感じに変更しました。
これからこれでいきます。


さて、本日の進捗なのですが
見た目的にはほとんど進んでいません。
困ったものです。わっはっは。


なにを進めたかというと"わざ"周りの
データ構成と実データ少々の実装
あと、"わざ"周りのUIの検討をしてました。
ここ最近このUIについてよく考えているのですが
正直、技を選択したり、道具を選択したり
するのって面倒臭い作業ですよね。
ユーザがやりたいことは誰に技を食らわすか
毎回選択させられることじゃないと思うんです。


そこで解決方法として
あえてユーザには選択させない、という方法を
取ろうかと考えています。


どういうことかというと、
例えば、回復の場合、パーティ全体を回復しちゃえば選択せずに済みます。
攻撃の場合は、明らかにこのキャラに攻撃があたるけど"たたかう"で
いいよね?っていうのがユーザに示せれば問題ないと思うんです。


ほんとにユーザに選択させなくていいのかは自分でもまだ迷っています。
でも、この選択があるかないかで、ユーザの入力負担は倍以上違ってきます。
だったら無くすメリットの方がかなり大きいんじゃないかと考えています。
もっといい解決方法あるよ!っていう人がいたら早めに教えてください。

iPhoneアプリ進捗22日目


先日作ったポップアップTableViewを
十字コマンドが隠れるように配置しました。
写真の通り少し色も加えてあります。
見た目は今後もう少しポップな感じに
変更していく予定です。


技名もひらがなになるしね。


TableViewのなかに”やめる”を追加して
”やめる”が選択されたら自身を開放する
ようにしました。


で、今回もう一つ仕込んだ部分としては
前から気になっていたログのスクロールアニメーション。
スクロールの途中でカクカクしちゃうので
どうしたもんかなと試行錯誤しました。


手法1としてはanimateメソッドを2度呼びして
変化が遅い方をdelayプロパティで開始を遅延させる方法。
これはシミュレータではうまく行きます。
実機では成功率50%ぐらいで、残りは2度目のanimateが
内容を上書きしてしまう状態が発生します。
原因が絞り込めないのでこの方法は諦めました。


手法2としては、ログのオブジェクトを2重化して
片方は移動用、もう片方は透明度変更用として
重ねあわせて、それぞれanimateする方法です。
こちらはダサイですが確実に動きます。
今回は仕方なくこちらを採用しました。

iPhoneアプリ進捗20日目


連続連夜寝落ちということで作業がすすまず
ということで久々に進捗報告。


ちょっとわかりにくい画面構成なのですが
今はとりあえず無理矢理出すところまで進めてます。


まず、戦闘用のコマンドを十字で出すことにしました。
それが右下のやつです。
これは実機で出してみて触りやすい位置に出しています。
なんとなくフリックできそうな十字なんですが
十字キーなのでポチポチしてください。


次に真ん中の「降龍十八掌」と書いたリスト。
「わざ」を選んだ時にポップアップするリストです。
試しに背景透過できるか試したものです。'transparent'が有効でした。
そしてこいつが、ポップアップ&フリックでリスト操作できます。


一応表示まで漕ぎ着けたのですが、一点ドハマリした点があったので
記録しておこうと思います。


createTableViewの挙動で、多くのサイトでは

var tableView = Ti.UI.createTableView({
    data:rows
});


こんな風に書かれているケースが多いのですが
現在の環境ではうまく動作させることができません。
具体的にはObjective-CのNSArrayがどーのこーの
というエラーが発生し起動ができません。
これはソースをコピペしてYATTA!!出来なかったので
かなりハマりました。
結局初期化ではプロパティの設定のみ行う形となり
データはappendRowで丁寧に足していく形にしました。


以上。成果報告。

iPhoneアプリ進捗16日目


内容は殆ど進んでません。
内部構造の変更と戦闘の構成検討しました。
で本日はテストを自分以外にお願いするときに
リモートで何とかできないかというお話。


やり方はあって、TestFlightというサービスを使うとできます。
https://testflightapp.com


こいつが素人が故にドハマリしたので
はまった場所を書いておきます。

1.まずSign Upします


Sign Upなんですが、PCだけでは完結しません。
iPhoneiPadで最初のデバイスも登録しないとダメ。
ここでまずPCからうだうだしてしまいました。

2.協力者もSign Upします


テスターアカウント作ってもらいます。
これをしてもらうと、リモートでUDIDを確認できるので
やってもらわないと、アホみたいな作業をすることになる。

3.iOS Provisioning Portal でテストデバイス登録します。


ここの項目思いつくまでにえらく時間かかりました。
Devices→Add Devicesします。
このとき上記の追加するデバイスのUDIDとデバイス名必要です。

4.Provisioning Profiles作り直します


editリンクから追加したデバイスのチェックをつけてsubmitします。
少し時間が経つとダウンロードできます。

5.アプリをビルドし直します。


このとき、上記で作りなおしたProvisioning Profilesを
Run on build画面で指定します。
上手くいかないときは一発フォルダ消去したり、clean buildで。

6.とりあえず、直接送れる実機は直接転送してテスト


TestFlightに流す前に実機で確実に起動することを確認。
これを怠るとテスターさんを巻き込む惨事になります。

7.TestFlightでUpdate Buildsします。


IPAファイル(実体をzip圧縮してリネームしたもの?)
をアップロードします。
※Titanium Mobile ではこのファイルは自動生成されています。
テスターさんをチームメンバーに指定してお知らせを送信します。
このときチームメンバーが選択できないような状態の時は
手順2,3,4,5のどれかが足りません、または異常です。
iOSの管理画面の方は異常だと異常だと表示してくれますから
必要な項目をEditしましょう。
自分は間違えてキーチェーンを削除したためにそこら中で
異常がはっせいしました。


以上がざっくりとした手順です。
正常系はほかのサイトでも紹介しているのでそちらを参考に。
うちはあくまでハマった点と、自分の作業メモ的にまとめました。


誰かの役にたてばいいですが。