2012年の目標2012年01月02日すた

あけましておめでとうございます。

C81の1日目以降ばーちゃん家に泊まってまったりとすごしています。
それでも電気外とC81は4日連続で行って参りました。

早朝に家出る本当の理由をばーちゃんに言えなくてすごく複雑でした・・・w


相変わらずくそな生活を送っていますが今年もよろしくお願いします。



2011年

2011年は大学2年生になったこともあって、中だるみやばす\/な年でした。
そしてとりたてて何かをしたわけでもありませんでした。

無理やり捻り出すとすれば

2月にプログラミングのバイトを友達に紹介してもらいました。
5月にAndroid向けアプリ アニメ見てるなう(アニメ番組表)を公開しました。
その他川田まみライブ×2とC80,C81電気外

あとは27インチディスプレイと机と自宅鯖とMBA購入でだいぶ部屋の環境が良くなりました!


今となっては起きる→大学→バイト→アニメ消化→寝るのサイクルがすっかり定着していますが、
プログラミングのバイトを紹介してもらったことはかなり大きかったと思います。

バイト中にAndroidアプリの作り方とかnode.jsについて勉強させてもらったお陰で
「アニメ見てるなう」のリリースに繋がったり趣味方面でのnode.jsの勉強が捗ったり

その他、今まではフォルダをコピーしてバックアップ代わりにしていたけど
gitがバイト先で流行って(?)いたのでそれを真似して使うようになったり

そしてそもそもMacに触れたのも初めてだしMBA買う後押しにもなったし
MBA買ってnode.jsやらRubyやらのモチベーションも上がったので、何だかんだでいい刺激を受けられたかなあと。


社員さんにメイド喫茶連れて行ってもらったのもなにげに良かったかも。
1人じゃさすがに入る勇気ないです・・・\/

とりあえず2012年の目標!

  • Ruby on RailsでPV50000/day以上またはGoogleAdSense収益3万/月以上のWebサービス作る!
  • 「まともな」Androidアプリを公開する
  • 勉強会に参加してみる

SSったー!はASP.NETでできていますが
C#だとどうしてもWindowsServerに限られてしまうので
この際一般的な環境で動くWebアプリも作れるようになろう、という魂胆。

そしてIISでもnode.jsは使えるみたいですが、まあこの際node.jsとrubyでどこか適当なVPSで何かを作ってみよう、という魂胆。


サーバとやりとりするAndroidアプリも作ってみたいです。
ついでに言うと、「アニメ見てるなう」は「アニメ」だけに大きな声で公開できるようなものじゃないので
普通に公開できるようなアプリを作りたいなあと。


そしてつい先日、大学やら高専やらの情報系サークル同士の交流会に行って来ましたが
「勉強会試しに行ってみなよ!!」とかやたらと勧められたので「じゃあ・・・w」ということで。



今年があと363日もあると思うと何でも出来る気しかしないのですが
そうはいいつつ去年は大したことせずに終わってしまったので
今年こそはやってやるです!

Canvas+node.js+socket.ioで簡易オンラインゲーム作ってみた2011年12月19日すた

Canvas+node.js+socket.ioで簡易オンラインゲーム作ってみました!
ほんとに簡易!


もともとはサークルの交流会のLTデモのためにちょちょっと作ったものなのでゲーム性はほとんどないです。
作成時間は半日くらい。その後の細かな手直しに4時間くらい。

js暦2ヶ月、node.js暦1ヶ月という短さですが、node.jsとsocket.ioの手軽さには本当に感服です!

サンプル

とりあえずブラウザでアクセス
Chrome16、Firefox7で動作確認。表示だけならAndroid2.3でも可。
※Avastなどのウイルス対策ソフトが動いてるとサーバーと接続できないみたいです

2chのプログラミングスレで晒してもなんとか動いてたので、たぶん、普通に動くはずです。

操作方法

矢印キーで移動、スペースキーで加速
物理をすっかり忘れてしまって未知なる力で動かしてるので、加速回りは怪しいかも

CPUもいますが勝手に自殺しちゃうので、
Chromeのタブ+シークレットウィンドウ使うか、Firefox+Chromeでアクセスすれば自分対自分ができます。

開発環境

node.js 0.6.0
socket.io 0.8.7
express 2.5.1

ソース

最近git使い始めたので、なんとなくgithubにもあげてみました。
https://github.com/pxsta/OnlineBallAtack-socketio

仕様

サーバ側でゲームのメインループまわして移動量計算・あたり判定、
クライアント側は定期的にボールの位置情報を受信してCanvasに描写してるだけです。

ユーザーの識別にはSocket.ioのセッションIDを使用。
再接続/リロード時のためにExpressのセッションIDとSocket.ioのセッションIDを紐つけています。
ExpressのセッションIDはサーバのみが保持して、クライアント側には他クライアントのセッションIDは知らせていません。

サーバ(メインループ部のみ)

src/server.js
//メインループ
var run = function()
{
    setInterval(function(){
           update();
           sync();
        },1000.0/MyApp.config.FPS);
};

//ゲームデータの更新
var update = function()
{
    var ballArray = MyApp.ballList.toArray();
    for(var i=0;i<ballArray.length;i++){
        //ここであたり判定とかボールが落ちてないかの確認とか
    }
    
    //各ボールを現在のスピード等に基づいて移動させる
    MyApp.ballList.update(param);
};

//クライアントに同期させる
var sync = function(){
    var ballArray = MyApp.ballList.toArray();
    var sendMessage = {ballList:MyApp.ballList.toJSON()};
    
    for(var i=0;i<ballArray.length;i++){
        //各クライアントにすべてのボールの位置情報を送る
        var socketID = ballArray[i].getSocketID();
        io.sockets.socket(socketID).volatile.emit("updateBallInfo",JSON.stringify(sendMessage));
    }
}

サーバ側で、updateとdrawを定期的に実行というありがちなメインループをまわす。
今回はdrawをsyncに変えて、描写の代わりにクライアントにゲームの状態を送信。

クライアント

src/client/client.js
//サーバからボールの情報を受信したときのイベントハンドラ
connection.on('updateBallInfo', function (msg) {
    var messageJson = JSON.parse(msg);
    
    //ボールの状態を更新する
    MyApp.ballList.get(messageJson.ballList[i].socketID).updateValue(messageJson.ballList[i]);    
});

//メインループ
var run = function()
{    
    MyApp.mainLoopID=setInterval(function()
    {
        update();
        draw();
    },1000.0/MyApp.config.FPS);
};

var update = function(){
    //落ちたボールをリストから削除したり
    //自分に落ちてるフラグがセットされてたら画面メインループ停止させたり
    //サーバから受信した各ボールの情報をもとにゲームオーバー判定とかするだけ。
};

//canvasに描写する
var draw = function()
{
    var ctx = MyApp.context;
    var offset = MyApp.getOffset();
    
    //Canvasをゼロクリアする
    ctx.clearRect(0,0,MyApp.canvasSize.width,MyApp.canvasSize.height);


    //マップを描写
    MyApp.map.draw(ctx,MyApp.getOffset());
    
    // ボールを描写
    MyApp.ballList.draw(ctx,MyApp.getOffset());
     
};
“updateBallInfo”としてサーバから定期的に送られてくるボール情報を受信して、ローカルに各ボールの状態を更新・保存、
その状態を元にボールを描写。

ボールの移動

src/client/client.js
$(window).keydown(function(e){
    //サーバにキー押下情報を送る
    connection.emit("keydown",code);
}
ボールの移動は、
クライアント側はキーイベントを監視して押されたボタンの情報をサーバに送るのみ。

src/server.js

//クライアントがキーを押した時
connection.on('keydown',function(code){
    var moveVector={x:0,y:0,mode:"normal"};
    if(37<=code&&code<=40||code==32){
        if(code==37){
            moveVector.x+=(-1);
        }
        else if(code==39){
            moveVector.x+=1;
        }
        else if(code==38){
            moveVector.y+=(-1);
        }
        else if(code==40){
            moveVector.y+=1;
        }
        else if(code==32){
            //ターボ
            moveVector.mode="tarbo";
        }
    }
    //ボールの行動バッファに加える
    MyApp.ballList.get(connection.id).setActionBuffer(function(){
        MyApp.ballList.get(connection.id).addSpeed(moveVector);
        MyApp.ballList.get(connection.id).setMode(moveVector.mode);
    });
});
サーバ側は受信したキー押下情報を元にスピードの上げ下げ。
バッファに1つだけ保存して、次のupdate内で実行。

クライアントからkeydownメッセージ受信した時点でスピード更新してもいい気がしたけど、
あるクライアントはメッセージ送信が1ms/回、あるクライアントは500ms/回とかだとまずい気がしたのでバッファに1つだけ保存して、updateで定期的に実行するようにしました。

とりあえず

updateとdrawの定期実行というよくあるメインループをサーバ側でやらせて、
drawをsyncに変えて描写の変わりにクライアントにゲーム状態を送るようにして、
クライアントではupdateの代わりにイベントハンドラでゲームの状態を受信して、それをdrawで定期的に描写してるだけです。

チート的なことをされないために、あたり判定などのメインループのコードはサーバ側だけに書いてます。
ボール移動の際も、クライアントからキーコードを送ってもらうだけで、具体的な処理はサーバ側で行っています。

ballAtack.jsでボールの基本的なクラスを定義して、serverBallAtack.jsでballAtack.jsの各クラスを継承して、ExpressのセッションID・ボール移動処理などのサーバのみに必要な値・メソッドを追加しています。

問題点

  • サーバは60FPSでゲームの状態を送信してますが、それに通信速度が追いつかないと問答無用でカクカクします。
  • 通信途切れたら動けません(再接続はできます)
  • クライアントからsocket.emit(“hoge”,”あばばばば・・・(1MB分続く・・・)”)みたいなの実行されて巨大なデータ送られ続けたらどうなるんだろう?
これでも読めば何か変わるんでしょうかね。


敷居の低さ

そもそもこれを作ったのは大学のサークル同士の交流会のLTのためなのですが、

前日になって、
スライドできてない><→node.js+socket.ioのことでも話すか!→デモでも作って穴埋めしよう→これならサクッと作れそう!
という単純な動機で作りました。

js暦2ヶ月、node.js暦1ヶ月ちょいの自分ですが、それでも半日程度で作ることができました。
そもそも、通信部分はサーバ/クライアント合わせてわずか100行ちょっとで、その他は普通のゲームと同じです。

ゲームに限らず、webサービスでリアルタイムなコンテンツをサクッと追加するのにも使えそうです!
何かおもしろいものないかなあ。

土日なにしてるの?2011年12月05日すた

クリスマスが近いというのに最近の胸キュン体験がましろ色シンフォニーと世界一初恋だけで割りと死にたい
そして最近ふとTwitter開くとハルbotのツイートがしばしば目に入ってなんかハルやっぱり性格よすぎて辛い、最近遅刻しすぎてじゃっかんくそ状態。穹ちゃんむぎゅうー。

それはともかく
バイト先で、新しい人とのGoogleドキュメントの共有がスタート。

で、おそらくgmailのアドレスからGoogle+の「友達候補」とかに表示されて、G+のアイコンがシオンだけに怪しまれたんですかね。

「俺君ってアニメとか好きなの?」
「アニメはどちらかと言えば見ないほうだと思いますよー(学科の中だと少ないほう)」

「じゃあ土日とかってなにしてるの?」

 俺「ぐぬぬ…」

別にやましいことしてるわけじゃないんだけど、特にこれといって何かをしてるわけじゃないんですよね。

たとえば先週は川田まみのライブにいったけど、先々週はたしか引き篭もりニートしてた気がするし。

この土日はと言えば、

金曜深夜
シャナ,世界一初恋,若干作業ゲーなプログラミング

土曜
15時起床,作業ゲーなプログラミング続き,UN-GOやらギルティやら消化

日曜
13時起床,デバッグ,ななとき体験版2,アニメ見つつプログラミング

やっぱりシャナはおもしろい。
世界一初恋もましろもキュンキュン出来ていい。リアルでできない分ここでキュンキュンするしかない。

作業ゲーなプログラミングはSSったー!の手入れ。久しぶり。
ちょっとはレスポンスの遅さ改善されるかと思って、データベースをxmlからsqlite3に変えた。気持ち軽くなったかな?

Rubyの基礎少し。

ななときは期待度MAX。不思議展開バトル展開ハラハラ。しかもOP川田まみ!!

なんだけど、とりたてて何かしたわけじゃないし
おそらく来週また「土日なにしてたの?」って聞かれてもこれだ!とは言えないんだなあ。

いま個人で稼働中のプロジェクトが特になくてなんか退屈。
HTML5でノベルゲーうんぬんを再開しようかと思いつつも諦め半分

Twisterすごい。node.js+socket.io。見た目も機能もTwitterそのまんま。
5時間×2ヶ月の作業時間で開発とかどこのニートwwwwかと思ったらまさかの大学生wwww
2ヶ月もの間、途中で投げ出さずに最後まで作りきったのすごいです。

こんな風にVIPで堂々と公開出来るクオリティーのもの作れるようになりたいです。
なんか学祭終わってからノベルゲーうんぬんの熱が覚めてしまって結局完成させられず。

よくわからないけど
実を言うとこの土日の半分近くはだらだらしてたんじゃないかって感じで、
SSったーも、ASP.NETやってて意味あるのかなあとか消極的になりながらの更新で、
こうなったらはやくrubyの基礎覚えて、あとは実際に作りながら覚えて行こう、
とか寝る前にふと湧きでたやる気を明日も思い出すための記事でした。

というか休みが3日あれば
1日目:アニメ+惰眠
2日目:プログラミング
3日目:えrg
ってやりたいこと全部できるのにね!

だらだらして結局ダメな予感しかしませんけど!

MacBook Air11インチ届きました2011年11月28日すた

ということでMBA11インチ特盛り届きました!先週の月曜に。


前々からほしいと思っていたのですが、まあうだうだ悩んでるなら欲しいと思ったうちに買ってしまおうということで!
DHDのときもそうでした。

Pro/Mini持ってないゆえん、スペックは特盛り(i7/4GB/256GB)にしました。
この1週間ちょびちょびと使ってみましたが、やはり買ってよかったです!

当然のことながら軽い、軽すぎる。そして小さい!(そして地味に今までの白MB13インチよりも解像度高いのね)

かばんにスッと入ってスッと出せてそもそも背負ってるのか分からないくらいの重さに感動
「あーどうして動かなかったんだろう」、ってモヤモヤしてる時とかも帰りのバスでスッとだせて便利です。

メモリ4GBなのは気になったけどSSDのおかげか、スワップも気にならず。
MB13インチ、メモリ2GBのときは死ぬ思いしてました。まじで。

バッテリーは公称5時間で正直、短め。
EclipseでやらMonoDevelopで作業して4時間前後でしょうか。

まあそこらへんはhyperjuiceで補えそう。
モバイルブースター3つ持ち歩くのと同じくらいの重さですかね。普段2つゆえんまあそこは気にならないかな。

そして家ではコスパ抜群のDELLの27インチIPS液晶に繋ぐことでかなり捗ります。2560×1440。

気になるのは、重たい作業させたときに熱くなってファンもうるさくなったり、(クリアカバーで覆ってるせいもある?)
そして本体が薄い分、もちろんキーボードも浅い。

でもその他動作面ではかなり満足!

そして実は11インチと13インチで1週間くらい迷っていました・・・w

が、ProならまだしもAirで13インチは大きくもなく小さくもなく中途半端な気がしたのと、
近くの電気屋で何度か実機触ってみて、11インチの小ささに改めて憧れてしまって最終的に11にしました。

そしてやはり11インチにしてよかったです!かばんにスッと入ってスッと出せるし重さを感じさせないのは本当に驚きでした。
まだ買ってから1週間ですが、動作に不満もなし。買ってよかったです!

これでnode.jsとruby捗るで!!乞うご期待

MAMI KAWADA m.a.l.l LIVE 2nd stage 1日目行ってきました2011年11月28日すた

ということで半年ぶりの川田まみのライブに行ってまいりました。

今回はバラードも多かったし新曲もあって、やっぱりやっぱり川田まみすごくよかった!!
そして聞きたかったIMMORALも聞けて文句なしでした!!

そして今回もまさかの3列目というね!!

となりは身長低めのおにゃのこだったけどマスクしてて顔が見えなかったwそして低いながらジャンプしまくっててちょっと驚いたw

序盤はバラード多めな感じ。
風と君を抱いてとか明日への涙とか雨とか。

最初は8曲くらい連続で来た気がする。長いww

で、MC。
OUT FLOWリリース後の打ち上げで、トイレで寝てしまったんだとか。なんだかツンとしたイメージとあわなくてふひひww

そしてこの11月で「川田まみ」としてデビューしてからちょうど10年、
これからも新しいことにどんどん挑戦していくつもりなんだとか。

ということで、自らギター持ちつつ弾き語り!w

緋色の空やらSee visionSやらNo buts!来てそれはもう激アツww
緋色の空は何度聞いてもやっぱりいいですね!!

とか思ってたらあっという間に
「その次これで最後になります。これからもよろしくお願いしますー。」

まじですかー!もうそんな時間ですかい
といいつつももちろんアンコール

そしてアンコールでまさかのIMMMORAL!!!

これが一番聞きたかったゆえん
なんか思わず鳥肌立ってしまったww

しかも服装がなんか露出度高くなってたw
その格好で「インモラル・・・インモラル・・・」とかボソボソ言うのはなんかえろかったw

そしてまあなんと今回のライブ初出の新曲もありまして!!
しっとり系の流れる感じでですごくよかったですね。

バラードの分量多目でしたがやはり川田まみのしっとり系はいいですね。
寒い中行ってよかった!来年もぜひぜひワンマンライブを!

そしてななときのOPフル、EDに期待!

——————————————————–
ちなみにこんな感じでした。

風と君を抱いて
明日への涙
intron tone
Beehive
TRILL

空の森で
a frame

-ギター弾き語り-
dilemma
緋色の空
sence

See visionS
masterpiece
No buts!
portamento

アンコール
IMMORAL
Half way(新曲)
CARPE DIEM

もっとゆとりたいもっとニートしたい2011年10月31日すた

金曜はそもそも授業1コマしかないわけだが、まさかの休校でまるまる1日休み。
で、事実上の3連休だったわけですが、

大学休みだとこんなにもゆとりが出来るんですね!!!

・今更ながらGUNSLINGER GIRL1~12読了
・翠の海フルコン
・「JavaScriptパターン ―優れたアプリケーションのための作法」半分くらい了
・平均睡眠時間7時間
・その他ずっとニート!!!

なんというかひさびさにニート満喫できたっていうか、毎週3連休にしてほしいです。

木曜日はゴルフ部の代替&引継ぎの飲み会だったわけだが特に変わったことなしw。

で、終わった後は1年生も含めてカラオケに行く予定だったけど
次の日1限から実験らしいから2人で近くの満喫。

メジャーなもの読んでおくか、ということでGUNSLINGER GIRLをテキトウに。7時間かけて12巻しか読めなかったけどww
ほとんど漫画読まないゆえん比較対象なくてあれだけど、まあ普通にすらすら読めてよかったのかな。

で、帰宅、睡眠。

でまあもちろん寝てる間にヤマトがやってくるも気づくわけもなく不在通知。
お届けものです!!ドンドンドンドンとかやってくれれば起きれたかもしれないのにねw

ということで、インターホンの音あらかじめ登録しておいて、それが聞こえたら大音量でアラーム鳴らす的な、昼寝時の対通販用Androidアプリだれかお願いします、ほんとに。

ということで再配達依頼、翠の海到着!!

で、金土とやってフルコン。体験版部分スキップで10時間ちょい、短かったような気もする・・・w

とりあえずOPとBGMはほんとによかったですね。

昼間は可愛いキャラでも、たまに現れる黒い本性がなんとも良かった。
なんというか、みんな黒い性格もってたり前半BADエンドラッシュだったのがゾクゾクしてよかったかな。

そりゃあ一日中いい顔なんてしてられないし人前では言えないこともありますよね。なんてw

BADのゾクゾクからの個別イチャラブのギャップ、なんの躊躇いもなく人殺しちゃう2人、そして「コイツ明らか悪いやつじゃねえかwww」って人が個別入ったら「まあしょうがないのかな・・・」なんて思えちゃうあたりがよかったかな。

まとまってたしOPED・BGMよかったし一応殺り合ってはくれたしまあ買ってよかったんじゃないかなと。

でまあ日曜日はいつもどおり13時起床。
こんな生活ダメだ、って分かっててもそう簡単には変えられないんですよね。

で、なんか体だるいし商業のやった後に学際向けの適当なノベルゲーの作業するモチベーションも上がらず、
なんとなくJavaScriptパターン ―優れたアプリケーションのための作法をちょこちょこと。

JavaScriptの文法やら定石やらはさっきのとパーフェクトJavaScriptで終わりにしようかと。

Rubyを始めたい方向けまとめ(2011年秋版)
なんて記事もちょうど上がってきたゆえんこの暇な後期はいろいろやりたいですね。

まずは学際をテキトウに!そしていいかげんリセリシアス以外の√と夏空カナタを消化せねば。

当然のことながら明日はくそめんどうな大学なわけですが
もっとニートしたかったです!!!!!

今後の予定2011年10月24日すた

ということで学祭に向けてテキトウに製作中のHTML5とJavascriptでギャルゲーを作ろうというあれですが、

まあそもそも大学もゆとりでくそ楽な時間割なわけで、それでもくそ面倒な授業ばかりなのですが、

まあ何だかんだで今期は世界一初恋2・ましろ・ギルティクラウン・シャナFINALが面白そうでして、

シャナFINALは期待してただけにOP/EDの残念感は正直あるんだな、これ。

ななときのOPがついに公開されたわけですが、まあ安定の川田まみクオリティでして、EDもわくてか。

先週は応用情報受けてきたわけですが春はノー勉強で当然ながら撃沈したゆえんまあ今度こそ受かりたいわけでして、
まあ午後はハッシュ法のオープンアドレス法が出たわけで「あ!これ授業でやったところ!!」となったようなならなかったようなあれでして、

ほとんど毎日午後登校ゆえん、くそみたいな新学期を過ごしてまいりました。

今後の予定

  1. キスまおコンプ
  2. フェードイン/フェードアウトの使い道考える
  3. 足りないもの探す
  4. 「localStorage」「Application Cache」を使ってみる
  5. 翠の海
  6. 2chスレから辞書作る
  7. 学祭、そしてβ版公開
  8. 夏空カナタ
  9. どこかにnode.js使った機能をねじ込む
  10. ついでにruby始める

そもそもなんで学祭の製作物をHTML5のノベルゲーにしたかといえば、node.jsのためにJavaScriptの練習したかったのと、
なんかHTML5が流行ってるっぽかったからでして

最近の記事だけどnode.jsやらHTML5やらこれから激アツなんじゃないのとかなんてわくてか。
【第21回 HTML5とか勉強会】ゲーム開発はHTML5+スマホベースが新潮流 – @IT
HTML5 Web Applicationのつくりかた
JavaScriptでゲーム制作@実務現場レポ
今日は JavaScript ゲーム製作勉強会 Vol.2 の日です – a geek born in Tomakomai

これに比べたらノベルゲーとかしょぼすぎて話しにならないレベル。画像やらシナリオやら抜き放題ですし、
そして今は個人的には今リセリシアスの可愛さが熱い。

でまあ大学行くのがめんどうといっても今期はなんだかんだでゆとりの午後登校ばっかりでして、

部屋の片隅でいつぞや組み立てた録画用鯖が延々と動いてるわけなのですが、

深夜アニメしか録画しないのに日中も全力で稼動しててなんかもったいない。
ついでに、いつまでもC#&ASP.NETで環境がWindows限定なことをやってるわけにもいかないので

暇ないま、Rubyをやってみようかと!あわよくばrailsも!

PythonはGAE使えるくらいしかメリットなさそうだし、PHPは、まあいいかな。という感じで。

どうでもいいけど世界一初恋2、どうして男同士の三角関係できゅんきゅんしなきゃいけないんだwwwwww

HTML5でノベルゲーα版v1.02011年10月24日すた

HTML5でノベルゲー α1

なんとなく始めたHTML5とJavascriptでギャルゲーを作ろうというあれですが、
学際があと2週間ちょい?で案外時間ないということで実働サンプル。右下のボタンで画面サイズ変更可能。

HTML5でノベルゲーα v1.0 サンプル

 

肝心のスクリプト部分は、まだ1スレしか変換してないゆえんスクリプトに直接埋め込むくそっぷり
最終的にはSSったー!のコンテンツにする予定。

Google Chrome14,Firefox7,iOS4のsafari、Android2.2/2.3のデフォルトブラウザで動作確認。
ちなみにAndroid2.2以下はAudioタグ非対応のため、Android2.2以下では音が出ません。

そして、ついさっきIE8で開いたらいつもどおり動きませんでした\/

じつはα v0.0?がだいぶ前に出来ていたのですが、AndroidやらiPodTouchで重かったり、
JavaScriptもHTML5もイマイチな頃にやっつけで書いていたのでまた書き直しました。

スクリプトの書式はうぃんどみるのCatSystem2をチラ見してから決めました。
いやあ、さすがホンモノ。すごいですなあ。

今回サポートしたのは

  • 背景の描写
  • 立ち絵の表示/削除[位置,フェードイン,フェードアウト]
  • キャラアイコンの描写/削除
  • メッセージの表示


エンジン自体の機能は
  • 画面サイズにフィット
  • バックログ
  • バックログからシーンジャンプ←簡単だけどこれ個人的に欠かせないw
  • マウスホイールで進む/ログ←これも個人的に欠かせないw
  • BGM

のみ。
最低限これさえあれば動くだろ的な。

ログからボイスの再生だけじゃなくてジャンプできるエンジンすーき!!

α2やらβ1やらに向けて。

α1ではキャラの表情はどうやって決めてるのかというと、

  1. 既存のギャルゲー(しぇいむ☆おん[初出VIP])からシナリオ抽出
  2. OpenCVでゲーム画面キャプチャ&立ち絵特定
  3. その立ち絵の感情とそのときのテキスト中の単語を紐付ける
  4. 自動クリックでゲーム進行
  5. ・・・繰り返し

とかやって、「その単語がどんな感情のときに使われやすいか」という辞書を作成、
あとはSS中のセリフをその辞書使って分析→感情推定

とかやってたけど、圧倒的に単語数が少ないんだなこれ!!!!!

「わたし・・・脱ぐね・・・。」とか満面の笑みよりも微照れの方が萌えますからwwwww。

ということで画期的なアイデアをだな。
2chのひたすらネガティブやら浮かれてるスレを監視

その書き込み内容は全部ネガティブやら嬉しいときのものだと決め付けて辞書作成

最低でも嬉しいと悲しいくらいは判断してくれないと困るっす。評価極性辞書なんて物もあるみたいですがまあとりあえず。
辞書の作成方法はここら辺を参考に→実践! 「MapReduceでテキストマイニング」徹底解説 (1/3) – @IT

で、まあその他、

【問題点】
・バックログがやっつけの実装←Canvas大量生成につきAndroidではメモリ不足で落ちるときがありますw
・そもそもバックログの挙動がおかしい
・Androidだとタッチしたときに色付いてじゃま。
・立ち絵小さい、少ない
・背景固定
HTML5には「localStorage」「Application Cache」なるものがあるらしい。が、未使用。
なんかつまんない
フェードイン/フェードアウトの使い道が思い浮かばない

辞書が完成しないとシナリオのスクリプトが作れないゆえんこれは一番最後。

なんとなく昨今のワイド対応意識して1280×780にしたけど、立ち絵が明らかに小さい。まあこれはどうにも。

あと、あきらかに著作権の問題があるけど、けいおんのSSスレ用にあずにゃんとかけいおんメンバーの立ち絵用意したらすごく面白い気がする。
まさにきゃっきゃうふふ、なんですかね。

Application Cache、ローカルにデータ保存できるのはいいですね。

そしておまけ程度にフェードイン/フェードアウト追加したけど用途不明なんだなこれ。どういうときに使うんでしたっけ?www

ということで、2週間ほど前に2つほど届いたのですがいまだ消化しきれててないんだなこれ。どうでもいいですが先週はAPでしたので。受かれ。

まあ、なんだ、今回ばかりは商業のものやるとすっごくモチベーション下がるのはどうしてなんでしょうね???w

まあ、なんだ、システムうんぬんよりもやっぱりCGやらBGMが重要なんだなあと
リセリシアスかわいすぎてああ、なんかもうだめだw


学祭まであと2週間ちょい。
「クオリティアップのため公開を2週間延期させていただくことをご報告申し上げます」とは言えないのですww。おうふ。

寄す処2011年09月26日すた

夏休み中の平日&ここらへんの三連休は意味もなくIDEに向かったりだらだらしたりしてたのですが、

先週?先々週だかは河口湖に大学の友達と行ってきまして
夏休み中初の東京脱出&自然すげーwwwとか感傷に浸ってきました。



 

友達の高速の運転の慣れてる感も尋常じゃなくてあれだったわけですが、

なんというか自然やべえwwwwwなんだろうこのわくわく感wwwww

とか勝手に感傷に浸っておりました。

毎日毎日IDEに向かってるとたぶん無意識にストレス溜まるというか
同じことの繰り返しで疲れるというかで

企画やら運転やらありがとうございました。

久しぶりにリフレッシュできてよかったかなあなんて

高速の左右も山ばっかりでなんか和みました。

ヨスガノソラの聖地が車でいけそうな距離?なので早く高速とか余裕だしwwwwってなりたいですね。

ということで春日野 穹 1/6すくみず届きました。



あの山並みやら、
高校の時に家出してパキスタンに行った話書いてく
35カ国くらい旅行してきたから写真うpする
なんでエロゲー・ギャルゲーの舞台ってド田舎が多いの?
やら見てたら

田舎やら海外やらの一人旅したい欲が再燃してまいりました。

そして先週、ようやく初心者マークなしで運転しても違法じゃなくなりました。さあ高速の練習をば!
冬休みこそはどこか一人旅行きたいですな。

OpenCVで虹顔の識別(※ただし表情がとぼしくて可愛いおにゃのこに限る)2011年09月25日すた

はい、ちょっと***な諸事情で、画像中に全く同じ画像が含まれているかを調べる必要があったのですが、自力ではうまく行かず、
OpenCV使ったら一瞬で出来てしまって不覚にも感動してしまいました。
、という更新。

こんな紛らわしい画像(右側は微妙に口の形が違う)も「違う」と判断してくれてさすがです。

 

、何がしたかったのかというと、虹画像の表情を判断したかったわけで、
さらにその表情ごとの画像は一意に決まってるというまあなんともレアケース。

笑ってるときは画像01、泣いてるときは画像02、みたいに。
表情が乏しいとも言います、はい。

むすっとした顔の穹ちゃんはかわいいけどね!!

、これらの画像から、下のおにゃのこの表情が何なのかを調べてみますと、
    

まあよく分かりませんが「一番左の画像が完全に一致」、と判定してくれるわけです。
OpenCV便利すぎくそわろうた、です。

今回はなんとなくC#でOpenCvSharp使いました。
OpenCv:2.1
.NET:4.0
公式のサンプル引っ張ってきただけです、はい。

要なのはこの2行だけで、

Cv.MatchTemplate(target, template, dst_img, MatchTemplateMethod.CCorrNormed);
Cv.MinMaxLoc(dst_img, out  min_val, out  max_val, out  min_loc, out  max_loc, null);

MatchTemplateで各点の相関係数をdst_imgに、
MinMaxLocで相関係数の最大値と最小値とそれぞれの位置を取得できるみたいです。

相関係数が1に近いほど正の相関があるので1に近ければ近いほど、類似の画像が含まれているということになります。
相関係数が1のときは完全に一致。

似たような画像でも0.998とか高めの値が出たので今回はしきい値を0.999にしました、テキトウw

using System;
using System.Collections.Generic;
using System.Linq;
using OpenCvSharp;
using System.IO;

namespace CVSharpTest
{
    class Program
    {        
        static void Main(string[] args)
        {
            //templateフォルダ以下にテンプレート画像を入れておく。
            IEnumerable<string> tempFiles = Directory.EnumerateFiles("./template","*",SearchOption.TopDirectoryOnly);
            Dictionary<string, double> NCCPair = new Dictionary<string, double>();

            IplImage target = IplImage.FromFile("target.png",LoadMode.Unchanged);            
            IplImage template;
           
            foreach (string file in tempFiles)
            {                
                template = IplImage.FromFile(file, LoadMode.Unchanged);
                double ncc = GetNCCMax(target,template);

                //対象画像からテンプレート画像を検索して表示する
                TemplateMatch(target, template);
               
                NCCPair.Add(file, ncc);
                Console.WriteLine("{0}:{1}", file, ncc);
            }

            //「相関係数の最大値が一番高いもの」が一致画像の可能性が高い
            var result = NCCPair.OrderByDescending((val) => val.Value).First();
            Console.WriteLine("MAX:{0} {1}",result.Key,result.Value);
           
            return;
        }
       
        /// <summary>
        /// 相関係数の最大値を計算する
        /// </summary>
        private static double GetNCCMax(IplImage target, IplImage template)
        {
            IplImage dst_img;                        
            double min_val, max_val;
            CvPoint min_loc, max_loc;
            CvSize dst_size;

            dst_size = new CvSize(target.Width - template.Width + 1, target.Height - template.Height + 1);
            dst_img = Cv.CreateImage(dst_size, BitDepth.F32, 1);
            Cv.MatchTemplate(target, template, dst_img, MatchTemplateMethod.CCorrNormed);
           
            //相関係数の最大値と最小値を取得
            Cv.MinMaxLoc(dst_img, out  min_val, out  max_val, out  min_loc, out  max_loc, null);
           
            Cv.ReleaseImage(dst_img);

            //相関係数の最大値を返す
            return max_val;
        }

        /// <summary>
        /// 対象画像からテンプレート画像の位置を探す
        /// </summary>        
        private static double TemplateMatch(IplImage target, IplImage template, double limen=0.999)
        {
            IplImage dst_img;
            double min_val, max_val;
            CvPoint min_loc, max_loc;
            CvSize dst_size;

            dst_size = new CvSize(target.Width - template.Width + 1, target.Height - template.Height + 1);
            dst_img = Cv.CreateImage(dst_size, BitDepth.F32, 1);
            Cv.MatchTemplate(target, template, dst_img, MatchTemplateMethod.CCorrNormed);

            Cv.MinMaxLoc(dst_img, out  min_val, out  max_val, out  min_loc, out  max_loc, null);

            if (max_val > limen)            
                Cv.Rectangle(target, max_loc,new CvPoint(max_loc.X + template.Width, max_loc.Y +template.Height),new CvScalar(0,0,250),3);                
           
            Cv.NamedWindow("Image", WindowMode.AutoSize);
            Cv.NamedWindow("Image2", WindowMode.AutoSize);
            Cv.ShowImage("Image", target);
            Cv.ShowImage("Image2", template);

            Cv.WaitKey(0);
            Cv.DestroyWindow("Image");
            Cv.DestroyWindow("Image2");  
            Cv.ReleaseImage(dst_img);

            return max_val;
        }
    }
}

今回の本当の目的はちょっとぴーぴーぴーなことなので詳しくはまあアレなのですが、
OpenCVの便利さ、そして手軽さはすごいなあと。

Dansette