スポンサーリンク

わずか1.7キロバイトのJavaScript マリオ風のゲーム (脱力系)



1.7キロバイトJavaScriptで,一応,右画像のようなスーパーマリオ風のゲームができた。
(1.3キロバイトに改良されました。)



こちらからプレーできます
http://www.name-of-this-site.org/coding/game/aamario.html


遊び方:

  • 右・左キーで移動,上キーでジャンプ
  • 「栗」と「亀」(クリボーノコノコのつもり)は上から踏める。
  • 「棘」(トゲゾー)は踏めない。
  • たまに「砲」(キラー)が飛んでくる。
  • しだいに敵の出現が速くなる。

Firefox3とIE7で動作確認済。


「七行プログラミング」の「七行テトリス」を見て感化された。

わずか565バイトテトリス
http://zapanet.info/blog/item/1130


自分のはその3倍で,22行(×79文字)もあるので,ショートコーディングとは言い難いけども…


下記はソースコードで,テキストにこれだけ貼り付ければ動作する。



1.7キロ版

<body id=d onKeydown=k(event.keyCode-38)><table style=position:absolute height=
100><tr><td width=280 id=td1 valign=bottom><div id=r>○<div id=t>大</div></div>
<td valign=top><p id=g style="position:absolute"></p></table><script>bm=r.vx=r.
vy=r.ax=0;r.ay=-4;b=10;xx=3*(yy=90);py(bm,r);px(20,r);function py(y,e){e.my=yy-
parseInt(e.style.paddingTop=yy-y+"px");}function px(x,e){e.mx=parseInt(e.style.
paddingLeft=x+"px");}function l(s){g.innerHTML=s;}function dpx(dx,e){fx=dx+e.mx
;if(0<fx&&fx<xx){px(fx,e);}else{e.vx=e.ax=0;}}function dpy(dy,e){fy=dy+e.my;if(
bm<fy&&fy<yy){py(fy,e);}else{r.vy=0;py(bm,e);if(!go){t.innerHTML="大";}}}l(n=0)
;j2=false;r.style.position="relative";function te(){cE();mE();}function tm(){r.
kvy=r.vy;r.ky=r.my;r.vy+=r.ay;dpx(r.vx,r);dpy(r.vy,r);}function k(kc){dpx(b*kc,
r);if(kc==0&&(r.my==bm||j2)){r.vy+=b*1.8;t.innerHTML="方";j2=false;}}function v
(){r.vy+=b*3;clearInterval(me);t.innerHTML="出";k=function(){};go=true;}q=15;ae
=[0,0,0,0,0,0,0,0];go=false;setInterval(tm,150);me=setInterval(te,150);function
mE(){for(i=0;i<ae.length;i++){if(ae[i]>0){ee=D.getElementById("e"+i);dpx
((-b)*((i==5)?2:1),ee);if(ee.mx<20){ae[i]=0;d.removeChild(ee);}ey=ee.my-w;if(r.
mx>ee.mx-q*0.1&&r.mx<ee.mx+q*1.3&&r.my>ey-q*1.5&&r.my<ey+q*1.5){if(i%3!=1&&r.ky
>0){ee.innerHTML="☆";ae[i]=0;k(0);j2=true;d.removeChild(ee);ee.innerHTML="";l(
n+=100);}else{v();}}}}}w=-20;D=document;function cE(){if(Math.random()<0.11+(n/
50000)){for(j=0;j<ae.length;j++){if(!ae[j]){ae[j]=1;break;}}if(j<ae.length){kr=
D.createElement("div");kr.id="e"+j;kr.innerHTML=(j==4)?"砲":(j%3==1)?"棘":j%2==
0?"亀":"栗";d.appendChild(kr);px(xx-b,kr);kr.style.position="absolute";py(w+((j
==4)?40:0),kr);}}}</script></body>


キャラクターがかわいいと思う。


遊び方のコツ:

  • 飛行中に左右への移動を駆使する。
  • 右足のあたりで踏むとちょうど倒せる。
  • 無理に倒そうとせず,画面の先を見て,生き残ること優先で進めるとよい。
  • 敵を踏んだ直後に上キーを押して連続ジャンプができる。


コードを少しでも短くするために

  • f(a=b) や a=b=c を多用
  • a?b:c を多用
  • document, bodyなどにも1文字の名前をふる (※これには高速化の効果もある。http://d.hatena.ne.jp/uupaa/20081005/1223196093 test12を参照)
  • 速度や位置などはDOMエレメントそのものに持たせる
  • 動的に追加すると管理が大変になる。かわりに,あらかじめ決めておいた配列の範囲内でローテーションを行なう
  • 関数はエレメント間で汎用に
  • 押されたキーのコードから38引いておき,左右の判別を容易に
  • parseIntで文字列から数値のみ取り出す

など,一般的なコツを心がけた。
evalによる文の使い回しは,後から手がつけられなくなりそうなので控えた。


関数の役割はそれぞれ,

  • px,py : 位置指定
  • dpx,dpy : 差分動作指定
  • tm,te : マリオと敵キャラの動作タイマー
  • cE, mE : 敵キャラを作り,動かす(衝突判定含む)
  • k : キーボード押下イベント
  • gv : ゲームオーバー

となっている。

1.3キロ版

こちらは17行。

<body id=d onKeydown=k(event.keyCode-38)><div id=I height=100 width=280 valign=
bottom><div id=r>○<div id=t>大</div></div></div><p id=g><script>a=-4;b=10;X=3*
(Y=90);D=document;s=setInterval;S=parseInt;H="innerHTML";A="style";p="position"
;O="absolute";g[A][p]=I[A][p]=O;r[A][p]="relative";l(o=B=r.v=J=n=0);Q(B,r);P(20
,r);q=15;E=[0,0,0,0,0,0,0,0];L=E.length;s(G,150);M=s(h,150);w=-20;function Q(z,
e){e.y=Y-S(e[A].paddingTop=Y-z+"px");}function l(z){g[H]=z;}function G(){r.v;r.
K=r.y;r.v+=a;if(B<(F=r.v+r.y)&&F<Y){Q(F,r);}else{r.v=0;Q(B,r);if(!o){t[H]="大";
}}}function h(){if(Math.random()<0.11+n/50000){for(j=0;j<L;j++){if(!E[j]){E[j]=
1;break;}}if(j<L){T=D.createElement("div");T.id="e"+j;T[H]=(j==4)?"砲":(j%3==1)
?"棘":j%2==0?"亀":"栗";d.appendChild(T);P(X-b,T);T[A][p]=O;Q(w+((j==4)?40:0),T)
;}}for(i=0;i<L;i++){if(E[i]>0){c=D.getElementById("e"+i);R((-b)*((i==5)?2:1),c)
;if(c.x<20){E[i]=0;d.removeChild(c);}if(r.x>c.x-q*0.1&&r.x<c.x+q*1.3&&r.y>(C=c.
y-w)-q*1.5&&r.y<C+q*1.5){if(i%3!=1&&r.K>0){E[i]=0;k(0);J=1;d.removeChild(c);c[H
]="";l(n+=100);}else{r.v+=b*3;t[H]="出";clearInterval(M);k=function(){};o=1;}}}
}}function P(z,e){e.x=S(e[A].paddingLeft=z+"px");}function R(z,e){if(0<(f=z+e.x
)&&f<X){P(f,e);}else{e.V=0;}}function k(z){R(b*z,r);if(!z&&(r.y==B||J)){r.v+=b*
1.7;t[H]="方";J=0;}}</script>


変数の説明

/*
A : "style"
a : y方向加速度
B : 画面の底
b : 移動ベース距離
C : 移動させたい敵キャラの正味のy位置
c : 移動させたい敵キャラ
D : document
d : body
E : 敵の利用フラグ配列
e : 関数内での一時変数
F : 移動予定先y位置
f : 移動予定先x位置
G : マリオの毎秒の移動操作
g : ログ出力スペース
H : "innerHTML"
h : 敵の毎秒の移動操作
I : ステージ領域
i : カウンタ
J : 連続ジャンプ可能フラグ
j : カウンタ
K : 一瞬前のy位置
k : キー押下イベント
L : Eの長さ
l : ログ出力
M : 敵キャラを動かすタイマーのID
n : スコア
O : "absolute"
o : ゲームオーバーフラグ
P : x位置セット
p : "position"
Q : y位置セット
q : 衝突判定のあそび
R : x差分移動
r : マリオ全体
S : parseInt
s : setInterval
T : 生成する敵キャラ
t : マリオの胴体
V : x方向速度
v : y方向速度
w : 敵の表示y位置のオフセット
X : x境界
x : x位置
Y : y境界
y : y位置
z : 関数内での一時変数
*/

番外

なお,本格的なJavaScriptマリオをたった14キロバイトで作成した方もいる。
Jacob Seidelinさんである。

NIHILOGIC:Super Mario in 14kB Javascript
http://blog.nihilogic.dk/2008/04/super-mario-in-14kb-javascript.html

非圧縮版ソース
ttp://www.nihilogic.dk/labs/mario/mario.js

圧縮版ソース
ttp://www.nihilogic.dk/labs/mario/mario_compressed.js

aike氏によるコードリーディング
http://d.hatena.ne.jp/aike/20080412

後にその14キロバイトのソースはPNGファイルに埋め込まれ,ファイルサイズは8キロバイトになった。

8KB JavaScriptマリオ
http://d.hatena.ne.jp/aike/20080505

追記

この中途半端なプログラムの作成によって会得したショートコーディングのコツは,下記の記事にまとめました。

JavaScript ショートコーディングの10のコツ
http://d.hatena.ne.jp/language_and_engineering/20081009/1223469525

関連する記事:

あなたが,勝つことも引き分けることもできない三目並べ (jQueryプラグイン「jQuery.fakeTicTacToe.js」によるマルバツ・ゲーム) - 主に言語とシステム開発に関して
http://d.hatena.ne.jp/language_and_engineering/20121204/jQueryFakeTicTacToeJs


日経平均株価の下落ぶりをMIDIサウンドで味わう (コマンドラインでMIDI生成) - 主に言語とシステム開発に関して
http://d.hatena.ne.jp/language_and_engineering/20081027/1225038111


touchではないiPod (mini + nano + classic) で,自作はどこまで可能か - 主に言語とシステム開発に関して
http://d.hatena.ne.jp/language_and_engineering/20081106/1225988771