Created
July 31, 2023 12:18
-
-
Save dannysmc95/fc9a853a66e4465557a904769bfa9745 to your computer and use it in GitHub Desktop.
Basic Pong (Vue 3 & TS)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div class="game"> | |
<div class="stats"> | |
<p class="points">P1: {{ points.p1 }} / P2: {{ points.p2 }}</p> | |
<p class="frames">Frames: {{ frames }} / {{ renderedFrames }}</p> | |
<p class="clear pull-right" @click="clear">Clear</p> | |
<p class="reset pull-right" @click="reset()">Reset</p> | |
</div> | |
<div v-if="!running" class="startscreen"> | |
<p v-if="lastLoser" class="losermessage"> | |
Player {{ lastLoser }} lost! | |
</p> | |
<button v-if="!running" class="start" @click="start()"> | |
{{ lastLoser ? 'Start Again' : 'Start' }} | |
</button> | |
</div> | |
<div class="player is-left" :style="{ top: `${players.player1.ypos}px` }"> | |
<!-- Player 1 --> | |
</div> | |
<div v-if="running" class="ball" :style="{ left: `${ball.xpos}px`, top: `${ball.ypos}px`}"> | |
<!-- Ball --> | |
</div> | |
<div class="player is-right" :style="{ top: `${players.player2.ypos}px` }"> | |
<!-- Player 2 --> | |
</div> | |
</div> | |
</template> | |
<script setup lang="ts"> | |
import { ref, reactive, onMounted } from 'vue'; | |
const points = { p1: 0, p2: 0 }; | |
const lastLoser = ref<null | number>(null); | |
const running = ref(false); | |
const frames = ref(0); | |
const renderedFrames = ref(0); | |
const ball = reactive({ | |
vertical: 'bottom', | |
horizontal: 'right', | |
xpos: 248, | |
ypos: 148, | |
bounds: { | |
top: 0, | |
right: 500, | |
bottom: 300, | |
left: 0, | |
}, | |
}); | |
const players = reactive({ | |
player1: { | |
ypos: 130, | |
}, | |
player2: { | |
ypos: 130, | |
}, | |
}); | |
const pressedKeys = reactive({ | |
KeyS: false, | |
KeyW: false, | |
ArrowUp: false, | |
ArrowDown: false, | |
}); | |
const render = () => { | |
frames.value++; | |
if (!running.value) { | |
requestAnimationFrame(render); | |
return; | |
} | |
renderedFrames.value++; | |
// ----- BALL ----- | |
// Update position. | |
ball.xpos = ball.xpos + (ball.horizontal === 'left' ? -5 : 5); | |
ball.ypos = ball.ypos + (ball.vertical === 'top' ? -5 : 5); | |
// Check position. | |
if (ball.vertical === 'bottom' && (ball.ypos + 5) >= ball.bounds.bottom) ball.vertical = 'top'; | |
if (ball.vertical === 'top' && ball.ypos <= ball.bounds.top) ball.vertical = 'bottom'; | |
// Check right collisions. | |
if (ball.horizontal === 'right' && (ball.xpos + 5) >= ball.bounds.right) { | |
if (ball.ypos >= players.player2.ypos && ball.ypos <= (players.player2.ypos + 40)) { | |
ball.horizontal = 'left'; | |
} else { | |
reset(2); | |
} | |
} | |
// Check left collisions. | |
if (ball.horizontal === 'left' && ball.xpos <= ball.bounds.left) { | |
if (ball.ypos >= players.player1.ypos && ball.ypos <= (players.player1.ypos + 40)) { | |
ball.horizontal = 'right'; | |
} else { | |
reset(1); | |
} | |
} | |
// ----- PLAYERS ----- | |
// Update position. | |
if (pressedKeys.KeyW && !pressedKeys.KeyS && players.player1.ypos > ball.bounds.top) players.player1.ypos -= 10; | |
if (pressedKeys.KeyS && !pressedKeys.KeyW && (players.player1.ypos + 40) < ball.bounds.bottom) players.player1.ypos += 10; | |
if (pressedKeys.ArrowUp && !pressedKeys.ArrowDown && players.player2.ypos > ball.bounds.top) players.player2.ypos -= 10; | |
if (pressedKeys.ArrowDown && !pressedKeys.ArrowUp && (players.player2.ypos + 40) < ball.bounds.bottom) players.player2.ypos += 10; | |
requestAnimationFrame(render); | |
}; | |
const reset = (loser?: number) => { | |
if (loser) points[`p${loser === 1 ? 2 : 1}`]++; | |
running.value = false; | |
players.player1.ypos = 130; | |
players.player2.ypos = 130; | |
ball.xpos = 248; | |
ball.ypos = 148; | |
lastLoser.value = loser ?? null; | |
ball.horizontal = loser === 1 ? 'left' : 'right'; | |
}; | |
const start = () => { | |
running.value = true; | |
}; | |
const clear = () => { | |
points.p1 = 0; | |
points.p2 = 0; | |
} | |
onMounted(() => { | |
render(); | |
document.addEventListener('keydown', event => { | |
if (typeof pressedKeys[event.code] === 'undefined') return; | |
if (!pressedKeys[event.code]) pressedKeys[event.code] = true; | |
}); | |
document.addEventListener('keyup', event => { | |
if (typeof pressedKeys[event.code] === 'undefined') return; | |
if (pressedKeys[event.code]) pressedKeys[event.code] = false; | |
}); | |
}); | |
</script> | |
<style scoped lang="scss"> | |
.game { | |
margin-top: 25px; | |
background-color: #272727; | |
width: 500px; | |
height: 300px; | |
position: relative; | |
.stats { | |
background-color: rgba(black, 0.3); | |
width: 100%; | |
height: 25px; | |
position: absolute; | |
top: -25px; | |
p { | |
margin: 0; | |
padding: 0; | |
display: inline-block; | |
font-size: 13px; | |
font-family: monospace; | |
height: 25px; | |
&.points { | |
padding: 0 10px; | |
border-right: 1px solid rgba(white, 0.3); | |
} | |
&.frames { | |
padding: 0 10px; | |
border-right: 1px solid rgba(white, 0.3); | |
} | |
&.clear { | |
cursor: pointer; | |
padding: 0 10px; | |
border-left: 1px solid rgba(white, 0.3); | |
} | |
&.reset { | |
cursor: pointer; | |
border-left: 1px solid rgba(white, 0.3); | |
padding: 0 10px; | |
} | |
&.clear:hover, &.reset:hover { | |
background-color: rgba(white, 0.1); | |
} | |
&.pull-right { | |
float: right; | |
} | |
} | |
} | |
.startscreen { | |
background-color: rgba(black, 0.2); | |
width: 250px; | |
height: 150px; | |
position: absolute; | |
top: 50%; | |
left: 50%; | |
padding: 30px 10px; | |
text-align: center; | |
transform: translate(-50%, -50%); | |
.start { | |
font-size: 15px; | |
border-radius: 5px; | |
border: 1px solid rgba(white, 0.5); | |
padding: 5px 8px; | |
} | |
.losermessage { | |
color: #c43b3b; | |
font-style: italic; | |
padding: 0; | |
margin: 0; | |
padding-bottom: 20px; | |
} | |
} | |
.ball { | |
background-color: white; | |
width: 5px; | |
height: 5px; | |
position: absolute; | |
top: 0; | |
left: 0; | |
border-radius: 50%; | |
} | |
.player { | |
width: 4px; | |
background-color: #999961; | |
height: 40px; | |
position: absolute; | |
left: -2px; | |
top: 130px; | |
&.is-right { | |
background-color: #5656bb; | |
left: inherit; | |
right: -2px; | |
} | |
} | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment