HTML5/Billiard 3 Balls

Billiard Random 3 Balls

Soul-Learner 2012. 4. 18. 15:56

HTML5 Canvas 당구시뮬레이션

테스트 환경: HTML5, Eclipse, Google Chrome, Javascript

Vector2D.js

Ball.js

hit_ogg


공 1개를 골라서 클릭하면 연장선이 나타나고 그 연장선으로 공의 방향을 제시하여 다시 클릭하면 해당 공이 이동한다.

Canvas를 지원하지 않는 브라우저입니다

<!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>