Drop the Ball: 두 판 사이의 차이
imported>Bd3076 (새 문서: {{pluginX|script=사용자:Bd3076/Drop the Ball/plugin|name=물리 엔진 실험|creator=Bd3076}} {{Bd3076의 게임}} 분류:백괴게임) |
잔글 ("Drop the Ball" 문서의 보호 설정을 변경했습니다: AuthorProtect 전체 적용 설정의 문제로 인해 자동 인증된 사용자 이상의 권한으로 보호 설정 변경 ([편집=자동 인증된 사용자만 허용] (무기한) [이동=자동 인증된 사용자만 허용] (무기한))) |
||
(사용자 7명의 중간 판 8개는 보이지 않습니다) | |||
1번째 줄: | 1번째 줄: | ||
{{pluginX|script=사용자:Bd3076/Drop the Ball/plugin|name= | {{게임 정보}} | ||
{{pluginX|script=사용자:Bd3076/Drop the Ball/plugin|name=Drop the Ball|creator=Bd3076}} | |||
{{Bd3076의 게임}} | {{Bd3076의 게임}} | ||
2024년 10월 27일 (일) 13:24 기준 최신판
원개발자 이외에는 편집을 할 수 없는 게임
이 게임은 원개발자 이외에는 편집을 할 수 없는 게임입니다.
이 게임을 잘못 수정하면 게임을 망치거나 오류가 날 수 있으므로 편집하지 마십시오.
버그가 있으면 수정하지 마시고 게임 토론이나 해당 개발자의 사용자 토론에 알려주세요.
이 게임을 잘못 수정하면 게임을 망치거나 오류가 날 수 있으므로 편집하지 마십시오.
버그가 있으면 수정하지 마시고 게임 토론이나 해당 개발자의 사용자 토론에 알려주세요.
var DB= window.localStorage; document.write('<div id="canvasArea"> </div> 단계를 선택할 때에는, 방향키 및 엔터만 사용하세요. (위쪽 방향키로 월드 선택 취소가 가능합니다.)<br /> 게임 중에는, 점선 위의 원하는 지역을 클릭해 공을 추가하세요. <br /> R키를 눌러 단계를 다시 시작할 수 있습니다. Q키로 단계에서 나갈 수 있습니다.<br />저장은 자동입니다.<br /><br /><br />'); var canvasArea = document.getElementById('canvasArea'); canvasArea.innerHTML = '<canvas id="myCanvas" width="720" height="480" style="border:1px solid #000000;"> </canvas>'; var canvas = document.getElementById("myCanvas"); var ctx = canvas.getContext("2d"); const restitution = 0.9; var abs = function(x) { if (x < 0) return -x; return x; }; var SQR = function(x) { return x * x; } var max = function(x, y){ if(x<y) return y; return x; } class Point { constructor(x, y) { this.x = x; this.y = y; } } var changeCoordinates = function(p, deg) { return new Point(p.x * Math.cos(deg) + p.y * Math.sin(deg), p.y * Math.cos(deg) - p.x * Math.sin(deg)); } class Sphere { constructor(x, y, r, movable) { this.type = 'Sphere'; this.center = new Point(x, y); this.r = r; this.movable = movable; this.vx = 0; this.vy = 0; this.exist = 1; if (movable) { this.mass = Math.PI * r * r; } else this.mass = 1e20; console.log(this.mass); } updateLocation() { if (!this.movable) return; if (this.center.x - this.r < 0) { this.vx = abs(this.vx) * restitution; this.center.x = this.r; } if (this.center.x + this.r > 720) { this.vx = -abs(this.vx) * restitution; this.center.x = 720 - this.r; } if (this.center.y - this.r < 0) { this.vy = abs(this.vy) * restitution; this.center.y = this.r; } if (this.center.y + this.r > 480) { this.vy = -abs(this.vy) * restitution; this.center.y = 480 - this.r; } this.vy += 0.98 * 1.7; // g = 9.8m/s^2 this.center.x += 0.01 * this.vx; this.center.y += 0.01 * this.vy; } drawInCanvas() { ctx.strokeStyle = "black"; ctx.setLineDash([]); ctx.beginPath(); ctx.arc(this.center.x, this.center.y, this.r, 0, 2 * Math.PI); if (!this.movable) { ctx.fillStyle = 'black'; ctx.fill(); } ctx.stroke(); } } class fixedRectangle { constructor(x, y, a, b, deg, func) { // a: 가로 길이의 반, b: 세로 길이의 반 this.type = "fixedRectangle"; this.center = new Point(x, y); this.size = new Point(a, b); this.deg = deg; this.mass = 1e20; this.movable = 0; this.exist = 1; this.func = func; // 0: normal, 1: die, 2: goal } drawInCanvas() { ctx.strokeStyle = "black"; ctx.setLineDash([]); var P1 = changeCoordinates(new Point(this.size.x, this.size.y), this.deg); var P2 = changeCoordinates(new Point(-this.size.x, this.size.y), this.deg); var P3 = changeCoordinates(new Point(-this.size.x, -this.size.y), this.deg); var P4 = changeCoordinates(new Point(this.size.x, -this.size.y), this.deg); ctx.beginPath(); ctx.moveTo(this.center.x + P1.x, this.center.y + P1.y); ctx.lineTo(this.center.x + P2.x, this.center.y + P2.y); ctx.lineTo(this.center.x + P3.x, this.center.y + P3.y); ctx.lineTo(this.center.x + P4.x, this.center.y + P4.y); ctx.lineTo(this.center.x + P1.x, this.center.y + P1.y); if(this.func == 0){ ctx.fillStyle = 'black'; } else if(this.func == 1){ ctx.fillStyle = 'red'; } else{ ctx.fillStyle = 'lime'; } ctx.fill(); ctx.stroke(); } } var stageData = []; var stageDataCnt = []; var stageLimit = []; var setStageData = function(){ for(var i=0; i<11; i++){ stageData.push([]); stageLimit.push(0); } // Stage 1-1 stageData.push([ new fixedRectangle(360, 400, 360, 80, 0, 2) ]); stageLimit.push(1); // Stage 1-2 stageData.push([ new fixedRectangle(360, 400, 80, 80, 0, 2) ]); stageLimit.push(1); // Stage 1-3 stageData.push([ new fixedRectangle(360, 400, 10, 10, 0, 2) ]); stageLimit.push(1); // Stage 1-4 stageData.push([ new fixedRectangle(100, 300, 50, 50, 0, 0), new fixedRectangle(300, 300, 50, 50, 0, 2) ]); stageLimit.push(2); // Stage 1-5 stageData.push([ new fixedRectangle(100, 300, 50, 50, 0, 1), new fixedRectangle(300, 300, 50, 50, 0, 2), new fixedRectangle(500, 300, 50, 50, 0, 0) ]); stageLimit.push(3); // stage 1-6 stageData.push([ new fixedRectangle(300, 200, 300, 30, 0, 0), new fixedRectangle(100, 380, 100, 100, 0, 2) ]); stageLimit.push(3); // stage 1-7 stageData.push([ new fixedRectangle(300, 200, 300, 30, 0, 0), new fixedRectangle(100, 380, 100, 100, 0, 2), new fixedRectangle(300, 430, 50, 50, 0, 1) ]); stageLimit.push(3); // stage 1-8 stageData.push([ new fixedRectangle(175, 200, 175, 30, 0, 0), new fixedRectangle(545, 200, 175, 30, 0, 0), new fixedRectangle(360, 400, 360, 80, 0, 2) ]); stageLimit.push(1); stageData.push([]); stageLimit.push(0); stageData.push([]); stageLimit.push(0); // stage 2-1 stageData.push([ new fixedRectangle(420, 120, 300, 10, 0, 0), new fixedRectangle(300, 300, 500, 10, -0.4, 0), new fixedRectangle(700, 440, 20, 20, 0, 2) ]); stageLimit.push(1); // stage 2-2 stageData.push([ new fixedRectangle(360, 300, 100, 100, Math.PI/4, 0), new fixedRectangle(-50, 420, 280, 10, 0, 0), new fixedRectangle(790, 420, 280, 10, 0, 0), new fixedRectangle(360, 480, 260, 10, 0, 2) ]); stageLimit.push(1); // stage 2-3 stageData.push([ new fixedRectangle(720, 270, 690, 170, 0, 0), new fixedRectangle(700, 460, 20, 20, 0, 2) ]); stageLimit.push(2); // stage 2-4 stageData.push([ new fixedRectangle(360, 300, 40, 40, 0, 2), new Sphere(280, 300, 40, 0), new Sphere(440, 300, 40, 0), new Sphere(360, 220, 40, 0), new fixedRectangle(360, 470, 360, 10, 0, 0) ]); stageLimit.push(1); // stage 2-5 stageData.push([ new Sphere(50, 400, 50, 0), new fixedRectangle(300, 130, 180, 10, 0, 1), new fixedRectangle(360, 470, 360, 10, 0, 1), new fixedRectangle(720, 130, 200, 10, 0, 1), new fixedRectangle(710, 220, 10, 70, 0, 2) ]); stageLimit.push(2); // stage 2-6 stageData.push([ new fixedRectangle(720, 130, 200, 10, 0, 1), new fixedRectangle(240, 130, 240, 10, 0, 1), new fixedRectangle(720, 470, 200, 10, 0, 1), new fixedRectangle(240, 470, 240, 10, 0, 1), new fixedRectangle(10, 220, 10, 70, 0, 2) ]); stageLimit.push(2); // stage 2-7 stageData.push([ new Sphere(40, 400, 40, 0), new fixedRectangle(360, 470, 360, 10, 0, 1), new fixedRectangle(720, 130, 630, 10, 0, 1), new fixedRectangle(500, 300, 5, 5, 0, 2) ]); stageLimit.push(1); // stage 2-5 stageData.push([ new Sphere(50, 400, 50, 0), new fixedRectangle(300, 130, 180, 10, 0, 1), new fixedRectangle(360, 470, 360, 10, 0, 1), new fixedRectangle(720, 130, 200, 10, 0, 1), new fixedRectangle(710, 220, 10, 60, 0, 2) ]); stageLimit.push(2); for(var i=0; i<stageData.length; i++){ stageDataCnt.push(stageData[i].length); } } setStageData(); var polygonList = []; var polygonCount = 0; var stageCleared = 0; var stageInterrupt = 0; var action = 0; // 0: selecting world, 1: selecting stage, 2: play var state = 0; // 0: main screen, xxy: world x - stage y const worldCount = 2; const stageCount = 8; var sphereCollision = function(a, b) { if (SQR(a.center.x - b.center.x) + SQR(a.center.y - b.center.y) > SQR(a.r + b.r)) return; //console.log('collide!'); var deg = Math.atan2(b.center.y - a.center.y, b.center.x - a.center.x); var colDist = (a.r + b.r) - Math.sqrt(SQR(a.center.x - b.center.x) + SQR(a.center.y - b.center.y)); if (a.movable) { a.center.x -= colDist / 2 * Math.cos(deg); a.center.y -= colDist / 2 * Math.sin(deg); } if (b.movable) { b.center.x += colDist / 2 * Math.cos(deg); b.center.y += colDist / 2 * Math.sin(deg); } var avt = a.vx * -Math.sin(deg) + a.vy * Math.cos(deg); var avc = a.vx * Math.cos(deg) + a.vy * Math.sin(deg); var bvt = b.vx * Math.sin(deg) + b.vy * -Math.cos(deg); var bvc = b.vx * -Math.cos(deg) + b.vy * -Math.sin(deg); var swapTmp; //console.log(avt + ' ' + avc + ' ' + bvt + ' ' + bvc); bvc = -bvc; var newAvc = (a.mass - b.mass) / (a.mass + b.mass) * avc; var newBvc = (b.mass - a.mass) / (a.mass + b.mass) * bvc; newAvc += (2 * b.mass) / (a.mass + b.mass) * bvc; newBvc += (2 * a.mass) / (a.mass + b.mass) * avc; newBvc = -newBvc; avc = newAvc; bvc = newBvc; //console.log(avt + ' ' + avc + ' ' + bvt + ' ' + bvc); var newAvx = avt * -Math.sin(deg) + avc * Math.cos(deg); var newAvy = avt * Math.cos(deg) + avc * Math.sin(deg); var newBvx = bvt * Math.sin(deg) + bvc * -Math.cos(deg); var newBvy = bvt * -Math.cos(deg) + bvc * -Math.sin(deg); a.vx = newAvx; a.vy = newAvy; b.vx = newBvx; b.vy = newBvy; } var sphereRectCollision = function(a, b) { // a: sphere, b: rectangle a.center.x -= b.center.x; a.center.y -= b.center.y; a.center = changeCoordinates(a.center, -b.deg); var aSpeed = changeCoordinates(new Point(a.vx, a.vy), -b.deg); a.vx = aSpeed.x; a.vy = aSpeed.y; if(b.func == 2){ if(-b.size.x <= a.center.x && a.center.x <= b.size.x && -b.size.y <= a.center.y && a.center.y <= b.size.y){ stageCleared = 1; } a.center = changeCoordinates(a.center, b.deg); a.center.x += b.center.x; a.center.y += b.center.y;aSpeed = changeCoordinates(new Point(a.vx, a.vy), b.deg); a.vx = aSpeed.x; a.vy = aSpeed.y; return; } if(b.func == 1){ if(-b.size.x <= a.center.x && a.center.x <= b.size.x && -b.size.y <= a.center.y && a.center.y <= b.size.y){ a.exist = 0; } else{ var _xabs = abs(a.center.x); var _yabs = abs(a.center.y); if(_xabs<=b.size.x && _yabs <= b.size.y+a.r) a.exist=0; else if(_xabs<=b.size.x+a.r&&_yabs<=b.size.y)a.exist=0; else if(!(_xabs > b.size.x+a.r && _yabs > b.size.y+a.r)){ var _xDiff = _xabs - b.size.x; var _yDiff = _yabs - b.size.y; if(SQR(_xDiff) + SQR(_yDiff) <= SQR(a.r)) a.exist=0; } } a.center = changeCoordinates(a.center, b.deg); a.center.x += b.center.x; a.center.y += b.center.y;aSpeed = changeCoordinates(new Point(a.vx, a.vy), b.deg); a.vx = aSpeed.x; a.vy = aSpeed.y; return; } //console.log(a.center.x + ' ' + a.center.y); //console.log(-b.size.x-a.r); if(a.center.x < -b.size.x-a.r || a.center.x > b.size.x+a.r || a.center.y < -b.size.y-a.r || a.center.y > b.size.y+a.r){ a.center = changeCoordinates(a.center, b.deg); a.center.x += b.center.x; a.center.y += b.center.y;aSpeed = changeCoordinates(new Point(a.vx, a.vy), b.deg); a.vx = aSpeed.x; a.vy = aSpeed.y; return; } if(a.center.x < -b.size.x){ if(a.center.y < -b.size.y){ var xDiff = -b.size.x - a.center.x; var yDiff = -b.size.y - a.center.y; if(SQR(xDiff) + SQR(yDiff) >= SQR(a.r)){ a.center = changeCoordinates(a.center, b.deg); a.center.x += b.center.x; a.center.y += b.center.y; aSpeed = changeCoordinates(new Point(a.vx, a.vy), b.deg); a.vx = aSpeed.x; a.vy = aSpeed.y; return; } sphereCollision(a, new Sphere(-b.size.x, -b.size.y, 1e-2, 0)); } else if(a.center.y > b.size.y){ var xDiff = -b.size.x - a.center.x; var yDiff = a.center.y - b.size.y; if(SQR(xDiff) + SQR(yDiff) >= SQR(a.r)){ a.center = changeCoordinates(a.center, b.deg); a.center.x += b.center.x; a.center.y += b.center.y; aSpeed = changeCoordinates(new Point(a.vx, a.vy), b.deg); a.vx = aSpeed.x; a.vy = aSpeed.y; return; } sphereCollision(a, new Sphere(-b.size.x, b.size.y, 1e-2, 0)); } else{ a.x = -b.size.x - a.r; a.vx = -abs(a.vx); } } else if(a.center.x > b.size.x){ if(a.center.y < -b.size.y){ var xDiff = a.center.x - b.size.x; var yDiff = -b.size.y - a.center.y; if(SQR(xDiff) + SQR(yDiff) >= SQR(a.r)){ a.center = changeCoordinates(a.center, b.deg); a.center.x += b.center.x; a.center.y += b.center.y; aSpeed = changeCoordinates(new Point(a.vx, a.vy), b.deg); a.vx = aSpeed.x; a.vy = aSpeed.y; return; } sphereCollision(a, new Sphere(b.size.x, -b.size.y, 1e-2, 0)); } else if(a.center.y > b.size.y){ var xDiff = a.center.x - b.size.x; var yDiff = a.center.y - b.size.y; if(SQR(xDiff) + SQR(yDiff) >= SQR(a.r)){ a.center = changeCoordinates(a.center, b.deg); a.center.x += b.center.x; a.center.y += b.center.y; aSpeed = changeCoordinates(new Point(a.vx, a.vy), b.deg); a.vx = aSpeed.x; a.vy = aSpeed.y; return; } sphereCollision(a, new Sphere(b.size.x, b.size.y, 1e-2, 0)); } else{ a.x = b.size.x + a.r; a.vx = abs(a.vx); } } else{ if(a.center.y > 0){ a.y = b.size.y + a.r; a.vy = abs(a.vy); a.center.y += a.vy * 0.01; } else{ a.y = -b.size.y - a.r; a.vy = -abs(a.vy); a.center.y += a.vy * 0.01; } } aSpeed = changeCoordinates(new Point(a.vx, a.vy), b.deg); a.vx = aSpeed.x; a.vy = aSpeed.y; a.center = changeCoordinates(a.center, b.deg); a.center.x += b.center.x; a.center.y += b.center.y; } canvas.addEventListener("click", function(e) { if(action != 2){ return; } var _st = (cursorX*8+cursorY+1)*10+cursorStage+1; var x = e.layerX; var y = e.layerY; if (y > 100 || polygonCount >= stageLimit[_st]) return; for (var i = 0; i < polygonList.length; i++) { if (polygonList[i].type == 'Sphere' && SQR(polygonList[i].center.x - x) + SQR(polygonList[i].center.y - y) < SQR(polygonList[i].r + 10)) return; } polygonCount++; polygonList.push(new Sphere(x, y, 10, 1)); }); var makeField = function() { ctx.clearRect(0, 0, 720, 480); ctx.setLineDash([5, 3]); ctx.strokeStyle = 'gray'; ctx.beginPath(); ctx.moveTo(0, 100); ctx.lineTo(720, 100); ctx.stroke(); ctx.setLineDash([]); var _st = (cursorX*8+cursorY+1)*10+cursorStage+1; ctx.fillStyle = "black"; ctx.textAlign = "end"; ctx.textBaseline = "top"; ctx.fillText(polygonCount + ' / ' + stageLimit[_st], 720, 0); ctx.textAlign = "center"; ctx.textBaseline = "middle"; } var cursorX = 0; var cursorY = 0; var cursorStage = 0; function updateLocations() { makeField(); for (var i = 0; i < polygonList.length; i++) { if (polygonList[i].movable) polygonList[i].updateLocation(); polygonList[i].drawInCanvas(); } for (var i = 0; i < polygonList.length; i++) { for (var j = i + 1; j < polygonList.length; j++) { if (polygonList[i].movable || polygonList[j].movable) { if (polygonList[i].type == 'Sphere' && polygonList[j].type == 'Sphere') { sphereCollision(polygonList[i], polygonList[j]); } else if (polygonList[i].type == 'fixedRectangle' && polygonList[j].type == 'Sphere') { sphereRectCollision(polygonList[j], polygonList[i]); } else if (polygonList[i].type == 'Sphere' && polygonList[j].type == 'fixedRectangle') { sphereRectCollision(polygonList[j], polygonList[j]); } } } } for(var i=0; i<polygonList.length; i++){ if(polygonList[i].exist == 0){ polygonList.splice(i, 1); i--; } } if(stageInterrupt) console.log(stageInterrupt); if(stageInterrupt == 1){ console.log('INTERRUPT!'); return; } if(!stageCleared) setTimeout(updateLocations, 10); else{ var _worldCnt = cursorX*8+cursorY+1; var _tmp = 1; if(cursorStage == 7) _tmp = 3; DB.setItem('stage', max(DB.getItem('stage'), _worldCnt * 10 + cursorStage + _tmp)); stageCleared = 0; console.log(stageData[11]); action = 1; setTimeout(drawMainScreen, 1000); } } var drawMainScreen = function(){ ctx.clearRect(0, 0, 720, 480); stageInterrupt = 0; ctx.fillStyle = "black"; ctx.font = "40px sans-serif"; ctx.textAlign = "center"; ctx.textBaseline = "middle"; ctx.fillText("DROP THE BALL", 360, 50); for(var i=0; i<4; i++){ for(var j=0; j<8; j++){ var _worldCnt = i*8+j+1; if(_worldCnt > worldCount) break; if(cursorX == i && cursorY == j) ctx.strokeStyle = "lime"; else ctx.strokeStyle = "black"; ctx.strokeRect(30+86.25*j, 120+86.25*i, 56.25, 56.25); ctx.font = "12px sans-serif"; ctx.fillStyle = "black"; ctx.fillText("World " + _worldCnt, 59+86.25*j, 160+86.25*i); var _st = DB.getItem('stage'); if(_st >= _worldCnt * 10 + 8){ ctx.fillStyle = "blue"; ctx.fillText("CLEAR", 59+86.25*j, 135+86.25*i); } else if(_st >= (_worldCnt-1) * 10 + 8){ ctx.fillStyle = "green"; ctx.fillText("NOW", 59+86.25*j, 135+86.25*i); } else{ ctx.fillStyle = "red"; ctx.fillText("LOCKED", 59+86.25*j, 135+86.25*i); } } } if(action == 1){ var curWorld = cursorX*8+cursorY+1; for(var j=0; j<8; j++){ if(cursorStage == j) ctx.strokeStyle = "lime"; else ctx.strokeStyle = "black"; ctx.strokeRect(30+86.25*j, 400, 56.25, 56.25); ctx.font = "12px sans-serif"; ctx.fillStyle = "black"; ctx.fillText("Stage " + (j+1), 59+86.25*j, 440); var _st = DB.getItem('stage'); if(_st >= curWorld * 10 + j + 1){ ctx.fillStyle = "blue"; ctx.fillText("CLEAR", 59+86.25*j, 415); } else if(_st == curWorld * 10 + j){ ctx.fillStyle = "green"; ctx.fillText("NOW", 59+86.25*j, 415); } else{ ctx.fillStyle = "red"; ctx.fillText("LOCKED", 59+86.25*j, 415); } } } } window.onkeydown = function() { var _key = event.keyCode; //console.log(_key); if(action == 2){ if(_key == 82){ var _worldCnt = cursorX*8+cursorY+1; stageInterrupt = 1; setTimeout(stageStart, 30, _worldCnt * 10 + cursorStage + 1); } else if(_key == 81){ polygonList = []; action = 1; stageInterrupt = 1; setTimeout(drawMainScreen, 30); } } else if(action == 0){ if(_key == 37){ if(cursorY){ cursorY--; drawMainScreen(); } } else if(_key == 38){ if(cursorX){ cursorX--; drawMainScreen(); } } else if(_key == 39){ var _cnt = cursorX*8+cursorY+2; if(_cnt > worldCount || cursorY==7) return; cursorY++; drawMainScreen(); } else if(_key == 40){ var _worldCnt = cursorX*8+cursorY+9; if(_worldCnt > worldCount) return; cursorX++; drawMainScreen(); } else if(_key == 13){ var _worldCnt = cursorX*8+cursorY+1; if(DB.getItem('stage') >= (_worldCnt-1) * 10 + 8){ action = 1; cursorStage = 0; drawMainScreen(); } } } else if(action == 1){ if(_key == 37){ if(cursorStage){ cursorStage--; drawMainScreen(); } } else if(_key == 39){ if(cursorStage < 7){ cursorStage++; drawMainScreen(); } } else if(_key == 13){ var _worldCnt = cursorX*8+cursorY+1; if(DB.getItem('stage') < _worldCnt * 10 + cursorStage){ return; } action = 2; stageStart(_worldCnt * 10 + cursorStage + 1); } else if(_key == 38){ action = 0; drawMainScreen(); } } } var gameStart = function(){ state = 0; canAddObjects = 0; action = 0; cursorX = cursorY = 0; if(DB.getItem("stage") == null){ DB.setItem("stage", 10); } else if(DB.getItem("stage")%10 >= 8){ DB.setItem("stage", DB.getItem("stage") + (10-(DB.getItem("stage")%10))); } drawMainScreen(); } var stageStart = function(stage){ makeField(); action = 2; polygonList = stageData[stage]; while(polygonList.length > stageDataCnt[stage]){ polygonList.pop(); } polygonCount = 0; stageCleared = 0; stageInterrupt = 0; updateLocations(); } gameStart();