js实现重力感应迷宫球滚动小游戏代码

代码语言:html

所属分类:游戏

代码描述:js实现重力感应迷宫球滚动小游戏代码

代码标签: 感应 迷宫 滚动 小游戏

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开


<!DOCTYPE html>
<html lang="en" >

<head>

 
<meta charset="UTF-8">

 
 
<style>
body
{
 
/* https://coolors.co/f06449-ede6e3-7d82b8-36382e-613f75  */
 
--background-color: #ede6e3;
 
--wall-color: #36382e;
 
--joystick-color: #210124;
 
--joystick-head-color: #f06449;
 
--ball-color: #f06449;
 
--end-color: #7d82b8;
 
--text-color: #210124;

 
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
 
background-color: var(--background-color);
}

html
,
body
{
 
height: 100%;
 
margin: 0;
}

#center {
 
display: flex;
 
align-items: center;
 
justify-content: center;
 
height: 100%;
}

#game {
 
display: grid;
 
grid-template-columns: auto 150px;
 
grid-template-rows: 1fr auto 1fr;
 
gap: 30px;
 
perspective: 600px;
}

#maze {
 
position: relative;
 
grid-row: 1 / -1;
 
grid-column: 1;
 
width: 350px;
 
height: 315px;
 
display: flex;
 
justify-content: center;
 
align-items: center;
}

#end {
 
width: 65px;
 
height: 65px;
 
border: 5px dashed var(--end-color);
 
border-radius: 50%;
}

#joystick {
 
position: relative;
 
background-color: var(--joystick-color);
 
border-radius: 50%;
 
width: 50px;
 
height: 50px;
 
display: flex;
 
align-items: center;
 
justify-content: center;
 
margin: 10px 50px;
 
grid-row: 2;
}

#joystick-head {
 
position: relative;
 
background-color: var(--joystick-head-color);
 
border-radius: 50%;
 
width: 20px;
 
height: 20px;
 
cursor: grab;

 
animation-name: glow;
 
animation-duration: 0.6s;
 
animation-iteration-count: infinite;
 
animation-direction: alternate;
 
animation-timing-function: ease-in-out;
 
animation-delay: 4s;
}

@keyframes glow {
 
0% {
   
transform: scale(1);
 
}
 
100% {
   
transform: scale(1.2);
 
}
}

.joystick-arrow:nth-of-type(1) {
 
position: absolute;
 
bottom: 55px;

 
width: 0;
 
height: 0;
 
border-left: 10px solid transparent;
 
border-right: 10px solid transparent;

 
border-bottom: 10px solid var(--joystick-color);
}

.joystick-arrow:nth-of-type(2) {
 
position: absolute;
 
top: 55px;

 
width: 0;
 
height: 0;
 
border-left: 10px solid transparent;
 
border-right: 10px solid transparent;

 
border-top: 10px solid var(--joystick-color);
}

.joystick-arrow:nth-of-type(3) {
 
position: absolute;
 
left: 55px;

 
width: 0;
 
height: 0;
 
border-top: 10px solid transparent;
 
border-bottom: 10px solid transparent;

 
border-left: 10px solid var(--joystick-color);
}

.joystick-arrow:nth-of-type(4) {
 
position: absolute;
 
right: 55px;

 
width: 0;
 
height: 0;
 
border-top: 10px solid transparent;
 
border-bottom: 10px solid transparent;

 
border-right: 10px solid var(--joystick-color);
}

#note {
 
grid-row: 3;
 
grid-column: 2;
 
text-align: center;
 
font-size: 0.8em;
 
color: var(--text-color);
 
transition: opacity 2s;
}

a:visited {
 
color: inherit;
}

.ball {
 
position: absolute;
 
margin-top: -5px;
 
margin-left: -5px;
 
border-radius: 50%;
 
background-color: var(--ball-color);
 
width: 10px;
 
height: 10px;
}

.wall {
 
position: absolute;
 
background-color: var(--wall-color);
 
transform-origin: top center;
 
margin-left: -5px;
}

.wall::before,
.wall::after {
 
display: block;
 
content: "";
 
width: 10px;
 
height: 10px;
 
background-color: inherit;
 
border-radius: 50%;
 
position: absolute;
}

.wall::before {
 
top: -5px;
}

.wall::after {
 
bottom: -5px;
}

.black-hole {
 
position: absolute;
 
margin-top: -9px;
 
margin-left: -9px;
 
border-radius: 50%;
 
background-color: black;
 
width: 18px;
 
height: 18px;
}

#youtube,
#youtube-card {
 
display: none;
}

@media (min-height: 425px) {
 
/** Youtube logo by https://codepen.io/alvaromontoro */
 
#youtube {
   
z-index: 2;
   
display: block;
   
width: 100px;
   
height: 70px;
   
position: absolute;
   
bottom: 20px;
   
right: 20px;
   
background: red;
   
border-radius: 50% / 11%;
   
transform: scale(0.8);
   
transition: transform 0.5s;
 
}

 
#youtube:hover,
 
#youtube:focus {
   
transform: scale(0.9);
 
}

 
#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: 20px;
   
left: 40px;
   
width: 45px;
   
height: 30px;
   
border: 15px solid transparent;
   
box-sizing: border-box;
   
border-left: 30px solid white;
 
}

 
#youtube span {
   
font-size: 0;
   
position: absolute;
   
width: 0;
   
height: 0;
   
overflow: hidden;
 
}

 
#youtube:hover + #youtube-card {
   
display: block;
   
position: absolute;
   
bottom: 12px;
   
right: 10px;
   
padding: 25px 130px 25px 25px;
   
width: 300px;
   
background-color: white;
 
}
}
</style>



</head>

<body translate="no" >
 
<div id="center">
 
<div id="game">
   
<div id="maze">
     
<div id="end"></div>
   
</div>
   
<div id="joystick">
     
<div class="joystick-arrow"></div>
     
<div class="joystick-arrow"></div>
     
<div class="joystick-arrow"></div>
     
<div class="joystick-arrow"></div>
     
<div id="joystick-head"></div>
   
</div>
   
<div id="note">
      Click the joystick to start!
     
<p>Move every ball to the center. Ready for hard mode? Press H</p>
   
</div>
 
</div>
</div>


 
 
     
<script>
/*

If you want to know how this game works, you can find a source code walkthrough video here: https://youtu.be/bTk6dcAckuI

Follow me on twitter for more: https://twitter.com/HunorBorbely

*/

Math.minmax = (value, limit) => {
  return Math.max(Math.min(value, limit), -limit);
};

const distance2D = (p1, p2) => {
  return Math.sqrt((p2.x - p1.x) ** 2 + (p2.y - p1.y) ** 2);
};

// Angle between the two points
const getAngle = (p1, p2) => {
  let angle = Math.atan((p2.y - p1.y) / (p2.x - p1.x));
  if (p2.x - p1.x < 0) angle += Math.PI;
  return angle;
};

// The closest a ball and a wall cap can be
const closestItCanBe = (cap, ball) => {
  let angle = getAngle(cap, ball);

  const deltaX = Math.cos(angle) * (wallW / 2 + ballSize / 2);
  const deltaY = Math.sin(angle) * (wallW / 2 + ballSize / 2);

  return { x: cap.x + deltaX, y: cap.y + deltaY };
};

// Roll the ball around the wall cap
const rollAroundCap = (cap, ball) => {
  // The direction the ball can't move any further because the wall holds it back
  let impactAngle = getAngle(ball, cap);

  // The direction the ball wants to move based on it's velocity
  let heading = getAngle(
  { x: 0, y: 0 },
  { x: ball.velocityX, y: ball.velocityY });


  // The angle between the impact direction and the ball's desired direction
  // The smaller this angle is, the bigger the impact
  // The closer it is to 90 degrees the smoother it gets (at 90 there would be no collision)
  let impactHeadingAngle = impactAngle - heading;

  // Velocity distance if not hit would have occurred
  const velocityMagnitude = distance2D(
  { x: 0, y: 0 },
  { x: ball.velocityX, y: ball.velocityY });

  // Velocity component diagonal to the impact
  const velocityMagnitudeDiagonalToTheImpact =
  Math.sin(impactHeadingAngle) * velocityMagnitude;

  // How far should the ball be from the wall cap
  const closestDistance = wallW / 2 + ballSize / 2;

  const rotationAngle = Math.atan(
  velocityMagnitudeDiagonalToTheImpact / closestDistance);


  const deltaFromCap = {
    x: Math.cos(impactAngle + Math.PI - rotationAngle) * closestDistance,
    y: Math.sin(impactAngle + Math.PI - rotationAngle) * closestDistance };


  const x = ball.x;
  const y = ball.y;
  const velocityX = ball.x - (cap.x + deltaFromCap.x);
  const velocityY = ball.y - (cap.y + deltaFromCap.y);
  const nextX = x + velocityX;
  const nextY = y + velocityY;

  return { x, y, velocityX, velocityY, nextX, nextY };
};

// Decreases the absolute value of a number but keeps it's sign, doesn't go below abs 0
const slow = (number, difference) => {
  if (Math.abs(number) <= difference) return 0;
  if (number > difference) return number - difference;
  return number + difference;
};

const mazeElement = document.getElementById("maze");
const joystickHeadElement = document.getElementById("joystick-head");
const noteElement = document.getElementById("note"); // Note element for instructions and game won, game failed texts

let hardMode = false;
let previousTimestamp;
let gameInProgress;
let mouseStartX;
let mouseStartY;
let accelerationX;
let accelerationY;
let frictionX;
let frictionY;

const pathW = 25; // Path width
const wallW = 10; // Wall width
const ballSize = 10; // Width and height of the ball
const holeSize = 18;

const debugMode = false;

let balls = [];
let ballElements = [];
let holeElements = [];

resetGame();

// Draw balls for the first time
balls.forEach(({ x, y }) => {
  const ball = document.createElement("div");
  ball.setAttribute("class", "ball");
  ball.style.cssText = `left: ${x}px; top: $.........完整代码请登录后点击上方下载按钮下载查看

网友评论0