Billiard Random 3 Balls
HTML5 Canvas 당구시뮬레이션
테스트 환경: HTML5, Eclipse, Google Chrome, Javascript
공 1개를 골라서 클릭하면 연장선이 나타나고 그 연장선으로 공의 방향을 제시하여 다시 클릭하면 해당 공이 이동한다.
<!DOCTYPE html>
<html>
<head>
<meta charset="EUC-KR">
<title>Canvas를 이용한 당구 시뮬레이션</title>
<style type="text/css">
#MyCanvas { border:1px dotted black;}
</style>
<!-- http://micropilot.tistory.com/attachment/cfile29.uf@116A554A4F8F9B510CA71D.js -->
<!-- http://micropilot.tistory.com/attachment/cfile30.uf@125BB84A4F8F9B502378E3.js -->
<!-- http://micropilot.tistory.com/attachment/cfile23.uf@163CA6494F8FABE22378B7 -->
<script type="text/javascript" src="Vector2D.js"></script>
<script type="text/javascript" src="Ball.js"></script>
<script type="text/javascript">
var canvas = null;
var ctx = null;
var redBall = null;
var greenBall = null;
var orangeBall = null;
var selectedBall = null;
var ballArray = new Array();
var radius = 30;
var timer = 0;
var prevtime = 0;
var currtime = 0;
var tailPt = new Vector2D(0,0);
var isPointed = false;
var directionRAD = 0;
var currentPower = 0;
window.onload = function() {
canvas = document.getElementById("MyCanvas");
canvas.addEventListener("mousedown", onMouseDown);
canvas.addEventListener("mousemove", onMouseMove);
ctx = canvas.getContext("2d");
if(!ctx){
alert("캔바스로부터 Context를 구할 수가 없었습니다");
return;
}
init();
gameLoop();
timer = setInterval("gameLoop()",10);
}
function init() {
if(ballArray.length==3) ballArray.splice(0,3);
var wLimit = canvas.width-radius*2;
var hLimit = canvas.height-radius*2;
var ptArr = new Array();
while(ptArr.length<3) {
var x = Math.round(Math.random() * 10000 % wLimit)+radius;
var y = Math.round(Math.random() * 10000 % hLimit)+radius;
var tmpPt = new Vector2D(x,y);
if(ptArr.length==0) {
ptArr[0] = tmpPt;
continue;
}
var contains = false;
for(var i=0;i<ptArr.length; i++) {
if(ptArr[i].sub(tmpPt).length()<=70) {
contains = true;
break;
}
}
if(!contains) ptArr.push(tmpPt);
}
redBall = new Ball(ctx,"rgba(255,0,0,0.4)",new Vector2D(ptArr[0].x, ptArr[0].y),radius, new Vector2D(0,0));
greenBall = new Ball(ctx,"rgba(0,255,0,0.4)",new Vector2D(ptArr[1].x, ptArr[1].y),radius, new Vector2D(0,0));
orangeBall = new Ball(ctx,"rgba(255,255,0,0.4)",new Vector2D(ptArr[2].x, ptArr[2].y),radius, new Vector2D(0,0));
ballArray.push(redBall, greenBall, orangeBall);
for(var i=0;i<ballArray.length;i++) {
ballArray[i].setBalls(ballArray);
}
}
function gameLoop() {
currtime = new Date().getTime();
if(prevtime==0) prevtime = currtime;
ctx.clearRect(0,0,ctx.canvas.width, ctx.canvas.height);
for(var i=0;i<ballArray.length;i++) {
ballArray[i].update(currtime);
ballArray[i].draw(ctx);
drawPower(12, 200);
}
drawLine();
prevtime = currtime;
}
function print(msg, vec) {
document.write(msg+"("+vec.x+", "+vec.y+"), 크기("+vec.length()+")<br/>");
}
function onMouseDown(e) {
var x = e.pageX-this.offsetLeft;
var y = e.pageY-this.offsetTop;
var tmpVec = new Vector2D(x, y);
if(!isPointed) {
for(var i=0;i<ballArray.length;i++) {
if(ballArray[i].pos.sub(tmpVec).length()<radius) {
selectedBall = ballArray[i];
isPointed = true;
break;
}
}
return;
}
tailPt.x = x;
tailPt.y = y;
findHeading();
setSpeed();
selectedBall = null;
isPointed = false;
}
function onMouseMove(e) {
if( ! isPointed ) return;
tailPt.x = e.pageX-this.offsetLeft;
tailPt.y = e.pageY-this.offsetTop;
currentPower = selectedBall.pos.sub(tailPt).length();
currentPower = currentPower>200 ? 200 : currentPower;
}
function drawLine() {
if( ! isPointed) return;
ctx.beginPath();
ctx.strokeStyle = "blue";
ctx.lineWidth = 3;
ctx.moveTo(selectedBall.pos.x, selectedBall.pos.y);
ctx.lineTo(tailPt.x, tailPt.y);
ctx.stroke();
}
function findHeading() {
// 클릭된 점과 수평선과의 내적을 계산한다. 추후에 내적을 이용한 cos값을 구할 때
// 사용할 목적으로 산출한 값
var directionPt = selectedBall.pos.sub(tailPt);
var dot = directionPt.x*1 + directionPt.y*0;
var len = directionPt.length();
var cosVal = dot/len;
var rad = Math.acos(cosVal);
if(directionPt.y<0) {//위쪽을 가리키고 있는 경우에는 각도를 보정해야 한다.
rad = Math.PI - rad + Math.PI;
}
directionRAD = rad;
}
function setSpeed() {
var speedLen = currentPower>200 ? 200/4 : currentPower/4;
selectedBall.speed.set(Math.cos(directionRAD)*speedLen, Math.sin(directionRAD)*speedLen);
}
function hitSound() {
var audioElement = document.createElement('audio');
audioElement.setAttribute('src', 'hit.ogg');
audioElement.play();
}
function drawPower(w,h) {
ctx.beginPath();
ctx.strokeStyle = "black";
ctx.lineWidth = 1;
ctx.strokeRect(ctx.canvas.width-w, ctx.canvas.height-h,w,h);
ctx.fillStyle = "rgba(0, 255, 0, 0.2)";
ctx.fillRect(ctx.canvas.width-w, ctx.canvas.height-currentPower,w,currentPower);
}
</script>
</head>
<body>
<canvas id="MyCanvas" width="400" height="300">
Canvas를 지원하지 않는 브라우저입니다
</canvas>
<br/>
<input type="button" value="다시 배치하기" onClick="init(); gameLoop();" style="border:1px solid black;"/>
</body>
</html>