今日はcanvasを触ってみます
まずは単純にJavaScriptで描画した六角形のHEXタイルを並べてみました。うまくいけばHEXを使った戦術シミュレーションを作れるし、その手のゲームのアルゴリズムに興味があるので。(今日はそこまではいきませんでしたが)
ソースコードはこんな感じ。
[javascript] <!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body>
<script type="text/javascript">
window.onload = function() {
var View = function(){
this.initialize();
};
// 画面描画
View.prototype.draw_hex = function(hex_position){
var canvas = document.getElementById(‘screen’);
if ( ! canvas || ! canvas.getContext ) {return false;}
var ctx = canvas.getContext(‘2d’);
ctx.save();
// HEXの描画位置
ctx.translate(
this.hex_width*hex_position[0]+(hex_position[1]%2 ? this.hex_width*0.5 : 0),
this.hex_width*0.75*hex_position[1]
);
ctx.beginPath();
ctx.moveTo( 0, this.hex_height*0.25);
ctx.lineTo( 0, this.hex_height*0.75);
ctx.lineTo(this.hex_width*0.5, this.hex_height);
ctx.lineTo(this.hex_width, this.hex_height*0.75);
ctx.lineTo(this.hex_width, this.hex_height*0.25);
ctx.lineTo(this.hex_width*0.5, 0);
ctx.lineTo( 0, this.hex_height*0.25);
ctx.closePath();
var grad = ctx.createLinearGradient(0, 0, 0, this.hex_height);
grad.addColorStop(0,’rgb(64, 256, 256)’);
grad.addColorStop(1,’rgb(64, 194, 256)’);
ctx.fillStyle = grad;
ctx.lineWidth = 1;
ctx.stroke();
ctx.fill();
ctx.fillStyle = "blue";
ctx.font = "10px ‘MS ゴシック’";
ctx.textAlign = "center";
ctx.textBaseline = "top";
ctx.shadowColor = ‘rgba(0, 0, 0, 0.5)’;
ctx.shadowBlur = 1;
ctx.shadowOffsetX = 1;
ctx.shadowOffsetY = 1;
ctx.fillText(hex_position[0]+’,’+hex_position[1], this.hex_width/2, 6);
ctx.restore();
};
View.prototype.draw_character = function(param){
var canvas = document.getElementById(‘screen’);
if ( ! canvas || ! canvas.getContext ) {return false;}
var ctx = canvas.getContext(‘2d’);
ctx.beginPath();
var x = (param.pos[0] * this.hex_width) + (this.hex_width / 2) + (param.pos[1]%2 ? this.hex_width*0.5 : 0);
var y = (param.pos[1] * (this.hex_height * 0.75)) + (this.hex_height * 0.5);
ctx.arc(
x,
y,
10,
0/180*Math.PI,360/180*Math.PI);
ctx.stroke();
ctx.fillStyle = "rgb(224, 0, 0)";
ctx.fill();
ctx.fillStyle = "white";
ctx.font = "16px ‘MS ゴシック’";
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.shadowColor = ‘rgba(0, 0, 0, 0.5)’;
ctx.shadowBlur = 2;
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
ctx.fillText(param.char, x, y);
};
View.prototype.initialize = function(){
this.hex_width = 32;
this.hex_height = 32;
var tile_width = 26;
var tile_height = 30;
for (var x = 0; x < tile_width; x++){
for (var y = 0; y < tile_height; y++){
this.draw_hex([x,y]);
}
}
var player = {char: ‘P’,pos : [1,5]};
this.draw_character(player);
};
// 描画開始
console.time(‘draw’);
var view = new View();
console.timeEnd(‘draw’);
};
</script>
<canvas id="screen" width="900" height="900"></canvas>
</body>
</html>[/javascript]
IE8では動きませんでした。
ここで大きな疑問が。
プレイヤーのキャラクター「P」を移動させるのに、マウスクリックイベントをどうやって受け取るか?
canvasだとDOM上ではcanvas要素ひとつだけなので、一番上のcanvasに対してクリックイベントをつけてやり、座標から何が押されたか調べる・・・?んなアホな・・・。
でもそういうやり方ぽいので他はどうしてるんだろうと思ったらcanvasを扱うゲーム向けのライブラリがいろいろあるようなのです。
KineticJSも触ってみます
なんだかドキュメントの充実してそうなKineticJSで書き直してみました。
APIが全然変わるので全面書き直し。でも基本は同じなのでソースコードは省略。
イベントはKinecticJSの書き方で
[javascript]var circle = new Kinetic.Circle({
x: x,
y: y,
radius: 10,
fill: "red",
stroke: "black",
strokeWidth: 1,
draggable: true
});
circle.on("mouseover mousedown mouseup", function() {
writeMessage(view.messageLayer, "Multi-event binding! ");
});
circle.on("mouseout", function() {
writeMessage(view.messageLayer, "");
});[/javascript]
といった感じで設定できるようになりました。
他にもマウスにあわせて動く指定がプロパティひとつで出来たり、レイヤーの概念ができて操作しやすかったりするようです。
これでばりばり動けばいいんですが
しかしやっぱりDOMではないのでjQueryが使えずやりづらい。
あと、なぜかテキストのalign:centerが効かなかった。
最初、六角形一つに対してレイヤを一つ割り当てて描画させるとブラウザがクラッシュする勢いだったんで全てを一つのレイヤにしたんですが、それでも素のcanvasが描画に56msかかるのに対して871msかかってました。
ちなみに六角形を26×30で780個並べたんですが、ドラッグ可能オブジェクトを置いたもののマウスの動きについてこれてないし、実際にゲームに使えるのかというと・・・
割と簡単なAPIなので、canvasにしろKineticJS使うにしろ単純なものにはいいと思うのですが、大量の描画になってくると速度が気になります。
一日使ってみただけで断定は出来ませんがcanvasは諦めてSVG+jQueryでやってみようかと思いました。