鸭子闯关游戏

Published on
/
/趣玩前端
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>鸭子闯关游戏</title>
    <style>
      @import url('https://fonts.googleapis.com/css2?family=Titan+One&display=swap');
      html {
        font-size: 3vh;
      }
      @media (orientation: portrait) {
        html {
          font-size: 2.9vw;
        }
      }

      body {
        display: flex;
        justify-content: center;
        align-items: center;
        height: 100vh;
        margin: 0;
        color: #fff;
        background: radial-gradient(#419197, #419197 60%, #fff 300%);
        overflow: hidden;
        font-family: 'Titan One', sans-serif;
        font-weight: 700;
        font-size: 1.5rem;
      }

      .game {
        position: relative;
        display: flex;
        flex-wrap: wrap;
        width: 29.03rem;
        transition: transform 0.5s ease;
        border: 1px solid #419197;
        overflow: hidden;
        perspective: 20rem;
        transform-style: preserve-3d;
        transform-origin: center center 0;
        border-radius: 0.5rem;
        background-color: #78d6c6;
      }
      .game:before,
      .game:after {
        content: '';
        display: flex;
        position: absolute;
        z-index: -1;
        top: 0;
        width: var(--cell);
        height: 100%;
        background: red;
        transform-style: preserve-3d;
        transform-origin: center center 0;
        background-color: rgba(65, 145, 151, 0.5);
        outline: 1px solid #fff;
      }
      .game:before {
        left: 0;
        transform: translateZ(calc(-0.5 * var(--cell))) translateX(
            calc(-0.5 * var(--cell))
          )
          rotate3d(0, 1, 0, 90deg);
      }
      .game:after {
        right: 0;
        transform: translateZ(calc(-0.5 * var(--cell))) translateX(
            calc(0.5 * var(--cell))
          )
          rotate3d(0, 1, 0, 90deg);
      }
      .game__player {
        position: absolute;
        z-index: 999;
        width: calc(var(--cell) * 0.8);
        height: calc(var(--cell) * 0.8);
        top: calc((var(--positionTop) + 0.1) * var(--cell));
        left: calc((var(--positionLeft) + 0.1) * var(--cell));
        transition-property: top, left, transform;
        transition-duration: 0.2s;
        transition-timing-function: ease;
        transform: var(--rotation) translateZ(0);
      }
      .game__player-eye {
        transform-origin: 50% 20%;
        animation: blink;
        animation-duration: 2s;
        animation-iteration-count: infinite;
      }
      @keyframes blink {
        0%,
        40%,
        60%,
        100% {
          transform: scaleY(1);
        }
        50% {
          transform: scaleY(0.2);
        }
      }
      @media (max-width: 767px) {
        .game__player {
          transition-duration: 0.1s;
        }
      }
      .game__cell {
        position: relative;
        z-index: -1;
        width: var(--cell);
        height: var(--cell);
        background: linear-gradient(135deg, #78d6c6, #fff 200%);
        outline: 1px solid #fff;
        transform: translateZ(calc(-1 * var(--cell)));
      }
      .game__cell--rock {
        position: relative;
        transform: translateZ(0);
        transform-style: preserve-3d;
        transform-origin: center center 0;
        background: none;
        outline: none;
      }
      .game__cell--rock-face {
        position: absolute;
        display: flex;
        background: linear-gradient(135deg, #919ea3, #fff 200%);
        border-radius: 0.1rem;
        outline: 1px solid #919ea3;
      }
      .game__cell--rock-lava .game__cell--rock-face {
        background: linear-gradient(45deg, orange, #ff7d66 200%);
        background-size: 100% 200%;
        animation: lava;
        animation-duration: 2s;
        animation-iteration-count: infinite;
        outline: 1px solid #ff7d66;
      }
      @keyframes lava {
        0%,
        100% {
          background-position: 0 0;
        }
        50% {
          background-position: 0 100%;
        }
      }
      .game__cell--rock-front {
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
      }
      .game__cell--rock-top,
      .game__cell--rock-bottom,
      .game__cell--rock-left,
      .game__cell--rock-right {
        width: 100%;
        height: var(--cell);
      }
      .game__cell--rock-top {
        top: 0;
        left: 0;
        transform: translateZ(calc(-0.5 * var(--cell))) translateY(
            calc(-0.5 * var(--cell))
          )
          rotate3d(1, 0, 0, 90deg);
      }
      .game__cell--rock-bottom {
        bottom: 0;
        left: 0;
        transform: translateZ(calc(-0.5 * var(--cell))) translateY(
            calc(0.5 * var(--cell))
          )
          rotate3d(1, 0, 0, 90deg);
      }
      .game__cell--rock-left {
        top: 0;
        left: 0;
        transform: translateZ(calc(-0.5 * var(--cell))) translateY(
            calc(-0.5 * var(--cell))
          )
          translateX(calc(var(--cell) / -2)) rotate3d(1, 0, 0, 90deg) rotate3d(
            0,
            1,
            0,
            90deg
          ) translateX(calc(var(--cell) / 2));
      }
      .game__cell--rock-right {
        top: 0;
        left: 0;
        transform: translateZ(calc(-0.5 * var(--cell))) translateY(
            calc(-0.5 * var(--cell))
          )
          translateX(calc(var(--cell) / -2)) rotate3d(1, 0, 0, 90deg) rotate3d(
            0,
            1,
            0,
            90deg
          ) translateX(calc(var(--cell) / 2)) translateZ(var(--cell));
      }
      .game__cell--horizontal {
        z-index: 0;
        transform: translateZ(calc(var(--cell) * -0.8));
        background: linear-gradient(135deg, #78d6c6, #eb80b1 200%);
      }
      .game__cell--horizontal:before,
      .game__cell--horizontal:after {
        content: '';
        position: absolute;
        width: 0;
        height: 0;
        border-top: calc(var(--cell) / 4) solid transparent;
        border-bottom: calc(var(--cell) / 4) solid transparent;
      }
      .game__cell--horizontal:before {
        bottom: calc(var(--cell) / 6);
        left: calc(var(--cell) / 6);
        border-left: calc(var(--cell) / 3) solid #fff;
      }
      .game__cell--horizontal:after {
        top: calc(var(--cell) / 6);
        right: calc(var(--cell) / 6);
        border-right: calc(var(--cell) / 3) solid #fff;
      }
      .game__cell--vertical {
        z-index: 0;
        transform: translateZ(calc(var(--cell) * -0.8));
        background: linear-gradient(135deg, #78d6c6, orange 200%);
      }
      .game__cell--vertical:before,
      .game__cell--vertical:after {
        content: '';
        position: absolute;
        width: 0;
        height: 0;
        border-left: calc(var(--cell) / 4) solid transparent;
        border-right: calc(var(--cell) / 4) solid transparent;
      }
      .game__cell--vertical:before {
        bottom: calc(var(--cell) / 6);
        left: calc(var(--cell) / 6);
        border-bottom: calc(var(--cell) / 3) solid #fff;
      }
      .game__cell--vertical:after {
        top: calc(var(--cell) / 6);
        right: calc(var(--cell) / 6);
        border-top: calc(var(--cell) / 3) solid #fff;
      }
      .game__cell--end {
        background-color: #fff;
        background-image: linear-gradient(
            45deg,
            #000038 25%,
            transparent 25%,
            transparent 74%,
            #000038 75%,
            #000038
          ), linear-gradient(45deg, #000038 25%, transparent 25%, transparent
              74%, #000038 75%, #000038);
        background-size: calc(var(--cell) / 2) calc(var(--cell) / 2);
        background-position: 0 0, calc(var(--cell) / 4) calc(var(--cell) / 4);
      }
      .game__wrapper {
        position: relative;
      }
      .game__water {
        position: absolute;
        transition-property: width, height;
        transition-duration: 0.2s;
        transition-timing-function: ease;
        transform-style: preserve-3d;
      }
      .game__water--0,
      .game__water--2 {
        width: 100%;
        height: calc(var(--depth) * var(--cell));
      }
      .game__water--1,
      .game__water--3 {
        height: 100%;
        width: calc(var(--depth) * var(--cell));
      }
      .game__water--0,
      .game__water--3 {
        bottom: 0;
        left: 0;
      }
      .game__water--1 {
        bottom: 0;
        right: 0;
      }
      .game__water--2 {
        top: 0;
        left: 0;
      }
      .game__water--front {
        position: relative;
        z-index: 2;
        width: 100%;
        height: 100%;
        background-color: rgba(65, 145, 151, 0.6);
        transform: translateZ(0);
      }
      .game__water--top,
      .game__water--left,
      .game__water--right,
      .game__water--bottom {
        position: absolute;
        display: flex;
        background: linear-gradient(45deg, rgba(65, 145, 151, 0.5), #fff 200%);
      }
      .game__water--top,
      .game__water--bottom {
        width: 100%;
        height: var(--cell);
        transform-origin: center 0 0;
      }
      .game__water--left,
      .game__water--right {
        width: var(--cell);
        height: 100%;
        transform-origin: center center 0;
      }
      .game__water--top {
        top: 0;
        left: 0;
        transform: translateZ(calc(-1 * var(--cell))) rotate3d(1, 0, 0, 90deg);
      }
      .game__water--left {
        top: 0;
        left: 0;
        transform: translateZ(calc(-0.5 * var(--cell))) translateX(
            calc(-0.5 * var(--cell))
          )
          rotate3d(0, 1, 0, 90deg);
      }
      .game__water--right {
        top: 0;
        right: 0;
        transform: translateZ(calc(-0.5 * var(--cell))) translateX(
            calc(0.5 * var(--cell))
          )
          rotate3d(0, 1, 0, 90deg);
      }
      .game__water--bottom {
        bottom: 0;
        left: 0;
        transform: translateZ(calc(-1 * var(--cell))) translateY(
            calc(var(--cell))
          )
          rotate3d(1, 0, 0, 90deg);
      }

      .title {
        position: absolute;
        top: 1rem;
        left: 1rem;
        color: #fff07f;
      }

      .level-text {
        position: absolute;
        top: 1rem;
        right: 1rem;
      }
      .level-text:before {
        content: '';
        position: absolute;
        right: 0;
        bottom: calc(4rem - 100vh);
        font-size: 0.5rem;
        text-align: right;
      }

      .water-level {
        position: absolute;
        top: calc(50vh - var(--height) * var(--cell) * 0.5);
        right: calc(50vw - var(--width) * var(--cell) * 0.5 - 0.15rem);
        display: flex;
        width: 0.3rem;
        height: calc(var(--height) * var(--cell));
        background: linear-gradient(#78d6c6 50%, transparent 50%);
        background-size: 100% 200%;
        background-position: 0 calc(100% + (var(--depth) / var(--height) * 100%));
        transition: all 0.2s ease;
      }
      .water-level:before,
      .water-level:after {
        content: '';
        position: absolute;
        left: -0.15rem;
        width: 5rem;
        color: #fff;
        font-size: 1rem;
      }
      .water-level:before {
        content: 'min -';
        top: calc(100% - (var(--min-depth) / var(--height) * 100%) - 0.7rem);
        left: -2.35rem;
      }
      .water-level:after {
        content: '- max';
        top: calc(100% - (var(--max-depth) / var(--height) * 100%) - 0.7rem);
      }
      .water-level--hidden {
        display: none;
      }

      .over-text {
        position: absolute;
        top: 0;
        left: 0;
        display: none;
        justify-content: center;
        align-items: center;
        width: 100vw;
        height: 100vh;
        color: #fff;
        background-color: rgba(65, 145, 151, 0.5);
        text-align: center;
        text-transform: uppercase;
      }
      .over-text--display {
        display: flex;
      }
      .over-text--lose {
        color: #000038;
        background-color: rgba(255, 125, 102, 0.5);
      }
      .over-text--win {
        display: flex;
        flex-direction: column;
        font-size: 10vw;
        color: #12486b;
        background-color: rgba(245, 252, 205, 0.5);
      }
      .over-text--win .over-text__timer {
        font-size: 5vw;
      }
      .over-text--tutorial {
        color: #12486b;
        background: rgba(255, 255, 255, 0.3);
        top: unset;
        bottom: 0;
        height: 4rem;
        pointer-events: none;
      }

      .controls {
        position: absolute;
        top: 0;
        left: 0;
        display: flex;
        flex-wrap: wrap;
        width: 100%;
        height: 100%;
      }
      .controls__arrow {
        display: flex;
        justify-content: center;
        align-items: center;
        cursor: pointer;
        -webkit-tap-highlight-color: transparent;
      }
      .controls__arrow:after {
        content: '';
        width: 0;
        height: 0;
        margin: 1rem;
        opacity: 0.3;
      }
      .controls__arrow--top,
      .controls__arrow--bottom {
        width: 100%;
        height: 40vh;
      }
      .controls__arrow--left,
      .controls__arrow--right {
        flex-direction: column;
        width: 50%;
        height: 20vh;
      }
      .controls__arrow--top,
      .controls__arrow--left {
        align-items: flex-start;
      }
      .controls__arrow--bottom,
      .controls__arrow--right {
        align-items: flex-end;
      }
      .controls__arrow--top:after {
        border-left: 1rem solid transparent;
        border-right: 1rem solid transparent;
        border-bottom: 1rem solid #fff;
      }
      .controls__arrow--left:after {
        border-left: 1rem solid transparent;
        border-right: 1rem solid transparent;
        border-top: 1rem solid #fff;
        transform: rotate(45deg);
      }
      .controls__arrow--right:after {
        border-left: 1rem solid transparent;
        border-right: 1rem solid transparent;
        border-top: 1rem solid #fff;
        transform: rotate(-45deg);
      }
      .controls__arrow--bottom:after {
        border-left: 1rem solid transparent;
        border-right: 1rem solid transparent;
        border-top: 1rem solid #fff;
      }

      .intro {
        position: absolute;
        top: 0;
        left: 0;
        display: flex;
        flex-direction: column;
        width: 100vw;
        height: 100vh;
        padding: 1rem;
        color: #fff07f;
        background-color: #419197;
        cursor: pointer;
      }
      .intro__title {
        font-size: 4rem;
      }
      .intro__subtitle {
        color: #f5fccd;
      }
      .intro__explanation {
        position: absolute;
        bottom: 3rem;
        left: 1rem;
        width: calc(100vw - 2rem);
        font-size: 1.5rem;
        text-align: right;
        color: #fff;
      }
      .intro__player {
        position: absolute;
        top: 10rem;
        right: 0;
        width: 40vw;
        height: 40vh;
        transform: rotate(10deg);
      }
      .intro__button {
        position: absolute;
        bottom: 30vh;
        left: 40vw;
        display: inline-flex;
        justify-content: center;
        width: 20vw;
        padding: 0.5rem 1rem;
        border-radius: 2rem;
        color: #12486b;
        background: #fff07f;
        outline: 2px solid #12486b;
        transition: transform 0.2s ease;
      }
      .intro__button:hover {
        transform: scale(1.2);
      }
      .intro__earth {
        position: absolute;
        top: 30vh;
        left: 15vw;
        width: 70vw;
        height: 70vw;
        border-radius: 50%;
        background-color: #12486b;
        transform: rotate(10deg);
        overflow: hidden;
      }
      @media (max-width: 767px) {
        .intro__earth {
          width: 120vw;
          height: 120vw;
          left: -10vw;
        }
      }
      .intro__earth:before {
        content: '';
        display: block;
        width: 100%;
        height: 100%;
        background-size: cover;
        transition: background-position 0.5s ease;
        animation: globeSpinning;
        animation-duration: 300s;
        animation-iteration-count: infinite;
        animation-timing-function: linear;
      }
      @keyframes globeSpinning {
        0% {
          background-position: 0 0;
        }
        100% {
          background-position: 288% 0;
        }
      }
      .intro--hidden {
        display: none;
      }

      .fullscreen {
        position: absolute;
        top: 1.2rem;
        right: 7rem;
        cursor: pointer;
      }

      .refresh {
        position: absolute;
        top: 1rem;
        right: 4rem;
        cursor: pointer;
      }

      .level-selector {
        position: absolute;
        top: 0;
        left: 0;
        width: 80vw;
        height: 100vh;
        padding: 0 10vw;
        color: #fff;
        background-color: rgba(65, 145, 151, 0.5);
        font-size: 2rem;
        display: none;
      }
      @media (min-height: 600px) {
        .level-selector {
          font-size: 1.5rem;
        }
      }
      .level-selector--active {
        display: flex;
        justify-content: center;
        align-items: center;
        align-content: center;
        flex-wrap: wrap;
      }
      .level-selector__button {
        padding: 1rem;
        border-radius: 0.5rem;
        cursor: pointer;
        transition: background-color 0.2s ease;
      }
      .level-selector__button:hover {
        background-color: rgba(0, 0, 56, 0.2);
      }
      .level-selector__button--current {
        background-color: #12486b;
      }
      .level-selector__button--disabled {
        opacity: 0.5;
        cursor: default;
        pointer-events: none;
      }
    </style>
  </head>
  <body>
    <!-- partial:index.partial.html -->
    <div id="game" class="game"></div>

    <div class="title"><br /></div>

    <div id="level-text" class="level-text">0</div>

    <div id="water-level" class="water-level"></div>

    <div id="controls" class="controls">
      <div id="top" class="controls__arrow controls__arrow--top"></div>
      <div id="left" class="controls__arrow controls__arrow--left"></div>
      <div id="right" class="controls__arrow controls__arrow--right"></div>
      <div id="bottom" class="controls__arrow controls__arrow--bottom"></div>
    </div>

    <div id="fullscreen" class="fullscreen">
      <svg
        fill="#FFF"
        width="1.3rem"
        height="1.3rem"
        viewBox="0 0 16 16"
        xmlns="http://www.w3.org/2000/svg"
      >
        <path
          d="M14 3.414L9.414 8 14 12.586v-2.583h2V16h-6v-1.996h2.59L8 9.414l-4.59 4.59H6V16H0v-5.997h2v2.583L6.586 8 2 3.414v2.588H0V0h16v6.002h-2V3.414zm-1.415-1.413H10V0H6v2H3.415L8 6.586 12.585 2z"
          fill-rule="evenodd"
        />
      </svg>
    </div>

    <div id="refresh" class="refresh">
      <svg
        fill="#fff"
        width="2rem"
        height="2rem"
        viewBox="0 0 32 32"
        xmlns="http://www.w3.org/2000/svg"
      >
        <path
          d="M27.1 14.313V5.396L24.158 8.34c-2.33-2.325-5.033-3.503-8.11-3.503C9.902 4.837 4.901 9.847 4.899 16c.001 6.152 5.003 11.158 11.15 11.16 4.276 0 9.369-2.227 10.836-8.478l.028-.122h-3.23l-.022.068c-1.078 3.242-4.138 5.421-7.613 5.421a8 8 0 0 1-5.691-2.359A7.993 7.993 0 0 1 8 16.001c0-4.438 3.611-8.049 8.05-8.049 2.069 0 3.638.58 5.924 2.573l-3.792 3.789H27.1z"
        />
      </svg>
    </div>

    <div id="over-text" class="over-text"></div>

    <div id="level-selector" class="level-selector"></div>

    <div id="intro" class="intro">
      <span class="intro__earth"><br /></span>

      <span class="intro__button">Play</span>
      <svg
        class="intro__player"
        height="800px"
        width="800px"
        xmlns:xlink="http://www.w3.org/1999/xlink"
        viewBox="0 0 512 512"
        xml:space="preserve"
      >
        <g>
          <path
            style="fill: #ff7d66"
            d="M90.465,186.912c0.086-7.581-5.26-27.49,2.771-43.781c8.025-16.291-42.226-20.546-67.682,0.367
		c-24.51,20.137,1.764,37.468,17.938,33.657C76.267,169.428,90.299,202.261,90.465,186.912z"
          />
          <path
            style="fill: #ff7d66"
            d="M73.315,96.009c0.079,7.574-5.26,27.483,2.764,43.782c8.025,16.277-46.799,25.105-67.674-0.375
		c-20.878-25.48,1.76-37.461,17.941-33.65C59.102,113.485,73.137,80.654,73.315,96.009z"
          />
          <path
            class="game__player-body"
            style="fill: #fff07f"
            d="M76.45,264.211c18.183-21.406,33.092-31.038,20.821-50.433
		c-23.402-23.408-34.309-48.743-34.309-84.458c0-35.709,14.476-68.035,37.876-91.436C124.243,14.483,156.563,0,192.278,0
		s68.035,14.483,91.443,37.884c23.401,23.402,37.87,55.728,37.87,91.436c0,52.789-42.222,95.011-42.222,121.4
		c-2.64,10.561,15.835,23.761,39.582,23.761c23.761,0,102.932,18.467,160.988-58.063c15.28-21.122,33.755-9.238,31.675,21.107
		C509.618,266.609,493.133,512,318.951,512c-50.135,0-43.788,0-139.874,0c-40.074,0-76.36-16.25-102.627-42.513
		c-26.273-26.27-42.52-62.554-42.52-102.649C33.93,326.765,50.176,290.474,76.45,264.211"
          />
          <path
            class="game__player-wing"
            style="fill: #dccc49"
            d="M219.533,340.458h193.216c21.108,0,26.388,36.941-7.92,58.063c0,26.38-13.201,65.97-52.782,65.97
		c-39.596,0-87.092,0-121.4,0c-34.316,0-58.064-39.59-58.064-63.337C172.584,377.399,195.777,340.458,219.533,340.458z"
          />
          <path
            class="game__player-wing"
            style="fill: #f5fccd"
            d="M206.331,324.616h193.218c21.108,0,26.388,36.949-7.92,58.064c0,26.395-13.194,65.983-52.776,65.983
		c-39.589,0-87.097,0-121.406,0s-58.057-39.589-58.057-63.344C159.39,361.565,182.583,324.616,206.331,324.616z"
          />
          <path
            class="game__player-eye"
            style="fill: #ffffff"
            d="M159.39,109.522c0,16.77-13.596,30.359-30.348,30.359c-16.763,0-30.355-13.589-30.355-30.359
		c0-16.748,13.592-30.344,30.355-30.344C145.794,79.177,159.39,92.773,159.39,109.522z"
          />
          <path
            class="game__player-eye"
            style="fill: #000038"
            d="M143.556,109.522c0,8.025-6.503,14.525-14.514,14.525c-8.018,0-14.518-6.5-14.518-14.525
		c0-8.003,6.5-14.503,14.518-14.503C137.052,95.018,143.556,101.518,143.556,109.522z"
          />
        </g>
      </svg>
    </div>

    <div class="drawer" style="display: none">
      <svg
        id="player"
        class="game__player"
        height="800px"
        width="800px"
        xmlns:xlink="http://www.w3.org/1999/xlink"
        viewBox="0 0 512 512"
        xml:space="preserve"
      >
        <g>
          <path
            style="fill: #ff7d66"
            d="M90.465,186.912c0.086-7.581-5.26-27.49,2.771-43.781c8.025-16.291-42.226-20.546-67.682,0.367
		c-24.51,20.137,1.764,37.468,17.938,33.657C76.267,169.428,90.299,202.261,90.465,186.912z"
          />
          <path
            style="fill: #ff7d66"
            d="M73.315,96.009c0.079,7.574-5.26,27.483,2.764,43.782c8.025,16.277-46.799,25.105-67.674-0.375
		c-20.878-25.48,1.76-37.461,17.941-33.65C59.102,113.485,73.137,80.654,73.315,96.009z"
          />
          <path
            class="game__player-body"
            style="fill: #fff07f"
            d="M76.45,264.211c18.183-21.406,33.092-31.038,20.821-50.433
		c-23.402-23.408-34.309-48.743-34.309-84.458c0-35.709,14.476-68.035,37.876-91.436C124.243,14.483,156.563,0,192.278,0
		s68.035,14.483,91.443,37.884c23.401,23.402,37.87,55.728,37.87,91.436c0,52.789-42.222,95.011-42.222,121.4
		c-2.64,10.561,15.835,23.761,39.582,23.761c23.761,0,102.932,18.467,160.988-58.063c15.28-21.122,33.755-9.238,31.675,21.107
		C509.618,266.609,493.133,512,318.951,512c-50.135,0-43.788,0-139.874,0c-40.074,0-76.36-16.25-102.627-42.513
		c-26.273-26.27-42.52-62.554-42.52-102.649C33.93,326.765,50.176,290.474,76.45,264.211"
          />
          <path
            class="game__player-wing"
            style="fill: #dccc49"
            d="M219.533,340.458h193.216c21.108,0,26.388,36.941-7.92,58.063c0,26.38-13.201,65.97-52.782,65.97
		c-39.596,0-87.092,0-121.4,0c-34.316,0-58.064-39.59-58.064-63.337C172.584,377.399,195.777,340.458,219.533,340.458z"
          />
          <path
            class="game__player-wing"
            style="fill: #f5fccd"
            d="M206.331,324.616h193.218c21.108,0,26.388,36.949-7.92,58.064c0,26.395-13.194,65.983-52.776,65.983
		c-39.589,0-87.097,0-121.406,0s-58.057-39.589-58.057-63.344C159.39,361.565,182.583,324.616,206.331,324.616z"
          />
          <path
            class="game__player-eye"
            style="fill: #ffffff"
            d="M159.39,109.522c0,16.77-13.596,30.359-30.348,30.359c-16.763,0-30.355-13.589-30.355-30.359
		c0-16.748,13.592-30.344,30.355-30.344C145.794,79.177,159.39,92.773,159.39,109.522z"
          />
          <path
            class="game__player-eye"
            style="fill: #000038"
            d="M143.556,109.522c0,8.025-6.503,14.525-14.514,14.525c-8.018,0-14.518-6.5-14.518-14.525
		c0-8.003,6.5-14.503,14.518-14.503C137.052,95.018,143.556,101.518,143.556,109.522z"
          />
        </g>
      </svg>
      <div id="water" class="game__water game__water--0">
        <div class="game__water--bottom"></div>
        <div class="game__water--left"></div>
        <div class="game__water--right"></div>
        <div class="game__water--top"></div>
        <div class="game__water--front"></div>
      </div>
      <div id="rock" class="game__cell game__cell--rock">
        <div class="game__cell--rock-face game__cell--rock-left"></div>
        <div class="game__cell--rock-face game__cell--rock-right"></div>
        <div class="game__cell--rock-face game__cell--rock-top"></div>
        <div class="game__cell--rock-face game__cell--rock-bottom"></div>
        <div class="game__cell--rock-face game__cell--rock-front"></div>
      </div>
    </div>
    <script>
      const game = document.getElementById('game');
      const player = document.getElementById('player');
      const water = document.getElementById('water');
      const rock = document.getElementById('rock');
      const overText = document.getElementById('over-text');
      const levelText = document.getElementById('level-text');
      const waterLevel = document.getElementById('water-level');
      const intro = document.getElementById('intro');
      const topArrow = document.getElementById('top');
      const leftArrow = document.getElementById('left');
      const rightArrow = document.getElementById('right');
      const bottomArrow = document.getElementById('bottom');
      const refresh = document.getElementById('refresh');
      const fullscreen = document.getElementById('fullscreen');
      const levelSelector = document.getElementById('level-selector');

      let level = 0;
      let width = 29;
      const puzzles = [
        {
          initialDepth: 1,
          minDepth: 1,
          maxDepth: 2,
          level: ['--', '--e--', '-ox--', '--x--'],
        },
        {
          initialDepth: 1,
          minDepth: 1,
          maxDepth: 3,
          level: ['', '', 'x--'],
        },
        {
          initialDepth: 1,
          minDepth: 1,
          maxDepth: 2,
          level: ['--', '-exx', '-x'],
        },
        {
          initialDepth: 1,
          minDepth: 1,
          maxDepth: 2,
          level: ['--xxx-', 'xex', '-xx'],
        },
        {
          initialDepth: 1,
          minDepth: 1,
          maxDepth: 4,
          level: [
            'x-x--',
            '-xx--xex',
            'xx-xx',
          ],
        },
        {
          initialDepth: 1,
          minDepth: 1,
          maxDepth: 6,
          level: [
            '-xx-',
            'xx-xx-',
            '-xx-',
          ],
        },
        {
          initialDepth: 1,
          minDepth: 1,
          maxDepth: 2,
          level: [
            'x--x',
            'x-xxx-x',
            'xe--x-x',
            'x-x-x-x',
            'xoxx',
            'x--x',
            'xoxxxxx',
          ],
        },
        {
          initialDepth: 1,
          minDepth: 1,
          maxDepth: 2,
          level: ['x--exxx', 'xo', 'oxe'],
        },
        {
          initialDepth: 1,
          minDepth: 0,
          maxDepth: 3,
          level: ['-x--x--', '-', '-x--x--', 'ox--',
            '-x--xx-',
            '-x--x--',
            '-x--xe-',
          ],
        },
        {
          initialDepth: 1,
          minDepth: 0,
          maxDepth: 1,
          level: [
            '-xxx--x--',
            'x-x',
            'xx-xx-x--',
            '',
            '-x--x--xx',
            '-x-ox-x--',
            '-x--x--e-',
          ],
        },
        {
          initialDepth: 1,
          minDepth: 1,
          maxDepth: 6,
          level: [
            'xxx--x--xx',
            '--xx',
            'x-xx-xxxx-xx--',
            'x--xxx-xx',
          ],
        },
        {
          initialDepth: 1,
          minDepth: 1,
          maxDepth: 2,
          level: [
            'xx-',
            '-',
            '-',
            '--x-x--',
            'oxe--x',
          ],
        },
        {
          initialDepth: 1,
          minDepth: 1,
          maxDepth: 2,
          level: [
            'x--xx',
            '-',
            '--xxx-x--',
            'oxe',
            'x--x',
            '--x--x-',
            '-e-x--',
            '-x-x-x',
            '--', '--'],
        },
        {
          initialDepth: 3,
          minDepth: 3,
          maxDepth: 4,
          level: ['', '', '-e-', '-xx', '', '--', 'ox-x--'],
        },
        {
          initialDepth: 0,
          minDepth: 0,
          maxDepth: 0,
          level: ['xx', '-e-x-x', 'x-xo',
            '--',
            '-',
            'x',
            '--xx-',
            '',
            '-x-x',
          ],
        },
        {
          initialDepth: 1,
          minDepth: 1,
          maxDepth: 2,
          level: [
            'x-x--x--x',
            '-x--x--x-',
            '',
            '--x--x-x-x-x',
            'xxo-x-x-x',
            'x-x',
          ],
        },
        {
          initialDepth: 6,
          minDepth: 5,
          maxDepth: 6,
          level: [
            'x-x--x--x',
            '-x--x--x-',
            '',
            '--x--xx',
            '-', '--oee-x',
            '--x-x-o--',
            '',
          ],
        },
        {
          initialDepth: 5,
          minDepth: 5,
          maxDepth: 5,
          level: [
            'xxx--x',
            'xxex',
            'x-x--x',
            'xx--', '', '', 'l--e-', '--l--', '--ol-', 'ex', 'xo-lxx', 'x--lxx'],
        },
        {
          initialDepth: 1,
          minDepth: 1,
          maxDepth: 2,
          level: ['--l--', '--l--', '-l-e-', '-o-l-', 'lll',
            'll',
            'l-lllll',
          ],
        },
        {
          initialDepth: 1,
          minDepth: 1,
          maxDepth: 3,
          level: [
            'll',
            'l-lll-l',
            'l-e-l-l',
            'l-l-l-l',
            'lollll',
            'l-l-ll',
            'l-lll',
            'l-ll',
            'l-l--l--l',
            'l-l-ll--l',
            'lo--le--l',
            'l-ll', 'lo--l--el', 'lll'],
        },
        {
          initialDepth: 1,
          minDepth: 1,
          maxDepth: 4,
          level: [
            'l-l-lllll',
            'll--ll',
            'l--lll-ll',
            'l-o--l-el',
            'lxl',
            '--lxll--',
            'x-',
            'xxxlllll',
          ],
        },
        {
          initialDepth: 3,
          minDepth: 2,
          maxDepth: 3,
          level: ['x-xl', '--l--l--', 'x-e-xx',
            'll-ll-ll',
            'xxexx-xx',
            'llllxx',
            'l--lll-l-ll',
            'xx-lllll',
            'llxxx-xxxxl',
            'xl-xx',
            'l--ll-ll-ll',
            'xx-xl--o',
            'xxxxxlllxx-',
          ],
        },
        {
          initialDepth: 0,
          minDepth: 0,
          maxDepth: 2,
          level: ['-e-', 'hhv', '-o-'],
        },
        {
          initialDepth: 0,
          minDepth: 0,
          maxDepth: 2,
          level: ['hhv--', '-ev--', 'hhv--', '-o---'],
        },
        {
          initialDepth: 1,
          minDepth: 0,
          maxDepth: 2,
          level: [
            'xxllhev',
            'xvx--lv',
            'xvh--lv',
            'xh-l-hh',
            'x--llo-',
            'xvhh--l',
          ],
        },
        {
          initialDepth: 0,
          minDepth: 0,
          maxDepth: 2,
          level: ['hvhh', 'vvvh', 'vhvh', '-ove'],
        },
        {
          initialDepth: 1,
          minDepth: 0,
          maxDepth: 1,
          level: ['vhhvlh', 'vv-hhh', 'vhvllv', '-ohlev'],
        },
        {
          initialDepth: 2,
          minDepth: 0,
          maxDepth: 2,
          level: [
            'vh--hhxh',
            'vv-hl--h',
            'vlv--llv',
            '-oh--lev',
            'vv-hl--h',
            'vv-hh--h',
          ],
        },
        {
          initialDepth: 1,
          minDepth: 1,
          maxDepth: 1,
          level: ['xlohhev'],
        },
      ];

      let rotation = 0;
      let rotationPosition = 0;
      let depth = 1;
      let initialPosition = [];
      let position = [];
      let end = [];
      let rocks = [];
      let startTimer;

      const getLevelInfo = () => {
        const currentLevel = puzzles[level];

        const rawWidth = puzzles[level].level[0].length;
        const rawHeight = puzzles[level].level.length;
        return {
          rawWidth,
          rawHeight,
          levelWidth: rawWidth - 1,
          levelHeight: rawHeight - 1,
          currentLevel,
        };
      };

      const changeLevelStyle = () => {
        const { rawWidth, rawHeight, currentLevel } = getLevelInfo();
        game.style.transform = `rotate(${90 * rotation}deg)`;
        water.classList = `game__water game__water--${rotationPosition}`;
        water.style = `--depth: ${depth};`;
        waterLevel.style = `--depth: ${depth}; --width: ${
          rotationPosition % 2 === 0 ? rawWidth : rawHeight
        }; --height: ${
          rotationPosition % 2 === 0 ? rawHeight : rawWidth
        }; --min-depth: ${currentLevel.minDepth}; --max-depth: ${
          currentLevel.maxDepth
        };`;
      };

      const topFunction = () => changeWater(true);
      const leftFunction = () => rotateLevel(false);
      const rightFunction = () => rotateLevel(true);
      const bottomFunction = () => changeWater(false);

      const registerArrows = () => {
        topArrow.addEventListener('click', topFunction);
        leftArrow.addEventListener('click', leftFunction);
        rightArrow.addEventListener('click', rightFunction);
        bottomArrow.addEventListener('click', bottomFunction);
      };

      const removeArrowsEvents = () => {
        topArrow.removeEventListener('click', topFunction);
        leftArrow.removeEventListener('click', leftFunction);
        rightArrow.removeEventListener('click', rightFunction);
        bottomArrow.removeEventListener('click', bottomFunction);
      };

      const buildLevel = () => {
        if (level === 0) {
          startTimer = Date.now();
        }
        const { rawWidth, rawHeight, levelWidth, levelHeight, currentLevel } =
          getLevelInfo();
        // Adapt cell size to level
        document.body.style = `--cell: ${width / rawWidth}rem`;
        // Reset rocks
        rocks = [];
        currentLevel.level.forEach((row, rowIndex) => {
          const cells = row.split('');
          cells.forEach((cell, cellIndex) => {
            const newDiv = document.createElement('div');
            newDiv.classList.add('game__cell');
            if (cell === 'o') {
              initialPosition = [cellIndex, rowIndex];
              position = [cellIndex, rowIndex];
              game.appendChild(newDiv);
            } else if (cell === 'x' || cell === 'l') {
              rocks.push([cellIndex, rowIndex, cell === 'x' ? 'rock' : 'lava']);
              const rockClone = rock.cloneNode(true);
              rockClone.id = '';
              if (cell === 'l') {
                rockClone.classList.add('game__cell--rock-lava');
              }
              const xFactor =
                (cellIndex > levelWidth / 2
                  ? levelWidth - cellIndex
                  : cellIndex) + 1;
              const yFactor =
                (rowIndex > levelHeight / 2
                  ? levelHeight - rowIndex
                  : rowIndex) + 1;
              rockClone.style.zIndex = Math.round(xFactor * yFactor) + 3;
              game.appendChild(rockClone);
            } else if (cell === 'h') {
              rocks.push([cellIndex, rowIndex, 'horizontal']);
              newDiv.classList.add('game__cell--horizontal');
              game.appendChild(newDiv);
            } else if (cell === 'v') {
              rocks.push([cellIndex, rowIndex, 'vertical']);
              newDiv.classList.add('game__cell--vertical');
              game.appendChild(newDiv);
            } else if (cell === 'e') {
              end = [cellIndex, rowIndex];
              newDiv.classList.add('game__cell--end');
              game.appendChild(newDiv);
            } else {
              game.appendChild(newDiv);
            }
          });
        });
        rotation = 0;
        rotationPosition = 0;
        levelText.innerHTML = level;
        depth = currentLevel.initialDepth;
        game.appendChild(water);
        changeLevelStyle();
        game.appendChild(player);
      };

      const positionPlayer = () => {
        player.style = `--positionLeft: ${position[0]}; --positionTop: ${
          position[1]
        }; --rotation: rotate(${-90 * rotation}deg)`;
      };

      const removeEvent = (e) => {
        e.preventDefault();
        e.stopPropagation();
      };

      const winLevel = () => {
        overText.classList.add('over-text--display');
        const winTexts = [
          'Well done! Next',
          'Ducktastic!',
          'You win!',
          'Amazing!',
          'Go go duck!',
          "You've got this!",
          'Keep going!',
          'Stay duck!',
          'Rotating to the next level...',
          'Best duck!',
          'You rock, duck!',
        ];
        overText.innerHTML =
          winTexts[Math.floor(Math.random() * winTexts.length)];
        document.addEventListener('keydown', removeEvent);
        removeArrowsEvents();
        setTimeout(() => {
          game.innerHTML = '';
          overText.classList.remove('over-text--display');
          level = level + 1;
          localStorage.setItem('ducky-fog', level);
          const maxLevel = localStorage.getItem('ducky-fog-max', level);
          localStorage.setItem(
            'ducky-fog-max',
            maxLevel > level ? maxLevel : level
          );
          buildLevel();
          positionPlayer();
          document.removeEventListener('keydown', removeEvent);
          registerArrows();
        }, 500);
      };

      const loseLevel = () => {
        overText.classList.add('over-text--display');
        overText.classList.add('over-text--lose');
        const loseTexts = [
          'You lose! Repeat',
          'Oh no',
          'Uuuh',
          'Better duck next time',
          'You died',
          'Mamma mia',
          'Looosing',
          'That hurted',
          'Roasted duck!',
          'Burned',
          'Toasted',
        ];
        overText.innerHTML =
          loseTexts[Math.floor(Math.random() * loseTexts.length)];
        document.addEventListener('keydown', removeEvent);
        removeArrowsEvents();
        setTimeout(() => {
          game.innerHTML = '';
          overText.classList.remove('over-text--display');
          overText.classList.remove('over-text--lose');
          buildLevel();
          positionPlayer();
          document.removeEventListener('keydown', removeEvent);
          registerArrows();
        }, 500);
      };

      const nextLevel = () => {
        if (position[0] === end[0] && position[1] === end[1]) {
          if (level === puzzles.length - 1) {
            // If this was the last level: win the game
            overText.classList.add('over-text--display');
            overText.classList.add('over-text--win');
            if (startTimer) {
              const s = (Date.now() - startTimer) / 1000;
              overText.innerHTML = `The end!<br/><span class="over-text__timer">${parseInt(
                s / 60 / 60
              )}h ${parseInt((s / 60) % 60)}m ${parseInt(s % 60)}s</span>`;
            } else {
              overText.innerHTML = 'The end!';
            }

            document.addEventListener('keydown', removeEvent);
            removeArrowsEvents();
          } else {
            winLevel();
          }
        }
      };

      const findRocks = (axis, perpendicularAxis, movingForward) => {
        const relevantRocks = rocks
          .filter((rock) => rock[axis] === position[axis]) // Filtering rocks in this axis
          .filter((rock) =>
            movingForward
              ? rock[perpendicularAxis] > position[perpendicularAxis]
              : rock[perpendicularAxis] < position[perpendicularAxis]
          ); // Filtering rocks that are in the desired direction

        const filteredRelevantRocks = relevantRocks.filter((rock) => {
          if (axis === 0 && rock[2] !== 'vertical') {
            return rock;
          } else if (axis === 1 && rock[2] !== 'horizontal') {
            return rock;
          }
        });

        if (filteredRelevantRocks.length) {
          // If there are rocks in this path
          const rockPosition = movingForward
            ? Math.min(
                ...filteredRelevantRocks.map((rock) => rock[perpendicularAxis])
              )
            : Math.max(
                ...filteredRelevantRocks.map((rock) => rock[perpendicularAxis])
              );
          const relevantRock = filteredRelevantRocks.filter(
            (rock) => rock[perpendicularAxis] === rockPosition
          )[0];

          const maxmin = movingForward ? rockPosition - 1 : rockPosition + 1;

          return { maxmin, rockPosition, relevantRock };
        }
        return {
          maxmin: undefined,
          rockPostion: undefined,
          relevantRock: undefined,
        };
      };

      // true = right, false = left
      const rotateLevel = (direction) => {
        const { levelWidth, levelHeight } = getLevelInfo();
        const y1 = position[1];
        const y2 = levelHeight - y1;
        const x1 = position[0];
        const x2 = levelWidth - x1;

        const next = [...position];

        const maxminCondition = (position, maxmin, next) => {
          return (
            maxmin !== undefined &&
            ((position >= maxmin && maxmin >= next) ||
              (position <= maxmin && maxmin <= next))
          );
        };

        if (rotationPosition === 0) {
          const next = direction ? levelWidth - depth : depth;
          const { maxmin, rockPosition, relevantRock } = findRocks(
            1,
            0,
            next - position[0] > 0
          );

          if (maxminCondition(position[0], maxmin, next)) {
            if (relevantRock[2] === 'lava' && next !== maxmin) {
              position[0] = rockPosition;
              loseLevel();
            } else {
              position[0] = maxmin;
            }
          } else {
            position[0] = next;
          }
        } else if (rotationPosition === 1) {
          const next = direction ? depth : levelHeight - depth;
          const { maxmin, rockPosition, relevantRock } = findRocks(
            0,
            1,
            next - position[1] > 0
          );

          if (maxminCondition(position[1], maxmin, next)) {
            if (relevantRock[2] === 'lava' && next !== maxmin) {
              position[1] = rockPosition;
              loseLevel();
            } else {
              position[1] = maxmin;
            }
          } else {
            position[1] = next;
          }
        } else if (rotationPosition === 2) {
          const next = direction ? depth : levelWidth - depth;
          const { maxmin, rockPosition, relevantRock } = findRocks(
            1,
            0,
            next - position[0] > 0
          );

          if (maxminCondition(position[0], maxmin, next)) {
            if (relevantRock[2] === 'lava' && next !== maxmin) {
              position[0] = rockPosition;
              loseLevel();
            } else {
              position[0] = maxmin;
            }
          } else {
            position[0] = next;
          }
        } else {
          const next = direction ? levelHeight - depth : depth;
          const { maxmin, rockPosition, relevantRock } = findRocks(
            0,
            1,
            next - position[1] > 0
          );

          if (maxminCondition(position[1], maxmin, next)) {
            if (relevantRock[2] === 'lava' && next !== maxmin) {
              position[1] = rockPosition;
              loseLevel();
            } else {
              position[1] = maxmin;
            }
          } else {
            position[1] = next;
          }
        }

        if (direction) {
          rotationPosition = (rotationPosition + 1) % 4;
        } else {
          rotationPosition = rotationPosition === 0 ? 3 : rotationPosition - 1;
        }

        waterLevel.classList.add('game__water-level--hidden');
        setTimeout(
          () => waterLevel.classList.remove('game__water-level--hidden'),
          300
        );

        rotation = direction ? rotation + 1 : rotation - 1;
        changeLevelStyle();
        positionPlayer();
        nextLevel();
      };

      // true = top, false = bottom
      const changeWater = (direction) => {
        const { levelWidth, levelHeight, currentLevel } = getLevelInfo();
        // Avoid change if depth is max or min
        if (
          (direction && depth === currentLevel.maxDepth) ||
          (!direction && depth === currentLevel.minDepth)
        ) {
          return;
        }

        const y1 = position[1];
        const y2 = levelHeight - y1;
        const x1 = position[0];
        const x2 = levelWidth - x1;

        let playerOutWater = false;

        // Avoid change if depth doesnt match player
        playerOutWater =
          (rotationPosition === 0 && depth !== y2) ||
          (rotationPosition === 1 && depth !== x2) ||
          (rotationPosition === 2 && depth !== y1) ||
          (rotationPosition === 3 && depth !== x1);

        depth = direction ? depth + 1 : depth - 1;
        changeLevelStyle();

        if (playerOutWater) {
          return;
        }

        const next = [...position];

        if (rotationPosition === 0) {
          next[1] = direction ? position[1] - 1 : position[1] + 1;
        } else if (rotationPosition === 1) {
          next[0] = direction ? position[0] - 1 : position[0] + 1;
        } else if (rotationPosition === 2) {
          next[1] = direction ? position[1] + 1 : position[1] - 1;
        } else {
          next[0] = direction ? position[0] + 1 : position[0] - 1;
        }

        const relevantRock = rocks.find(
          (rock) => rock[0] === next[0] && rock[1] === next[1]
        );

        if (!relevantRock) {
          position = next;
        } else if (relevantRock[2] === 'lava') {
          position = next;
          loseLevel();
        } else if (
          rotationPosition % 2 === 0
            ? relevantRock[2] === 'vertical'
            : relevantRock[2] === 'horizontal'
        ) {
          position = next;
        }
        positionPlayer();
        nextLevel();
      };

      const removeTutorial = () => {
        overText.classList.remove('over-text--display');
        overText.classList.remove('over-text--tutorial');
      };

      const buildLevelSelector = () => {
        const maxLevel = localStorage.getItem('ducky-fog-max', level) ?? level;
        puzzles.forEach((puzzle, index) => {
          const newButton = document.createElement('div');
          newButton.innerHTML = index;
          newButton.classList.add('level-selector__button');
          if (index === level) {
            newButton.classList.add('level-selector__button--current');
          }
          if (index <= maxLevel) {
            newButton.addEventListener('click', () => {
              level = index;
              localStorage.setItem('ducky-fog', level);
              levelSelector.classList.remove('level-selector--active');
              game.innerHTML = '';
              buildLevel();
              positionPlayer();
            });
          } else {
            newButton.classList.add('level-selector__button--disabled');
          }
          levelSelector.appendChild(newButton);
        });
        levelSelector.classList.add('level-selector--active');
      };

      document.addEventListener(
        'DOMContentLoaded',
        () => {
          const storedLevel = localStorage.getItem('ducky-fog');
          if (storedLevel) {
            level = Number(storedLevel);
            buildLevelSelector();
          } else {
            overText.classList.add('over-text--display');
            overText.classList.add('over-text--tutorial');
            overText.addEventListener('click', removeTutorial);
            overText.innerHTML =
              'Use arrow keys or buttons to rotate and control water';
          }
          // Init
          buildLevel();
          positionPlayer();
          registerArrows();
        },
        false
      );

      intro.addEventListener('click', () => {
        intro.classList.add('intro--hidden');
        setTimeout(() => {
          removeTutorial();
          overText.removeEventListener('click', removeTutorial);
        }, 4000);
      });

      refresh.addEventListener('click', () => {
        game.innerHTML = '';
        buildLevel();
        positionPlayer();
      });

      fullscreen.addEventListener('click', () => {
        if (!document.fullscreenElement) {
          document.documentElement.requestFullscreen();
        } else if (document.exitFullscreen) {
          document.exitFullscreen();
        }
      });

      window.addEventListener('keydown', (event) => {
        if (event.key === 'ArrowRight') {
          rotateLevel(true);
        } else if (event.key === 'ArrowLeft') {
          rotateLevel(false);
        } else if (event.key === 'ArrowDown') {
          changeWater(false);
        } else if (event.key === 'ArrowUp') {
          changeWater(true);
        }
      });
    </script>
  </body>
</html>