Skip to content

Instantly share code, notes, and snippets.

@dannysmc95
Created July 31, 2023 12:18
Show Gist options
  • Save dannysmc95/fc9a853a66e4465557a904769bfa9745 to your computer and use it in GitHub Desktop.
Save dannysmc95/fc9a853a66e4465557a904769bfa9745 to your computer and use it in GitHub Desktop.
Basic Pong (Vue 3 & TS)
<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