UnixのslコマンドをAndroidで完全再現!〜SL on Android〜

Androidアプリ第二号 あのUnixのslコマンドがAndroidに!?

Google Play:SL on Android


この怪しいフォルダ型のアイコンを間違って押してしまうと・・・




アスキーアートの素敵な蒸気機関車(SteamLocomotive)がひたすら飛び回ります。


表示中も他のアプリを普通に使えて

30秒弱で律儀にexitと表示してから消えます。



こういったアプリの作り方

バックグラウンドで動作する機能をServiceというようで、
ActivityではServiceを起動してすぐ終了

public class MyActivity extends Activity{
    public void onCreate(Bundle savedInstanceState){
    	super.onCreate(savedInstanceState);
    	startService(new Intent(getBaseContext(),MyService.class));
    	finish();
    }
}

Serviceでは表示したいViewを作ってWindowManagerに追加

public class MyService extends Service{
    public void onCreate(){
        WindowManager.LayoutParams params=[TYPE_SYSTEM_OVERLAYとかでレイアウト決める];
        WindowManager wm=(WindowManager)getSystemService(WINDOW_SERVICE);
        wm.addView(myViewToShow,params);
    }
}

こんなことをすれば出来るらしい。

ダウンロードはこちらから!

https://play.google.com/store/apps/details?id=tompng.sl

MyDice 超シンプルなサイコロアプリforAndroid

Androidアプリ第一号作りました。

MyDice〜俺のサイコロ
Androidのサイコロアプリです。
シンプルな操作 シンプルな外観 振るか画面タッチするだけ!
ぜひ使ってみてください。
https://play.google.com/store/apps/details?id=tompng.mydice

MyDiceの特徴

  • 見やすい
    • サイコロが大きくて見やすい。
    • これより大きいと転がる余地が無くなるというギリギリのサイズ
  • 簡単
    • スマホを振る、もしくは画面をタップするだけ。
    • とりあえず触ってみれば動いてしまう。
    • 他の操作(サイコロを増やすとか)は無い。
  • リアル
    • 物理演算でリアルな音と動き
    • 振る、傾ける、ひっくり返すとかしてみるといいかも

サイコロはこんなに便利!

  • 道に迷った時にサイコロ任せに進むと、いつか必ず目的地に辿り着けます!
  • 重大な決断をサイコロ任せにしても、失敗した時に神のせいにできます!


Downloadはこちらから!

Google Play
https://play.google.com/store/apps/details?id=tompng.mydice

PCで体験したい方はこちらでどうぞ(要WebGL)
http://www.geocities.jp/flyinpng/dice20120816/dice.html

MacOSXで動くCUIな動画プレイヤー 『aaplayer』

今回は作ったツールの紹介
aaplayer ~ [CUI] AsciiArt Video Player for MacOSX ~
https://github.com/tompng/aaplayer/

ターミナルで動くシンプルな動画プレイヤーです。
sshでアニメを見たり(音は本体で鳴ります)、
作業してると見せかけてアニメ見たり、
ctrl+zで瞬時に隠したり・・・

使い方

./aaplayer 動画ファイル


操作

space 再生/停止
10秒前へ
10秒後へ
ctrl+z 中断
ctrl+c 終了
q[enter] 終了
f[enter] 反転
時間[enter] 指定時間へ飛ぶ
+時間[enter] 指定時間進む
-時間[enter] 指定時間戻る
v音量[enter] 音量変更(0〜100)




ときどき次のエラーが出て再生出来ない動画があります。特に最近のmp4等。

-2010: The movie contains some invalid data.

QuickTimePlayerでは問題なく再生できるのにQTKitを使っているこれで再生できないのが謎。

WebGLで大量のパーティクルを

WebGLでパーティクルを大量に使いたい時


javascriptで全部の点の座標を指定していたら重くて数を増やせないはず。そんなときに使える技。
頂点が沢山あるVBOを作って、点の位置を全部シェーダで決定させればいい
OpenGLのPointSpriteを使えたら良いけど見つからなかったから正三角形のビルボード(常に視点を向くように調整した平板なポリゴン)を使う事にする。

サンプル
WebGLの使えるブラウザでどうぞ
http://www.geocities.jp/flyinpng/particle20120417/sample.html
on/off切り替えてから回転させて見てみると分かりやすいかも

VertexShader

uniform mat4 modelViewMatrix;
uniform mat4 projectionMatrix;
uniform float size,time;
attribute vec2 delta;
attribute vec3 random0,random1,random2,random3;
varying vec2 texcoord;
varying vec3 color;
void main(){
	texcoord=delta;
	//3頂点で共通の乱数を使いパーティクルの位置を決定
	vec3 pos=random0*time+random1*time*time+random2*time*time*time;
	//正三角形になるようdeltaだけ座標をずらす
	gl_Position=projectionMatrix*(modelViewMatrix*vec4(pos,1)+vec4(delta,0,0)*size);
	color=(vec3(1,1,1)+random3)/2.;
}

FragmentShader

#ifdef GL_ES
precision mediump float;
#endif
varying vec2 texcoord;
varying vec3 color;
void main(void){
	float r2=dot(texcoord,texcoord);
	if(r2>1.)discard;//正三角形の内接円外部は描画しない
	gl_FragColor=vec4(color*(1.-r2)*(1.-r2),1);
}

VBO初期化

var numParticle=1000;
var arrayBufferDelta,arrayBufferRandom=[];
function initArrayBuffers(){
	var deltaArr=[],sqrt3=Math.sqrt(3);
	//正三角形(ビルボードの形)の頂点座標
	for(var i=0;i<numParticle;i++){deltaArr.push(-1.7320508,-1);deltaArr.push(1.7320508,-1);deltaArr.push(0,2);}
	gl.bindBuffer(gl.ARRAY_BUFFER,arrayBufferDelta=gl.createBuffer());
	gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(deltaArr),gl.STATIC_DRAW);
	
	for(var i=0;i<5;i++){
		var rndArr=[];
		for(var j=0;j<numParticle;j++){
			var s=2*Math.random()-1,t=2*Math.PI*Math.random(),r=Math.sqrt(1-s*s);
			var x=r*Math.cos(t),y=r*Math.sin(t),z=s;
			//3頂点で共通の乱数値 これを使ってパーティクルの位置をVertexShaderで決定する
			rndArr.push(x,y,z);rndArr.push(x,y,z);rndArr.push(x,y,z);
		}
		gl.bindBuffer(gl.ARRAY_BUFFER,arrayBufferRandom[i]=gl.createBuffer());
		gl.bufferData(gl.ARRAY_BUFFER,new Float32Array(rndArr),gl.STATIC_DRAW);
	}
}

描画

function render(size,time){
	gl.clear(gl.COLOR_BUFFER_BIT);
	gl.enable(gl.BLEND);
	gl.disable(gl.DEPTH_TEST);
	gl.blendFunc(gl.ONE, gl.ONE);
	
	gl.uniformMatrix4fv(gl.getUniformLocation(gl.program,"modelViewMatrix"),modelViewMatrix);
	gl.uniformMatrix4fv(gl.getUniformLocation(gl.program,"projectionMatrix"),projectionMatrix);
	gl.uniform1f(gl.getUniformLocation(gl.program,"size"),size);
	gl.uniform1f(gl.getUniformLocation(gl.program,"time"),time);
	gl.enableVertexAttribArray(0);
	gl.bindBuffer(gl.ARRAY_BUFFER,arrayBufferDelta);
	gl.vertexAttribPointer(0,2,gl.FLOAT,false,0,0);
	for(var i=0;i<4;i++){
		gl.enableVertexAttribArray(i+1);
		gl.bindBuffer(gl.ARRAY_BUFFER,arrayBufferRandom[i]);
		gl.vertexAttribPointer(i+1,3,gl.FLOAT,false,0,0);
	}
	gl.drawArrays(gl.TRIANGLES,0,3*numParticle);
}

javascript側では描画時に時間を指定しているだけで重い処理は無い。
つまりGPUが十分速ければパーティクルが100万個あっても動く!!

2段階で動きを変化させた花火っぽいサンプル
http://www.geocities.jp/flyinpng/particle20120417/fireworks.html#N=100000
うちのPCだと8万粒くらいが60fps出せる限界

線で軌跡を描画するサンプル
http://www.geocities.jp/flyinpng/particle20120417/sample2.html#N=10000

制約と誓約

  • シェーダで時間から位置を直接計算できないといけない
    • particle.x+=dt*f(particle.x,particle.y,particle.z);みたいな処理は出来ない。
    • ローレンツアトラクタとかやりたくても出来ない(VertexShaderFetchとかを使えば可能かも)。
  • その代わりべらぼうに速い

新年

あけましておめでとうございます。
だいぶ放置してたなぁ。

動く年賀状をつくってみました。(PC&&!IE)
http://www.geocities.jp/flyinpng/dragon.html

ドラゴン年らしくドラゴン曲線(をちょっといじった物体)です。
マウスでグリグリうごかせます。

フラクタル次元が2かそれよりちょっと大きめにすると見栄えが良さそう
再帰関数で作れる図形は当たり判定も再帰関数でらくちん

棋譜ビューア更新

棋譜ビューアアップデートしました。

http://www.geocities.jp/flyinpng/kifuviewer/
駒落ち将棋に対応 そして、棋譜のURLが使える様に

サンプル
http://www.geocities.jp/flyinpng/kifuviewer/#6A1yyKhr6d2prFVj6mtxVbefZXmftR9MhlQOQR0qkB/
http://www.geocities.jp/flyinpng/kifuviewer/#BPtTFnoRQCYzoVt8Jxw4Q6Vnd5Dj88sW6t1xhzx3FRkuuuS/
(2011/10/13 ちょい修正)
URLの#以下に棋譜のデータを圧縮して埋め込んでます

操作方法は前と同じで
・loadで読み込み(Lキーでショートカット)
・矢印キーorマウスホイールで棋譜再生
・flip(Fキーでショートカット)で反転
IEでは動かない




棋譜の圧縮について

棋譜はどこまで圧縮できるのか
基本的には
『移動元(9x9 or 持ち駒)、移動先(9x9)、駒の種類(成駒も合わせて14種類)、成るか否か』
の情報があれば良い。
素直に記述すると、移動元2Byte 移動先2Byte 種類1Byte+成/不成1Byteで1手あたり6Byte
ぎりぎりまで詰め込もうとしたら、1手当たりlog((81+1)x81x14x2)/log(256)=2.2Byteになる。


もっと圧縮したければ、その局面で実際に可能な手の数を実際に数えてやるといい。
例:初手は動かせる駒が20通り、金を選んだなら動かせる場所は3通り
合わせて1手が0.74Byteで収まる。

実際の棋譜で試したところ、平均で約100Byte(1手あたり0.9Byte)にまで潰せることが分かった。

・・・というのを使ってます。(A-Za-z0-9しか使ってないのと対局者名も入れてるから実際には1.5倍くらいに)

棋譜ビューア

すごく久しぶりの日記。
ちょっと頓挫してしまったプロジェクトのコードがもったいないからと残骸を組み立てて将棋の棋譜ビューアを作ってみました。
http://www.geocities.jp/flyinpng/kifuview/1_0_0/kifuview.html

使い方は、左上のloadを押して棋譜貼付けるだけ。
あとは右の棋譜クリックor矢印キーorマウスホイールで操作

先手:kilohand
後手:fivehands
▲2六歩△4二玉▲2五歩△3二玉▲2四歩s△4二飛▲2三歩成
まで7手で先手の勝ち

と、これだけじゃつまらないからと、ちょっと妙な仕掛けを試してみた。
ローカルにDLしても常に最新版が使える、自動更新機能付のHTMLファイル
http://www.geocities.jp/flyinpng/kifuview/kifuview.html ダウンロードしてからブラウザで開く
(2011/9/20 ↑間違って上書きしてしまったorz元データ無くしたし・・・ 最新版はこちら http://www.geocities.jp/flyinpng/kifuviewer/ )

初回起動時にHTMLアプリで必要になるhtml/画像/スクリプトをサーバーから取ってきて全部localStorageに保存。
次回以降は更新確認後、localStorageからindex.htmlとmain.jsを取り出して動く、という仕組み。
サーバーからデータを取得するのには、iframe(iframe内でXMLHTTPRequest)とpostMessage(異なるドメインのwindow同士での通信)を使った。
localStorageが汚れてしまう点が欠点。


この仕掛けが今後何かの役に立ってくれたらいいな
ソフトウェアのお気軽版をhtmlで配った上で、ソフトウェアアップデートも自動でできるとか。
ほむほむ。