2013年6月14日金曜日

Magic Trackpad のボタンが埋まる

Magic Trackpad を使っているのですが、先日から調子が悪いです。
左下のゴムのスイッチ部分が埋まった(沈んだ)感じになり、
クリックしてもカチカチしてくれません。
少し力を入れて押せばボタンが押されるのですが、
押し心地がとても悪いです。

いつも親指で左下のボタンを押していたので、
負荷がかかっていたのかも。



確か保証期間内なので Apple Store へ持って行ってみようかと思っているのですが、
なぜか Tackpad だけ箱が見当たらず・・・汗。

実は Magic Mouse もおかしくて、クリックはできるもののマウスカーソルが動かない状態です。
こちらは保証が切れているので放置中。

インタフェースが不調だとちょっとテンション下がりますね。

2013年6月13日木曜日

Go で整数をバイト配列に変換する

Go で int64 などの整数を []byte へ変換する方法です。
encoding/binary パッケージを使います。
package main

import (
    "encoding/binary"
    "fmt"
)

func main() {
    src := int64(123456789123456789)
    result := make([]byte, binary.MaxVarintLen64)
    binary.PutVarint(result, src)
    fmt.Printf("Bytes: %X", result) // Bytes: AAFC82CDF5D2CDB60300
}

変換後の []byte のサイズが小さいとクラッシュしてしまいます。
binary パッケージに変換元のデータ型に合わせて []byte の長さが定義されています。
int64 を変換するなら binary.MaxVarintLen64 といった具合です。

変換では各バイトの先頭ビットを continuation bit として使用しているため、
int64 だからといって 8 バイトになる訳ではなく、決め打ちするとクラッシュすることがあります。

binary package source - Go Lang
http://golang.org/src/pkg/encoding/binary/varint.go?m=text

2013年6月12日水曜日

Go で Unix タイムの取得

Go言語では time パッケージを使って現在の Unix タイムを取得出来ます。
import (
    "time"
    "log"
)

log.Printf("UnixTime: %d", time.Now().Unix())
log.Printf("UnixTimeNano: %d", time.Now().UnixNano())

time.Now() で現在時刻を取得し、Unix()でUnixタイムに変換しています。
UnixNano() にするとナノ秒で表示できます。

2013年6月11日火曜日

JavaScript で Base64 エンコード

結局使わなかった。

Base64 - Wikipedia
http://ja.wikipedia.org/wiki/Base64

/**
 * 文字列をBase64エンコードする
 * @function
 * @param {String} str エンコード前の文字列
 * @returns {String} エンコードされた文字列
 */
encodeBase64: function(str) {

    // バイト配列に変換
    var bytes = [];
    var char = 0;
    for(var i =  0; i < str.length; i++) {
        char = str.charCodeAt(i);
        for(var j = 0; j < 8; j++) {
            bytes.push((char & 0x80) >>> 7);
            char = char << 1;
        }
    }

    // 6bit で割り切れるようにビットを追加する
    var surplus = bytes.length % 6;
    for(var i = 0; i < 6 - surplus; i++) {
        bytes.push(0);
    }

    // 6bit ごとにグループ化
    var groups = [];
    for(var i = 0; i < bytes.length / 6; i++) {
        groups[i] = parseInt(bytes.slice(i * 6, i * 6 + 6).join(''), 2);
    }
  
    // 変換する
    var result = "";
    var Base64Table = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L',
        'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a',
        'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
        'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4',
        '5', '6', '7', '8', '9', '+', '/'];
    for(var i = 0; i < groups.length; i++) {
        result += Base64Table[groups[i]];
    }
 
    // 4 で割り切れる文字数へ = を追加して調整する
    var surplus = result.length % 4;
    for(var i = 0; i < surplus; i++) {
        result += '=';
    }
  
    return result;
}

2013年6月10日月曜日

GAE で複数のアプリを1つにまとめる

Google App Engine は無料で使える Web アプリのホスティングサービスです。
データベース(data store)やユーザ認証などのサービスが付いています。
サーバサイドの言語として Python, Java, Go, PHP が使えます。

Google App Engine - Google
https://developers.google.com/appengine/?hl=ja

ただし、無料アカウントの場合は 10 個までしかアプリを作成できません。
ちょっとしたミニゲームやツールを次々に公開していては、
すぐに 10 個を超えてしまいます。

そこで、ミニゲームやツールをまとめて 1 つのアプリ内に配置するのがお勧めです。
1 つのアプリ内に複数のディレクトリを作って、リクエストされたURLパターンから振り分けることができます。

ただし、GAE では 1アプリに付きデータベースが 1 つしか使えません。
単純なランキングなら1つのデータベースにまとめていれてしまっても問題ないのですが、複雑な操作をする場合は別のアプリとして独立させたほうが良いでしょう。

以下、実際に1つのアプリ内に複数アプリを共存させる方法です。


ディレクトリの配置

今回は okanoworld というアプリ内に複数のアプリを共存させてみます。
okanoworld 直下に複数のミニゲームディレクトリを置きます。
ミニゲームとは別に sever というディレクトリを作っておきます。

okanoworld の中に reversi3ds を配置



URLによる振り分け

app.yaml の header: ディレクティブでURLパターンとファイルパスを関連付けます。
http://okanoworld.appengine.com/アプリ名
でアプリのファイルが参照できるようにします。

app.yaml
application: okanoworld
version: 1
runtime: go
api_version: go1

handlers:

# リバーシ for 3ds
- url: reversi3ds
  static_files: reversi3ds/index.html
  upload: reversi3ds/index.html
- url: /reversi3ds
  static_dir: reversi3ds

# アプリその2
......

url に reversi3ds を指定することで http:okanoworld.appspot.com/reversi3ds に対する設定ができます。
まず、 reversi3ds をリクエストした時に index.html が表示されるように設定しています。
更に、画像ファイルなどのリソースへアクセスできるようにディレクトリ自体を static_dir に設定しています。


リソースの参照

アプリ内で画像などのリソースを読み込む場合は、
先ほど設定した URL パターンに合わせて以下のように書く必要があります。
<img src="/reversi3ds/hoge.png" />

これは <base> で相対パスの基準を変えることによって、簡単に出来ます。
<head>
    ...
    <base href="/reversi3ds/">
    ...
</head>
<body>
    ...
    <img src="hoge.png" />
    ...
</body>

GAE 以外からアプリを持ってきた場合、<base> を加えるだけでいいので楽ちんです。
以上で複数のミニゲームやツールを1つのアプリにまとめることができました。

2013年6月9日日曜日

3dsブラウザで blur が効かない

3ds のウェブブラウザでは、画面上に <button> や <input> や <a> などがあるとき十字キーでフォーカスを合わせることができます。

フォーカスを合わせると青いラインで囲われて、その状態でAボタンを押せばイベントが発生します。

十字キーでフォーカスが当たる

Bボタンを押すとフォーカスが解除されます。

この Bボタンの動作をJavaScriptから発生させる方法がわかりません。
他のブラウザなら blur イベントを使ってフォーカスを外すことができるのですが、
3ds では blur に反応してくれません。

フォーカスが当たっている状態で、CSS の display を none にして画面から消すと、
青い枠は消えてくれます。
しかし、display を block にして再表示すると、十字キーでフォーカスが合わなくなってしまいます。
この場合、画面上を1度タッチすることで、再びフォーカスを合わせることができるようになります。
内部で選択状態を保存していて、CSS を操作するだけではダメなようです。

ゲーム内のボタンやメニューを十字キーで操作させたいときは、
<div> タグと JavaScript で自分で作成するのが良いと思います。
リバーシ for 3DS では、メニューはすべて <div> にしています。

2013年6月8日土曜日

リバーシ for 3DS を公開

Nintendo 3DS のウェブブラウザで遊べるリバーシを公開しました。

公式サイト: http://yokano.github.io/reversi3ds/
アプリ本体: http://okanoworld.appspot.com/reversi3ds
(アプリは 3ds のウェブブラウザ専用です)

MITライセンスです。公式サイトからソースコードが落とせます。

3DSのWebブラウザ上で動きます

十字キーとAボタンで操作出来ます


ウェブアプリですが、十字キーとAボタンで遊べます。
もちろんタッチペンでも操作出来ます。
CPU と対戦することができます。1台で2人対戦することもできます。
2人対戦はタッチペンが2本あるとやりやすいかも。

十字キーの上下で画面がスクロールされないようにコンテンツを下画面にフィットさせています。(320x212px)
イベントのコールバック中に return false; しても、
preventDefault() してもイベントがキャンセルできないため、
コンテンツを2画面に広げてしまうと十字キーの上下でスクロールが発生してしまいます。
2画面で十字キーの上下を使えれば理想なのですが・・・。

Canvas は使わず DOM で動作しています。
アニメーションはスプライトを作成して、CSS の background-position を操作しています。
3ds は @keyframe にも対応しているのですが、step() を指定できずパラパラアニメができません。
結局、JavaScript から定期的に background-position を操作しています。
アニメはすべて CSS でやりたいのですが、良い方法が無いものか・・・。