そろそろこういう機能が必須だと思うのです。

昨日、大学の先輩が亡くなりました。
家人とも共通の先輩でしたので、家人は彼のHPからお悔やみのメールを送信しました。


しかし、そのメールをご遺族の方は読む事が出来るのでしょうか。
使っているPCがパスワードロックされていたら、どうやってそのメールにアクセスできるのでしょう。


少し前から、持ち主が亡くなった場合の機能を、そろそろOSは持つべきではないかと、思っていましたが、その思いを一層強くしました。


下のような機能です。

  • 亡くなった後にのみアクセスするアカウントが作成できる。そのパスワードは、遺言状などに記載する。
  • そのアカウントが起動すると持ち主の意向に沿って、次のような処理が行われる。
    • 持ち主が削除したいと登録したフォルダとその中のファイルの削除。
    • 登録したSNSへの自動送信。(文面は事前に持ち主が作成)
    • 特定のメールフォルダ内のメールの削除
    • アドレス帳の特定のグループの削除
    • 特定のメールアドレスへの自動送信(文面は事前に持ち主が作成)
    • デスクトップにメッセージを納めたファイルへのリンクの出現(近しい人達へのメッセージ)
    • 重要なファイルへのリンクの出現(仕事やHPの更新に必要な手続きなどを記載した書類群へのリンクなど)


OSでサポートしなくても可能な気もしますが、しかし、PCにデフォルトで入っていて欲しい機能だと思いますので、OSの機能と考えました。


亡くなりました先輩のご冥福をお祈り致します。

missing value というエラー

macのNumbersでゲームの設定データを用意して、applescriptcvsファイルにコンバートしていたのですが、なぜか空白のセルのデータが"missing value"という文字列に化けるようになってしまいました。
原因は良く判らないのですが、OSのバージョンが変わったためかも知れません。とほほ。


appleScriptと格闘したり、ググったりしたのですが、さっぱり分かりません。
絶望の縁でアレコレ弄っていたら何とかなりましたので、備忘録として記載。

set cv to value of offsetCell's cell
if cv is missing value then
	set textBuffer to textBuffer & ","
else
	set textBuffer to textBuffer & "," & cv
end if


とやっていたのですが、全然ダメ。
cvの値を表示させるとmissing valueなのですが、(cv is missing value)はfalseになるばかり。
セルに"_"を入れて、cvの値を"_"と比較して、というのもダメ。

set cv to value of offsetCell's cell
if cv is "_" then
	set textBuffer to textBuffer & ","
else
	set textBuffer to textBuffer & "," & cv
end if


どうも、Numbersのセルの値が何か違う形式になっているようです。
そこで、

set cv to value of offsetCell's cell as string
if cv is "_" then
	set textBuffer to textBuffer & ","
else
	set textBuffer to textBuffer & "," & cv
end if

とやってみると、上手くいく!
もしや! と閃いて、下のようにした所上手くいきました。

set cv to value of offsetCell's cell as string
if cv is "missing value" then
	set textBuffer to textBuffer & ","
else
	set textBuffer to textBuffer & "," & cv
end if


文字列にキャストして、文字列として比較すれば良かった、というお話でした。

脳内企画会議 妄想ドラクエGO

エンカウント

「まず、エンカウント」
「モンスターの位置をサーバで決めて、そこに近づいたらエンカウント。これは良いよね?」
「歩いてて、スマフォが振動して、画面を見たらARでモンスターが居る、ってのね」
「まあ。だけど、橋を渡ったら出てくるモンスターが強くなるみたいなのはどうするの?」
「それ問題」
「モンスターの強さは、プレイヤーのレベル相対ってのはどう?」
「う〜ん、それだと、みんなで同じボスモンスターに挑むみたいなの難しくなるからなぁ」
「モンスターの強さを場所限定とかARに合ってないし」
「だよね。『先生! ウチの村には強い敵が居ません!』」
「それまだマシ。『先生! ウチの村には強い敵しか居ません!倒せません!』」
「とすると、現実世界のマップと仮想世界のマップを1対多対応にして、ダンジョンの階層みたいにするのは?」
「なるほど。自分のレベルに見合った階層の仮想マップをプレイする訳ね」
「そしたら、同じ程度のメンツで同じボスモンスター攻略が出来る」
「じゃ、エンカウントは、ソレで」

パーティー

「パーティー組みたいよね」
「ARだから、リアルにソロゾロ」
「で、仲間に回復かけたら、ソイツをARで見ると、回復エフェクトがかかる」
「攻撃されたら、攻撃エフェクトが見える」
「…」
「?どうした?」
「あのさ、GPSの座標ってかなり誤差があるでしょ」
「うん」
「すると、そのカメラに写ってる人物とパーティーの仲間が同一って、どうやって判別するの?」
「あ!? 難しいか」
「近接通信とかでなんとかならない?」
「三角測量しないと場所は特定できないよ」
「むりぽ」
「これ保留が良さそう」
「で、問題は、エラい人にどうやって説明するか、だよね」
(一同、乾いた笑い)
「でも、回復とかはスマフォどおしをぶつけ合うとかでできるんじゃね? エフェクトは無理としても」
「あ、ソレ良いな! ARっぽい!」
「アイテム上げたりするのも良い感じ」
「じゃ、エラい人にはエフェクトはムリですけど、こういうのが、って方向で」
「うんうん」

ドロップアイテム

「さっき出てきたボスモンスターに皆で挑むってヤツ。良く考えたら別にパーティー組んでなくてもイイじゃん感じだけど」
「確かに」
「ARって考えたら、実際に近接してる同士がパーティーって、遊んでる仲間内でそう思えば良いし」
「その方が自然だね。システムでサポートしなくても遊び方の誘導をしても良いかも」
「でも、パーティー間チャットとかは欲しいでしょ。近接するまで」
「確かに。その辺くらいにしとくのが良さそう」
「で、話は戻るんだけど、ボスモンスターのドロップアイテム」
「だれがゲットするか」
「思うんだけど、一つだけ落すんじゃなくてさ、細かいの、例えばお金とかEXPとか、じゃらじゃらばらまいて」
「それを画面で見つけてタッチしてゲットか」
「楽しそう」
「なんだからそれって、棟上げの餅撒きみたい」
「楽しそうだからイイ!」
「もしかしたらさ、落すの狙ったハイエナプレイってあるよね」
「確かに」
「ま、ボスにエンカウントしてれば、その権利はあって良いんじゃない?」
「そしたら、初心者がおこぼれで経験値稼げる」
「あー、そういうツアー組むヤツ出てきそう」
「ありそう、ありそう」

攻撃回避

「敵から回避もさ、実際に動いて避けるとかどう?」
「面白い!」
「おい、待てよ。モンスターからの攻撃避けようとして車道に出て交通事故とかマジ洒落にならん」
「はい、米国で100万ドルの損売賠償訴訟」
「ダメか」
「!」
「どした?」
「あのさ、ファーストパーソンじゃなくてさ、サードパーソンってのあるかも」
「何ソレ?」
「つまり、戦闘中、自分のキャラが画面に映ってて、そいつをフリックして回避するの」
「なるほどね〜」
「確かに自キャラとか見たいよね」
「でも、オッサンが集まって自キャラが全部女性キャラとか恥ずかしい…」
「そこがこういうARのアレなトコだな」
「ま、なんとなくコンセプトが分かってきたよ」
「自分の街がダンジョンになる。そこで実際に冒険する。だから主人公は自分自身」
「そう割り切れば、なんとかなるか。ネットワーク世界とはちょっと違う」
「AR変態MMO(笑)」

ミナデイン

「ボス戦、当然イベントで集まってアレやりたいよね」
「みんなでスマフォ掲げて、せーのでふり下ろして」
ミナデイン!」
「それで倒したりしたら、その後、見ず知らずの人とでも一緒に酒飲みたくなる!」
「おとなのロマンだなぁ。しみじみ。(笑)」

冷凍枝豆を美味しく解凍する放置方法

枝豆が美味しい季節ですが、冷凍枝豆を自然解凍するとどうも水っぽくなって美味しくないです。
先日、自然解凍でも水っぽくない方法を見つけました。


保冷バックに解凍しようと思った枝豆を入れっ放しにしてて、取り出したら、良い感じに解凍されてて、水っぽくなかったんです。
それで、再度、保冷バックに入れて解凍した所、再現性を確認。


なぜ、保冷バックに入れると水っぽくならないのか? ちょっと考えてみたら、多分こういう事ではないかと。


部屋で自然解凍すると、枝豆が結露してビチャビチャになるから、水っぽくなる。


保冷バックだと、保冷バック内の水分しか結露できないから、水っぽくならない。


まだ試していませんが、枝豆をフリージングバッグに入れて自然解凍しても水っぽくならないと思います。

workbook.Activateのおかしな挙動

良くExcel VBAでマクロを組みます。
それで出会ったおかしな挙動の忘備録です。


一つのブックから情報を収集して、別のブックにコピーするというマクロなのですが、その時、workbook.Activateでブックを切り替えるのですが、これがおかしな挙動をして、まったく困った事がありました。


どういう事かと言うと、記述したタイミングでブックの切り替えが行われず、後から切り替わる為、シート指定で実行時エラーになったり、ソートが正しく行われなかったりと言う事が起こるのです。


どうも、大きなセル範囲のコピーを行うと(多分、そこにそれなりの量のオートシェイプがあると)、そのコピーはバックグラウンドで行われ、その間、ブックはロックされて切り替わらない。で、コピーが終わったタイミングで、ブックの切り替えが行われる為、workbook.Activateの後でソートなどを行っても、コピーしてる最中だから切り替わらず、狙ったブックじゃないところがソートされたか、ソート自体がスキップされたようです。


ぐぐってもまったく似た症例が見つからなかったので、相当なレアケースだとは思います。


もし、ブック切り替えでコードを読んでも判らない時は、画面表示をONにして、ブック切り替えの挙動を目で追うと良いと思います。


それにしても、Basicなのに逐次実行じゃないなんて、Excelのばか〜〜〜って言いたくなりました。とほほ。

リストア機能がうまく動作しない罠

アプリ内課金の機能の一つにリストアというのがあります。
iPhoneを買い替えた時など、リストアを行うと、アプリ内課金で購入済みのプロダクトをそのiPhoneでも購入済みの状態にするという機能です。


で、いろいろあり、あるページにリストアボタンを追加しテストしたところ、リストアボタンを押しても購入済みのプロダクトが復活しません!


調べると、本来、リストアで回るはずの下の箇所を通っていません。
ここ通らなきゃ、プロダクト復活するはずもなく。

  • (void)paymentQueue:(SKPaymentQueue *)queue updatedTransactions:(NSArray *)transactions


にもかかわらず、リストア成功の場合の下のメソッドが呼ばれます。

  • (void)paymentQueueRestoreCompletedTransactionsFinished:(SKPaymentQueue *)queue


ありゃ、どっかでエンバクしたかと、ソースを見ても判らない。。
仕方なく、配布したadHocをテストして、リストアが動かなくなった時点を特定していくと、最新で動くもののアプリ内課金関係のソースと、現在のソースは全く同じものと判明。


この間4〜5時間ほど。原因が全く判らず、途方に暮れてました。


ソースが同じと判ったところで、作業ログを見て、なんとなくプロダクト関係でやった事を思い出すと、すぐには使わないプロダクトを削除した事を思い出しました。


もしや! と思い、Sandbox テスターを新しく作って再テスト。
さっくり動きます!!!
なんてこった!


どうやら、Sandbox テスターの情報とプロダクト情報の間の関連付けが壊れたのが原因のようです。
あまり無いとは思いますが、似たような症状になったら、Sandbox テスターを新しく作って再テストしてみると良いかも知れません。

時間軸を変動させて、動きを変化させる

例えば、放物線運動を物理方式どおり作ったとして、どうしてもぽわーんとした動きに感じられるケースがあったとします。
重力加速度などを弄っても、上手くいかないと。


そういう時、運動の時間軸の方を伸縮させて、解決する方法があります。
紹介している方法は、時間軸を調整して、放物線運動の頂点部分をスローモーションに感じさせるものです。
おそらく、他にもいろいろと応用出来る方法だと思います。


もっとも、運動自体が、y=f(x)みたいな式で出来ている場合に限ります。
差分方程式的に、y += add; みたいな形式では行えません。


時間軸を伸縮させるというと分かりにくいのですが、通常の時間と仮想の時間に分けて、通常の時間から、伸縮させた仮想の時間を求め、その時間を運動の式に与えるという方式です。


ますますややこしい。(汗)


下のものは、ジャンプした時の加速運動の高さ求めるものです。

// 重力加速度、放物線移動する全体時間の長さと、現在の時間からY座標を求める関数
CGFloat turuGetYPositionWithGravityAndTotalTimeAndTime(CGFloat gravity, NSInteger totaltime, CGFloat now)
{
	return gravity * now * (now - totaltime);
}


で、普通はこのnowにフレーム毎に+1した値を与えると、放物線運動のYの値が得られます。
それだと、状況によっては、ぽや〜んとした少し間抜けな動きになる事があります。


そこで、実際のフレーム数をカウントする_currentMovingFrame から、仮想の_currentVirtualFrame を求め、それを先の関数に入れてやる、という方式です。


頂点部分の時間経過をゆっくりにする変換式と、その使い方です。

@property (readwrite, nonatomic) NSInteger totalMovingFrame;
@property (readwrite, nonatomic) NSInteger currentMovingFrame;
@property (readwrite, nonatomic) CGFloat currentVirtualFrame;

// ここから下は、1フレーム毎の割り込み処理での記述

	const CGFloat bottom = 0.2f; // 0~1の範囲。この値を小さくするほど、頂点部分がゆっくりになります。1だと時間の伸縮効果はありません。
	const CGFloat top = 2 - bottom;
	const CGFloat sub =top - bottom;
	
	if (_currentMovingFrame < _totalMovingFrame)
	{
		_hoge.position = CGPointMake(0,turuGetYPositionWithGravityAndTotalTimeAndTime(_gravity,otalMovingFrame,_currentVirtualFrame));
		_currentVirtualFrame += fabs(-sub/((CGFloat)_totalMovingFrame/2.0f)*(CGFloat)_currentMovingFrame + sub)+bottom;
		_currentMovingFrame++;
	}

下のへっぽこな図は、左が普通の時間経過。実1フレームあたり、仮想時間が等しい関係のグラフです。
右が伸縮させた時の、実1フレーム当たりの仮想時間量が変化しているグラフです。
tが実フレームで、vtが仮想時間量です。

この緑色の面積が、経過した時間を現します。
同じように、オレンジ色の面積が経過した仮想時間の累積になります。


概念的には、先に、仮想時間の微分的な変化量を計算で割り出して、それを積算して、運動方程式に与えています。
その時、緑色の面積と、オレンジ色の面積が同じになるように設定すると、双方の運動量は等しくなります。
経過時間が同じですからね。


仮想時間の変化量を微分的に割り出して、それを積算(積分)、という方法でした。
例のプログラムは、経過時間が等しくなるように調整しています。