2012/05/08

iPhone用ゲーム「ビー玉ころころ」公開

「iPhoneのsafariから差速度センサを使う」 のビー玉を転がすサンプルを拡張してWebアプリでゲームを作ってみました。

  • http://k-games.appspot.com/bcoro/

iPhone/iPodTouch専用です。iOS5でしか確認していないのですが Android でも動きそうな気がするので動作報告等して頂けると ありがたいです。

一応、「マーブル・マッドネス」を目指したのですがマップが平面なので だいぶ違う感じのものになってしましました。

それでも思いのほかスムーズに動作していて遊べる物になっています。 効果音はどうやっても安定しないので今回は諦めました。

マップエディタも作ったのでユーザ向けにも開放してあります。 Googleアカウントが有れば独自のマップが作れますのでぜひ作って見て下さい。



実装について:

jQuery はさすがに重いと思ったので裸の JavaScript で実装しています。

画面は Canvas を使わず img タグを動かしています。 描画性能的にどちらが良いのかはまだ良く分からないのですが、 次は Canvas を使って試して見ようかと思っています。

以外に面倒だったのが当り判定で、ビー玉同士が当って弾かれる方向などは 三角関数が必要で学生時代に頭を戻して何とか違和感の無いようにしました。

マップやスコアの保存はGAEを使っています。 単純なデータの保存先として使う分には課金が発生することは無さそうです。


2012/04/29

実行中のJavaScriptパス名の取得

備忘録。

汎用的なJavaScriptライブラリを書いていると呼び出し元の HTMLファイルのパスに依存しないJavaScriptファイルのパスが 欲しくなる事がある。 (リソースとか依存JS/CSSとか)

通常の方法は無さげなのだがなんとかならないかと思って 調べてみたらこんなのが出て来た。

  • 参考1:http://littlebravehero.blog13.fc2.com/blog-entry-242.html

実行時点で document ツリーの最後に有る script タグが実行中の JS だろって事らしい。
スゲー乱暴な気がするがとりあえず試してみる。

function absPath(path) { if (!(path.match(/^\//) || path.match(/^https?:/i))) { var scripts = document.getElementsByTagName("script"); path = (scripts[scripts.length-1].src).replace(/[^\/]*$/,path); } return path; } alert(absPath("resource.path"));

ちゃんと http://localhost/js/resource.path が返って来ました。
ブラウザ依存な気がしたのでググたら既に調べた人がいて大体OKらしいです。

  • 参考2:http://d.hatena.ne.jp/Climber/20070711/1184115807

つー訳でこれは「有り」って事にしたいと思います。


2012/04/16

jQueryMobile+iPhone で QUnit を使う。

jQuery Monile 1.1.0 に対応した JQMDP-1.0rc2 を googlecode に置きました。
  • http://code.google.com/p/jqmdp/downloads/list

本題。
JavaScriptのテストコードってどうすれば良いかと調べると QUnit って言うのが見付かった。
  • 本家:http://docs.jquery.com/Qunit
  • 参考:http://d.hatena.ne.jp/Jxck/20100721/1279681676
使い方はほぼ JUnit と同じ。
特殊なのは JavaScript はスレッドが使えないので非同期処理をするための 仕掛けが用意されている事くらい。

参考サイトは非常に良くまとめてくれるいるので先に参照して欲しい。

で、現実的なテストの場合、アプリとテストコードは分離したいので 別Window(又は iframe)でテストアプリを起動してやる必要がある。

参考サイトにはこの辺の解説が無かったので自分で調べてみた。

本家サイトのデモを見ると基本系はこんな感じだが

module("Module name"); test("test1", function() { equal( true, true, "passing test" ); }); test("test2", function() { equal( true, false, "failing test" ); });

module()関数の第2引数にオプションを指定すると開始と終了をフックできる。

module("Module name", { setup: function(){ 開始処理 }, teardown: function{ 終了処理 } }); test("test1", function() { // ここで this は module()第2引数になる。 });

なのでおおざっぱに考えると

  • setup() で window.open("アプリURL");
    • onload でテスト起動
  • teardown() で window.close();
してやれば良さげ。

具体的にはこうなった。

var Sandbox = function(url){ this.url = url; this.win = null; this.onload = []; this.autoClose = true; } Sandbox.prototype = { setup: function() { var self = this; this.win = window.open(this.url, "_blank"); this._onload = function(){ var $handle = $(self.win.document); for (var i=0; i<self.onload.length; i++) { self.onload[i]($handle, self); } }; function checker() { if (self.win.document.readyState == "complete") { self._onload(); } else { setTimeout(checker, 50); } } setTimeout(checker, 100); }, teardown: function() { if (this.autoClose) this.win.close() }, load: function(callback){ this.onload.push(callback); } }; module("module name", new Sandbox("アプリURL")); test("test1", function() { stop(); this.load(function($sandbox){ // Sandbox.load() start(); same($sandbox.find("#id").val(), "正解", "項目詳細"); }); });

IEは別 Window の onload が取れないのでしかたなくポーリングにした。 IEいらないなら this.win.onload = function(){...} で良いはず。

Sandbox.load()で設定したコールバックが別Windowの onload で呼ばれるので、 引数の $sandbox (別Windowの$(document))から値を引っ張り出してチェックすれば良い。

PC の Chrome, IE, Safari で動作が確認できた。
が、残念ながら iPhone では動かなかったので iframe に変更してみた。

$(function(){ $(document.body).append($("<iframe id='sandbox'></iframe>")); }) var Sandbox = function(url){ this.url = url; this.win = null; this.onload = []; this.autoClose = true; } Sandbox.prototype = { setup: function() { var self = this; var ifr = document.getElementById("sandbox"); this.win = ifr.contentWindow; function onload(){ var $handle = $(self.win.document); for (var i=0; i<self.onload.length; i++) { self.onload[i]($handle, self); } }; ifr.onload = onload; // for IE ifr.onreadystatechange = function(){ if (this.readyState == "complete") { onload(); } }; ifr.src = this.url; }, teardown: function() { }, load: function(callback){ this.onload.push(callback); } };

iframe だとちゃんと iPhone でも QUnit が動いた。(iOS5、他未確認)

デバックは別Windowの方がやり易いので切替えられるようにしたいかな。

あと、普通のWebアプリのテストにも使えそうなので環境が面倒な Selenium の代わりになりそうに思います。


2012/04/15

jQuery Mobile 1.1.0 Final がリリースされてた

昨日、jQuery Monile 1.1.0 の正式版がリリースされていたようです。

rc2 で試してましたが iPhone でもスクロール時にフッターが
ガクガクしなくなったのでそれだけでも乗り換えの価値有りです。

JQMDP の移行では内部APIを使っていた所以外は変更無かったので
通常は差し替えだけでいけるんじゃないかな。



2011/12/25

JavaScriptからPicasaにアクセス

#やっと抜歯の痛みが引いて来たよ。一部歯茎の腫れが引かないけど..

iPhone は safari から画像の Upload が出来ないんで JavaScript から画像ライブラリにアクセスする方法を探していたんだけど Picasa の webapi で出来る事が分かった。

参考サイト:

  • http://tnker.com/?p=1996
  • http://code.google.com/intl/ja/apis/picasaweb/docs/2.0/developers_guide.html

GoogleにはJavaScript用のライブラリは用意されていないようだが WebAPI なので直接叩けばなんとかなる。

しかも公開設定になっているアルバムはユーザ名がわかればログインしなくても 参照できる事が分かった。

アルバム一覧の取得

http://picasaweb.google.com/data/feed/api/user/${email}?kind=album&alt=json

このURLの${email}にGMailのアドレスを入れてGETすればアルバムの一覧がJSONで帰ってくる。

大事なとこだけ抜粋:

{ "encoding": "UTF-8", "feed": { "author": […], "category": […], "entry": [ { … "gphoto$access": {"$t": "public"}, … "gphoto$id": {"$t": "5684368764816860881"}, … "media$group": { "media$thumbnail": [ { "width": 160, "height": 160, "url": "http://lh4.ggpht.com/….jpg", } ], } }, … ], } }

entry
アルバムのリスト
gphoto$access
public/private
ログインしてると自分のprivateは見えちゃうのでpublicのチェックが必要。
gphoto$id
アルバムのID。
media$thumbnail
アルバムのサムネイル情報

アルバム内写真一覧の取得

http://picasaweb.google.com/data/feed/api/user/${email}/albumid/${album_id}?alt=json

このURLの${email}にGMail、${album_id}に上記のアルバムIDを入れてGETすれば写真の一覧がJSONで帰ってくる。

大事なとこだけ抜粋:

{ "encoding": "UTF-8", "feed": { "author": […], "category": […], "entry": [ { … "content": { "src": "http://lh4.ggpht.com/…/xxxxxx.JPG", "type": "image/jpeg" }, … "gphoto$access": { "$t": "public" }, … "media$group": { … "media$thumbnail": [ { "height": 54, "width": 72, "url": "http://lh4.ggpht.com/…/s72/xxxxxx.JPG", }, { "height": 108, "width": 144, "url": "http://lh4.ggpht.com/…/s144/xxxxxx.JPG", }, { "height": 216, "width": 288, "url": "http://lh4.ggpht.com/…/s288/xxxxxx.JPG", } ], } }, … ] } }

entry
写真のリスト
content.src
写真のURL
gphoto$access
public/private
media$thumbnail
写真のサムネイル情報。3サイズ。

JavaScriptからの呼び出し

普通に呼び出そうとするとXSSになるのでJSONPを使う。 具体的には callback をURLパラメータに追加するだけで良い。

jQuery から使う場合は $.getJSON を使わず $.ajax で dataType:"jsonp" とする。

例:

var URL_ALBUM = "http://picasaweb.google.com/data/feed/api/user/${user}?kind=album&alt=json"; var url = URL_ALBUM.replace(/[$][{]user[}]/,self.user); $.ajax({ url:url, cache:true, dataType: "jsonp", error: function(xreq,stat,err) { alert("load error:"+err+" "+url); }, success: function(json, type) { var list = []; for (var i=0; i<json.feed.entry.length; i++) { var e = json.feed.entry[i]; if (e.gphoto$access.$t == "public") { list.push({ thumbnail: e.media$group.media$thumbnail[0].url, albumid: e.gphoto$id.$t }); } } self.albums = list; } });

サンプル

JQMDPで作ったサンプル。

画像をクリックしてアルバムの一覧へ

アルバムのサムネをクリックして写真の一覧へ

写真をクリックすると元の画像が選択したものに差し変わる。


2011/10/18

CSS だけでサムネイル表示。

HTML5 ならCSSだけでサイズ補正したサムネイル表示が 出来ないかと思って調べて見たのだができないっぽい。

JavaScript を使えば出来るは明白なのだが サムネイルがリストだったりすると結構めんどくさいので 何とかCSSだけでごまかす方法を考えてみた。

imgタグは縦横比を変えないで縮小するには幅か長さの どちらかしか指定できない。 両方指定すると変形してしまう。

なので縦幅のみをサムネイルに合わせて横がはみ出た場合は overflow: hidden; で隠して中心部分を表示するようにしてみた。 (縦横は逆も可)

=>
=>

いい感じだ。
よっぽど要件が厳しくないかぎり許容範囲ではないだろうか。
ちなみに毎度の事ながら IE7 では動かない。

ソース:

<style> span.Thumbnail{ width:72px; height:72px; border: 1px solid black; display: inline-block; overflow: hidden; background-color: black; } span.Thumbnail > div{ width:216px; height:216px; margin-top: -72px; margin-left: -72px; display: block; } span.Thumbnail > div > div{ width:216px; height:216px; display: table-cell; text-align: center; vertical-align: middle; } span.Thumbnail img{ /*width: 72px;*/ height: 72px; display: block; margin: auto auto; } </style> <table> <tr> <td align=center> <img border=1 height="200" src="/old/img/auone/LOVELOG_IMG/TS3M0018.JPG"/> </td> <td>=></td> <td> <span class="Thumbnail"> <div><div><img src="/old/img/auone/LOVELOG_IMG/TS3M0018.JPG" /></div></div> </span> </td> </tr> <tr> <td> <img border=1 width="200" src="/old/img/auone/LOVELOG_IMG/100328_kebabu-1.JPG"/> </td> <td>=></td> <td> <span class="Thumbnail"> <div><div><img src="/old/img/auone/LOVELOG_IMG/100328_kebabu-1.JPG" /></div></div> </span> </td> </tr> </table>

2011/09/30

jsLex が 404 Not found に…

EclipseでJavaScriptファイルを最小化するプラグインをググったら jsLex と言うのが定番らしい。

しかし、リンクをクリックしたら 404 Not found。
あれっと思って別のページのリンクを叩いても 404。
どこかに引っ越したわけじゃなく無くなっちゃたらしい。

代替のプラグインも見付からない...

最小化自体は YUIComplessor で出来るようなので ant でやろうと思ったら何と AntTask が付いて無い。

YUIComplessor の Anttask は幾つか公開されていたが どれも今一な感じなので自前で作ってみた。

使い方はこんな感じ。

<taskdef name="yuicompress" classname="org.kotemaru.yui.YuiCompressTask" classpath="lib/yuicompress-ant-task.jar;lib/yuicompressor-2.4.6.jar" /> <target name="all-min.js"> <concat destfile="tmp/all.js" > <fileset dir="js/modules" /> </concat> <yuicompress file="js/all-min.js" verbose="true" type="js" charset="utf-8" column="40" munge="true" semi="false" optimize="true" > <fileset file="tmp/all.js" /> </yuicompress> </target>

オプションは CUI と一対なので以下を参考にしてください。

Usage: java -jar yuicompressor-x.y.z.jar [options] [input file] Global Options -h, --help Displays this information --type <js|css> Specifies the type of the input file --charset <charset> Read the input file using <charset> --line-break <column> Insert a line break after the specified column number -v, --verbose Display informational messages and warnings -o <file> Place the output into <file>. Defaults to stdout. Multiple files can be processed using the following syntax: java -jar yuicompressor.jar -o '.css$:-min.css' *.css java -jar yuicompressor.jar -o '.js$:-min.js' *.js JavaScript Options --nomunge Minify only, do not obfuscate --preserve-semi Preserve all semicolons --disable-optimizations Disable all micro optimizations

concat 機能も一緒に付けたかったが面倒臭くなったのでパス。

ソース抜粋:

package org.kotemaru.yui; import java.util.ArrayList; import java.util.List; import org.apache.tools.ant.BuildException; import org.apache.tools.ant.DirectoryScanner; import org.apache.tools.ant.Task; import org.apache.tools.ant.types.FileSet; import com.yahoo.platform.yui.compressor.YUICompressor; public class YuiCompressTask extends Task { private ArrayList<FileSet> filesets = new ArrayList<FileSet>(); private String file; private boolean verbose = false; private String type = null; private String charset = null; private int column = 0; private boolean munge = true; private boolean semi = true; private boolean optimize = true; public FileSet createFileSet() { FileSet fs = new FileSet(); filesets.add(fs); return fs; } public void execute() throws BuildException { if (file == null) throw new BuildException("Require file attribute."); try{ _execute(); } catch(Exception e) { throw new BuildException(e); } } private void _execute() throws Exception { List<String> argList = new ArrayList<String>(32); opt(argList, "-o", file); if (type != null) opt(argList, "--type", type); if (charset != null) opt(argList, "--charset", charset); if (column > 0) opt(argList, "--line-break", ""+column); if (verbose) opt(argList, "--verbose", null); if (!munge) opt(argList, "--nomunge", null); if (!semi) opt(argList, "--preserve-semi", null); if (!optimize) opt(argList, "--disable-optimizations", null); for (FileSet fs : filesets) { DirectoryScanner ds = fs.getDirectoryScanner(getProject()); String dir = ds.getBasedir().getPath(); String[] files = ds.getIncludedFiles(); for (int i=0; i<files.length; i++) { String inFile = dir+"/"+files[i]; argList.add(inFile); } } log("YUICompressor"+argList); YUICompressor.main((String[])argList.toArray(new String[0])); } private List<String> opt(List<String> list, String a1, String a2) { list.add(a1); if (a2 != null)list.add(a2); return list; } // setter 略 }

ソース:

  • https://kotemaru.googlecode.com/svn/trunk/yuicompress-ant-task/

2011/09/25

フリガナ自動入力支援

フォームの項目でフリガナってっ結構うざい。
同じ内容を2回入力するって言うのがイラっとするんだと思う。

自動で入力する方法が無いかググってみたところ 以下のページで面白い方法をやっていた

  • http://ceo.sourcelab.jp/archives/97

IMEの入力途中の状態が input タグの値に入っているので それをフリガナの input タグに javascript でコピーするという方法。

このページのコードは実験的な物のようなので jQuery プラグインで 書き直してみた。

使い方:

$(function(){ var form1 = document.form1; $(form1.kanji).furikana("init",{target: form1.kana}); }); </script> : <form action="" name="form1"> Kanji:<input name="kanji" value="" /><br/> Kana:<input name="kana" value="" /> </form>

こんな感じになる。

BS 等で破綻した場合は※を入れてバリデーションエラーとなるようにした。

「BS」

不完全ではあるがなんとか実用範囲内の挙動ではないだろうか。

実はこのコードはボツになった。 スマホで日本語入力するとフリガナを全て入力する前に 漢字の候補が決定しまうため全く使い物にならないのだ。

結局、サーバ側の kakasi で変換して戻すことにした (´・ω・`)ショボーン

とは言え、PC用サイトなら御手軽な方法ではあるので残して置こう。

ソース: furikana.js


プロフィール
20年勤めた会社がリーマンショックで消滅、紆余曲折を経て現在はフリーランスのSE。 失業をきっかけにこのブログを始める。

サイト内検索

登録
RSS/2.0

カテゴリ

最近の投稿【javascript】

リンク

アーカイブ