본문 바로가기

프론트엔드/자바스크립트

프로젝트 - 퐁

반응형

<!-- index.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>Document</title>

  <script src="https://kit.fontawesome.com/833be080c6.js" crossorigin="anonymous"></script>
  <link rel="stylesheet" href="./main.css">
  <script defer src="./index.js"></script>
</head>

<body>
  <div class="game-over">
    <button class="start-over-btn">Start</button>
  </div>

  <div class="frame-1">
    <canvas>
    </canvas>
    <img class="background-bg" src="./assets/images/sky1.webp" alt="">
  </div>

  <div class="frame-2 show">
    <div class="ball"></div>
  </div>
</body>

</html>
/* main.css */

* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  height: 100vh;
  overflow: hidden;
}

.frame-1 {
  height: 100vh;
  width: 100%;
  transition: 0.4s ease;
}

canvas {
  border: 4px solid #000;
  border-bottom: none;
  margin: auto;
  display: block;
}

.game-over {
  position: fixed;
  top: 0;
  left: 0;
  height: 100%;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
}

.start-over-btn {
  font-size: 2rem;
  padding: 10px 15px;
  border-radius: 5px;
  border: none;
  box-shadow: 1px 1px 2px 1px rgba(0, 0, 0, 0.3);
  transition: 0.4s ease;
}

.start-over-btn:hover {
  filter: brightness(110%);
}

.start-over-btn:active {
  transform: scale(0.98);
}

.game-over.hide {
  display: none;
}

img {
  object-fit: cover;
  object-position: center;
}

.background-bg {
  position: fixed;
  height: 100vh;
  width: 100%;
  z-index: -1;
  top: 0;
  left: 0;
}

.frame-2 {
  height: 100vh;
  width: 100%;
  background: url('./assets/images/city.jpg');
  background-size: cover;
  background-repeat: no-repeat;
  background-position: center;
  transform: translateY(100%);
  transition: 0.4s ease;
  flex-grow: 1;
  position: relative;  
}

.frame-2.show {
  animation: blur 1s 1s ease forwards;
}

.ball {
  height: 20px;
  width: 20px;
  background-color: #000;
  position: absolute;
  top: 0;
  left: 50%;
  border-radius: 50%;
  z-index: 5;  
}

.frame-2.show .ball {
  animation: fall 1s ease-in forwards;
}


@keyframes fall {
  from {
    top: 0;
    transform: scale(0);
  }

  to {
    top: 30%;
    transform: scale(4);
  }
}

@keyframes blur {
  from {
    filter: grayscale(0);
  }

  to {
    filter: grayscale(100);
  }
}
/* index.js */

//elements
const canvas = document.querySelector('canvas')
const gameOverEl = document.querySelector('.game-over')
const startOverBtn = document.querySelector('.start-over-btn')
const firstFrameEl = document.querySelector('.frame-1')
const secondFrameEl = document.querySelector('.frame-2')

//canvas setup
const cv = canvas.getContext('2d')
canvas.height = window.innerHeight - 70
canvas.width = 550

//ball variable
let ballSize = 11
let ballX = canvas.width / 2
let ballY = canvas.width / 2
let ballMove

//panel variable
let panelWidth = 100
let panelHeight = 20
let panelX = canvas.width / 2
let panelColor = 'green'
let panelSpeed = 5

//game logic variable
let ballDirectionX = ''
let ballDirectionY = 'down'

//event handlers
window.addEventListener('keydown', (e) => {
  cv.clearRect(panelX - panelWidth / 2, 600, panelWidth, panelHeight)

  if (e.key === 'ArrowRight') {
    panelX += panelSpeed
    if (panelX > 500) {
      panelX -= panelSpeed + 1
    }
  } else if (e.key === 'ArrowLeft') {
    panelX -= panelSpeed
    if (panelX < 50) {
      panelX += panelSpeed + 1
    }
  }
  updatePanelPosition()
})
let gameStarted = false
startOverBtn.addEventListener('click', () => {
  secondFrameEl.classList.remove('show')
  if (gameStarted) {
    firstFrameEl.style.transform = 'translateY(0%)'
    secondFrameEl.style.transform = 'translateY(100%)'
  }
  gameStarted = true
  gameOverEl.classList.add('hide')
  initiateGame()
})

//functions
function initiateGame() {
  //ball variable
  ballSize = 11
  ballX = canvas.width / 2
  ballY = canvas.width / 2
  ballMove

  //panel variable
  panelWidth = 100
  panelHeight = 20
  panelX = canvas.width / 2
  panelColor = 'green'
  panelSpeed = 5

  //ball
  cv.beginPath()
  cv.fillStyle = '#000'
  cv.arc(ballX - ballSize / 2, ballY - ballSize / 2, ballSize, 0, Math.PI * 2)
  cv.fill()

  //panel
  cv.fillStyle = panelColor
  cv.lineCap = 'round'
  cv.fillRect(panelX - panelWidth / 2, 600, panelWidth, panelHeight)

  moveBall()
}

function updatePanelPosition() {
  cv.fillStyle = panelColor
  cv.fillRect(panelX - panelWidth / 2, 600, panelWidth, panelHeight)
}

function updateBallPosition() {
  checkCollision()
  cv.beginPath()
  decideBallDirectionX()
  decideBallDirectionY()
  moveBallX()
  moveBallY()
  cv.fillStyle = '#000'
  cv.arc(ballX - ballSize / 2, ballY - ballSize / 2, ballSize, 0, Math.PI * 2)
  cv.fill()
}

function decideBallDirectionX() {
  if (ballX > 541) {
    ballDirectionX = 'left'
  }

  if (ballX < 18) {
    ballDirectionX = 'right'
  }
}

function decideBallDirectionY() {
  if (ballY > 645) {
    // ballDirectionY = 'top'
    stopGame()
    firstFrameEl.style.transform = 'translateY(-100%)'
    secondFrameEl.style.transform = 'translateY(-100%)'
    secondFrameEl.classList.add('show')
  }

  if (ballY < 18) {
    ballDirectionY = 'down'
  }
}

function moveBallX() {
  if (ballDirectionX === 'left') {
    ballX--
  } else {
    ballX++
  }
}

function moveBallY() {
  if (ballDirectionY === 'top') {
    ballY--
  } else {
    ballY++
  }
}

function stopGame() {
  clearInterval(ballMove)
  setTimeout(() => {
    clearGameBoard()
    gameOverEl.classList.remove('hide')
  }, 200)
}

function clearGameBoard() {
  cv.clearRect(0, 0, canvas.width, canvas.height)
}

function moveBall() {
  ballMove = setInterval(() => {
    clearBall()
    updateBallPosition()
  }, 10)
}

function clearBall() {
  cv.globalCompositeOperation = 'destination-out'
  cv.arc(
    ballX - ballSize / 2,
    ballY - ballSize / 2,
    ballSize + 2,
    0,
    Math.PI * 2
  )
  cv.fill()
  cv.globalCompositeOperation = 'source-over'
}

//collision
function checkCollision() {
  if (ballY > 590) {
    if (ballX > panelX - 50 && ballX < panelX + 50) {
      ballDirectionY = 'top'
    }
  }

  if (ballY > 590 + 10) {
    if (ballX == panelX - 58) {
      ballDirectionX = 'left'
    }

    if (ballX == panelX + 70) {
      ballDirectionX = 'right'
    }
  }
}

데모

Document (jin-co-jcg.vercel.app)

 

Document

 

jin-co-jcg.vercel.app

 

728x90
반응형

'프론트엔드 > 자바스크립트' 카테고리의 다른 글

자바스크립트 컴포넌트 - 스탭퍼  (0) 2023.02.01
자바스크립트 컴포넌트 - 고무고무 카드  (0) 2023.01.28
데이터 타입 - Blob  (0) 2023.01.08
JavaScript?  (0) 2023.01.08
프로젝트 - 그림판  (0) 2023.01.04