본문 바로가기
프로젝트/한글 게임

17. 포인트 기능

by 갱생angel 2024. 5. 11.

<추가사항>

 -정답을 맞출 떄마다 점수 10점 씩 증가

 -만점 받을 시 포인트를 1씩 증가해서 서버 데이터로 보내 저장

 -서버에 저장된 각 게임 포인트 데이터를 가져와 페이지에 표시

 

-백엔드-

 

model - <scoreModel.js>

const mongoose = require("mongoose");

const Schema = mongoose.Schema;

const ScoreSchema = new Schema({
  imageScore: {
    type: Number, // 숫자 타입으로 변경
    default: 0, // 초기값 설정 (옵션)
  },
  combineScore: {
    type: Number, // 숫자 타입으로 변경
    default: 0, // 초기값 설정 (옵션)
  },
});

module.exports = mongoose.model("Score", ScoreSchema);

 

controller - <scoreController.js>

const asynchHandler = require("express-async-handler");
const Score = require("../model/scoreModel");

const getScore = asynchHandler(async (req, res) => {
  const score = await Score.find();
  res.status(200).send(score);
});

const addImageScore = asynchHandler(async (req, res) => {
  const { imageScore } = req.body;
  const score = await Score.findOne();
  if (!score) { //document가 없을 경우
    score = await Score.create({ imageScore }); //document 생성
  } else { //document가 있을 경우
    score.imageScore += parseInt(imageScore); //포인트 1 증가
    await score.save(); //변경된 내용 저장
  }
});

const addCombineScore = asynchHandler(async (req, res) => {
  const { combineScore } = req.body;
  const score = await Score.findOne();
  if (!score) { //document가 없을 경우
    score = await Score.create({ combineScore }); //document 생성
  } else { //document가 있을 경우
    score.combineScore += parseInt(combineScore); //포인트 1 증가
    await score.save(); //변경된 내용 저장
  }
});

module.exports = { getScore, addImageScore, addCombineScore };

 

route - <scoreRoute.js>

const express = require("express");
const router = express.Router();
const {
  getScore,
  addImageScore,
  addCombineScore,
} = require("../controller/scoreController");

router.route("/score").get(getScore);
router.route("/imageScore").post(addImageScore);
router.route("/combineScore").post(addCombineScore);

module.exports = router;

 

<app.js>

const express = require("express");
const cors = require("cors");
const dbConnect = require("./config/dbConnect");

const app = express();

dbConnect();

app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use("/file", express.static("file"));

app.use("/", require("./route/userRoute"));
app.use("/", require("./route/postRoute"));
app.use("/", require("./route/gameRoute"));
app.use("/", require("./route/scoreRoute")); //포인트 라우터 추가

app.listen(5000, () => {
  console.log("5000 포트에서 서버 실행 중");
});

-프론트엔드-

 

page - Game - <ImageGame.js>

import axios from "axios";
import React, { useEffect, useState } from "react";
import "../../css/game.css";
import Canvas from "../../component/Canvas";
import Typing from "../../component/Typing";

function ImageGame() {
  const winNum = 1; //서버에 보낼 포인트 증가 데이터
  const [imageData, setImagaData] = useState([]);

  const [quiz, setQuiz] = useState("");
  const [count, setCount] = useState(1);
  const [score, setScore] = useState(0); //점수 

  const [gameOver, setGameOver] = useState(false);
  const [checkQuiz, setCheckQuiz] = useState(false);
  const [moreChance, setMoreChance] = useState(0);

  const [answerObj, setAnswerObj] = useState(false);
  const [answerObjName, setAnswerObjName] = useState("타이핑");
  const [answerObjButton, setAnswerObjButton] = useState(false);

  const resetButton = () => {
    window.location.reload();
  };

  const changeAnswerObj = () => {
    setAnswerObj((answerObj) => !answerObj);
    if (answerObjName === "타이핑") {
      setAnswerObjName("캔버스");
    } else {
      setAnswerObjName("타이핑");
    }
  };

  const checkAnswer = async (text) => {
    if (text === quiz) {
      alert("정답입니다.");
      setCheckQuiz(true);
      setAnswerObjButton(true);
      setScore((score) => score + 10); //정답을 맞출 때마 점수 10 증가
    } else {
      if (moreChance === 0) {
        alert("오답입니다. 한 번 더 시도해보세요.");
        setMoreChance((moreChance) => moreChance + 1);
      } else if (moreChance === 1) {
        alert("오답입니다. 다음 라운드로 넘어갑니다.");
        setMoreChance(0);
        setCheckQuiz(true);
        setAnswerObjButton(true);
      }
    }
  };

  const fetchData = () => {
    axios.get("http://localhost:5000/game").then((res) => {
      if (res.data.game && res.data.game.length > 0) {
        setImagaData(res.data.game[0].image);
        setQuiz(res.data.game[0].title);
        setCount(res.data.count);
        if (count >= 5) {
          setGameOver(true);
          alert(res.data.message);
        }
      } else {
        setGameOver(true);
        alert(res.data.message);
      }
    });
  };

  useEffect(() => {
    fetchData();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => { //만점을 받을 시 서버로 증가할 포인트 데이터 보내기
    if (score >= 50) {
      axios.post("http://localhost:5000/imageScore", { imageScore: winNum });
    }
  }, [score]);

  return (
    <div className="imageGameContainer">
      <div className="imageDiv">
        {gameOver ? (
          <div>
            <h1>Game Over, 점수: {score} / 50</h1>
            <button onClick={resetButton}>다시하기</button>
            <button >홈으로</button>
          </div>
        ) : (
          <div>
            <div className="roundDiv">
              <h2>Round: {count} / 5</h2>
              <button onClick={changeAnswerObj} disabled={answerObjButton}>
                {answerObjName}
              </button>
            </div>
            <img alt="이미지" src={`http://localhost:5000/file/${imageData}`} />
          </div>
        )}
      </div>
      {!gameOver && (
        <div>
          {answerObj ? (
            <div>
              <Typing
                checkAnswer={checkAnswer}
                fetchData={fetchData}
                quiz={quiz}
                checkQuiz={checkQuiz}
                setCheckQuiz={setCheckQuiz}
                setAnswerObjButton={setAnswerObjButton}
              />
            </div>
          ) : (
            <div>
              <Canvas
                checkAnswer={checkAnswer}
                fetchData={fetchData}
                quiz={quiz}
                checkQuiz={checkQuiz}
                setCheckQuiz={setCheckQuiz}
                setAnswerObjButton={setAnswerObjButton}
              />
            </div>
          )}
        </div>
      )}
    </div>
  );
}

export default ImageGame;

 

page - Game - <CombineGame.js>

import axios from "axios";
import React, { useEffect, useState } from "react";
import "../../css/game.css";
import Canvas from "../../component/Canvas";
import Typing from "../../component/Typing";

function CombineGame() {
  const CHO = ['ㄱ', 'ㄲ', 'ㄴ', 'ㄷ', 'ㄸ', 'ㄹ', 'ㅁ',   
               'ㅂ', 'ㅃ', 'ㅅ', 'ㅆ', 'ㅇ', 'ㅈ', 'ㅉ',
               'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'];
  const JUNG = ['ㅏ', 'ㅐ', 'ㅑ', 'ㅒ', 'ㅓ', 'ㅔ', 'ㅕ',  
                'ㅖ', 'ㅗ', 'ㅘ', 'ㅙ', 'ㅚ', 'ㅛ', 'ㅜ',
                'ㅝ', 'ㅞ', 'ㅟ', 'ㅠ', 'ㅡ', 'ㅢ', 'ㅣ'];
  const JONG = ['', 'ㄱ', 'ㄲ', 'ㄳ', 'ㄴ', 'ㄵ', 'ㄶ',    
                'ㄷ', 'ㄹ', 'ㄺ', 'ㄻ', 'ㄼ', 'ㄽ', 'ㄾ',
                'ㄿ', 'ㅀ', 'ㅁ', 'ㅂ', 'ㅄ', 'ㅅ', 'ㅆ',
                'ㅇ', 'ㅈ', 'ㅊ', 'ㅋ', 'ㅌ', 'ㅍ', 'ㅎ'];
                
  const winNum = 1; //서버에 보낼 포인트 증가 데이터
  const [quiz, setQuiz] = useState("");
  const [count, setCount] = useState(1);
  const [score, setScore] = useState(0); //점수

  const [gameOver, setGameOver] = useState(false);
  const [checkQuiz, setCheckQuiz] = useState(false);
  const [moreChance, setMoreChance] = useState(0);

  const [answerObj, setAnswerObj] = useState(false);
  const [answerObjName, setAnswerObjName] = useState("타이핑");
  const [answerObjButton, setAnswerObjButton] = useState(false);

  const [charArray, setCharArray] = useState([]);

  const separateText = () => {
    const result = [];
    for (let char of quiz) {
      const unicode = char.charCodeAt(0) - 44032;
      console.log(unicode);

      const choIndex = parseInt(unicode / 588);
      const jungIndex = parseInt((unicode - choIndex * 588) / 28);
      const jongIndex = parseInt(unicode % 28);

      const choChar = CHO[choIndex];
      const jungChar = JUNG[jungIndex];
      const jongChar = JONG[jongIndex];

      result.push(choChar, jungChar, jongChar);
    }
    return result;
  };

  const resetButton = () => {
    window.location.reload();
  };

  const changeAnswerObj = () => {
    setAnswerObj((answerObj) => !answerObj);
    if (answerObjName === "타이핑") {
      setAnswerObjName("캔버스");
    } else {
      setAnswerObjName("타이핑");
    }
  };

  const checkAnswer = (text) => {
    if (text === quiz) {
      alert("정답입니다.");
      setCheckQuiz(true);
      setAnswerObjButton(true);
      setScore((score) => score + 10); //맞출 때마다 점수 10 증가
    } else {
      if (moreChance === 0) {
        alert("오답입니다. 한 번 더 시도해보세요.");
        setMoreChance((moreChance) => moreChance + 1);
      } else if (moreChance === 1) {
        alert("오답입니다. 다음 라운드로 넘어갑니다.");
        setMoreChance(0);
        setCheckQuiz(true);
        setAnswerObjButton(true);
      }
    }
  };

  const fetchData = () => {
    axios.get("http://localhost:5000/game").then((res) => {
      if (res.data.game && res.data.game.length > 0) {
        setQuiz(res.data.game[0].title);
        setCount(res.data.count);
        if (count >= 5) {
          setGameOver(true);
          alert(res.data.message);
        }
      } else {
        setGameOver(true);
        alert(res.data.message);
      }
    });
  };

  useEffect(() => {
    fetchData();
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffect(() => {
    setCharArray(separateText().sort(() => Math.random() - 0.5));
    //eslint-disable-next-line react-hooks/exhaustive-deps
  }, [quiz]);

  useEffect(() => {
    if (score >= 50) { //만점을 받을 시 서버로 증가할 포인트 데이터 보내기
      axios.post("http://localhost:5000/combineScore", {
        combineScore: winNum,
      });
    }
  }, [score]);

  return (
    <div className="combineGameContainer">
      <div className="combineDiv">
        {gameOver ? (
          <div>
            <h1>Game Over, 점수: {score} / 50</h1>
            <button onClick={resetButton}>다시하기</button>
          </div>
        ) : (
          <div>
            <div className="roundDiv">
              <h2>Round: {count} / 5</h2>
              <button onClick={changeAnswerObj} disabled={answerObjButton}>
                {answerObjName}
              </button>
            </div>
            <div className="textQuizDiv">
              {charArray.map((char, index) => (
                <span key={index}>{char}</span>
              ))}
            </div>
          </div>
        )}
      </div>
      {!gameOver && (
        <div>
          {answerObj ? (
            <div>
              <Typing
                checkAnswer={checkAnswer}
                fetchData={fetchData}
                quiz={quiz}
                checkQuiz={checkQuiz}
                setCheckQuiz={setCheckQuiz}
                setAnswerObjButton={setAnswerObjButton}
              />
            </div>
          ) : (
            <div>
              <Canvas
                checkAnswer={checkAnswer}
                fetchData={fetchData}
                quiz={quiz}
                checkQuiz={checkQuiz}
                setCheckQuiz={setCheckQuiz}
                setAnswerObjButton={setAnswerObjButton}
              />
            </div>
          )}
        </div>
      )}
    </div>
  );
}

export default CombineGame;

 

page - <Home.js>

import React, { useEffect, useState } from "react";
import { useNavigate } from "react-router-dom";
import axios from "axios";

function Home() {
  const navgate = useNavigate();
  const [scoreData, setScoreData] = useState([]);

  const resetImage = () => {
    axios.post("http://localhost:5000/game/reset");
    navgate("/imageGame");
  };
  const resetText = () => {
    axios.post("http://localhost:5000/game/reset");
    navgate("/combineGame");
  };

  useEffect(() => { //포인트 데이터 가져오기
    axios
      .get("http://localhost:5000/score")
      .then((res) => setScoreData(res.data[0]));
  }, []);

  return (
    <div>
      <div>
        <button onClick={() => navgate("/login")}>로그인</button>
        <button onClick={() => navgate("/register")}>회원가입</button>
        <button onClick={() => navgate("/post")}>커뮤니티</button>
        <button onClick={resetImage}>이미지 게임</button>
        <button onClick={resetText}>낱말 조합</button>
      </div>
      <div>
        <h1>이미지 게임 점수 : {scoreData.imageScore}</h1>
        <h1>조합 게임 점수 : {scoreData.combineScore}</h1>
      </div>
    </div>
  );
}

export default Home;

 

'프로젝트 > 한글 게임' 카테고리의 다른 글

19. 종성 ' ' 제외, 쉼표(,) 추가  (0) 2024.06.07
18. 초성/중성/종성 파일 모듈화  (0) 2024.05.20
16. 무작위 나열  (0) 2024.04.29
15. 초성/중성/종성 분리  (0) 2024.04.29
14. 재도전 기회  (0) 2024.04.26