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