canvas实现大猩猩城市对决互相扔石头攻击对方游戏代码
代码语言:html
所属分类:游戏
代码描述:canvas实现大猩猩城市对决互相扔石头攻击对方游戏代码,支持与电脑对战,双人单人模式、自动模式、暗黑模式。
代码标签: canvas 大猩猩 城市 对决 互相 扔 石头 攻击 对方 游戏 代码
下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开
<!DOCTYPE html> <html lang="en" > <head> <meta charset="UTF-8"> <style> @import url("https://fonts.googleapis.com/css2?family=Inconsolata:wght@400;700&display=swap"); body { margin: 0; padding: 0; font-family: "Inconsolata", monospace; font-size: 14px; color: white; user-select: none; -webkit-user-select: none; display: flex; justify-content: center; align-items: center; height: 100%; overflow: hidden; } button { cursor: pointer; border: none; color: white; background: transparent; font-family: "Inconsolata", monospace; padding: 10px; font-size: 1em; } button:hover { background-color: rgba(255, 255, 255, 0.1); } #info-left, #info-right { position: absolute; top: 20px; } #info-left { left: 25px; } #info-right { right: 25px; text-align: right; } #bomb-grab-area { position: absolute; width: 30px; height: 30px; border-radius: 50%; background-color: transparent; cursor: grab; } #instructions, #congratulations { position: absolute; transition: visibility 0s, opacity 0.5s linear; } @media (min-height: 535px) { #instructions { min-height: 200px; } } #congratulations { background-color: rgba(255, 255, 255, 0.9); color: black; padding: 50px 80px; opacity: 0; visibility: hidden; max-width: 300px; backdrop-filter: blur(5px); } #congratulations p a { color: inherit; } #congratulations button { border: 1px solid rgba(0, 0, 0, 0.9); color: inherit; } #settings { position: absolute; top: calc(20px + 16.385px - 10px); display: flex; align-items: center; gap: 10px; right: 11em; } #settings, #info-left, #info-right { animation: fadeInAnimation ease 6s; animation-iteration-count: 1; animation-fill-mode: forwards; } @media (max-width: 450px) { #settings, #info-left, #info-right { opacity: 0; } #instructions { visibility: hidden; } } /* Basic CSS for the dropdown */ .dropdown { position: relative; display: inline-block; } .dropbtn:after { content: "▼"; margin-left: 7px; font-size: 0.8em; vertical-align: text-top; } .dropdown-content { display: none; position: absolute; background-color: #f9f9f9; min-width: 120px; box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2); } .dropdown-content a { color: black; padding: 12px 16px; text-decoration: none; display: block; white-space: nowrap; font-size: 0.9em; } .dropdown-content a:hover { background-color: #f1f1f1; } /* Show dropdown content when hovering over the button */ .dropdown:hover .dropdown-content { display: block; } #windmill { position: absolute; right: 0; fill: rgba(255, 255, 255, 0.5); transform-origin: bottom; } #windmill-head { animation-name: rotate; animation-duration: 4s; animation-iteration-count: infinite; animation-timing-function: linear; } @keyframes rotate { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } #wind-info { position: absolute; width: 100px; text-align: center; margin-bottom: 30px; } #youtube, #youtube-card { display: none; } @media (min-height: 425px) { /** Youtube logo by https://codepen.io/alvaromontoro */ #youtube { z-index: 2; display: block; width: 30px; height: 21px; background: red; position: relative; border-radius: 50% / 11%; transition: transform 0.5s; color: black; } #youtube:hover, #youtube:focus { transform: scale(1.2); } #youtube::before { content: ""; display: block; position: absolute; top: 7.5%; left: -6%; width: 112%; height: 85%; background: red; border-radius: 9% / 50%; } #youtube::after { content: ""; display: block; position: absolute; top: 6px; left: 11px; width: 15px; height: 10px; border: 5px solid transparent; box-sizing: border-box; border-left: 10px solid white; } #youtube span { font-size: 0; position: absolute; width: 0; height: 0; overflow: hidden; } #youtube:hover + #youtube-card { color: black; display: block; position: absolute; top: -20px; right: -20px; padding: 25px 60px 25px 25px; width: 200px; background-color: white; } } @keyframes fadeInAnimation { 0% { opacity: 0; } 70% { opacity: 0; } 100% { opacity: 1; } } </style> </head> <body translate="no"> <canvas id="game"></canvas> <svg width="200" height="250" id="windmill"> <defs> <path id="arm" d="M -7 -20 C -7 -10 7 -10 7 -20 L 2 -80 L -2 -80" /> </defs> <g transform="translate(100, 100)"> <g id="windmill-head"> <circle r="8"></circle> <use href="#arm" /> <use href="#arm" transform="rotate(+120)" /> <use href="#arm" transform="rotate(-120)" /> </g> </g> <path transform="translate(100, 0)" d="M -7 250 L 7 250 L 3 115 L -3 115" ></path> </svg> <div id="wind-info">Wind Speed: <span id="wind-speed">0</span></div> <div id="info-left"> <h3><span class="name">Player</span></h3> <p>Angle: <span class="angle">0</span>°</p> <p>Velocity: <span class="velocity">0</span></p> </div> <div id="info-right"> <h3><span class="name">Computer</span></h3> <p>Angle: <span class="angle">0</span>°</p> <p>Velocity: <span class="velocity">0</span></p> </div> <div id="instructions"> <h3 id="game-mode">Player vs. Computer</h3> <h1>Drag the bomb to aim!</h1> </div> <div id="bomb-grab-area"></div> <div id="congratulations"> <h1><span id="winner">?</span> won!</h1> <p> Learn How to Code This Game with Plain JavaScript and HTML Canvas on <a href="https://youtu.be/2q5EufbUEQk?si=w2Himy4oN99AQeks" target="_top" >YouTube</a >! </p> <p> Say hello <a href="https://twitter.com/HunorBorbely" target="_top">@HunorBorbely</a >. </p> <div class="dropdown"> <button class="dropbtn">New Game</button> <div class="dropdown-content"> <a href="#" class="single-player">Single Player</a> <a href="#" class="two-players">Two-Player</a> <a href="#" class="auto-play">Autoplay</a> </div> </div> </div> <div id="settings"> <div class="dropdown"> <button class="dropbtn">New Game</button> <div class="dropdown-content"> <a href="#" class="single-player">Single Player</a> <a href="#" class="two-players">Two-Players</a> <a href="#" class="auto-play">Autoplay</a> </div> </div> <button id="color-mode">Dark Mode</button> </div> <script > let state = {}; let isDragging = false; let dragStartX = undefined; let dragStartY = undefined; let previousAnimationTimestamp = undefined; let animationFrameRequestID = undefined; let delayTimeoutID = undefined; let simulationMode = false; let simulationImpact = {}; // Settings const settings = { numberOfPlayers: 1, // 0 means two computers are playing against each other mode: "light" }; const blastHoleRadius = 18; // The main canvas element and its drawing context const canvas = document.getElementById("game"); canvas.width = window.innerWidth * window.devicePixelRatio; canvas.height = window.innerHeight * window.devicePixelRatio; canvas.style.width = window.innerWidth + "px"; canvas.style.height = window.innerHeight + "px"; const ctx = canvas.getContext("2d"); // Windmill const windmillDOM = document.getElementById("windmill"); const windmillHeadDOM = document.getElementById("windmill-head"); const windInfoDOM = document.getElementById("wind-info"); const windSpeedDOM = document.getElementById("wind-speed"); // Left info panel const name1DOM = document.querySelector("#info-left .name"); const angle1DOM = document.querySelector("#info-left .angle"); const velocity1DOM = document.querySelector("#info-left .velocity"); // Right info panel const name2DOM = document.querySelector("#info-right .name"); const angle2DOM = document.querySelector("#info-right .angle"); const velocity2DOM = document.querySelector("#info-right .velocity"); // Instructions panel const instructionsDOM = document.getElementById("instructions"); const gameModeDOM = document.getElementById("game-mode"); // The bomb's grab area const bombGrabAreaDOM = document.getElementById("bomb-grab-area"); // Congratulations panel const congratulationsDOM = document.getElementById("congratulations"); const winnerDOM = document.getElementById("winner"); // Settings toolbar const singlePlayerButtonDOM = document.querySelectorAll(".single-player"); const twoPlayersButtonDOM = document.querySelectorAll(".two-players"); const autoPlayButtonDOM = document.querySelectorAll(".auto-play"); const colorModeButtonDOM = document.getElementById("color-mode"); colorModeButtonDOM.addEventListener("click", () => { if (settings.mode === "dark") { settings.mode = "light"; colorModeButtonDOM.innerText = "Dark Mode"; } else { settings.mode = "dark"; colorModeButtonDOM.innerText = "Light Mode"; } draw(); }); newGame(); function newGame() { // Reset game state state = { phase: "aiming", // aiming | in flight | celebrating currentPlayer: 1, round: 1, windSpeed: generateWindSpeed(), bomb: { x: undefined, y: undefined, rotation: 0, velocity: { x: 0, y: 0 }, highlight: true }, // Buildings backgroundBuildings: [], buildings: [], blastHoles: [], stars: [], scale: 1 }; // Generate stars for (let i = 0; i < window.innerWidth * window.innerHeight / 12000; i++) { const x = Math.floor(Math.random() * window.innerWidth / state.scale); const y = Math.floor(Math.random() * window.innerHeight / state.scale); state.stars.push({ x, y }); } // Generate background buildings for (let i = 0; i < 12; i++) { generateBackgroundBuilding(i); } // Generate buildings for (let i = 0; i < 8; i++) { generateBuilding(i); } calculateScale(); initializeBombPosition(); initializeWindmillPosition(); setWindMillRotation(); // Cancel any ongoing animation and timeout cancelAnimationFrame(animationFrameRequestID); clearTimeout(delayTimeoutID); // Reset HTML elements if (settings.numberOfPlayers > 0) { showInstructions(); } else { hideInstructions(); } hideCongratulations(); angle1DOM.innerText = 0; velocity1DOM.innerText = 0; angle2DOM.innerText = 0; velocity2DOM.innerText = 0; // Reset simulation mode simulationMode = false; simulationImpact = {}; draw(); if (settings.numberOfPlayers === 0) { computerThrow(); } } function showInstructions() { singlePlayerButtonDOM.checked = true; instructionsDOM.style.opacity = 1; instructionsDOM.style.visibility = "visible"; } function hideInstructions() { state.bomb.highlight = false; instructionsDOM.style.opacity = 0; instructionsDOM.style.visibility = "hidden"; } function showCongratulations() { congratulationsDOM.style.opacity = 1; congratulationsDOM.style.visibility = "visible"; } function hideCongratulations() { congratulationsDOM.style.opacity = 0; congratulationsDOM.style.visibility = "hidden"; } function generateBackgroundBuilding(index) { const previousBuilding = state.backgroundBuildings[index - 1]; const x = previousBuilding ? previousBuilding.x + previousBuilding.width + 4 : -100; const minWidth = 60; const maxWidth = 110; const width = minWidth + Math.random() * (maxWidth - minWidth); const minHeight = 80; const maxHeight = 350; const height = minHeight + Math.random() * (maxHeight - minHeight); state.backgroundBuildings.push({ x, width, height }); } function generateBuilding(index) { const previousBuilding = state.buildings[index - 1]; const x = previousBuilding ? previousBuilding.x + previousBuilding.width + 4 : 0; const minWidth = 80; const maxWidth = 130; const width = minWidth + Math.random() * (maxWidth - minWidth); const platformWithGorilla = index === 1 || index === 6; const platformWithWindmill = index === 7; const smallerBuilding = platformWithGorilla || platformWithWindmill; const minHeight = 40; const maxHeight = 300; const minHeightGorilla = 30; const maxHeightGorilla = 150; const height = smallerBuilding ? minHeightGorilla + Math.random() * (maxHeightGorilla - minHeightGorilla) : minHeight + Math.random() * (maxHeight - minHeight); // Generate an array of booleans to show if the light is on or off in a room const lightsOn = []; for (let i = 0; i < 50; i++) { const light = Math.random() <= 0.33 ? true : false; lightsOn.push(light); } state.buildings.push({ x, width, height, lightsOn }); } function calculateScale() { const lastBuilding = state.buildings.at(-1); const totalWidthOfTheCity = lastBuilding.x + lastBuilding.width; state.horizontalScale = window.innerWidth / totalWidthOfTheCity ?? 1; state.verticalScale = window.innerHeight / 500; console.log(state.horizontalScale, state.verticalScale); state.scale = Math.min(state.horizontalScale, state.verticalScale); } window.addEventListener("resize", () => { canvas.width = window.innerWidth * window.devicePixelRatio; canvas.height = window.innerHeight * window.devicePixelRatio; canvas.style.width = window.innerWidth + "px"; canvas.style.height = window.innerHeight + "px"; calculateScale(); initializeBombPosition(); initializeWindmillPosition(); draw(); }); function initializeBombPosition() { const building = state.currentPlayer === 1 ? state.buildings.at(1) // Second building : state.buildings.at(-2); // Second last building const gorillaX = building.x + building.width / 2; const gorillaY = building.height; const gorillaHandOffsetX = state.currentPlayer === 1 ? -28 : 28; const gorillaHandOffsetY = 107; state.bomb.x = gorillaX + gorillaHandOffsetX; state.bomb.y = gorillaY + gorillaHandOffsetY; state.bomb.velocity.x = 0; state.bomb.velocity.y = 0; state.bomb.rotation = 0; // Initialize the position of the grab area in HTML const grabAreaRadius = 15; let left = state.bomb.x * state.scale - grabAreaRadius; let bottom = state.bomb.y * state.scale - grabAreaRadius; if (state.horizontalScale > state.verticalScale) { const lastBuilding = state.buildings.at(-1); const totalWidthOfTheCity = lastBuilding.x + lastBuilding.width; const shift = (window.innerWidth - totalWidthOfTheCity * state.scale) / 2; left += shift; } bombGrabAreaDOM.style.left = `${left}px`; bombGrabAreaDOM.style.bottom = `${bottom}px`; } function initializeWindmillPosition() { // Move windmill into position const lastBuilding = state.buildings.at(-1); let rooftopY = lastBuilding.height * state.scale; let rooftopX = (lastBuilding.x + lastBuilding.width / 2) * state.scale; // If the view is centered vertically then move the windmill as well if (state.horizontalScale > state.verticalScale) { const lastBuilding = state.buildings.at(-1); const totalWidthOfTheCity = lastBuilding.x + lastBuilding.width; const shift = (window.innerWidth - totalWidthOfTheCity * state.scale) / 2; rooftopX += shift; } windmillDOM.style.bottom = `${rooftopY}px`; windmillDOM.style.left = `${rooftopX - 100}px`; windmillDOM.style.scale = state.scale; windInfoDOM.style.bottom = `${rooftopY}px`; windInfoDOM.style.left = `${rooftopX - 50}px`; } function draw() { ctx.save(); // Flip coordinate system upside down ctx.scale(window.devicePixelRatio, window.devicePixelRatio); drawBackground(); ctx.translate(0, window.innerHeight); ctx.scale(1, -1); if (state.horizontalScale > state.verticalScale) { const lastBuilding = state.buildings.at(-1); const totalWidthOfTheCity = lastBuilding.x + lastBuilding.width; const shift = (window.innerWidth - totalWidthOfTheCity * state.scale) / 2; ctx.translate(shift, 0); } ctx.scale(state.scale, state.scale); // Draw scene drawBackgroundBuildings(); drawBuildingsWithBlastHoles(); drawGorilla(1); drawGorilla(2); drawBomb(); // Restore transformation ctx.restore(); } function drawBackground() { const gradient = ctx.createLinearGradient(0, 0, 0, window.innerHeight); if (settings.mode === "dark") { gradient.addColorStop(1, "#27507F"); gradient.addColorStop(0, "#58A8D8"); } else { gradient.addColorStop(1, "#F8BA85"); gradient.addColorStop(0, "#FFC28E"); } // Draw sky ctx.fillStyle = gradient; ctx.fillRect(0, 0, window.innerWidth, window.innerHeight); // Draw stars if (settings.mode === "dark") { ctx.fillStyle = "white"; state.star.........完整代码请登录后点击上方下载按钮下载查看
网友评论0