데모: http://cnwander.com/demo/billiards/
원래 주소: http://cnwander.com/blog/?p=11
JS 미니 게임 시리즈:
[JS 미니게임] 스네이크 + 상세댓글
먼저 코드를 붙여넣으세요.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" " http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd ">
<html xmlns=" http://www.w3.org/1999/xhtml ">
<머리>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>CNwander의 당구</title>
<스타일 유형="텍스트/css">
* {여백:0;
본문 {배경:검정색; 텍스트 정렬:글꼴 크기:12px}
h1 {글꼴 크기:12px; 색상:회색; 글꼴 무게:일반 높이:200%}
h1 .sub {수직 정렬:수퍼; 색상:빨간색;
.info {위치:절대; 오른쪽:색상:회색}
#table {position:relative; width:800px; height:544px; 배경:url( ); _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod=' scale', src=" ); _Background:none; _filter: progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled='true', sizingMethod='scale', src=" ) _Background:none; .AlphaImageLoader(enabled='true', sizingMethod='scale', src=" ) 반복 없음}
#force {위치:절대; 상단:18px; 높이:20px; 글꼴 크기:1px}
#scoreBoard {위치:절대값:230px; 글꼴 크기:50px; 필터:알파(불투명도=0); }
#팁 {패딩:15px 0 0 20px; 텍스트 정렬:왼쪽; 글꼴 크기:12px}
</style>
<스크립트 유형="텍스트/자바스크립트">
// 흔한
함수 $(str) {
return document.getElementById(str);
}
함수 $tag(str,target) {
대상 = 대상 || 문서;
return target.getElementsByTagName(str);
}
함수 addEventHandler(obj,eType,fuc){
if(obj.addEventListener){
obj.addEventListener(eType,fuc,false);
}else if(obj.attachEvent){
obj.attachEvent("on" + eType,fuc);
}또 다른{
obj["on" + eType] = fuc;
}
}
함수 제거이벤트 핸들러(obj,eType,fuc){
if(obj.removeEventListener){
obj.removeEventListener(eType,fuc,false);
}else if(obj.attachEvent){
obj.detachEvent("on" + eType,fuc);
}
}
함수 ranowNum(시작,끝) {
return Math.floor(Math.random()*(end - start)) + start;
}
Array.prototype.remove=function(dx) {
if(isNaN(dx)||dx>this.length){return false;}
for(var i=0,n=0;i<this.length;i++)
{
if(이[i]!=이[dx])
{
이것[n++]=이것[i]
}
}
this.length-=1
}
//상수
var TOTALR = 15, //공의 반경(그림자 포함)
R = 12, //공의 실제 반경
포커 = 20,
W = 736, //케이스 너비
H = 480, //케이스 높이
THICKNESS = 32, //가장자리 두께
RATE = 100, //새로 고침 빈도
F = 0.01, //마찰력
LOSS = 0.2, // 충돌 속도 손실
TIPS = ["Tip1: 기준구, 타겟볼, 타겟백, 3점, 1라인이 골을 넣는 가장 기본적인 방법입니다","Tip2: 오른쪽 하단의 파란색 막대는 타격력을 나타냅니다. 작은 힘 큐볼 위치 조절이 더 쉽습니다.","Tip3: 오른쪽 하단 흰색 공에 있는 파란색 점은 타격 지점을 제어합니다. 하이바, 로우바, 플러그를 제어합니다. 여기서 마스터와 마스터의 차이가 나타나는 경우가 많습니다. ","Tip4: 탁구에서는 타깃 공이 실제로 플레이되는 것이 아니라 큐볼입니다."];
var 테이블, //케이스
큐볼, //큐볼
guideBall, //참조 볼
dotWrap, //참조선
속도 = 12,
롤업 = 0,
롤오른쪽 = 0,
시간제 노동자,
강제타이머,
공 = [],
움직이는 공 = [],
찌르기 = [[0,0],[W/2,-5],[W,0],[0,H],[W/2,H+5],[W,H]],
hasShot = 거짓;
샷 = 0; //콤보 샷 수
window.onload = 함수() {
초기화테이블();
initShootPos();
쇼팁();
게임 시작();
}
함수 startGame() {
초기화볼();
addEventHandler(table,"mousemove",dragCueBall);
addEventHandler(table,"mouseup",setCueBall);
}
함수 initTable() {
테이블 = $("테이블");
var dotWrapDiv = document.createElement("div"),
guideBallDiv = document.createElement("div");
dotWrapDiv.id = "dotWrap";
guideBallDiv.className = "가이드볼";
setStyle(guideBallDiv,"display","none");
dotWrap = table.appendChild(dotWrapDiv);
guideBall = table.appendChild(guideBallDiv);
}
함수 initBall() {
//큐볼 추가
ueBall = new Ball("큐",170,H/2);
ball.push(cueBall);
//타겟볼 추가
for(var i = 0; i < 5; i++) {
for(var j = 0; j <= i; j++) {
var ball = new Ball("대상",520 + i*2*R, H/2 - R*i + j*2*R);
공.푸시(공);
}
}
}
함수 initShootPos() {
var Wrap = $("shootPos"),
핸들러 = $("점"),
화살표R = 18;
addEventHandler(wrap,"mousedown",selectDot);
함수 selectDot(e) {
e = e || 이벤트;
var pos = getElemPos(wrap),
x = e.clientX - pos[0] - handler.offsetWidth/2,
y = e.clientY - pos[1] - handler.offsetHeight/2;
if(Math.sqrt((x-22)*(x-22) + (y-22)*(y-22)) > arrowR) {
var angle = Math.atan2(x-22,y-22);
x = arrowR*Math.sin(angle) + 22;
y = arrowR*Math.cos(angle) + 22;
}
setPos(핸들러,x,y);
}
}
함수 getElemPos(대상,참조) {
참조 = 참조 || 문서;
var 왼쪽 = 0, 상단 = 0;
return getPos(대상);
함수 getPos(대상) {
if(대상 != 참조) {
왼쪽 += target.offsetLeft;
상단 += target.offsetTop;
return getPos(target.parentNode);
} 또 다른 {
return [왼쪽,위];
}
}
}
// 공 클래스
함수 공(유형,x,y) {
var div = document.createElement("div");
div.className = 유형 + "공";
this.elem = table.appendChild(div);
this.type = 유형;
this.x = x; //위치
this.y = y;
this.angle = 0; //각도
this.v = 0; //속도(방향 제외)
setBallPos(this.elem,x,y);
이거 돌려줘;
}
함수 setCueBall() {
RemoveEventHandler(table,"mousemove",dragCueBall);
RemoveEventHandler(table,"mouseup",setCueBall);
스타트샷();
}
함수 startShot() {
쇼(cueBall.elem);
addEventHandler(table,"mousemove",showGuide);
addEventHandler(table,"mousedown",updateForce);
addEventHandler(table,"mouseup",shotCueBall);
}
함수 dragCueBall(e) {
var toX,toY;
e = e || 이벤트;
toX = e.clientX - table.offsetLeft - 두께,
toY = e.clientY - table.offsetTop - 두께;
toX = toX >= R ? toX : R;
toX = toX <= 170 ? toX : 170;
toY = toY >= R ? toY : R;
toY = toY <= H - R ? toY : H - R;
setBallPos(cueBall,toX,toY);
}
함수 샷큐볼() {
RemoveEventHandler(table,"mousemove",showGuide);
RemoveEventHandler(table,"mousedown",updateForce);
RemoveEventHandler(table,"mouseup",shotCueBall);
window.clearInterval(forceTimer);
속도 = $("force").offsetWidth * 0.15;
var dotDisX = $("dot").offsetLeft-22,
dotDisY = $("점").offsetTop-22,
dotDis = Math.sqrt(dotDisX*dotDisX + dotDisY*dotDisY),
dotAngle = Math.atan2(dotDisX,dotDisY);
RollRight = Math.round(dotDis*Math.sin(dotAngle))/5;
RollUp = -Math.round(dotDis*Math.cos(dotAngle))/5;
var formPos = getBallPos(cueBall.elem),
toPos = getBallPos(guideBall),
angle = Math.atan2(toPos[0] - formPos[0],toPos[1] - formPos[1]);
hide(dotWrap);
hide(guideBall);
cueBall.v = 속도;
CueBall.angle = 각도;
MovingBalls.push(cueBall);
타이머 = window.setInterval(roll,1000 / RATE);
}
함수 showGuide(e) {
var fromX,fromY,toX,toY;
e = e || 이벤트;
toX = e.clientX - table.offsetLeft - 두께,
toY = e.clientY - table.offsetTop - 두께;
setBallPos(guideBall,toX,toY);
표시(dotWrap);
쇼(guideBall);
drawLine();
//참조선
함수 drawLine() {
var dotNum = 16,
pos = getBallPos(cueBall.elem);
dotWrap.innerHTML = "";
fromX = 위치[0];
fromY = 위치[1];
var partX = (toX - fromX) / dotNum,
partY = (toY - fromY) / dotNum;
for(var i = 1; i < dotNum; i++) {
var x = fromX + partX * i,
y = fromY + partY * i;
drawDot(dotWrap, x, y);
}
}
}
함수 롤() {
if(movingBalls.length <= 0) {
if(!hasShot) 샷 = 0;
else Shots ++ // 누적된 콤보
hasShot = 거짓;
setStyle($("force"),"너비",80+"px");
setPos($("점"),22,22);
window.clearInterval(타이머);
if(shots > 1) showScore(shots); //콤보 수를 표시합니다.
스타트샷();
}
for(var i = 0; i < MovingBalls.length; i++) {
var 공 = 움직이는 공[i],
죄 = Math.sin(공.각도),
cos = Math.cos(ball.angle);
ball.v -= F;
//정지된 공 제거
if(Math.round(ball.v) == 0) {
ball.v = 0;
MovingBalls.remove(i);
계속하다;
}
var vx = ball.v * 죄,
vy = ball.v * cos;
ball.x += vx;
ball.y += vy;
//가방에 넣어두기
if(isPocket(ball.x,ball.y)) {
hide(ball.elem);
if(ball.type == "큐") {
if(!hasShot) 샷 = 0;
hasShot = 거짓;
window.setTimeout(함수(){
ball.v = 0;
setBallPos(공,170,250);
},500);
}또 다른 {
//포장된 공을 제거합니다.
hasShot = 사실;
ball.v = 0;
for(var k = 0, l =0; k < 공.길이; k++) {
if(공[k] != 공) {
공[l++] = 공[k];
}
}
공.길이 -= 1;
}
반품;
}
//가장자리 충돌
if(ball.x < R || ball.x > W - R) {
공.각도 *= -1;
공.각도 %= Math.PI;
ball.v = ball.v * (1 - 손실);
vx = ball.v*Math.sin(ball.angle);
vy = ball.v*Math.cos(ball.angle);
if(ball.x < R) ball.x = R;
if(ball.x > W - R) ball.x = W - R;
//큐볼 채우기
if(ball.type == "큐") {
if(ball.angle > 0) vy -= RollRight;
그렇지 않으면 vy += RollRight;
vx += 롤업;
롤업 *= 0.2;
롤오른쪽 *= 0.2;
ball.v = Math.sqrt(vx*vx + vy*vy);
ball.angle = Math.atan2(vx,vy);
}
}
if(ball.y < R || ball.y > H - R) {
ball.angle = 공.angle > 0 ? Math.PI - ball.angle : - Math.PI - ball.angle ;
공.각도 %= Math.PI;
ball.v = ball.v * (1 - 손실);
vx = ball.v*Math.sin(ball.angle);
vy = ball.v*Math.cos(ball.angle);
if(ball.y < R) ball.y = R;
if(ball.y > H - R) ball.y = H - R;
//큐볼 채우기
if(ball.type == "큐") {
if(Math.abs(ball.angle) < Math.PI/2) vx += RollRight;
그렇지 않으면 vx -= RollRight;
vy += 롤업;
롤업 *= 0.2;
롤오른쪽 *= 0.2;
ball.v = Math.sqrt(vx*vx + vy*vy);
ball.angle = Math.atan2(vx,vy);
}
}
//공 충돌
for(var j = 0; j < 공.길이; j++) {
var obj = 공[j];
if(obj == ball) 계속;
var disX = obj.x - ball.x,
disY = obj.y - ball.y,
간격 = 2 * R;
if(disX <= 간격 && disY <= 간격) {
var dis = Math.sqrt(Math.pow(disX,2)+Math.pow(disY,2));
if(dis <= 간격) {
//정지된 경우 MovingBalls 배열에 추가합니다.
if(Math.round(obj.v) == 0)
MovingBalls.push(obj);
//충돌 계산을 위해 좌표를 x축으로 회전시킵니다.
// 각도와 사인 및 코사인 값을 계산합니다. - 정확한 값
//var c = (obj.x*ball.y - obj.y*ball.x)/(2*R),
// d = Math.sqrt(ball.x*ball.x + ball.y*ball.y),
// 각도 = Math.asin(ball.y/d) - Math.asin(c/d) - ball.angle%(Math.PI/2),
//각도 = Math.asin(oy / (2 * R)),
//두 공의 접선 상태를 복원합니다 - 대략적인 값
ball.x -= (gap - dis)*sin;
ball.y -= (gap - dis)*cos;
disX = obj.x - ball.x;
disY = obj.y - ball.y;
// 각도와 사인 및 코사인 값을 계산합니다.
변수 각도 = Math.atan2(disY, disX),
히트신 = Math.sin(각도),
히트코스 = Math.cos(각도),
objVx = obj.v * Math.sin(obj.angle),
objVy = obj.v * Math.cos(obj.angle);
//추적(각도*180/Math.PI);
// 좌표 회전
변수 x1 = 0,
y1 = 0,
x2 = disX * hitcos + disY * hitsin,
y2 = disY * hitcos - disX * hitsin,
vx1 = vx * 히트코스 + vy * 히트신,
vy1 = vy * hitcos - vx * hitsin,
vx2 = objVx * hitcos + objVy * hitsin,
vy2 = objVy * hitcos - objVx * hitin;
// 충돌 후 속도와 위치
var plusVx = vx1 - vx2;
vx1 = vx2;
vx2 = 플러스Vx + vx1;
//큐볼 채우기
if(ball.type == "큐") {
vx1 += 롤업;
롤업 *= 0.2;
}
x1 += vx1;
x2 += vx2;
// 위치를 뒤로 회전
var x1Final = x1 * hitcos - y1 * hitsin,
y1Final = y1 * hitcos + x1 * hitsin,
x2Final = x2 * 히트코스 - y2 * 히트신,
y2Final = y2 * hitcos + x2 * hitsin;
obj.x = ball.x + x2Final;
obj.y = ball.y + y2Final;
공.x = 공.x + x1Final;
ball.y = ball.y + y1Final;
// 속도를 뒤로 회전
vx = vx1 * hitcos - vy1 * hitsin;
vy = vy1 * 히트코스 + vx1 * 히트신;
objVx = vx2 * hitcos - vy2 * hitsin;
objVy = vy2 * hitcos + vx2 * hitin;
//최종 속도
ball.v = Math.sqrt(vx*vx + vy*vy) * (1 - 0);
obj.v = Math.sqrt(objVx*objVx + objVy*objVy) * (1 - 0);
// 각도 계산
ball.angle = Math.atan2(vx, vy);
obj.angle = Math.atan2(objVx, objVy);
//부서지다;
}
}
}
setBallPos(ball,ball.x,ball.y);
}
}
함수 isPocket(x,y) {
if(y < POKER) return check(0,2);
else if (y > H - POKER) return check(3,5);
그렇지 않으면 false를 반환합니다.
함수 검사(m,n) {
for(var i=m; i<=n; i++) {
if(x >= pokes[i][0] - POKER && x <= pokes[i][0] + POKER) {
var dis = Math.sqrt(Math.pow(x - pokes[i][0],2) + Math.pow(y - pokes[i][1],2));
if(dis <= POKER)는 true를 반환합니다.
그렇지 않으면 false를 반환합니다.
}
}
}
}
함수 getBallPos(obj) {
var 위치 = [];
pos.push(obj.offsetLeft - 두께 + 합계);
pos.push(obj.offsetTop - 두께 + 합계);
반환 위치;
}
함수 setPos(obj,x,y) {
obj.style.left = x + "px";
obj.style.top = y + "px";
}
함수 setBallPos(공,x,y) {
if(ball.constructor == 공) {
공.x = x;
공.y = y;
공 = ball.elem;
}
setPos(공,x + 두께 - 합계,y + 두께 - 합계);
}
함수 drawDot(wrap,x,y) {
var elem = document.createElement("div");
setStyle(요소,{
위치: "절대",
너비: "1px",
높이: "1px",
글꼴 크기: "1px",
배경: "흰색"
});
setPos(elem,x,y);
Wrap.appendChild(elem);
}
함수 업데이트포스() {
var obj = $("강제"),
렌 = 80,
위 = 사실;
forceTimer = window.setInterval(update,10);
함수 업데이트() {
if(up) setStyle(obj,"너비",len+++"px");
else setStyle(obj,"너비",len--+"px");
if(len > 136) up = false;
if(len <= 0) up = true;
}
}
함수 setStyle() {
if(arguments.length == 2 && typeof 인수[1] == "객체") {
for(인수[1]의 var 키) {
인수[0].스타일[키] = 인수[1][키];
}
} else if (arguments.length > 2) {
인수[0].스타일[인수[1]] = 인수[2];
}
}
함수 hide(obj) {
setStyle(obj,"디스플레이","없음");
}
함수 표시(obj) {
setStyle(obj,"디스플레이","블록");
}
//정보 출력
함수 추적(sth,who) {
누구 = 누구 || $("팁");
if(document.all) who.innerText = sth;
else who.textContent = sth;
누구를 반환;
}
함수 showScore(n) {
var Wrap = $("scoreBoard");
Trace(n+"커넥팅 로드",wrap);
fadeIn(wrap);
}
함수 fadeIn(obj){
var fromY = 230,
posStep = [8,14,19,23,26,28,29,29,30,30,30],
opaStep = [0,0.05,0.1,0.15,0.2,0.25,0.3,0.4,0.5,0.6,0.8],
fromOpa = 0,
티 = 0,
단계 = posStep.length,
inTimer = window.setInterval(showIn,20),
아웃타이머;
함수 showIn() {
setOpacity(obj,opaStep[t]);
obj.style.top = fromY + posStep[t] + "px";
티++;
if(t>=단계) {
window.clearInterval(inTimer);
outTimer = window.setInterval(fadeOut,50);
}
}
함수 fadeOut() {
티--;
setOpacity(obj,opaStep[t]);
obj.style.top = fromY + posStep[t] + "px";
if(t <= 0) {
window.clearInterval(outTimer);
숨기기(obj);
}
}
}
함수 setOpacity(obj,n) {
obj.style.cssText = "filter:alpha(opacity="+ n*100 +"); -moz-opacity:"+ n +"; 불투명도:"+ n;
}
함수 showTips() {
var 나는 = 0;
팁();
window.setInterval(tip,3000);
함수 팁() {
추적(TIPS[i++]);
if(i >= TIPS.length) i = 0;
}
}
</script>
</head>
<본문>
<div class="info">토론: <a href=" http://bbs.blueidea.com/thread-2951566-1-1.html"> Blueidea</a > <a href=" http: //cnwander.com/blog/?p=11">방랑자의 공간</a></div>
<h1>중국인들이여 일어나라! <span class="sub">60주년</span></h1>
<div id="테이블">
<div id="scoreBoard"></div>
</div>
<div 클래스="봇">
<div id="팁"></div>
<div 클래스 = "ctrl">
<div id="강제"></div>
<div id="shootPos">
<div id="점"></div>
</div>
</div>
</div>
</body>
</html>
뻔뻔하게 탁구라는 이름을 붙였으나 실제로는 실제 탁구와는 거리가 멀고 아직 개선할 부분이 많다.
해결해야 할 구체적인 문제:
분명 다른 문제도 많을 텐데, 연휴 동안 너무 정신이 팔려 나중에는 못 할 것 같아 그냥 한 번에 끝내겠습니다. 조금 서두르겠습니다. 이 주제에 관심이 있는 학생들을 위해 먼저 문제를 천천히 풀어보겠습니다.
대학 수학은 기본적으로 형식에 불과하며 고등학교 때 물리학과 수학에 대해 거의 잊어버린 적이 없었습니다. 실제로 일을 시작하고 나서야 이 분야에 제가 너무 약하다는 것을 깨달았습니다. 지역이 나에게 조언을 해줄 것이다.