Vue
by joplomacedo
HTML
<link rel="preconnect" href="https://fonts.gstatic.com">
<link href="https://fonts.googleapis.com/css2?family=Press+Start+2P&display=swap" rel="stylesheet">
<div id="app">
<div class="scoreBar">
<p>Score: {{score}}</p>
</div>
<div class="field" ref="field">
<img
@click="onTargetClick"
@load="onImgLoad"
class="target"
ref="target"
src="https://upload.wikimedia.org/wikipedia/commons/7/78/Jos%C3%A9_S%C3%B3crates_cropped.png"
:style="`--coord-x:${targetX}px; --coord-y:${targetY}px`">
</div>
</div>
CSS
* {
padding: 0;
margin: 0;
border: 0;
}
html,
body,
#app {
height: 100%;
}
#app {
display: flex;
flex-direction: column;
font-family: 'Press Start 2P', cursive;
}
.scoreBar {
padding: .5em;
text-align: right;
}
.field {
flex-grow: 1;
}
.target {
width: 150px;
transition: .5s transform, .1s outline;
transform: translateX(var(--coord-x)) translateY(var(--coord-y));
user-drag: none;
user-select: none;
-moz-user-select: none;
-webkit-user-drag: none;
-webkit-user-select: none;
-ms-user-select: none;
cursor: crosshair;
}
.target.is-clicked{
filter: hue-rotate(296deg);
}
Vue
new Vue({
el: "#app",
data: {
targetWidth: undefined,
targetHeight: undefined,
fieldWidth: undefined,
fieldHeight: undefined,
targetX: 40,
targetY: 40,
maxTargetX: undefined,
maxTargetY: undefined,
score: 0,
targetMoveInterval: undefined,
targetClickSequenceTimeout: undefined,
currentLevel: 0,
levelOptions: [
{
targetRestDuration: 1000,
},
{
targetRestDuration: 700,
},
{
targetRestDuration: 500,
},
{
targetRestDuration: 300,
},
{
targetRestDuration: 200,
}
]
},
computed: {
currentLevelOptions() {
return this.levelOptions[this.currentLevel];
}
},
watch: {
score( score ) {
if ( score%5 === 0) {
this.currentLevel++;
}
},
currentLevel( currentLevel ) {
clearInterval(this.targetMoveInterval);
this.targetMoveInterval = setInterval( () => {
this.moveTargetRandomly();
}, this.currentLevelOptions.targetRestDuration)
}
},
methods: {
getRandomNumBetween( num1, num2) {
return Math.floor(Math.random() * num2) + num1;
},
moveTargetRandomly() {
this.targetX = this.getRandomNumBetween(0,this.maxTargetX);
this.targetY = this.getRandomNumBetween(0,this.maxTargetY);
},
onImgLoad() {
this.targetWidth = this.$refs.target.offsetWidth;
this.targetHeight = this.$refs.target.offsetHeight;
this.maxTargetX = this.fieldWidth - this.targetWidth;
this.maxTargetY = this.fieldHeight - this.targetHeight;
this.targetMoveInterval = setInterval( () => {
this.moveTargetRandomly();
}, this.currentLevelOptions.targetRestDuration)
},
onPageResize() {
if ( this.targetWidth && this.targetHeight ) {
this.maxTargetX = this.fieldWidth - this.targetWidth;
this.maxTargetY = this.fieldHeight - this.targetHeight;
}
...