WebGLで作った3DネトゲにjQueryで吹き出しチャットを付けてみた
WebGLでヌルヌル動く3Dネトゲを作ってみた
タイトルは釣りだけど、WebGLで3DネトゲっぽいUIを作ってみたよ!
動かし方
まだWebGLに正式対応したブラウザが無いから、開発版のブラウザをインストールする必要があります。めんどくさい!
詳しくはここらへんを見てね。
Getting a WebGL Implementation - WebGL Public Wiki
ここでは一番簡単に使えるChromiumのインストールのしかたを説明します。
- ダウンロードページ(http://build.chromium.org/buildbot/continuous/win/LATEST/)から最新版をダウンロード
- 以下のようにコマンドラインオプションを付けて起動
コマンドラインオプションを付けないとWebGLが有効にならないので注意してください。
あと、OpenGL2.0に対応したグラフィックボードが必要だから、ノートPCとかじゃできないかもよ。
で、ブラウザの準備ができたら下記のURLにアクセス!
http://meengr.sakura.ne.jp/demo/
作り方
ソースを見てね☆
使ったライブラリは以下の通り。
http://www.kelvinluck.com/assets/jquery/jScrollPane/jScrollPane.html
デフォルトのスクロールバーだと見栄えが悪かったので変えるのに使用。
タイヤ買取ナンバーワン、ホイール買取
アイコン画像を使わせていただきました。ありがとう!
Cometeoのサーバ構成を晒してみる
スケールアウトからスケールアップへの回帰:Kenn's Clairvoyance - CNET Japanに対抗して、
Lingrのクローンというかパクりの超高速無料レンタルチャットCometeoのサーバ構成を晒しちゃうよ!
サーバ: さくらインターネット 専用サーバ エントリープラン
CPU: Atom 1.6GHz
メモリ: 1GB
HDD: 160GB
回線: 10M共有
料金: 月額7,800円
これにMySQLとフルスクラッチのhttpd(C++で書いた!)が乗ってる。
DBのバックアップは毎晩AmazonS3に転送して直近7日分を保管。S3の月額は1ドル未満。
で、サービス状況はというと、
月間PV: 8万くらい
同時接続数: ピーク時で350〜400くらい
総チャットルーム数: 5500くらい
総発言数: 340万くらい
CPU: スカスカ
HDD: スカスカ
メモリ: 余裕
回線: 1ルームに200人とか来た日は辛いけど普段はスカスカ
で、ビジネス的にはどうかというと、
アフィリエイト収入: 月3,000円くらい
全然赤字だよ☆
GoでCometチャットサーバを書いてみた
最近流行りのGoでCometなチャットサーバを書いてみたよ!
いちおう動いてるっぽいけど正しいかは知らないよ!
package main import ( "flag"; "http"; "log"; "container/list"; "strconv"; "bytes"; "json"; "time"; ) type post struct { id uint64; name string; comment string; at *time.Time; } type chatData struct { lastId uint64; posts list.List; waits list.List; } type request interface { execute(data *chatData); } type addRequest struct { name string; comment string; } type getRequest struct { id uint64; resCh chan []post; } func (req addRequest) execute(data *chatData) { data.lastId++; p := post{data.lastId, req.name, req.comment, time.LocalTime()}; data.posts.PushBack(p); if data.posts.Len() > 100 { data.posts.Remove(data.posts.Front()); } for ch := range data.waits.Iter() { res := make([]post, 1); res[0] = p; ch.(chan []post) <- res; } data.waits.Init(); } func (req getRequest) execute(data *chatData) { if req.id == data.lastId { data.waits.PushBack(req.resCh); }else{ i := 0; e := data.posts.Front(); for ; e != nil; i,e = i+1,e.Next() { if e.Value.(post).id > req.id { break; } } res := make([]post, data.posts.Len()-i); for i = 0; e != nil; i,e = i+1,e.Next() { res[i] = e.Value.(post); } req.resCh <- res; } } var requestCh = make(chan request) var addr = flag.String("addr", ":8080", "http service address") func backend() { var data chatData; for { req := <- requestCh; req.execute(&data); } } func add(c *http.Conn, req *http.Request) { requestCh <- addRequest{req.FormValue("name"), req.FormValue("c")}; c.WriteHeader(http.StatusOK); } func get(c *http.Conn, req *http.Request){ id,err := strconv.Atoui64(req.FormValue("id")); if err != nil { c.WriteHeader(http.StatusBadRequest); }else{ q := getRequest{id, make(chan []post)}; requestCh <- q; res := <- q.resCh; c.SetHeader("Content-Type", "application/json; charset=utf-8"); var buf bytes.Buffer; buf.WriteString("{\"post\":["); last := len(res)-1; for i,val := range res { buf.WriteString("{\"id\":" + strconv.Uitoa64(val.id) + ",\"name\":" + json.Quote(val.name) + ",\"c\":" + json.Quote(val.comment) + ",\"at\":"+ json.Quote(val.at.String()) + "}"); if(i != last){ buf.WriteString(","); } } buf.WriteString("]}"); c.Write(buf.Bytes()); } } func main() { flag.Parse(); http.Handle("/", http.FileServer("www", "")); http.Handle("/add", http.HandlerFunc(add)); http.Handle("/get", http.HandlerFunc(get)); go backend(); err := http.ListenAndServe(*addr, nil); if err != nil { log.Exit("ListenAndServe:", err); } }