原生js实现火车变轨通行引导游戏代码
代码语言:html
所属分类:游戏
代码描述:原生js实现火车变轨通行引导游戏代码,在图中点击鼠标变动错乱的轨道让火车可以通行。
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Coustard&display=block'> <style> body { margin: 0; background-color: #252021; height: 100vh; display: flex; align-items: center; text-transform: uppercase; overflow: hidden; } .canvas-container { position: relative; width: 100vmin; height: 100vmin; display: block; text-align: center; margin: 0 auto; } .canvas-container a { display: none; position: absolute; right: 5%; top: 5%; } .canvas-container canvas { height: 100%; } .modal { position: absolute; width: 130px; height: 183px; font-size: 14px; background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/21151/ticket.svg); background-repeat: no-repeat; background-size: contain; color: #019897; text-align: center; left: 50%; top: 50%; font-family: "Coustard", serif; transform: translateX(-50%) translateY(-50%); padding: 20px; transition: 0.2s all; } .modal__gameover, .modal__win { display: none; } .modal__gameover .modal__title, .modal__win .modal__title { padding: 40px 0 25px; } .modal__loading { display: none; } .game--active .canvas-container a { display: block; } .game--active .modal { pointer-events: none; opacity: 0; transform: translateX(-50%) translateY(0); } .game--over .modal__gameover { display: block; } .game--over .modal__main, .game--over .modal__win { display: none; } .game--win .modal__win { display: block; } .game--win .modal__gameover, .game--win .modal__main { display: none; } .game--loading .modal__main { display: none; } .game--loading .modal__loading { display: block; } .modal__title { padding: 10px 0 17px; margin: 0; color: #f38073; line-height: 1.1; font-weight: normal; } .modal__text { margin: 2.5em 0; } .modal__controls { display: flex; justify-content: center; margin: 17px 0 10px; } .btn { font-family: "Coustard", serif; display: inline-block; line-height: 40px; background-color: #d8d1c6; padding: 0 20px; color: #252021; cursor: pointer; text-transform: none; } .btn:hover { background-color: #c3b9a8; } input[type=range] { -webkit-appearance: none; background-color: transparent; } input[type=range]::-webkit-slider-runnable-track { width: 129px; height: 6px; background-color: #01aead; border: none; border-radius: 3px; } input[type=range]::-moz-range-track { width: 129px; height: 6px; background-color: #01aead; border: none; border-radius: 3px; } input[type=range]::-ms-track { width: 129px; height: 6px; background-color: #01aead; border: none; border-radius: 3px; margin: 5px 0; } input[type=range]::-webkit-slider-thumb { -webkit-appearance: none; border: none; height: 16px; width: 16px; border-radius: 50%; background-color: #f38073; margin-top: -5px; } input[type=range]::-moz-range-thumb { -webkit-appearance: none; border: none; height: 16px; width: 16px; border-radius: 50%; background-color: #f38073; margin-top: -5px; } input[type=range]::-ms-thumb { margin-top: 0; } /*input[type=range]::-ms-fill-lower { background: #2a6495; border: 0.2px solid #010101; border-radius: 2.6px; box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; } input[type=range]::-ms-fill-upper { background: #3071a9; border: 0.2px solid #010101; border-radius: 2.6px; box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; }*/ input[type=range]:focus { outline: none; } input[type=range]:focus::-webkit-slider-runnable-track { background-color: #016565; } input[type=range]:focus::-moz-range-track { background-color: #016565; } </style> </head> <body class="game game--loading"> <div class="canvas-container"><a class="btn" onclick="finish()">Finished</a> <canvas width="1380" height="1380"></canvas> </div> <div class="modal"> <div class="modal__content modal__main"> <h2 class="modal__title">Train Puzzle</h2> <label>Difficulty <input type="range" min="1" max="100" value="25" oninput="setSpeed(this)"/> </label> <div class="modal__controls"><a class="btn" onclick="playLevel(false, false)">Play</a></div> </div> <div class="modal__content modal__loading"> <h2 class="modal__title">Train Puzzle</h2> <div class="modal__text">Loading...</div> </div> <div class="modal__content modal__gameover"> <h2 class="modal__title">Game Over</h2> <div class="modal__controls"><a class="btn" onclick="gotoMenu()">Try again</a></div> </div> <div class="modal__content modal__win"> <h2 class="modal__title">Well done!</h2> <div class="modal__controls"><a class="btn" onclick="gotoMenu()">Thanks</a></div> </div> </div> <script> const lerp = (norm, min, max) => { return (max - min) * norm + min; } const norm = (value, min, max) => { return (value - min) / (max - min); } const map = (value, sourceMin, sourceMax, destMin, destMax) => { return lerp(norm(value, sourceMin, sourceMax), destMin, destMax); } const TileTypes = Object.freeze({ "upleft": 1, "upright": 2, "downleft": 3, "downright": 4, "horizontal": 5, "vertical": 6, "shadow": 7, "blocker": 9 }); const Directions = Object.freeze({ "up": 1, "right": 2, "down": 3, "left": 4 }); class Line { constructor(startPos, endPos) { this.startPos = startPos; this.endPos = endPos; } isIntersecting(line) { let det = (this.endPos.x - this.startPos.x) * (line.endPos.y - line.startPos.y) - (line.endPos.x - line.startPos.x) * (this.endPos.y - this.startPos.y), gamma, lambda; if (det === 0) { return false; } else { lambda = ((line.endPos.y - line.startPos.y) * (line.endPos.x - this.startPos.x) + (line.startPos.x - line.endPos.x) * (line.endPos.y - this.startPos.y)) / det; gamma = ((this.startPos.y - this.endPos.y) * (line.endPos.x - this.startPos.x) + (this.endPos.x - this.startPos.x) * (line.endPos.y - this.startPos.y)) / det; return (0 < lambda && lambda < 1) && (0 < gamma && gamma < 1); } } } class PathPos { constructor(x, y, trail) { this.x = x; this.y = y; this.trail = [...trail]; this.finishFound = false; this.tileType = ""; } getAdjacent(l, prev) { let directions = [ { x: 0, y: -1, dir: 'up' }, { x: 0, y: 1, dir: 'down' }, { x: -1, y: 0, dir: 'left' }, { x: 1, y: 0, dir: 'right' } ], adjPathPositions = []; if(Math.random() >= 0.5) { directions = directions.reverse(); } for (var i = 0; i < directions.length; i++) { let dir = directions[i], newpos = { x: this.x + dir.x, y: this.y + dir.y }, posKey = newpos.x + 'x' + newpos.y; if(newpos.x >= 0 && newpos.y >= 0 && newpos.x < 8 && newpos.y < 8) { if(l.level[newpos.y][newpos.x] !== 9 && !prev.includes(posKey)) { this.trail.push(this); prev.push(posKey); let newPathPos = new PathPos(newpos.x, newpos.y, this.trail); if(newpos.x === l.end.x && newpos.y === l.end.y) { newPathPos.finishFound = true; } adjPathPositions.push(newPathPos); } } }; return adjPathPositions; } } const levelFactory = { newLevel: (difficulty, debug) => { let l = null, path = [], minLength = 9; //difficulty > 50 ? 8 : 6; while(path.length < minLength) { l = levelFactory.generateLevel(difficulty); path = levelFactory.findPath(l); } levelFactory.addTrailToMap(l.level, path, l.end); for(let i = 0; i < l.level.length; i++) { for(let j = 0; j < l.level[i].length; j++) { if(l.level[i][j] === 0) { l.level[i][j] = levelFactory.randomNumber(1, 6); } } } // Remove frame for (let i = 0; i <= 7; i++) { if(l.level[i][0] === 9) { l.level[i][0] = 0; } if(l.level[0][i] === 9) { l.level[0][i] = 0; } if(l.level[i][7] === 9) { l.level[i][7] = 0; } if(l.level[7][i] === 9) { l.level[7][i] = 0; } } if(debug) { levelFactory.drawLevel(l, path); } return l; }, drawLevel: (l, path) => { let c = document.getElementById("canvas"); let ctx = c.getContext("2d"); let colors = { "c1": "coral", "c2": "green", "c3": "aqua", "c4": "sienna", "c5": "maroon", "c6": "ivory", "c9": "pink" // blocker } ctx.clearRect(0, 0, c.width, c.height); for(let i = 0; i < l.level.length; i++) { for(let j = 0; j < l.level[i].length; j++) { let tileType = l.level[i][j]; if(tileType !== 0) { levelFactory.drawSquare(ctx, j, i, colors['c' + tileType]); } } } /*for(let i = 0; i < path.length; i++) { levelFactory.drawSquare(ctx, path[i].x, path[i].y, 'rgba(0,255,0,0.1)'); };*/ }, generateLevel: difficulty => { const l = { level: [ [9, 9, 9, 9, 9, 9, 9, 9], [9, 0, 0, 0, 0, 0, 0, 9], [9, 0, 0, 0, 0, 0, 0, 9], [9, 0, 0, 0, 0, 0, 0, 9], [9, 0, 0, 0, 0, 0, 0, 9], [9, 0, 0, 0, 0, 0, 0, 9], [9, 0, 0, 0, 0, 0, 0, 9], [9, 9, 9, 9, 9, 9, 9, 9], ], start: Math.random() >= 0.5 ? { x: levelFactory.randomNumber(1, 6), y: 0 } : { x: 0, y: levelFactory.randomNumber(1, 6) }, end: Math.random() >= 0.5 ? { x: levelFactory.randomNumber(1, 6), y: 7 } : { x: 7, y: levelFactory.randomNumber(1, 6) }, spare: levelFactory.randomNumber(1, 6) }; let minBlockers = Math.floor(levelFactory.randomNumber(1, 100) / 10); // difficulty / 10 l.level[l.start.y][l.start.x] = (l.start.x == 0) ? 6 : 5; l.level[l.end.y][l.end.x] = (l.end.x == 7) ? 6 : 5; // Add blockers for (let i = 0; i < levelFactory.randomNumber(minBlockers, 10); i++) { let x = levelFactory.randomNumber(1, 6), y = levelFactory.randomNumber(1, 6); l.level[y][x] = 9; if(Math.random() > 0.5) { l.level[y][x + 1] = 9; } if(Math.random() > 0.5) { l.level[y + 1][x] = 9; } } return l; }, randomNumber: (min, max) => { return Math.floor(Math.random() * (max - min + 1)) + min; }, findPath: l => { let pos = new PathPos(l.start.x, l.start.y, []), prev = []; let t = levelFactory.recursiveAdjacentPositions([pos], l, prev); return t; }, addTrailToMap: (level, path, endPos) => { let dir = ""; for(let i = 0; i < path.length; i++) { let trailTile = path[i], nextPos = {}; if(path[i + 1]) { nextPos = { x: path[i + 1].x, y: path[i + 1].y } } else { nextPos = endPos; } let change = levelFactory.getNextTilePosition(trailTile, nextPos); if(trailTile.y === 0) { level[trailTile.y][trailTile.x] = 6; // vertical dir = 'down'; } else if(trailTile.x === 0) { level[trailTile.y][trailTile.x] = 5; // horizontal dir = 'right'; } if(change) { if(dir === 'down') { if(change === 'left') { level[trailTile.y][trailTile.x] = 3; dir = 'left'; } else if (change === 'right') { level[trailTile.y][trailTile.x] = 4; dir = 'right'; } else { level[trailTile.y][trailTile.x] = 5; } } else if(dir === 'up') { if(change === 'left') { level[trailTile.y][trailTile.x] = 1; dir = 'left'; } else if (change === 'right') { level[trailTile.y][trailTile.x] = 2; dir = 'right'; } else { level[trailTile.y][trailTile.x] = 5; } } else if(dir === 'right') { if(change === 'up') { level[trailTile.y][trailTile.x] = 3; dir = 'up'; } else if (change === 'down') { level[trailTile.y][trailTile.x] = 1; dir = 'down'; } else { level[trailTile.y][trailTile.x] = 6; } } else if(dir === 'left') { if(change === 'up') { level[trailTile.y][trailTile.x] = 4; dir = 'up'; } else if (change === 'down') { level[trailTile.y][trailTile.x] = 2; dir = 'down'; } else { level[trailTile.y][trailTile.x] = 6; } } } } }, getNextTilePosition: (trailTile, nextPos) => { if(!nextPos) return; let change = { x: nextPos.x - trailTile.x, y: nextPos.y - trailTile.y } if(change.x === -1) return 'left'; if(change.x === 1) return 'right'; if(change.y === -1) return 'up'; if(change.y === 1) return 'down'; }, recursiveAdjacentPositions: (positions, l, prev) => { let manyPos = []; for (let i = 0; i < positions.length; i++) { let pos = positions[i], adjacentPositions = pos.getAdjacent(l, prev); manyPos = manyPos.concat(adjacentPositions); for (let j = 0; j < adjacentPositions.length; j++) { let p = adjacentPositions[j]; if(p.finishFound) { return p.trail; } } } if(manyPos.length) { let res = levelFactory.recursiveAdjacentPositions(manyPos, l, prev); if(res.length) return res; } return []; }, drawSquare: (ctx, x, y, color) => { ctx.beginPath(); ctx.fillStyle = color; ctx.rect(40 * x, 40 * y, 40, 40); ctx.fill(); } } const puzzleSpritesFactory = quality => { class Rectangle { constructor(center, radius, rotation) { this.radius = radius; this.center = center; this.rotation = rotation; this.rotate(rotation); } rotate(r) { this.rotation = r; this.p1 = this.getPoint(this.center, r + 30, this.radius); this.p2 = this.........完整代码请登录后点击上方下载按钮下载查看
网友评论0