はてなハイク STAR FIGHTERS
by
lieutar
2010-12-30 [2010/12/30 15:12:55]
はてなハイクで実行すると、星を打ちあう簡単な対戦型シューティングが初まる。カーソルキーで移動、Zで星発射。ESCで終了
@@ -7,8 +7,6 @@
*/
-
-
(function(){
@@ -164,7 +162,7 @@
this._y = y;
this._pre_x = NaN;
this._pre_y = NaN;
- this._spped = 1;
+ this._speed = 1;
this._dx = 0;
this._dy = 0;
this._pdx = 0;
@@ -300,20 +298,21 @@
}, function(SUPER,Class){
this.initialize = function(name){
+
SUPER.initialize.apply(this,[0,0]);
this.name = name;
var img = this.initImage(
'http://www.st-hatena.com/users/' + name.substring(0,2) +
'/' + name + '/profile.gif'
);
- this.setSpeed(5);
- this._move_k = {n:0,s:0,w:0,e:0};
+ this._defaultSpeed = 5;
+ this.setDirection(0, -1);
+ this.setSpeed(0);
this._x =
Math.floor((window.innerWidth - img.clientWidth ) / 2
);
this._y =
(window.innerHeight - img.clientHeight - 10);
- this.setShotDirection(0,-1);
};
this.getHotSpot = function(){
@@ -327,83 +326,99 @@
this.shot = function(){
var pos = this.getPosition();
var bullet = new Bullet(pos.x, pos.y);
- var dir = this.getShotDirection();
+ var dir = this.getDirection();
bullet.setDirection(dir.x, dir.y);
- bullet.setSpeed(this.getSpeed() + 2);
+ bullet.setSpeed(this._defaultSpeed + 2);
};
-
- this.setDirection = (
- function(){
- var timer = null;
- return function(x,y){
- var self = this;
- SUPER.setDirection.apply(this, [x,y]);
- if(x != 0 || y != 0){
- if(timer){
- clearTimeout(timer);
- timer = null;
- } else {
- timer = setTimeout(
- function(){
- self.setShotDirection(x, y);
- timer = null;
- },
- 50);
- }
- }
- };
- })();
-
- this.move = function(dir){
- var _move_k = this._move_k;
- switch(dir){
- case 'n':
- _move_k.n = 1;
- if(_move_k.s > 0) _move_k.s = 2;
- break;
- case 'N':
- _move_k.n = 0;
- if(_move_k.s > 0) _move_k.s = 1;
- break;
- case 's':
- _move_k.s = 1;
- if(_move_k.n > 0) _move_k.n = 2;
- break;
- case 'S':
- _move_k.s = 0;
- if(_move_k.n > 0) _move_k.n = 1;
- break;
- case 'w':
- _move_k.w = 1;
- if(_move_k.e > 0) _move_k.e = 2;
- break;
- case 'W':
- _move_k.w = 0;
- if(_move_k.e > 0) _move_k.e = 1;
- break;
- case 'e':
- _move_k.e = 1;
- if(_move_k.w > 0) _move_k.w = 2;
- break;
- case 'E':
- _move_k.e = 0;
- if(_move_k.w > 0) _move_k.w = 1;
- }
- var x = 0;
- var y = 0;
- if(_move_k.s != _move_k.n){
- y = _move_k.s > _move_k.n ? 1 : -1;
- }
- if(_move_k.w != _move_k.e){
- x = _move_k.e > _move_k.w ? 1 : -1;
+ this.setDirection = function(x, y){
+ if(x == 0 && y == 0){
+ this.setSpeed(0);
+ } else {
+ this.setSpeed(this._defaultSpeed);
+ SUPER.setDirection.apply(this, [x,y]);
}
- this.setDirection(x,y);
};
-
}
);
+
+ var ArrowKeyManager = defclass(
+ {
+ name: 'ArrowKeyManager',
+ base: Object
+ },
+ function(SUPER, Class){
+
+ this.initialize = function(hook){
+ this.pressed = {n:0,s:0,w:0,e:0};
+ this._hook = hook;
+ };
+
+ this.pushKey = function(k){
+ var pressed = this.pressed;
+ switch(k){
+ case 'n':
+ pressed.n = (pressed.s > 0) ? 2 : 1;
+ break;
+ case 's':
+ pressed.s = (pressed.n > 0) ? 2 : 1;
+ break;
+ case 'w':
+ pressed.w = (pressed.e > 0) ? 2 : 1;
+ break;
+ case 'e':
+ pressed.e = (pressed.w > 0) ? 2 : 1;
+ break;
+ }
+ this._hook(this);
+ };
+
+ this.releaseKey = (
+ function(){
+ var timer = null;
+ return function(k){
+ var pressed = this.pressed;
+ switch(k){
+ case 'n':
+ pressed.n = 0;
+ break;
+ case 's':
+ pressed.s = 0;
+ break;
+ case 'w':
+ pressed.w = 0;
+ break;
+ case 'e':
+ pressed.e = 0;
+ }
+ var self = this;
+ if(timer){
+ clearTimeout(timer);
+ timer = null;
+ }
+ timer = setTimeout(
+ function(){
+ self._hook(self);
+ timer = null;
+ },
+ 50
+ );
+ };
+ }
+ )();
+
+ this.getCurrentDirection = function(){
+ var pressed = this.pressed;
+ var x = 0;
+ var y = 0;
+ if(pressed.s != pressed.n) y = pressed.s > pressed.n ? 1 : -1;
+ if(pressed.w != pressed.e) x = pressed.e > pressed.w ? 1 : -1;
+ return {x:x, y:y};
+ };
+
+ }
+ );
var name = document.evaluate(
'.//p[@class="username"]/a/text()',
@@ -413,6 +428,12 @@
null).snapshotItem(0).data;
var user = new User(name);
+ var akman = new ArrowKeyManager(
+ function(){
+ var dir = this.getCurrentDirection();
+ user.setDirection(dir.x, dir.y);
+ }
+ );
document.addEventListener( 'keypress',
function(e){ e.preventDefault();}, false);
@@ -424,16 +445,16 @@
// console.log(e.keyCode);
switch(e.keyCode){
case 37: //LEFT
- user.move('w');
+ akman.pushKey('w');
break;
case 38: //UP
- user.move('n');
+ akman.pushKey('n');
break;
case 39: //RIGHT
- user.move('e');
+ akman.pushKey('e');
break;
case 40: //DOWN
- user.move('s');
+ akman.pushKey('s');
break;
}
}, true
@@ -446,16 +467,16 @@
e.preventDefault();
switch(e.keyCode){
case 37: //LEFT
- user.move('W');
+ akman.releaseKey('w');
break;
case 38: //UP
- user.move('N');
+ akman.releaseKey('n');
break;
case 39: //RIGHT
- user.move('E');
+ akman.releaseKey('e');
break;
case 40: //DOWN
- user.move('S');
+ akman.releaseKey('s');
break;
case 90: // Z
user.shot();
/*
* @title haiku-shoot
* @description はてなハイクで星を撃つ
* @include http://h.hatena.ne.jp/*
* @license MIT License
* @require
*/
(function(){
if(! 'forEach' in Array.prototype){
Array.prototype.forEach = function(cb){
for(var i=0,l=this.length;i<l;i++){
cb(this[i],i);
}
};
}
if(! 'map' in Array.prototype){
Array.prototype.map = function(cb){
var R = [];
for(var i=0,l=this.length;i<l;i++){
R.push(cb(this[i],i));
}
return R;
};
}
var defclass = function(spec, initializer){
var base = spec.base;
var klass = function(){};
klass.prototype = base.prototype;
var proto = new klass;
if(!('initialize' in proto)) proto.initialize = function(){};
var R = function(){
this.constructor = arguments.callee;
this.initialize.apply(this,arguments);
};
R.prototype = proto;
R.name = spec.name;
R.base = base;
R.getBaseClasses = function(){
var R = [this];
if('getBaseClasses' in base){
R.push.apply(R, base.getBaseClasses());
} else {
R.push(base);
}
return R;
};
initializer.apply(
proto,
[
base.prototype,
R
]
);
return R;
};
var Game = new (
defclass(
{
base: Object,
name: 'Game'
},
function(SUPER, Class){
this.initialize = function(){
this.allElems = {};
this.elemDic = {};
};
this.registerElement = function(elem){
var self = this;
var elemDic = this.elemDic;
this.allElems[elem.key] = elem;
elem.constructor.getBaseClasses().forEach(
function(cl){
if(!cl.name) return;
(elemDic[cl.name] || (elemDic[cl.name] = {}))[elem.key] = elem;
}
);
};
this.unregisterElement = function(elem){
delete this.allElems[elem.key];
var elemDic = this.elemDic;
elem.constructor.getBaseClasses().forEach(
function(cl){
if(!(cl.name && elemDic[cl.name])) return;
delete elemDic[cl.name][elem.key];
}
);
};
this.iter = function(){
var allElems = this.allElems;
var elemDic = this.elemDic;
var i,l, ff;
var elem;
for(f in allElems){
allElems[f].step();
}
var checked = {};
for(f in allElems){
elem = allElems[f];
var tclasses = elem.getTargetClasses();
l = tclasses.length;
if(l < 1) continue;
var chslot = (checked[f] || (checked[f] = {}));
for(i=0,l=tclasses.length;i<l;i++){
var edslot = elemDic[tclasses[i]];
for(ff in edslot){
if(chslot[ff]) continue;
chslot[ff] = true;
var target = edslot[f];
if(!elem.checkHit(target)) continue;
(checked[target.key] ||
(checked[target.key] = {}))[f] = true;
elem.onHit(target);
target.onHit(elem);
}
}
}
for(f in allElems){
allElems[f].redraw();
}
};
this.start = function(){
var self = this;
(function(){
self.iter();
setTimeout(arguments.callee, 10);
})();
};
}) // end of defclass
); // end of new
var GameElement = defclass(
{
base: Object,
name: 'GameElement'
},
function(SUPER, Class){
var counter = 0;
this.initialize = function(x,y){
this.key = 'elem_'+ counter++;
this._x = x;
this._y = y;
this._pre_x = NaN;
this._pre_y = NaN;
this._speed = 1;
this._dx = 0;
this._dy = 0;
this._pdx = 0;
this._pdy = -1;
this._img = null;
Game.registerElement(this);
};
this.initImage = function(url){
var img = document.createElement('img');
document.body.appendChild(img);
img.style.position = 'fixed';
img.style.zIndex = '65536';
img.src = url;
this._img = img;
return img;
};
this.setSpeed = function(s){
this._speed = s;
};
this.getPosition = function(){
return {
x: this._x ,
y: this._y
};
};
this.getSpeed = function(){
return this._speed;
};
this.setDirection = function(x, y){
this._dx = x;
this._dy = y;
};
this.getDirection = function(){
return { x:this._dx, y:this._dy };
};
this.setShotDirection = function(x,y){
this._pdx = x;
this._pdy = y;
};
this.getShotDirection = function(){
return { x:this._pdx, y:this._pdy };
};
// ステップごとの自己状態の変更
this.step = function(){
this._pre_x = this._x;
this._pre_y = this._y;
this._x = this._x + this._dx * this._speed;
this._y = this._y + this._dy * this._speed;
};
//
this.dispose = function(){
var img = this._img;
img.parentNode.removeChild(img);
};
// フレームごとの計算結果を元に
this.redraw = function(){
var img = this._img;
if(this._dispose){
Game.unregisterElement(this);
this.dispose();
return;
}
var sx = this._x;
var sy = this._y;
img.style.top = (sy - img.clientHeight / 2) + 'px';
img.style.left = (sx - img.clientWidth / 2) + 'px';
};
// 当たり判定の対象となるクラス群
this.getTargetClasses = function(){
return [];
};
// 自身のフレームごとの軌跡
this.getTrack = function(){
var R = 0;
return R;
};
// elem との当り判定を書く
this.checkHit = function(elem){
return false;
};
// elem 衝突時の振舞い
this.onHit = function(elem){
};
this.onScreen = function(){
var sx = this._x;
var sy = this._y;
return (sx > 0 && sx < window.innerWidth &&
sy > 0 && sy < window.innerHeight);
};
}
);
var Bullet = defclass(
{
base: GameElement,
name: 'Bullet'
},
function(SUPER, Class){
this.initialize = function(x,y){
SUPER.initialize.apply(this,[x, y]);
this.setDirection(0,-1);
this.setSpeed(10);
this.initImage('http://s.hatena.ne.jp/images/star.gif');
};
this.step = function(){
SUPER.step.apply(this, []);
if(!this.onScreen()) this._dispose = true;
};
}
);
var User = defclass(
{
base: GameElement,
name: 'User'
}, function(SUPER,Class){
this.initialize = function(name){
SUPER.initialize.apply(this,[0,0]);
this.name = name;
var img = this.initImage(
'http://www.st-hatena.com/users/' + name.substring(0,2) +
'/' + name + '/profile.gif'
);
this._defaultSpeed = 5;
this.setDirection(0, -1);
this.setSpeed(0);
this._x =
Math.floor((window.innerWidth - img.clientWidth ) / 2
);
this._y =
(window.innerHeight - img.clientHeight - 10);
};
this.getHotSpot = function(){
var img = this._img;
return {
x: Math.floor(this._x + img.clientWidth / 2),
y: Math.floor(this._y + img.clientHeight / 2)
};
};
this.shot = function(){
var pos = this.getPosition();
var bullet = new Bullet(pos.x, pos.y);
var dir = this.getDirection();
bullet.setDirection(dir.x, dir.y);
bullet.setSpeed(this._defaultSpeed + 2);
};
this.setDirection = function(x, y){
if(x == 0 && y == 0){
this.setSpeed(0);
} else {
this.setSpeed(this._defaultSpeed);
SUPER.setDirection.apply(this, [x,y]);
}
};
}
);
var ArrowKeyManager = defclass(
{
name: 'ArrowKeyManager',
base: Object
},
function(SUPER, Class){
this.initialize = function(hook){
this.pressed = {n:0,s:0,w:0,e:0};
this._hook = hook;
};
this.pushKey = function(k){
var pressed = this.pressed;
switch(k){
case 'n':
pressed.n = (pressed.s > 0) ? 2 : 1;
break;
case 's':
pressed.s = (pressed.n > 0) ? 2 : 1;
break;
case 'w':
pressed.w = (pressed.e > 0) ? 2 : 1;
break;
case 'e':
pressed.e = (pressed.w > 0) ? 2 : 1;
break;
}
this._hook(this);
};
this.releaseKey = (
function(){
var timer = null;
return function(k){
var pressed = this.pressed;
switch(k){
case 'n':
pressed.n = 0;
break;
case 's':
pressed.s = 0;
break;
case 'w':
pressed.w = 0;
break;
case 'e':
pressed.e = 0;
}
var self = this;
if(timer){
clearTimeout(timer);
timer = null;
}
timer = setTimeout(
function(){
self._hook(self);
timer = null;
},
50
);
};
}
)();
this.getCurrentDirection = function(){
var pressed = this.pressed;
var x = 0;
var y = 0;
if(pressed.s != pressed.n) y = pressed.s > pressed.n ? 1 : -1;
if(pressed.w != pressed.e) x = pressed.e > pressed.w ? 1 : -1;
return {x:x, y:y};
};
}
);
var name = document.evaluate(
'.//p[@class="username"]/a/text()',
document.body,
null,
XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE,
null).snapshotItem(0).data;
var user = new User(name);
var akman = new ArrowKeyManager(
function(){
var dir = this.getCurrentDirection();
user.setDirection(dir.x, dir.y);
}
);
document.addEventListener( 'keypress',
function(e){ e.preventDefault();}, false);
window.addEventListener(
'keydown', function(e){
e.stopPropagation();
e.preventDefault();
// console.log(e.keyCode);
switch(e.keyCode){
case 37: //LEFT
akman.pushKey('w');
break;
case 38: //UP
akman.pushKey('n');
break;
case 39: //RIGHT
akman.pushKey('e');
break;
case 40: //DOWN
akman.pushKey('s');
break;
}
}, true
);
window.addEventListener(
'keyup', function(e){
e.stopPropagation();
e.preventDefault();
switch(e.keyCode){
case 37: //LEFT
akman.releaseKey('w');
break;
case 38: //UP
akman.releaseKey('n');
break;
case 39: //RIGHT
akman.releaseKey('e');
break;
case 40: //DOWN
akman.releaseKey('s');
break;
case 90: // Z
user.shot();
}
}, true
);
Game.start();
})();
- Permalink
- このページへの個別リンクです。
- RAW
- 書かれたコードへの直接のリンクです。
- Packed
- 文字列が圧縮された書かれたコードへのリンクです。
- Userscript
- Greasemonkey 等で利用する場合の .user.js へのリンクです。
- Loader
- @require やソースコードが長い場合に多段ロードする Loader コミのコードへのリンクです。
- Metadata
- コード中にコメントで @xxx と書かれたメタデータの JSON です。