[인프런] 웹 게임을 만들며 배우는 Vue 3

웹/Vue.js 2024. 1. 30. 22:28

인프런 프론트엔드 강의 3일차.

웹 게임을 만들며 배우는 Vue 1

 

Vue로 간단한 웹게임 만들어보기.

1일차는 섹션 0. 강좌소개 수강 (24.01.23 완료)

2일차는 섹션 1. 끝말잇기 수강 (24.01.24 완료)

3일차는 섹션 2. 숫자야구 수강 (24.01.29 완료)

 

1. vue 프로젝트 생성 순서 및 명령어

# vue 프로젝트 생성 순서

#package.json이 생성된다
npm init

#vue 설치
npm install vue

#개발할 때만 webpack 실행하도록 -D 옵션 지정, devDependencies에 추가된다.
npm install webpack webpack-cli -D


#vue컴포넌트를 js로 변환하는 webpack 로더
npm install vue-loader -D

# vue 컴파일러
npm install vue-template-compiler -D

webpack.config.js 파일 생성

 

2. package.json

{
  "name": "number-baseball",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "vue": "^3.4.15"
  },
  "devDependencies": {
    "vue-loader": "^17.4.2",
    "vue-template-compiler": "^2.7.16",
    "webpack": "^5.90.0",
    "webpack-cli": "^5.1.4"
  }
}

 

3. webpack.config.js

// vue-loader를 사용하기 위한 준비
const { VueLoaderPlugin } = require("vue-loader");
// node가 만들어준 스크립트 활용
const path = require("path");

// node의 module 제작
// 웹팩이 모듈로 만든 객체를 사용
// 스크립트를 하나로 합칠 파일이 필요
// 가장 대표가 되는 파일이 entry임
// entry의 app은 하나로 합쳐질 파일
module.exports = {
  mode: "development",
  // 개발할때는 eval
  // 배포할 때는 hidden-source-map
  devtool: "eval",
  resolve: {
    // 확장자 처리
    // 여기 넣어주면 main.js에 import 시에 확장자를 제거할 수 있다
    extensions: [".js", ".vue"],
  },
  entry: {
    // 현재 폴더 안에 들어있는 main.js 찾아서 dir 합침
    app: path.join(__dirname, "main.js"),
  },
  // entry부터 처리하다가 이상한 걸 만나면 module의 rules부터 처리
  module: {
    // 파일명에 .vue가 들어가면 vue-loader가 처리를 한다.
    rules: [
      {
        test: /\.vue$/,
        loader: "vue-loader",
      },
    ],
  },
  // output 나오기 전에 plugin으로 가공
  plugins: [
    // vue-loader를 사용하기 위한 준비
    new VueLoaderPlugin(),
  ],
  // 최종 결과물
  output: {
    //filename: 'app.js'
    //[name]이라고 하면 알아서 app.js를 명함
    filename: "[name].js",
    //폴더경로
    path: path.join(__dirname, "dist"),
    // 정리하자면 dist라는 폴더가 생성될 것이고, app.js로 최종 결과물이 생성될 것
  },
};

 

4. NumberBaseball.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>숫자야구</title>
  </head>

  <body>
    <div id="root"></div>
    <script src="./dist/app.js"></script>
  </body>
</html>

 

 

5. NumberBaseball.vue

<template>
  <div>
    <h1>{{ result }}</h1>
    <form @submit.prevent="onSubmitForm">
      <input ref="answer" minlength="4" maxlength="4" v-model="value" />
      <button>입력</button>
    </form>
    <div>시도: {{ tries.length }}</div>
    <ul>
      <li v-for="t in tries" :key="t.try">
        <div>{{ t.try }}</div>
        <div>{{ t.result }}</div>
      </li>
    </ul>
  </div>
</template>

<script>
const getNumbers = () => {
  const candidates = [1, 2, 3, 4, 5, 6, 7, 8, 9];
  const array = [];
  for (let i = 0; i < 4; i++) {
    const chosen = candidates.splice(Math.floor(Math.random() * (9 - i)), 1)[0];
    array.push(chosen);
  }
  return array;
};
export default {
  data() {
    return {
      answer: getNumbers(),
      tries: [],
      value: "",
      result: "",
    };
  },
  methods: {
    onSubmitForm() {
      if (this.value === this.answer.join("")) {
        this.tries.push({
          try: this.value,
          result: "홈런",
        });
        this.result = "홈런";
        alert("게임을 다시 실행합니다.");
        this.value = "";
        this.answer = getNumbers();
        this.tries = [];
        this.$refs.answer.focus();
      } else {
        if (this.tries.length >= 9) {
          this.result = `10번 넘게 틀려서 실패! 답은 ${this.answer.join(
            ","
          )}였습니다!`;
          alert("게임을 다시 시작합니다.");
          this.value = "";
          this.answer = getNumbers();
          this.tries = [];
          this.$refs.answer.focus();
        } else {
          let strike = 0;
          let ball = 0;
          const answerArray = this.value.split("").map((v) => parseInt(v));
          for (let i = 0; i < 4; i++) {
            if (answerArray[i] === this.answer[i]) {
              strike++;
            } else if (this.answer.includes(answerArray[i])) {
              ball++;
            }
          }
          this.tries.push({
            try: this.value,
            result: `${strike} 스트라이크, ${ball} 볼입니다.`,
          });
          this.value = "";
          this.$refs.answer.focus();
        }
      }
    },
  },
};
</script>
<style></style>

 

6. main.js

//Vue2 버전
//import Vue from "vue";

//Vue3버전
import { createApp } from "vue";
import NumberBaseball from "./NumberBaseball";

//vue2버전
//new Vue(NumberBaseball).$mount('#root');

//vue3버전
createApp(NumberBaseball).mount("#root");

 

CDN 으로 Vue를 실행하는 대신 Vue 프로젝트로 직접 구현해보는 섹션!