MikuMikuWatch製作記
この記事は「coins Advent Calendar 2014」の14日目の記事です。
AdventCalendarから来られた方のために簡単に自己紹介します。
ねぎです。3編生です。概念としての初音ミクが好きです。
What is "MikuMikuWatch" ?
MikuMikuWatchとは、開発中のAndroid Wear向けアプリケーションです。
腕時計型の端末の画面上に、時計と一緒に初音ミクを映します
→ 日常生活の中でふと時計を見ると、初音ミクが生活している様子が伺えます
→ 幸せになります
→ やったぜ。
製作記
- 10月初頭、ひらめいた
MikuMikuWatch作ります
— ねぎ (@negi_magnet) October 2, 2014
時間帯によって絵が変わって、ミクさんの生活が垣間見れるイメージ
— ねぎ (@negi_magnet) October 2, 2014
- ゴリゴリ実装する
いいんでねーの pic.twitter.com/6XOV1MqXhZ
— ねぎ (@negi_magnet) October 2, 2014
(ドット絵なのは自分がドット絵じゃないとまともに描けないからです)
進捗です(寝起き→朝食) http://t.co/zmVbNLdKcF
— ねぎ (@negi_magnet) October 3, 2014
時間帯によって絵が変わります
- 権利的にはクリプトンファミリーいけるんだよな…
リンちゃんなう #MikuMikuWatch pic.twitter.com/N9VKjZOsXN
— ねぎ (@negi_magnet) October 14, 2014
製作で困ったポイント
- 初音ミクという概念の具現化
初音ミクの1日の生活について考える必要がある
— ねぎ (@negi_magnet) October 2, 2014
— ねぎ (@negi_magnet) October 3, 2014
同じ睡眠でも布団で寝るのとプラグ差してスリープモードに入るのぐらい変わってくる
— ねぎ (@negi_magnet) October 3, 2014
初音ミクというのは外見と声以外の公式設定がほぼ存在せず、1人1人が考える初音ミクというのには差異があります。
そのため、このアプリで初音ミクの1日を描くというときに、「これは自分が考える初音ミクであって、真の初音ミクではないのではないか…?」という疑念と葛藤に襲われました。
(考えている本人は大真面目です)
最終的に、このアプリに登場する初音ミクは自分が考える初音ミクであると割り切りました。
- 圧倒的絵心不足
- 320x320というキャンパスに対して32x32のドット絵を貼り付けていくスタイル
- 描いていくうちに絵柄が変わってきて昔のを描き直したりしてるとつらいことになった
現状
- プログラムはほぼ完成しました
- 絵を描く時間とスピードが足りないッ…!
- ということで製作停滞中。描ききったらGoogle Playに出したいです
- (2015/7/25追記) Google Playで公開しました
https://play.google.com/store/apps/details?id=negi.magnet.mmw
ハル研プロコン2014参加記
ハル研究所プログラミングコンテスト2014に参加してました
400万点の壁を超えられなかった(かなしい)
工夫点
Uターンするような蓮の配置のとき
- 定期的に加速していると蓮を通りすぎてしまうことがあり、大きなロスになる(先輩忍者がよく通り過ぎてる)
- 蓮を踏んだ瞬間に次の蓮の方向へ加速することで、Uターン時のロスを最小限に
- Uターンしない時も踏んだ瞬間に加速していると勿体無いことがあるので、角度によって加速するか場合分けした
- かなり効果があった
なるべく内側を掠めるように蓮を踏む
- 去年もやったなーとか思いつつ。それなりに効果があった
先輩忍者との衝突回避
邪魔なんだよ先輩!- 数ターン後の位置まで推定して、このままの速度で進むと衝突しそうなら角度を最小限だけ変えて回避するように実装した
- わりと実装がんばったけど使わないほうがスコアが良かったので使わなかった(つらい)
最初にスタートダッシュ
- 最初は先輩が全力疾走するので、1つ目の蓮のあたりで先輩同士が衝突し合って非常にごたごたする
- ゆっくり行ってごたごたに巻き込まれるより、サッと踏んでサッと次に向かった方がいいのでは? ということで実装
- ただし加速回数を大きく消耗するので、初期配置的に2つ目の蓮にサッと向かえなさそうなら止めたり、1つ目までの距離が長いときは止めるようにしてある
- 若干の効果があった
余裕があったら加速
- ゴール時に加速度が残っているのは勿体無い。MOTTAINAI
- 残りの蓮の数を計算し、加速回数に余裕がありそうなら加速頻度を高めた
- 主に小規模なコースで効果を発揮
場の流れの考慮
- 単純に目標地点から引いてみたらいい感じに動いたのでそうしておいた
javascriptとSPARQLでオープンデータをいじくる
オープンデータ・アプリコンテストが気になったので、とりあえずjavascriptからSPARQLを使ってオープンデータで遊んでみました
SPARQLってなんぞや
SPARQLはクエリ言語で、データベースを扱うためのSQLと似たようなものです。
SQLがデータベースを操作するなら、SPARQLはオープンデータを操作します。(SPARQLは検索だけですが)
文法とかについては割愛しますが、なんとなく雰囲気を掴むならCodeIQの問題が分かりやすかったです。
がっつり学ぶなら公式ドキュメントの和訳サイトでしょうか。
あと、SPARQLで遊びたいだけならDBpediaとかがあります。
javascriptからSPARQLを使うには
SPARQLは、エンドポイントと呼ばれるURIにGETリクエストでクエリを送りつけると、クエリに応じたjsonとかxmlとか(指定可能)が返ってきます。
あとはjavascriptの方でjson(またはxml)を解析することでオープンデータとキャッキャウフフできます。
最小限のサンプルコード
javascriptでSPARQLのクエリを鯖江市のエンドポイントに送り、返ってきたjsonをそのまま文字列として表示します。
鯖江市が提供しているオープンデータについては、こことかここを参考にしています。
(※GRAPHについてはいまいち分かってないです)
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>sparql</title> <script type="text/javascript" src="http://code.jquery.com/jquery-2.0.3.min.js"></script> <script type="text/javascript"> // GETリクエストを送信 $.get( "http://sparql.sabae.jrrk.org/data/sparql", // エンドポイント {query:"\ PREFIX schema: <http://schema.org/> \ SELECT ?desc ?img \ WHERE { \ GRAPH ?g { \ ?id schema:description ?desc. \ ?id schema:image ?img. \ } \ } limit 20 \ "}, // クエリ(説明文と画像を最大20件まで要求) success, // 返ってきたデータを処理する関数 "json" // 返ってきてほしいデータの形式 ); // getリクエストで得たdataを処理する function success(data) { // 文字列に変換 var html = JSON.stringify(data); // そのまま表示 $("#disp").html(html); } </script> </head> <body> <div id="disp"></div> <p>このアプリケーションは、以下の著作物を改変して利用しています。<br> 鯖江市、さばかん、クリエイティブ・コモンズ・ライセンス 表示 2.1 日本(http://creativecommons.org/licenses/by/2.1/jp/)、オープンデータ・アプリコンテスト利用規約(http://www.opendata.gr.jp/2013contest/terms/index.html#rules)</p> </body> </html>
「{"head":{"vars":["desc","img"]},"results":{"bindings":[{"desc":{"type":"literal","value":"店主が毎朝市場へ…」みたいな文字が出たらうまくいってます。きっと
jsonを解析して体裁を整えたバージョン
success関数の中身を書き換えます。
tableを使って体裁を整えるのと、取得した画像パスから画像を表示します。
function success(data) { var head = data.head.vars; var results = data.results.bindings; var html = "<table>"; for(var i=0; i<results.length; i++) { html += "<tr><td>"; html += results[i].desc.value; html += "</td><td>"; html += "<img src=\""+results[i].img.value+"\"></img>"; html += "</td></tr>"; } html += "</table>"; $("#disp").html(html); }
上記コードによって出来たのがこちら
(追記:上記リンクのプロトコルをhttpsにしていたため表示できないバグがありましたが修正しました)
DXライブラリで多角形を描く (with C++サンプル)
DXライブラリで2Dゲーム作ってるときに、多角形を描く必要が出てきました
しかし、DXライブラリには三角形を描画する関数ならありますが多角形を描画する関数はありません
ということで、多角形を三角形に分割して描くことにしました
どうやって多角形を三角形にするのか?という理論については、こちらのサイトが分かりやすかったです。無断リンクお許しください
Javaゲーム制作記 任意多角形の三角形分割
以下、C++のサンプルコードです
タイトルからDXライブラリって描いてましたが、描画部分を変えれば他のライブラリでも使えます(多分)
なお、このコードは辺と辺が交差していない多角形でのみ使用できます。注意
// ベクトル構造体 struct t_vector{ double sx, sy; double vx, vy; }; // p1からp2へ伸びるベクトルを生成 t_vector makeVector( pair<double,double> p1, pair<double,double> p2 ){ t_vector v; v.sx = p1.first; v.sy = p1.second; v.vx = p2.first - p1.first; v.vy = p2.second - p1.second; return v; } // v1とv2の外積を計算 double cross( t_vector v1, t_vector v2 ){ return v1.vx*v2.vy - v1.vy*v2.vx; } //---------------------------------------------------------- /// @brief 点の集合vの中で、v1,v2で構成される三角形内部に点があるか確認する /// @param v1,v2 : 三角形を構成するベクトル。始点が同じである必要あり /// v : 点の集合 /// @return 1つでも含まれている→true, ない→false //---------------------------------------------------------- bool IsExistPointInTriangle(t_vector v1, t_vector v2, vector< pair<double,double> > &v){ // v2の向き反転 v2.sx += v2.vx; v2.sy += v2.vy; v2.vx *= -1; v2.vy *= -1; // v1の先端からv2の後端に伸びるベクトルv3生成 t_vector v3; v3.sx = v1.sx + v1.vx; v3.sy = v1.sy + v1.vy; v3.vx = v2.sx - v3.sx; v3.vy = v2.sy - v3.sy; // 全ての点について、ベクトルv1~v3の左右どちらにあるか判定していく t_vector *vn[3] = {&v1, &v2, &v3}; for(int i=0; i<v.size(); i++){ t_vector vp; bool outside = false; for(int j=0; j<3; j++){ vp.sx = vn[j]->sx; vp.sy = vn[j]->sy; vp.vx = v[i].first - vp.sx; vp.vy = v[i].second - vp.sy; if( cross( *vn[j], vp ) >= 0 ){ outside = true; break; } } if( !outside ) return true; } return false; } // 三角形構造体 struct t_triangle{ double x[3], y[3]; }; //---------------------------------------------------------- /// @brief 点の集合vで表される多角形を三角形分割し、trisに格納する /// @param v : 多角形を作る点の集合vector。辺が繋がっている順番である必要あり /// tris : 生成した三角形を格納するvector /// v,trisとも、pairのfirstがx座標を、secondがy座標を表す //---------------------------------------------------------- void SplitTriangles(vector< pair<double,double> > v, vector<t_triangle> &tris){ // 三角形が作れなくなるまで繰り返す while( v.size() >= 3 ){ // 原点から最も遠い点を探す int mfar = 0; for(int i=1; i<v.size(); i++){ if( v[mfar].first*v[mfar].first+v[mfar].second*v[mfar].second < v[i].first*v[i].first+v[i].second*v[i].second ) mfar = i; } // 最も遠い点から伸びる2つのベクトルを生成 t_vector v1, v2; v1 = makeVector( v[mfar], v[(mfar+1)%v.size()] ); v2 = makeVector( v[mfar], v[(mfar+v.size()-1)%v.size()] ); // 参考元ではここで180度判定をしていたが、特に必要ない気がするので、はしょる // 三角形内部に点があるとき if( IsExistPointInTriangle(v1, v2, v) ){ // 外積の記録 double cr = cross( v1, v2 ); // 見つかるまでループ while(1){ // 1つ横の点を選ぶ mfar = (mfar+1)%v.size(); // ベクトル生成 v1 = makeVector( v[mfar], v[(mfar+1)%v.size()] ); v2 = makeVector( v[mfar], v[(mfar+v.size()-1)%v.size()] ); // 外積の符号が異なる→ループ最初に戻る if( cr*cross(v1,v2) < 0.0 ) continue; // 内部に点があるか確認 // 点がある→ループ最初に戻る if( IsExistPointInTriangle(v1, v2, v) ) continue; // 点がない→脱ループ break; } } // 三角形の3点を_trisに記録 t_triangle t; t.x[0] = v1.sx; t.y[0] = v1.sy; t.x[1] = v1.sx+v1.vx; t.y[1] = v1.sy+v1.vy; t.x[2] = v2.sx+v2.vx; t.y[2] = v2.sy+v2.vy; _tris.push_back(t); // 選ばれた点をvから除外 v.erase( remove( v.begin(), v.end(), v[mfar] ) ); } } // 描画はこんな感じで void Draw(){ for(int i=0; i<tris.size(); i++){ DrawTriangle( tris[i].x[0], tris[i].y[0], tris[i].x[1], tris[i].y[1], tris[i].x[2], tris[i].y[2], GetColor( 255, 255, 255 ), TRUE ); } }
powerpointでフローチャート描くときの小技
思いついたメモ
<問題点>
情報系の講義の課題で、プログラムのフローチャートを描くことを強いられています(集中線)
フローチャート描くのにはpowerpoint(2007)を使ってるんですが、いつも困ることがありました
それは、下図の赤矢印を描くときです
実際に描いてみてもらえると分かると思うのですが、この矢印をカギ線コネクタで一気に描こうとすると、矢尻を整えるのが面倒くさいです
よく↑みたいな感じで矢尻が歪む
さらに、矢尻を微調整しても、その矢印を少し動かすだけで再びグシャアってなります
募る苛立ち…( ˘ω˘ )
<解決策>
四角形などの図形には、矢印がピタッとひっつくポイントがあります
なので、矢印の先を透明な四角形にひっつけておき、透明な四角形を動かしてやればいいのです
四角形を作り、矢印をピタッとひっつける
矢印が合うように四角形を動かす
四角形の書式設定から、線の色をなくす
すると矢尻がばっちり整ってますし、矢印を動かしても崩れることがありません
さらば苛立ち…( ˘ω˘ )
C++で二次元配列を動的生成する3つの方法
C++で二次元配列を動的生成するには?ということで、思いついた3つの方法
①newする
動的生成といえばnew。C言語ならmallocとかcallocにあたります
以下はint型の二次元配列をnewして使ってdeleteする方法
#include<iostream> using namespace std; int main(){ /* new */ // int*の配列を動的生成 int **arr = new int*[20]; // 配列の各要素でintの配列を動的生成 for( int i=0; i<20; i++ ){ arr[i] = new int[10]; } // 実際に配列を使ってなんやかんや arr[19][9] = 12345; cout << arr[19][9] << endl; /* delete */ // 各要素を先にdelete for( int i=0; i<20; i++ ){ delete[] arr[i]; arr[i] = 0; // ※(記事の最後の方で説明) } delete[] arr; arr = 0; // ※ return 0; }
newをすると必ずdeleteが必要になり、し忘れるとメモリリークを起こします
そんな危険性を含んでいる①、正直おすすめの方法ではありません
②STLのvectorを使う
みんな大好きSTL。C++の標準ライブラリのことです
これを使って二次元配列を動的生成してみましょう
#include<iostream> #include<vector> // vectorを使うにはこれが必要 using namespace std; int main(){ // resize関数を使って動的にサイズを変えれる vector< vector<int> > arr; arr.resize(20); // ()内の数字が要素数になる for( int i=0; i<20; i++ ){ arr[i].resize(10); } arr[19][9] = 12345; cout << arr[19][9] << endl; // deleteのような処理はデストラクタ内で行なってくれるので不要 return 0; }
①より簡単で危険性も減ります。おすすめ
③一次元配列を二次元配列のように使う
最後はこれです。とりあえずサンプルコード
#include<iostream> using namespace std; int main(){ int *arr; // [20][10]の二次元配列を生成 arr = new int[20*10]; // arr[19][9]に代入 arr[9*20+19] = 12345; // arr[19][9]の値を表示 cout << arr[9*20+19] << endl; delete[] arr; arr = 0; return 0; }
幅w,高さhの二次元配列を作りたいとき、w*hの一次元配列を生成します
そして要素[x][y]へのアクセスの際に[y*w+x]とすることで、一次元配列を二次元配列のように扱えます
vectorは使いたくないという人にはこの方法をおすすめします。①よりは単純になります
※について。余談というか補足というか
deleteした後のポインタには0を代入しておくことが望ましいです
というのも、deleteした後のポインタにはnewの時に代入されたアドレスがそのまま格納されているからです
そして、変数aをdeleteした後にnewした変数bのアドレスは変数aと同じであることがあるからです
例えば、下記のようなコード
#include<iostream> using namespace std; int main(){ int *a = new int(); cout << a << endl; // 0x381ee0(自分がテストした時はこのアドレスだった) delete a; cout << a << endl; // 0x381ee0。delete前と同じ int *b = new int(); cout << b << endl; // 0x381ee0。aと同じ *b = 0; cout << *b << endl; // 「0」と表示される *a = 100; // aをdeleteしたことを忘れて、代入すると…(これが怖いから※1の処理をしてる) cout << *b << endl; // 「100」と表示される! delete b; return 0; }
このようなことが発生し、思わぬ所でデータをぶっ壊したりします。やべぇ
そんなことがないように、使い終わったポインタには0を入れることをオススメします
プロキシ環境下でのMacPorts設定
備忘録
MacでPHPの開発環境整えようとしてMacPorts使った時にプロキシで引っかかったのでメモ
(参考:http://destefano.wordpress.com/2011/03/18/macports-behind-a-proxy/)
[問題]
MacPortsで"sudo port install apache2"と入力した際に、こんなエラーが
Error: org.macports.fetch for port apr returned: fetch failed Error: Failed to install apr
[解決法]
/opt/local/etc/macportsディレクトリにあるmacports.confを編集するだけの簡単なお仕事
1.ターミナル上で、"sudo vim /opt/local/etc/macports/macports.conf"と入力
(vimを使ったことがない人は"vim"を"emacs"にしましょう。普通の操作で使えます)
パスワードを求められるので入力する。画面が無反応でいっつも不安になる
2.macports.confの最下部に、プロキシに関する設定をする箇所がある
以下の箇所を変更
・proxy_http、proxy_https、proxy_ftp、proxy_rsync
この4行の先頭にある"#"を削除し、右側に書いてあるプロキシ情報の入力サンプルを書き換える
プロキシのIPアドレスがxxx.xxx.xxx.xxx、ポートがyyyyだとすると、"xxx.xxx.xxx.xxx:yyyy"と書く
ログインが必要な場合、ユーザIDをzzzz、パスワードをwwwwだとすると、"zzzz:wwww@xxx.xxx.xxx.xxx:yyyy"と書く
・proxy_skip
プロキシを適用しない例外サイトを指定できる
先頭の"#"を削除し、右側の入力サンプルにはプロキシを通さなくていいIPアドレスを書く
よく分からなかったらとりあえずlocalhostと書いといたらちゃんと動いたし結果オーライ! #kuzu
3.保存、リトライ、成功L( ^ω^ )┘