자바스크립트 예제

타이핑 게임 ( setInterval, axios.get() 등 )

자무카 2023. 1. 21.

새로운 지식보다는 게임이라서 로직에 빠져들어야 했다. +_+

좋은 예제

Math.floor(Math.random() * array.length)

buttonChange

1. 버튼 비활성화 상태에서 시작

2. axios 로 데이터 다운 후, 활성화 ::: removeChild('loading') # 버튼 동작 (비활성화- loading 후 활성화) - cursor: pointer; - cursor: not-allowed; #ccc

## 종료->게임오버?(초기화)

# 타임아웃시 동작?? 클리어인터벌, 그리고??? 시간 초기화. 다시 스타트

# run()

1)getWords() -> buttonChange(게임시작)

2)실시간으로 상태체크 :checkInterval = setInterval(checkStatus, 50) : !isPlaying && time === 0 ? 게임시작->버튼활성화, 상태체크 clear checkMatch() buttonCh //random-word-api.herokuapp.com/word?number=100

이 분 강의 너무 좋다.

https://youtu.be/_CsGSE5gwTA

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

<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>Typing Game</title>
    <link href="https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,100;0,200;0,300;0,500;1,400&display=swap" rel="stylesheet">
    <link href="./style.css" rel="stylesheet">
</head>

<body>
    <div class="typing__wrap">
        <input type="text" class="input__field">
        <div class="typing__inner">
            <div class="typing__text">
                <p></p>
            </div>
            <div class="typing__info">
                <ul>
                    <li class="time">
                        <p>Time Left: </p>
                        <span><b>60</b>s</span>
                    </li>
                    <li class="mistake">
                        <p>Mistakes: </p>
                        <span>0</span>
                    </li>
                    <li class="wpm">
                        <p>wpm: </p>
                        <span>0</span>
                    </li>
                    <li class="cpm">
                        <p>cpm: </p>
                        <span>0</span>
                    </li>
                </ul>
                <button class="again">Try Again</button>
            </div>
        </div>
    </div>
    <script src="main.js"></script>
</body>

</html>
*{
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: "Poppins";
        }
        body{
            background: #17A2B8;
        }
        .typing__wrap {
            display: flex;
            align-items: center;
            justify-content: center;
            height: 100vh;
        }
        .typing__inner {
            width: 60vw;
            min-width: 900px;
            min-height: 40vh;
            background: #fff;
            border-radius: 20px;
            padding: 40px;
        }
        .input__field {
            position: absolute;
            left: 10px;
            top: 10px;
            padding: 10px;
        }
        .typing__text {
            border: 1px solid #C3C3C3;
            border-radius: 10px;
            padding: 30px;
            min-height: 300px;
            font-size: 22px;
            font-weight: 300;
            text-align: justify;
            word-break: break-all;
        }
        .typing__text p span {
            position: relative;
        }
        .typing__text p span.correct {
            color: #637da5;
        }
        .typing__text p span.incorrect {
            color: #cb3439;
            background: #ffc0cb;
            outline: 1px solid #fff;
            border-radius: 4px;
        }

        .typing__text p span.active {
            color: #17a2b8;
        }
        .typing__text p span.active::before {
            content: '';
            position: absolute;
            left: 0;
            bottom: 0;
            width: 100%;
            height: 2px;
            background: #17a2b8;
            animation: blink 1s ease-in-out infinite;
            opacity: 0;
        }
        @keyframes blink {
            50% {opacity: 1;}
        }
        .typing__info {
            display: flex;
            align-items: center;
            justify-content: space-between;
            margin-top: 30px;
        }
        .typing__info button {
            width: 210px;
            background: #17A2B8;
            color:#fff;
            font-family: "Poppins";
            border: 0;
            border-radius: 5px;
            padding: 10px;
            font-size: 22px;
            margin-left: 20px;
            cursor: pointer;
        }
        .typing__info ul {
            display: flex;
            width: 100%;
            justify-content: space-around;
        }
        .typing__info ul li {
            width: 20%;
            list-style: none;
            display: flex;
            font-size: 20px;
            border-left: 1px solid #C3C3C3;
            padding-left: 40px;
        }
        .typing__info ul li:first-child {
            padding-left: 0;
            border-left: 0;
        }
        
        .typing__info li p {
            white-space: nowrap;
        }
        .typing__info ul li span {
            padding: 0 10px;
        }
       const paragraphs = [
            "one in four American adults is unvaccinated or only partially vaccinated, and that number isnt budging much these days. Fewer than 80,000 adults are getting their first shot every day a 96% drop from the more than 2 million a day in April 2021. Its easy to believe that anyone who hasnt gotten a shot by now is unlikely to get one in the future—but there is still a group of people, however small, just finally coming ",
            "To find out, TIME analyzed vaccination survey data of U.S. adults from the Centers for Disease Control and Prevention (CDC). The survey, which began in late April 2021, shows how willing people have been to getting the shot, and how vaccination rates among various demographics have changed over time  Vaccine uptake among these groups didnt happen in a sudden rush in early 2021 but rather at a slower, steadier pace",
            "Certain segments of the population were slow out of the gate, but managed to catch up to—or even surpass—the national average by January 2022, according to TIMEs analysis. Mostly, these are Americas marginalized communities: Black and hispanic people, LGBTQ people, those living in under-resourced counties, and the uninsured. Vaccine uptake among these groups didnt happen in a sudden rush in early 2021 but rather",
            "If the countrys vaccination rate ticks higher, it will likely be because people who are still feeling unsure today finally took the plunge. Grassroots health organizations are working to find those people. But theyre not always easy to spot name a dun brazil that isn't a highbrow playroom. The unwished beast comes from a thorny oxygen among these groups didnt happen in a sudden rush in early 2021 but",
            "In modern times the first scrawny kitten is, in its own way, an input. An ostrich is the beginner of a roast. An appressed exhaust is a gun of the mind. A recorder is a grade from the right perspective. A hygienic is the cowbell of a skin. Few can name a dun brazil that isn't a highbrow playroom. The unwished beast comes from a thorny oxygen. An insured advantage's respect comes with it the thought that the lucid specialist is a fix.",
            "In ancient times the legs could be said to resemble stroppy vegetables. We can assume that any instance of a centimeter can be construed as an enate paste. One cannot separate pairs from astute managers. Those americas are nothing more than fish. If this was somewhat unclear, authors often misinterpret the gosling as an unfelt banjo, when in actuality it feels more like a professed galley. A bow of the squirrel is assumed.",
            "What we don't know for sure is whether or not a pig of the coast is assumed to be a hardback pilot. The literature would have us believe that a dusky clave is not but an objective. Few can name a limbate leo that isn't a sunlit silver. The bow is a mitten. However, the drawer is a bay. If this was somewhat unclear, few can name a paunchy blue that isn't a conoid bow. The undrunk railway reveals itself as a downstage bamboo to those who look.",
            "Their politician was, in this moment, a notour paperback. The first armless grouse is, in its own way, a gear. The coat is a wash. However, a cake is the llama of a caravan. Snakelike armies show us how playgrounds can be viscoses. Framed in a different way, they were lost without the fatal dogsled that composed their waitress. Far from the truth, the cockney freezer reveals itself as a wiggly tornado to those who look. The first hawklike sack.",
            "An aunt is a bassoon from the right perspective. As far as we can estimate, some posit the melic myanmar to be less than kutcha. One cannot separate foods from blowzy bows. The scampish closet reveals itself as a sclerous llama to those who look. A hip is the skirt of a peak. Some hempy laundries are thought of simply as orchids. A gum is a trumpet from the right perspective. A freebie flight is a wrench of the mind. Some posit the croupy.",
            "A baby is a shingle from the right perspective. Before defenses, collars were only operations. Bails are gleesome relatives. An alloy is a streetcar's debt. A fighter of the scarecrow is assumed to be a leisured laundry. A stamp can hardly be considered a peddling payment without also being a crocodile. A skill is a meteorology's fan. Their scent was, in this moment, a hidden feeling. The competitor of a bacon becomes a boxlike cougar.",
            "A broadband jam is a network of the mind. One cannot separate chickens from glowing periods. A production is a faucet from the right perspective. The lines could be said to resemble zincoid females. A deborah is a tractor's whale. Cod are elite japans. Some posit the wiglike norwegian to be less than plashy. A pennoned windchime's burst comes with it the thought that the printed trombone is a supply. Relations are restless tests.",
            "In recent years, some teeming herons are thought of simply as numbers. Nowhere is it disputed that an unlaid fur is a marble of the mind. Far from the truth, few can name a glossy lier that isn't an ingrate bone. The chicken is a giraffe. They were lost without the abscessed leek that composed their fowl. An interviewer is a tussal bomb. Vanward maracas show us how scarfs can be doubts. Few can name an unguled punch that isn't pig.",
            "A cough is a talk from the right perspective. A designed tractor's tray comes with it the thought that the snuffly flax is a rainbow. Their health was, in this moment, an earthy passbook. This could be, or perhaps the swordfishes could be said to resemble healthy sessions. A capricorn is a helium from the right perspective. However, a sled is a mailman's tennis. The competitor of an alarm becomes a toeless raincoat. Their twist was, in this moment.",
            "Authors often misinterpret the flag as a wayless trigonometry, when in actuality it feels more like a bousy gold. Few can name a jasp oven that isn't a stutter grape. They were lost without the huffy religion that composed their booklet. Those waves are nothing more than pedestrians. Few can name a quartered semicolon that isn't a rounding scooter. Though we assume the latter, the literature would have us believe.",
            "This could be, or perhaps few can name a pasteboard quiver that isn't a brittle alligator. A swordfish is a death's numeric. Authors often misinterpret the mist as a swelling asphalt, when in actuality it feels more like a crosswise closet. Some posit the tonal brother-in-law to be less than newborn. We know that the sizes could be said to resemble sleepwalk cycles. Before seasons, supplies were only fighters. Their stew was, in this moment.",
            "The vision of an attempt becomes a lawny output. Dibbles are mis womens. The olden penalty reveals itself as a bustled field to those who look. Few can name a chalky force that isn't a primate literature. However, they were lost without the gamy screen that composed their beret. Nowhere is it disputed that a step-uncle is a factory from the right perspective. One cannot separate paints from dreary windows. What we don't know for sure is whether.",
            "A tramp is a siamese from the right perspective. We know that a flitting monkey's jaw comes with it the thought that the submersed break is a pamphlet. Their cream was, in this moment, a seedy daffodil. The nest is a visitor. Far from the truth, they were lost without the released linen that composed their step-sister. A vibraphone can hardly be considered a pardine process without also being an archaeology. The bay of a hyacinth becomes.",
            "The frosts could be said to resemble backstage chards. One cannot separate colleges from pinkish bacons. Far from the truth, the mom of a rooster becomes a chordal hydrogen. A tempo can hardly be considered a purer credit without also being a pajama. The first combined ease is, in its own way, a pantyhose. Extending this logic, the guides could be said to resemble reddest monkeies. Framed in a different way, an addle hemp is a van.",
            "Far from the truth, an ajar reminder without catamarans is truly a foundation of smarmy semicircles. An alike board without harps is truly a satin of fated pans. A hubcap sees a parent as a painful beautician. The zeitgeist contends that some intense twigs are thought of simply as effects. A cross is a poppied tune. The valanced list reveals itself as an exchanged wrist to those who look. Recent controversy aside.",
            "The hefty opinion reveals itself as a sterile peer-to-peer to those who look. This could be, or perhaps the watch of a diamond becomes a bosom baboon. In recent years, some posit the unstuffed road to be less than altern. It's an undeniable fact, really; the livelong lettuce reveals itself as an unstuffed soda to those who look. In ancient times a bit is a balance's season. The popcorn of a morning becomes a moonless beauty.",
            "If this was somewhat unclear, a friend is a fridge from the right perspective. An upset carriage is a stitch of the mind. To be more specific, a temper is a pair from the right perspective. Authors often misinterpret the liquid as a notchy baseball, when in actuality it feels more like an unbarbed angle. Though we assume the latter, the first vagrom report is, in its own way, a tower. We know that the octopus of a cd becomes an unrent dahlia.",
            "A reptant discussion's rest comes with it the thought that the condemned syrup is a wish. The drake of a wallaby becomes a sonant harp. If this was somewhat unclear, spotty children show us how technicians can be jumps. Their honey was, in this moment, an intime direction. A ship is the lion of a hate. They were lost without the croupous jeep that composed their lily. In modern times a butcher of the birth is assumed to be a spiral bean.",
            "Those cowbells are nothing more than elements. This could be, or perhaps before stockings, thoughts were only opinions. A coil of the exclamation is assumed to be a hurtless toy. A board is the cast of a religion. In ancient times the first stinko sailboat is, in its own way, an exchange. Few can name a tutti channel that isn't a footless operation. Extending this logic, an oatmeal is the rooster of a shake. Those step-sons are nothing more than matches."
        ];

        const typingText = document.querySelector(".typing__text p")
        const inputField = document.querySelector(".input__field")
        const typingMistake = document.querySelector(".mistake span")
        const typingTime = document.querySelector(".time span b");
        const typingWpm = document.querySelector(".wpm span");
        const typingCpm = document.querySelector(".cpm span");
        const typingAgain = document.querySelector(".again");


        let charIndex = 0;
        let mistakes = 0;
        let timer, maxTime = 60, timeLeft = maxTime;
        let isTyping = 0;


        function randomParagraph(){
            //let randIndex = Math.floor(Math.random() * paragraphs.length)   //랜덤으로 나오게
            typingText.innerHTML = "";
            paragraphs[0].split("").forEach(span => {   //글씨 쪼개기
                let spanTag = `<span>${span}</span>`;
                typingText.innerHTML += spanTag;
            })  
            document.addEventListener("keydown", () => inputField.focus());
            typingText.addEventListener("click", () => inputField.focus())
        }   
        
        function initTyping(){ // 키 타이핑할 경우
            const characters = typingText.querySelectorAll("span");
            let typedChar = inputField.value.split("")[charIndex]

            if(charIndex < characters.length-1 && timeLeft > 0) { // 게임이 종료되지 않은 경우에만
                if(!isTyping){  // 처음 눌렀을때만 작동 (타이머)
                isTyping = true
                timer = setInterval(initTimer,1000)
                }
                if(typedChar == null) { //지우기를 눌렀을때 
                    charIndex--; 
                    if(characters[charIndex].classList.contains("incorrect")){ // 틀린거 지우면 mistakes 감소
                        mistakes--;
                    }
                    characters[charIndex].classList.remove("correct", "incorrect")
                }else { // 글자를 입력한 상황
                    if(characters[charIndex].innerText === typedChar){
                    characters[charIndex].classList.add("correct")
                    }else {
                        mistakes++;
                        characters[charIndex].classList.add("incorrect")
                    }
                    charIndex++;
                }

                // 입력할 글자 하이라이트를 위한 작업
                characters.forEach(span => span.classList.remove("active")); //지나간 부분 active를 다 지우고
                characters[charIndex].classList.add("active")  //해당 부분에 active를 추가
                
                // 타이핑마다 mistakes 갱신
                typingMistake.innerText = mistakes;
                
                // 타자율 wpm과 cpm 계산
                let wpm = Math.round((((charIndex - mistakes)/5) / (maxTime - timeLeft)) * 60);
                wpm = wpm < 0 || !wpm || wpm == Infinity ? 0 : wpm;
                typingWpm.innerText = wpm;
                typingCpm.innerText = charIndex - mistakes;
            } else {
                // 게임이 종료된 경우 타이머 종료
                clearInterval(timer)
                inputField.value = "";
            }
        }
        function initTimer(){ // 시간 1초씩 감소
            if(timeLeft > 0){
                timeLeft --;
                typingTime.innerText = timeLeft;
            }  else{
                clearInterval(timer)
            }
        }
        function resetGame(){ // 게임 종료 및 try again 버튼 클릭 시 리셋
            randomParagraph()
            charIndex = mistakes = isTyping = 0;
            timer, maxTime = 60
            clearInterval(timer)
            inputField.value = "";
            timeLeft = maxTime;
            typingWpm.innerText = 0;
            typingCpm.innerText = 0;
            typingTime.innerText = timeLeft
            typingMistake.innerText = 0
        }
        // 단어 랜덤 선택
        randomParagraph();

        // 키 입력 시
        typingAgain.addEventListener("click", resetGame)
        inputField.addEventListener("input", initTyping);

댓글