feature/MAPG-203-initial-multiplayer-implementation #8
@ -102,6 +102,15 @@
|
||||
display: none;
|
||||
}
|
||||
|
||||
#startMultiGameButton {
|
||||
display: none;
|
||||
}
|
||||
|
||||
#players > p {
|
||||
font-size: 14px;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 599px) {
|
||||
#mapName {
|
||||
display: none;
|
||||
|
@ -5,6 +5,8 @@
|
||||
NUMBER_OF_ROUNDS: 5,
|
||||
MAX_SCORE: 1000,
|
||||
|
||||
mapBounds: null,
|
||||
multi: { token: null, owner: false },
|
||||
rounds: [],
|
||||
scoreSum: 0,
|
||||
panoId: null,
|
||||
@ -15,8 +17,190 @@
|
||||
adaptGuess: false,
|
||||
googleLink: null,
|
||||
|
||||
initialize: function () {
|
||||
MultiConnector: {
|
||||
connection: null,
|
||||
reconnectCounter: 0,
|
||||
|
||||
connect: function () {
|
||||
if (Game.MultiConnector.connection && Game.MultiConnector.connection.readyState !== WebSocket.CLOSED) {
|
||||
return;
|
||||
}
|
||||
|
||||
Game.MultiConnector.connection = new WebSocket((MapGuesser.isSecure ? 'wss' : 'ws') + '://' + multiUrl);
|
||||
|
||||
Game.MultiConnector.connection.onopen = function () {
|
||||
document.getElementById('loading').style.visibility = 'hidden';
|
||||
|
||||
Game.MultiConnector.reconnectCounter = 0;
|
||||
|
||||
Game.MultiConnector.connection.send(JSON.stringify({ func: 'connect_to_room', args: { roomId: roomId, token: Game.multi.token } }));
|
||||
};
|
||||
|
||||
Game.MultiConnector.connection.onclose = Game.MultiConnector.noConnection;
|
||||
|
||||
Game.MultiConnector.connection.onerror = function (event) {
|
||||
console.error('WebSocket error in Game.MultiConnector:', event);
|
||||
};
|
||||
|
||||
Game.MultiConnector.connection.onmessage = function (message) {
|
||||
var json;
|
||||
|
||||
try {
|
||||
json = JSON.parse(message.data);
|
||||
} catch (e) {
|
||||
console.error('Cannot parse message!');
|
||||
console.error(message.data);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (json.type) {
|
||||
case 'initialize':
|
||||
Game.MultiConnector.initialize(json.data);
|
||||
break;
|
||||
|
||||
case 'member_joined':
|
||||
Game.MultiConnector.memberJoined(json.data);
|
||||
break;
|
||||
|
||||
case 'new_round':
|
||||
Game.MultiConnector.newRound(json.data);
|
||||
break;
|
||||
|
||||
case 'results':
|
||||
//TODO
|
||||
break;
|
||||
|
||||
case 'guess':
|
||||
//TODO
|
||||
break;
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
noConnection: function () {
|
||||
if (Game.MultiConnector.reconnectCounter === 2) {
|
||||
console.error('Could not reconnect WebSocket for Game.MultiConnector...')
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
Game.MultiConnector.reconnectCounter++;
|
||||
|
||||
console.log('Reconnecting WebSocket for Game.MultiConnector... ' + Game.MultiConnector.reconnectCounter);
|
||||
Game.MultiConnector.connect();
|
||||
}, 1000 + Math.min(Game.MultiConnector.reconnectCounter * 500, 9000));
|
||||
},
|
||||
|
||||
initialize: function (data) {
|
||||
if (data.history) {
|
||||
for (var i = 0; i < data.history.length; ++i) {
|
||||
var round = data.history[i];
|
||||
Game.rounds.push({ position: round.position, guessPosition: round.guessPosition, realMarker: null, guessMarker: null, line: null });
|
||||
Game.addRealGuessPair(round.position, round.guessPosition, true);
|
||||
Game.scoreSum += round.score;
|
||||
}
|
||||
|
||||
document.getElementById('currentRound').innerHTML = String(Game.rounds.length) + '/' + String(Game.NUMBER_OF_ROUNDS);
|
||||
document.getElementById('currentScoreSum').innerHTML = String(Game.scoreSum) + '/' + String(Game.rounds.length * Game.MAX_SCORE);
|
||||
}
|
||||
|
||||
if (data.place) {
|
||||
Game.panoId = data.place.panoId;
|
||||
Game.pov = data.place.pov;
|
||||
|
||||
document.getElementById('panoCover').style.visibility = 'hidden';
|
||||
MapGuesser.hideModal();
|
||||
|
||||
Game.startNewRound();
|
||||
}
|
||||
|
||||
document.getElementById('loading').style.visibility = 'hidden';
|
||||
|
||||
var div = document.getElementById('players');
|
||||
|
||||
for (var i = 0; i < data.members.length; ++i) {
|
||||
var member = data.members[i];
|
||||
|
||||
var p = document.createElement('p');
|
||||
p.innerHTML = member.userName + (member.me ? ' (me)' : '');
|
||||
div.appendChild(p);
|
||||
}
|
||||
},
|
||||
|
||||
memberJoined: function (data) {
|
||||
var div = document.getElementById('players');
|
||||
|
||||
var p = document.createElement('p');
|
||||
p.innerHTML = data.userName;
|
||||
div.appendChild(p);
|
||||
},
|
||||
|
||||
newRound: function (data) {
|
||||
//TODO: workaround until results are not sent
|
||||
if (Game.adaptGuess) {
|
||||
document.getElementById('guess').classList.remove('adapt');
|
||||
}
|
||||
|
||||
if (Game.rounds.length === Game.NUMBER_OF_ROUNDS) {
|
||||
Game.reset();
|
||||
}
|
||||
|
||||
// if player didn't guess - TODO: show everything on a map
|
||||
if (data.result && Game.rounds.length > 0 && !Game.rounds[Game.rounds.length - 1].position) {
|
||||
Game.rounds[Game.rounds.length - 1].position = data.result.position;
|
||||
Game.addRealGuessPair(data.result.position, null);
|
||||
}
|
||||
|
||||
Game.panoId = data.place.panoId;
|
||||
Game.pov = data.place.pov;
|
||||
|
||||
MapGuesser.hideModal();
|
||||
Game.resetRound();
|
||||
Game.startNewRound();
|
||||
}
|
||||
},
|
||||
|
||||
prepare: function () {
|
||||
var data = new FormData();
|
||||
var userNames;
|
||||
|
||||
if (roomId) {
|
||||
var userNames = localStorage.userNames ? JSON.parse(localStorage.userNames) : {};
|
||||
if (!userNames.hasOwnProperty(roomId)) {
|
||||
userNames[roomId] = prompt('Your name: ');
|
||||
localStorage.userNames = JSON.stringify(userNames);
|
||||
}
|
||||
|
||||
data.append('userName', userNames[roomId]);
|
||||
}
|
||||
|
||||
document.getElementById('loading').style.visibility = 'visible';
|
||||
|
||||
var url = roomId ? '/multiGame/' + roomId + '/prepare.json' : '/game/' + mapId + '/prepare.json';
|
||||
MapGuesser.httpRequest('POST', url, function () {
|
||||
document.getElementById('loading').style.visibility = 'hidden';
|
||||
|
||||
document.getElementById('mapName').innerHTML = this.response.mapName;
|
||||
Game.mapBounds = this.response.bounds;
|
||||
|
||||
Game.initialize();
|
||||
|
||||
if (roomId) {
|
||||
Game.multi.token = this.response.token;
|
||||
Game.multi.owner = this.response.owner;
|
||||
|
||||
MapGuesser.showModal('multi');
|
||||
if (Game.multi.owner) {
|
||||
document.getElementById('startMultiGameButton').style.display = 'block';
|
||||
}
|
||||
|
||||
document.getElementById('loading').style.visibility = 'visible';
|
||||
|
||||
Game.MultiConnector.connect();
|
||||
}
|
||||
}, data);
|
||||
},
|
||||
|
||||
initialize: function () {
|
||||
document.getElementById('panoCover').style.visibility = 'visible';
|
||||
document.getElementById('currentRound').innerHTML = '1/' + String(Game.NUMBER_OF_ROUNDS);
|
||||
document.getElementById('currentScoreSum').innerHTML = '0/0';
|
||||
@ -24,9 +208,16 @@
|
||||
Game.map.setOptions({
|
||||
draggableCursor: 'crosshair'
|
||||
});
|
||||
Game.map.fitBounds(mapBounds);
|
||||
Game.map.fitBounds(Game.mapBounds);
|
||||
|
||||
MapGuesser.httpRequest('GET', '/game/' + mapId + '/initialData.json', function () {
|
||||
if (roomId) {
|
||||
// if it is multiplayer mode, data is sent via WS
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('loading').style.visibility = 'visible';
|
||||
|
||||
MapGuesser.httpRequest('POST', '/game/' + mapId + '/initialData.json', function () {
|
||||
document.getElementById('loading').style.visibility = 'hidden';
|
||||
document.getElementById('panoCover').style.visibility = 'hidden';
|
||||
|
||||
@ -63,8 +254,10 @@
|
||||
for (var i = 0; i < Game.rounds.length; ++i) {
|
||||
var round = Game.rounds[i];
|
||||
|
||||
if (round.realMarker && round.guessMarker && round.line) {
|
||||
if (round.realMarker) {
|
||||
round.realMarker.setMap(null);
|
||||
}
|
||||
if (round.guessMarker) {
|
||||
round.guessMarker.setMap(null);
|
||||
round.line.setMap(null);
|
||||
}
|
||||
@ -96,8 +289,10 @@
|
||||
var lastRound = Game.rounds[Game.rounds.length - 1];
|
||||
|
||||
lastRound.realMarker.setVisible(false);
|
||||
lastRound.guessMarker.setVisible(false);
|
||||
lastRound.line.setVisible(false);
|
||||
if (lastRound.guessMarker) {
|
||||
lastRound.guessMarker.setVisible(false);
|
||||
lastRound.line.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('panoCover').style.visibility = 'hidden';
|
||||
@ -108,7 +303,12 @@
|
||||
Game.map.setOptions({
|
||||
draggableCursor: 'crosshair'
|
||||
});
|
||||
Game.map.fitBounds(mapBounds);
|
||||
Game.map.fitBounds(Game.mapBounds);
|
||||
|
||||
if (roomId) {
|
||||
// if it is multiplayer mode, data is sent via WS
|
||||
return;
|
||||
}
|
||||
|
||||
Game.startNewRound();
|
||||
},
|
||||
@ -124,8 +324,14 @@
|
||||
handleErrorResponse: function (error) {
|
||||
// for the time being we only handle the "no_session_found" error and reset the game
|
||||
|
||||
MapGuesser.httpRequest('GET', '/game/' + mapId + '/json', function () {
|
||||
mapBounds = this.response.bounds;
|
||||
if (roomId) {
|
||||
//TODO: better error message
|
||||
alert('Your session is invalid, please start multiplayer again!')
|
||||
return;
|
||||
}
|
||||
|
||||
MapGuesser.httpRequest('GET', '/game/' + mapId + '/prepare.json', function () {
|
||||
Game.mapBounds = this.response.bounds;
|
||||
|
||||
Game.reset();
|
||||
});
|
||||
@ -160,7 +366,8 @@
|
||||
data.append('lat', String(guessPosition.lat));
|
||||
data.append('lng', String(guessPosition.lng));
|
||||
|
||||
MapGuesser.httpRequest('POST', '/game/' + mapId + '/guess.json', function () {
|
||||
var url = roomId ? '/multiGame/' + roomId + '/guess.json' : '/game/' + mapId + '/guess.json';
|
||||
MapGuesser.httpRequest('POST', url, function () {
|
||||
if (this.response.error) {
|
||||
Game.handleErrorResponse(this.response.error);
|
||||
return;
|
||||
@ -204,6 +411,10 @@
|
||||
Game.panoId = this.response.place.panoId;
|
||||
Game.pov = this.response.place.pov;
|
||||
} else {
|
||||
if (!Game.multi.owner) {
|
||||
//TODO: "waiting for" disabled button
|
||||
document.getElementById('continueButton').style.display = 'none';
|
||||
}
|
||||
Game.panoId = null;
|
||||
Game.pov = null;
|
||||
}
|
||||
@ -233,6 +444,10 @@
|
||||
window.open('https://www.google.com/maps/search/?api=1&query=' + this.getPosition().toUrlValue(), '_blank');
|
||||
});
|
||||
|
||||
if (!guessPosition) {
|
||||
return;
|
||||
}
|
||||
|
||||
round.guessMarker = new google.maps.Marker({
|
||||
map: Game.map,
|
||||
visible: !hidden,
|
||||
@ -304,7 +519,10 @@
|
||||
scoreInfo.children[0].style.display = 'none';
|
||||
scoreInfo.children[1].style.display = 'block';
|
||||
document.getElementById('showSummaryButton').style.display = null;
|
||||
document.getElementById('startNewGameButton').style.display = 'block';
|
||||
|
||||
if (Game.multi.owner) {
|
||||
document.getElementById('startNewGameButton').style.display = 'block';
|
||||
}
|
||||
|
||||
var resultBounds = new google.maps.LatLngBounds();
|
||||
|
||||
@ -325,12 +543,17 @@
|
||||
fontWeight: '500',
|
||||
text: String(i + 1)
|
||||
});
|
||||
|
||||
round.realMarker.setVisible(true);
|
||||
round.guessMarker.setVisible(true);
|
||||
round.line.setVisible(true);
|
||||
if (round.guessMarker) {
|
||||
round.guessMarker.setVisible(true);
|
||||
round.line.setVisible(true);
|
||||
}
|
||||
|
||||
resultBounds.extend(round.position);
|
||||
resultBounds.extend(round.guessPosition);
|
||||
if (round.guessMarker) {
|
||||
resultBounds.extend(round.guessPosition);
|
||||
}
|
||||
}
|
||||
|
||||
Game.map.fitBounds(resultBounds);
|
||||
@ -378,13 +601,7 @@
|
||||
}
|
||||
};
|
||||
|
||||
MapGuesser.sessionAvailableHooks.reinitializeGame = function () {
|
||||
MapGuesser.httpRequest('GET', '/game/' + mapId + '/json', function () {
|
||||
mapBounds = this.response.bounds;
|
||||
|
||||
Game.initialize();
|
||||
});
|
||||
};
|
||||
MapGuesser.sessionAvailableHooks.reinitializeGame = Game.prepare;
|
||||
|
||||
if (!('ontouchstart' in document.documentElement)) {
|
||||
Game.adaptGuess = true;
|
||||
@ -445,7 +662,9 @@
|
||||
Game.rewriteGoogleLink();
|
||||
});
|
||||
|
||||
Game.initialize();
|
||||
if (COOKIES_CONSENT) {
|
||||
Game.prepare();
|
||||
}
|
||||
|
||||
document.getElementById('showGuessButton').onclick = function () {
|
||||
this.style.visibility = 'hidden';
|
||||
@ -462,7 +681,19 @@
|
||||
}
|
||||
|
||||
document.getElementById('continueButton').onclick = function () {
|
||||
Game.resetRound();
|
||||
if (roomId) {
|
||||
if (!Game.multi.owner) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('loading').style.visibility = 'visible';
|
||||
|
||||
MapGuesser.httpRequest('POST', '/multiGame/' + roomId + '/nextRound.json', function () {
|
||||
document.getElementById('loading').style.visibility = 'hidden';
|
||||
});
|
||||
} else {
|
||||
Game.resetRound();
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('showSummaryButton').onclick = function () {
|
||||
@ -470,6 +701,31 @@
|
||||
}
|
||||
|
||||
document.getElementById('startNewGameButton').onclick = function () {
|
||||
Game.reset();
|
||||
if (roomId) {
|
||||
if (!Game.multi.owner) {
|
||||
return;
|
||||
}
|
||||
|
||||
document.getElementById('loading').style.visibility = 'visible';
|
||||
|
||||
MapGuesser.httpRequest('POST', '/multiGame/' + roomId + '/initialData.json', function () {
|
||||
document.getElementById('loading').style.visibility = 'hidden';
|
||||
});
|
||||
} else {
|
||||
Game.reset();
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById('startMultiGameButton').onclick = function () {
|
||||
if (!roomId || !Game.multi.owner) {
|
||||
return;
|
||||
}
|
||||
|
||||
MapGuesser.hideModal();
|
||||
document.getElementById('loading').style.visibility = 'visible';
|
||||
|
||||
MapGuesser.httpRequest('POST', '/multiGame/' + roomId + '/initialData.json', function () {
|
||||
document.getElementById('loading').style.visibility = 'hidden';
|
||||
});
|
||||
}
|
||||
})();
|
||||
|
@ -1,4 +1,5 @@
|
||||
var MapGuesser = {
|
||||
isSecure: window.location.protocol === 'https:',
|
||||
cookiesAgreed: false,
|
||||
sessionAvailableHooks: {},
|
||||
|
||||
|
@ -5,10 +5,19 @@
|
||||
|
||||
@extends(templates/layout_full)
|
||||
|
||||
@section(pagemodal)
|
||||
<div id="multi" class="modal">
|
||||
<h2>Multiplayer (beta)</h2>
|
||||
<p class="marginTop">Waiting for players...</p>
|
||||
<div id="players" class="marginTop"></div>
|
||||
<button id="startMultiGameButton" class="button fullWidth marginTop green">Start game</button>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@section(subheader)
|
||||
<span id="mapName" class="bold"><?= $mapName ?></span><!--
|
||||
--><span>Round <span id="currentRound" class="bold"></span></span><!--
|
||||
--><span>Score <span id="currentScoreSum" class="bold"></span></span>
|
||||
<span id="mapName" class="bold"></span><!--
|
||||
--><span>Round <span id="currentRound" class="bold"></span></span><!--
|
||||
--><span>Score <span id="currentScoreSum" class="bold"></span></span>
|
||||
@endsection
|
||||
|
||||
@section(main)
|
||||
@ -50,7 +59,8 @@
|
||||
|
||||
@section(pageScript)
|
||||
<script>
|
||||
var mapId = <?= $mapId ?>;
|
||||
var mapBounds = <?= json_encode($bounds) ?>;
|
||||
var multiUrl = '<?= $_ENV['MULTI_WS_HOST'] . ':' . $_ENV['MULTI_WS_PORT'] ?>';
|
||||
var roomId = <?= isset($roomId) ? '\'' . $roomId . '\'' : 'null' ?>;
|
||||
var mapId = <?= isset($mapId) ? '\'' . $mapId . '\'' : 'null' ?>;
|
||||
</script>
|
||||
@endsection
|
||||
|
Loading…
Reference in New Issue
Block a user