vue 테트리스 코드

2023-03-07

아래 코드에 문제가 있는데, 라인이 완성되었을때 라인을 지우고 새로운 라인을 집어 넣어야 하는데,

dom 을 직접 컨트롤하는게 안맞는거 같아서 여기서 멈췄습니다.

아무 생각없이 js 코드를 따라 치다보니 이런 문제가 생겼고, 지금은 머리가 살짝 아픈 상황이네요.

일단 코드만 여기로 옮겨 두었고, 시간될때 변경해 보고자 합니다.

변경이 되고 나면 코드를 다시 올릴까도 싶네요.

app.vue

<template>
  <div class="wrapper">
    <div class="score">0</div>
    <div class="playground">
        <ul>
            <li ref="playground" v-for="i in 20">
                <ul>
                    <li id="matrix" v-for="j in 10"></li>
                </ul>
            </li>
        </ul>
    </div>
  </div>
</template>

<script setup>
import { ref, onMounted } from "vue";
import BLOCKS from "./blocks";

// DOM
const playground = ref(null);

// variables
let score = 0;
let duration = 500;
let downInterval;
let tempMovingItem;

const movingItem = {
  type: "",
  direction: 0,
  top: 0,
  left: 0,
}

onMounted(async () => {
  tempMovingItem = { ...movingItem };
  generateNewBlock();
  
  window.addEventListener('keydown', e => {
    switch(e.keyCode) {
      case 39:
        moveBlock("left", 1);
        break;
      case 37:
        moveBlock("left", -1);
        break;
      case 40:
        moveBlock("top", 1);
        break;
      case 38:
        changeDirection();
        break;
      case 32:
        dropBlock();
        break;
      default:
        break;
    }
  });
});

const renderBlocks = (moveType = "") => {
  const { type, direction, top, left } = tempMovingItem;

  const movingBlocks = document.querySelectorAll(".moving");
  movingBlocks.forEach(moving => {
    moving.classList.remove(type, "moving");
  });
  
  BLOCKS[type][direction].some(block => {
    const x = block[0] + left;
    const y = block[1] + top;
    const target = playground._rawValue[y]?.childNodes?.[0]?.childNodes?.[x]?.nextElementSibling;
    const isAvailable = checkEmpty(target);
    if(isAvailable) {
      // type 이 색상을 나타냄, 이동할 칸에 색칠하는 것
      target.classList.add(type, "moving");
    } else {
      tempMovingItem = { ...movingItem };
      setTimeout(() => {
        renderBlocks();
        if (moveType === "top") {
          seizeBlock();
        }
      }, 0);
      return true;
    }
  });
  movingItem.left = left;
  movingItem.top = top;
  movingItem.direction = direction;
}

// 끝났다는걸 의미
const seizeBlock = () => {
  const movingBlocks = document.querySelectorAll(".moving");
  movingBlocks.forEach(moving => {
    moving.classList.remove("moving");
    moving.classList.add("seized");
  });
  checkMatch();
}

const checkMatch = () => {
  const childNodes = playground._rawValue;
  childNodes.forEach(child => {
    let matched = true;
    const children = child.children[0];
    const childNodes = children.childNodes;
    child.children[0].childNodes.forEach(li => {
      if(li?.nextElementSibling?.classList == undefined)
        return
      if(!li?.nextElementSibling?.classList?.contains("seized")) {
        matched = false;
      }
    })
    if(matched) {
      child.remove();
    }
  });

  generateNewBlock();
}

// 새로 init 하는 거
const generateNewBlock = () => {
  clearInterval(downInterval);
  downInterval = setInterval(() => {
    moveBlock("top", 1);
  }, duration);
  
  const blockArray = Object.entries(BLOCKS);
  const randomIndex = Math.floor(Math.random() * blockArray.length);
  movingItem.type = blockArray[randomIndex][0];
  movingItem.top = 0;
  movingItem.left = 3;
  movingItem.direction = 0;
  tempMovingItem = { ...movingItem };
  renderBlocks();
}

const checkEmpty = (target) => {
  if(!target || target.classList.contains("seized")) {
    return false;
  } else {
    return true;
  }
}

const moveBlock = (moveType, amount) => {
  tempMovingItem[moveType] += amount;
  renderBlocks(moveType);
}

const changeDirection = () => {
  tempMovingItem.direction = (tempMovingItem.direction + 1) % 4;
  renderBlocks();
}

const dropBlock = () => {
  clearInterval(downInterval);
  downInterval = setInterval(() => {
    moveBlock("top", 1);
  }, 10);
}

</script>

<style>
    * {
      margin: 0;
        padding: 0;
    }
    ul {
        list-style: none;
    }
    body {
        height: 100%;
        overflow: hidden;
    }
    .score {
        text-align: center;
        font-size: 36px;
        margin-bottom: 2rem;
    }
    .playground > ul {
        border: 1px solid #333;
        width: 250px;
        margin: 0 auto;
    }
    .playground > ul > li {
        width: 100%;
        height: 25px;
    }
    .playground > ul > li > ul {
        display: flex;
    }
    .playground > ul > li > ul > li {
        width: 25px;
        height: 25px;
        outline: 1px solid #ccc;
    }
    .tree {
        background: #67c23a;
    }
    .bar {
        background: #c2613a;
    }
    .zee {
        background: #c2b03a;
    }
    .elLeft {
        background: #833ac2;
    }
    .elRight {
        background: #3ac2a2;
    }
    .square {
        background: #3a5cc2;
    }
</style>

blocks.js

const BLOCKS = {
  square: [
    [[0,0],[0,1],[1,0],[1,1]],
    [[0,0],[0,1],[1,0],[1,1]],
    [[0,0],[0,1],[1,0],[1,1]],
    [[0,0],[0,1],[1,0],[1,1]],
  ],
  bar: [
    [[1,0],[2,0],[3,0],[4,0]],
    [[2,-1],[2,0],[2,1],[2,2]],
    [[1,0],[2,0],[3,0],[4,0]],
    [[2,-1],[2,0],[2,1],[2,2]],
  ],
  tree: [
    [[1,0],[0,1],[1,1],[2,1]],
    [[1,0],[0,1],[1,1],[1,2]],
    [[2,1],[0,1],[1,1],[1,2]],
    [[2,1],[1,2],[1,1],[1,0]],
  ],
  zee: [
    [[0,0],[1,0],[1,1],[2,1]],
    [[0,1],[1,0],[1,1],[0,2]],
    [[0,1],[1,1],[1,2],[2,2]],
    [[2,0],[2,1],[1,1],[1,2]],
  ],
  elLeft: [
    [[0,0],[0,1],[1,1],[2,1]],
    [[1,0],[1,1],[1,2],[0,2]],
    [[0,1],[1,1],[2,1],[2,2]],
    [[1,0],[2,0],[1,1],[1,2]],
  ],
  elRight: [
    [[1,0],[2,0],[1,1],[1,2]],
    [[0,0],[0,1],[1,1],[2,1]],
    [[0,2],[1,0],[1,1],[1,2]],
    [[0,1],[1,1],[2,1],[2,2]],
  ],
}

export default BLOCKS;

results matching ""

    No results matching ""

    99 other / uml

    04 react / JSX