My personal website's games section https://games.johanv.net
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

227 lines
9.6 KiB

{% include 'header.html' %}
<div id="app" class="gameArea extraSpace" v-cloak>
<div class="leftCol">
<h1 class="scale">Boggle 2.0<span class="hideLarge" v-if="game != undefined"> Time: [[ showTime(game.secondsLeft) ]]</span></h1>
<table v-if="game != undefined" class="boggleBoard noselect"><tbody>
<tr v-for="(row, i) in game.board">
<td v-for="(item, j) in row">
<div onclick="app.letterClick(this)" ontouchstart="app.letterTap(this, event)" ontouchmove="app.letterDrag(this, event)" ontouchend="app.letterRelease(this, event)">
<span v-if="item == 'Qu'" v-bind:style="styleObjectQu" v-bind:i="i" v-bind:j="j">[[ item ]]</span>
<span v-else v-bind:style="styleObject" v-bind:i="i" v-bind:j="j">[[ item ]]</span>
</div>
</td>
</tr>
</tbody></table>
</div>
<div class="rightCol">
<h1 class="scale hideSmall" v-if="game != undefined">Time: [[ showTime(game.secondsLeft) ]]</h1>
<p class="scale" style="border: 2px solid black; overflow-wrap: break-word; padding: 5px;" onclick="app.buttonClick('Enter')" ontouchstart="app.buttonTap('Enter', event)">[[ word ]]&nbsp;</p>
<button onclick="app.buttonClick('Enter')" ontouchstart="app.buttonTap('Enter', event)" class="grayButton bigButton">Enter</button>
<button onclick="app.buttonClick('Backspace')" ontouchstart="app.buttonTap('Backspace', event)" class="grayButton bigButton">&#9003;</button>
<button onclick="app.buttonClick('Escape')" ontouchstart="app.buttonTap('Escape', event)" class="grayButton bigButton">Clear</button>
<p style="border-bottom: 2px solid black; overflow-wrap: break-word; font-size: .9em;">
<span v-for="(word, i) in words"><span v-if="i>0">, </span>[[ word ]]</span>
</p>
<span v-if="game != undefined">Game #[[ game._id ]]</span><br/>
<span v-if="isHost">
host (you): [[ username ]]<br/>
</span>
<span v-else-if="game != undefined">
host: [[ game.players[0] ]]<br/>
you: [[ username ]]<br/>
</span>
<p v-if="game != undefined" style="font-size: .9em;">Words need at least [[ game.letters ]] letters.</p>
<form method="{{ formMethod }}">
<input type="hidden" name="username" value="{{ username }}"/>
<input type="hidden" name="action" value="cancel"/>
<input type="hidden" name="id" value="{{ id }}"/>
<input type="hidden" name="page" value="lobby"/>
<input class="redButton" type="submit" value="Leave Game"/>
</form>
<br/>
<h2 class="scale">Video Call</h2>
<p><a target="_blank" href="https://drive.confuzer.cloud/index.php/call/wscgqe9r">Join the video chat!</a></p>
<h2 v-if="game != undefined">[[ game.players.length ]] players total</h2>
<p class="scale" v-if="game != undefined">
<span v-for="(player, i) in game.players"><span v-if="i>0">, </span>[[ player ]]</span>
</p>
</div>
<div class="singleCol"></div>
</div>
{% include 'boggle/common.html' %}
<script>
const app = new Vue ({
delimiters: ['[[',']]'],
el: "#app",
data: {
game: undefined,
numQu: 0,
styleObject: undefined,
styleObjectQu: undefined,
word: "",
words: [],
username: "{{ username }}",
isHost: false,
swipe: []
},
created () {
fetch('?request=game&id={{ id }}')
.then(response => response.json())
.then(json => {
this.game = json.game
console.log(this.game)
this.isHost = (this.game.players[0] == this.username)
this.updateLetterSize()
if (this.game.typedWords != undefined && this.game.typedWords[this.username] != undefined) {
this.words = this.game.typedWords[this.username];
}
this.numQu = 0;
for (var i=0; i<this.game.board.length; i++) {
for (var j=0; j<this.game.board[i].length; j++) {
if (this.game.board[i][j] == "Qu") {
this.numQu++;
}
}
}
})
},
methods: {
everySecond: function() {
if (this.game != undefined) {
if (this.game.secondsLeft <= 0) {
this.game.isDone = true;
if (this.word.length >= this.game.letters) {
this.enterWord(this.word);
this.word = "";
}
window.location = "?username={{ username }}&id={{ id }}&page=view";
} else {
this.game.secondsLeft--;
}
}
this.getBasic();
},
getBasic: function() {
fetch('?request=basic&id={{ id }}')
.then(response => response.json())
.then(json => {
console.log(json)
this.game.players = json.players;
this.isHost = (this.game.players[0] == this.username)
})
},
//show time in the mm:ss format, with zero-padding on the seconds
showTime: function (t) {
var minutes = Math.floor(t / 60);
var seconds = (t % 60);
return minutes + ':' + (seconds < 10 ? '0' : '') + seconds;
},
updateLetterSize: function() {
if (window.innerWidth > 720) {
scaleFactor = 27*4/5;
} else {
scaleFactor = 50;
}
fontSize = scaleFactor / this.game.size;
this.styleObject = {fontSize: fontSize + 'vw'};
this.styleObjectQu = {fontSize: fontSize*.7 + 'vw'};
},
letterClick: function(divItem) {
this.enterLetter(divItem.children[0].innerHTML);
},
letterTap: function(divItem, event) {
event.preventDefault();
this.swipe = [];
},
letterDrag: function(divItem, event) {
var touch = event.targetTouches[0]
var x = touch.clientX;
var y = touch.clientY;
var item = document.elementFromPoint(x, y);
if (item.tagName == "SPAN") {
var i = item.getAttribute("i");
var j = item.getAttribute("j");
if (!this.swipe.includes(i+","+j)) {
this.swipe.push(i+","+j);
console.log(x, y, i, j, item);
this.enterLetter(item.innerHTML);
}
}
},
letterRelease: function(divItem, event) {
if (this.swipe.length == 0) {
this.letterClick(divItem);
}
},
buttonClick: function(key) {
this.enterLetter(key);
},
buttonTap: function(key, event) {
event.preventDefault();
this.buttonClick(key);
},
enterLetter: function(key) {
console.log(key);
if (key == "Enter" || key == " " || key == ",") {
if (this.word.length >= this.game.letters) {
this.enterWord(this.word);
this.word = "";
}
} else if (key == "Escape") {
this.word = "";
} else if (key == "Backspace") {
this.word = this.word.slice(0, -1);
} else if (this.game != undefined && this.word.length < (this.game.size*this.game.size + this.numQu)) {
//only accept a-z, ignoring case but converting to upper
var letterPattern = /^[A-Z]$/i;
if (!key.search(letterPattern) || key == "Qu") {
this.word += key.toUpperCase();
}
}
},
enterWord: function(word) {
word = word.toLowerCase();
if (this.words.indexOf(word) == -1) {
this.words.push(word);
// this.game.typedWords[this.username].push(word);
fetch('?request=savewords&id={{ id }}&username={{ username }}&words=' + this.words.join(","));
}
}
},
mounted () {
this.interval = setInterval(() => {
this.everySecond();
}, 1000);
let self = this;
window.onresize = function() {
self.updateLetterSize();
}
window.addEventListener('keydown', function(event) {
if (event.key == " ") {
//disable scrolling the page on spacebar
event.preventDefault();
}
console.log(event)
self.enterLetter(event.key);
});
setTimeout(() => { // setTimeout to put this into event queue
// executed after render
location.href="#app";
}, 500)
}
});
document.onkeydown = KeyPress;
function KeyPress(e) {
if (!e.metaKey){
e.preventDefault();
}
}
</script>
{% include 'footer.html' %}