Drop the Ball: 두 판 사이의 차이
잔글 (게임정보 일괄 수정: 장르분류 삭제, 게임정보 추가) 태그: 되돌려진 기여 |
잔글 (BANBOT의 편집을 172.19.0.1의 마지막 판으로 되돌림) 태그: 일괄 되돌리기 |
||
1번째 줄: | 1번째 줄: | ||
{{게임 | {{pluginX|script=사용자:Bd3076/Drop the Ball/plugin|name=Drop the Ball|creator=Bd3076}} | ||
{{Bd3076의 게임}} | |||
[[분류:리버티게임]]{{장르 분류}} |
2023년 8월 25일 (금) 11:13 판
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();