朝はパンだけど、本当は卵ご飯が大好きな、ユゲタです。
canvasについて、ネットで調べていると、unityの記事ばかりに引っかかります。
どんなスマホでも動くという、アプリ開発のunityは、canvasでのGUI処理をするライブラリなんですかね?
こんどちゃんと使ってみないと、細かなことはわかりませんが、検索結果から、世の中でのニーズが伺えます。
本日のIT謎掛け
「unity」と、かけまして・・・
「今どきの低燃費車」と、ときます。
そのココロは・・・
ハイブリッドが売りです。
コンピュータ処理
前回クリック対応して○印を表示することができたので、今回はまず、コンピュータ側の×マークを表示して、ユーザーがクリックした次の手をコンピュータが打つという感じで交互に表示をしてみたいと思います。
この際に、まだ勝ち負けの思考アルゴリズムは入れずに表示とフローだけに絞るので、まだ完成ではありません。
※今回もindex.htmlは前回から変更はありません。
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>TicTacToe</title>
<style>
#mycanvas{
border:1px solid #ccc;
}
</style>
<script src="tictactoe.js"></script>
</head>
<body>
<canvas id="mycanvas" width="400" height="200">not canvas</canvas>
</body>
</html>
(function(){
var LIB = function(){};
LIB.prototype.event = function(target, mode, func , flg){
flg = (flg) ? flg : false;
if (target.addEventListener){target.addEventListener(mode, func, flg)}
else{target.attachEvent('on' + mode, function(){func.call(target , window.event)})}
};
LIB.prototype.construct = function(){
switch(document.readyState){
case "complete" : new MAIN();break;
case "interactive" : this.event(window , "DOMContentLoaded" , (function(){new MAIN()}).bind(this));break;
default : this.event(window , "load" , (function(){new MAIN()}).bind(this));break;
}
};
var MAIN = function(){
// 棋譜格納用のバッファ
this.buffer = [];
this.drawBase();
this.setEvent();
};
MAIN.prototype.drawBase = function(){
var ctx = document.getElementById("mycanvas").getContext("2d");
// 背景
ctx.fillStyle = "#14bdac";
ctx.fillRect(0,0,400,200);
// 枠線
ctx.strokeStyle = "#0da192";
ctx.lineWidth = 6;
ctx.beginPath();
ctx.moveTo(170,20);
ctx.lineTo(170,180);
ctx.stroke();
ctx.fill();
ctx.beginPath();
ctx.moveTo(230,20);
ctx.lineTo(230,180);
ctx.stroke();
ctx.fill();
ctx.beginPath();
ctx.moveTo(120,70);
ctx.lineTo(280,70);
ctx.stroke();
ctx.fill();
ctx.beginPath();
ctx.moveTo(120,130);
ctx.lineTo(280,130);
ctx.stroke();
ctx.fill();
};
MAIN.prototype.setEvent = function(){
var ctx = document.getElementById("mycanvas");
new LIB().event(ctx , "click" , (function(e){this.clickCtx(e)}).bind(this));
};
MAIN.prototype.clickCtx = function(e){
var canvas = e.currentTarget;
// canvas内のクリックされた座標
var posX = e.clientX - canvas.getBoundingClientRect().left;
var posY = e.clientY - canvas.getBoundingClientRect().top;
// 座標から枠判定 [1-9]
var cell = this.checkCell(posX , posY);
if(!cell){return;}
// バッファに登録(登録済みのセルの場合は、処理しない)
if(this.buffer.indexOf(cell) !== -1){return;}
this.buffer.push(cell);
// 記号を表示する
this.drawBuffer();
// 続けてコンピュータの手
this.turnComputer();
// 打つ手が無くなったら終了
if(this.buffer.length >= 9){this.finish();}
};
MAIN.prototype.checkCell = function(posX , posY){
if(118 <= posX && posX <= 118 + 47
&& 18 <= posY && posY <= 18 + 47){
return 1;
}
if(177 <= posX && posX <= 177 + 47
&& 18 <= posY && posY <= 18 + 47){
return 2;
}
if(236 <= posX && posX <= 236 + 47
&& 18 <= posY && posY <= 18 + 47){
return 3;
}
if(118 <= posX && posX <= 118 + 47
&& 76 <= posY && posY <= 76 + 47){
return 4;
}
if(177 <= posX && posX <= 177 + 47
&& 76 <= posY && posY <= 76 + 47){
return 5;
}
if(236 <= posX && posX <= 236 + 47
&& 76 <= posY && posY <= 76 + 47){
return 6;
}
if(118 <= posX && posX <= 118 + 47
&& 134 <= posY && posY <= 134 + 47){
return 7;
}
if(177 <= posX && posX <= 177 + 47
&& 134 <= posY && posY <= 134 + 47){
return 8;
}
if(236 <= posX && posX <= 236 + 47
&& 134 <= posY && posY <= 134 + 47){
return 9;
}
return null;
};
MAIN.prototype.drawBuffer = function(){
var canvas = document.getElementById("mycanvas");
var ctx = canvas.getContext("2d");
// 描画をクリアする
ctx.clearRect(0, 0, canvas.width, canvas.height);
// 基盤を表示
this.drawBase();
// バッファ全ての座標を指定
for(var i=0; i<this.buffer.length; i++){
// 奇数番
if(i % 2 === 0){
this.drawMark_0(this.buffer[i]);
}
// 偶数
else{
this.drawMark_1(this.buffer[i]);
}
}
};
// player-mark @ [0:○ , 1:×]
MAIN.prototype.drawMark_0 = function(cell){
var ctx = document.getElementById("mycanvas").getContext("2d");
var x = y = null , r=16;
switch(cell){
case 1:
x = 118 + 24;
y = 18 + 24;
break;
case 2:
x = 177 + 24;
y = 18 + 24;
break;
case 3:
x = 236 + 24;
y = 18 + 24;
break;
case 4:
x = 118 + 24;
y = 76 + 24;
break;
case 5:
x = 177 + 24;
y = 76 + 24;
break;
case 6:
x = 236 + 24;
y = 76 + 24;
break;
case 7:
x = 118 + 24;
y = 134 + 24;
break;
case 8:
x = 177 + 24;
y = 134 + 24;
break;
case 9:
x = 236 + 24;
y = 134 + 24;
break;
}
if(x === null && y === null){return;}
ctx.strokeStyle = "white";
ctx.beginPath();
ctx.arc(x,y,r, 0/180*Math.PI , 360/180*Math.PI);
ctx.stroke();
};
// com-mark @ [0:○ , 1:×]
MAIN.prototype.drawMark_1 = function(cell){
var ctx = document.getElementById("mycanvas").getContext("2d");
var x1 = y1 = x2 = y2 = null , size1 = 8 , size2 = 38;
switch(cell){
case 1:
x1 = 118 + size1;
y1 = 18 + size1;
x2 = 118 + size2;
y2 = 18 + size2;
break;
case 2:
x1 = 177 + size1;
y1 = 18 + size1;
x2 = 177 + size2;
y2 = 18 + size2;
break;
case 3:
x1 = 236 + size1;
y1 = 18 + size1;
x2 = 236 + size2;
y2 = 18 + size2;
break;
case 4:
x1 = 118 + size1;
y1 = 76 + size1;
x2 = 118 + size2;
y2 = 76 + size2;
break;
case 5:
x1 = 177 + size1;
y1 = 76 + size1;
x2 = 177 + size2;
y2 = 76 + size2;
break;
case 6:
x1 = 236 + size1;
y1 = 76 + size1;
x2 = 236 + size2;
y2 = 76 + size2;
break;
case 7:
x1 = 118 + size1;
y1 = 134 + size1;
x2 = 118 + size2;
y2 = 134 + size2;
break;
case 8:
x1 = 177 + size1;
y1 = 134 + size1;
x2 = 177 + size2;
y2 = 134 + size2;
break;
case 9:
x1 = 236 + size1;
y1 = 134 + size1;
x2 = 236 + size2;
y2 = 134 + size2;
break;
}
if(x1 === null && y1 === null
&& x2 === null && y2 === null){return;}
ctx.strokeStyle = "white";
ctx.beginPath();
ctx.moveTo(x1,y1);
ctx.lineTo(x2,y2);
ctx.stroke();
ctx.fill();
ctx.strokeStyle = "white";
ctx.beginPath();
ctx.moveTo(x1,y2);
ctx.lineTo(x2,y1);
ctx.stroke();
ctx.fill();
};
MAIN.prototype.turnComputer = function(){
// 打つ手が無くなったら終了
if(this.buffer.length >= 9){return;}
// 現在の盤から、空きセルを検索
var emptyCells = this.getEmptyCells();
// 場所を決める
var cellNum = this.getComPlace(emptyCells);
this.buffer.push(cellNum);
// 記号を表示する
this.drawBuffer();
};
MAIN.prototype.getEmptyCells = function(){
var arr = [];
for(var i=1; i<=9; i++){
if(this.buffer.indexOf(i) !== -1){continue;}
arr.push(i);
}
return arr;
}
MAIN.prototype.getComPlace = function(emptyCells){
var num = Math.floor(Math.random() * emptyCells.length);
return emptyCells[num];
}
MAIN.prototype.finish = function(){
console.log("Finish !");
};
new LIB().construct();
})();
解説
ユーザー(先手)、コンピュータ側(後手)、ということで、ユーザーがクリックしたら、すぐにコンピュータが入力する仕様にしてみました。
打った手は、this.buffer(配列)に、打った順に登録していっているので、奇数を「○」、偶数を「×」として表示するようにします。
表示する記号の「○」はcanvasのcircleで書きますが、「×」は線を二本書くので、全く形状と座標が違うため、別関数にして処理するようにしました。
ここでの座標もベタ処理をしているので、今後のリファクタリングで、効率改善したいと思います。
クリックして、コンピュータ表示もできて、あとは、アルゴリズムだけかな・・・と思ったんですが、
コンピュータがあまりに早い対応をするので、ゲームをしている感覚にならないため、コンピュータの考える時間を演出する必要があると感じましたね。
やっぱりゲームをするっていうのは、こういう感情コントロールが重要だとよく分かりました!
0 件のコメント:
コメントを投稿