Merged in feature/MAPG-25-multi-round-score-localstorage (pull request #27)

Feature/MAPG-25 multi round score localstorage
This commit is contained in:
Bence Pőcze 2020-05-21 23:46:21 +00:00
commit 67358d91ea
4 changed files with 257 additions and 105 deletions

View File

@ -138,6 +138,10 @@ div.buttonContainer.bottom {
font-size: 24px; font-size: 24px;
} }
#distanceInfo > p:nth-child(2), #scoreInfo > p:nth-child(2) {
display: none;
}
#scoreBarBase { #scoreBarBase {
height: 24px; height: 24px;
margin: 0 auto; margin: 0 auto;
@ -153,6 +157,10 @@ div.buttonContainer.bottom {
transition-duration: 2.0s; transition-duration: 2.0s;
} }
#showSummaryButton, #startNewGameButton {
display: none;
}
@media screen and (max-width: 599px) { @media screen and (max-width: 599px) {
button { button {
padding: 0; padding: 0;

View File

@ -1,36 +1,114 @@
'use strict';
(function () { (function () {
var Core = { var Core = {
NUMBER_OF_ROUNDS: 5,
MAX_SCORE: 1000, MAX_SCORE: 1000,
rounds: [],
scoreSum: 0,
realPosition: null, realPosition: null,
panorama: null, panorama: null,
adaptGuess: false,
guessMap: null, guessMap: null,
guessMarker: null, guessMarker: null,
resultMap: null, resultMap: null,
resultMarkers: { guess: null, real: null }, adaptGuess: false,
resultLine: null,
googleLink: null, googleLink: null,
getNewPosition: function () { initialize: function () {
Core.panorama.setVisible(false); if (sessionStorage.rounds) {
var roundsLoaded = JSON.parse(sessionStorage.rounds);
for (var i = 0; i < roundsLoaded.length; ++i) {
var round = roundsLoaded[i];
Core.rounds.push({ realPosition: round.realPosition, guessPosition: round.guessPosition, realMarker: null, guessMarker: null, line: null });
if (round.guessPosition) {
Core.addRealGuessPair(round.realPosition, round.guessPosition);
}
}
}
if (sessionStorage.scoreSum) {
Core.scoreSum = parseInt(sessionStorage.scoreSum);
}
if (Core.rounds.length > 0 && !Core.rounds[Core.rounds.length - 1].guessPosition) {
Core.realPosition = Core.rounds[Core.rounds.length - 1].realPosition;
Core.loadPositionInfo(Core.realPosition);
} else {
Core.startNewRound();
}
},
startNewGame: function () {
for (var i = 0; i < Core.rounds.length; ++i) {
var round = Core.rounds[i];
round.realMarker.setMap(null);
round.guessMarker.setMap(null);
round.line.setMap(null);
}
Core.rounds = [];
Core.scoreSum = 0;
var distanceInfo = document.getElementById('distanceInfo');
distanceInfo.children[0].style.display = null;
distanceInfo.children[1].style.display = null;
var scoreInfo = document.getElementById('scoreInfo');
scoreInfo.children[0].style.display = null;
scoreInfo.children[1].style.display = null;
document.getElementById('continueButton').style.display = null;
document.getElementById('startNewGameButton').style.display = null;
Core.prepareNewRound();
},
prepareNewRound: function () {
document.getElementById('scoreBar').style.width = null;
if (Core.adaptGuess) {
document.getElementById('guess').classList.remove('adapt');
}
document.getElementById('showGuessButton').style.visibility = null;
document.getElementById('guess').style.visibility = null;
document.getElementById('result').style.visibility = null;
Core.guessMap.fitBounds(guessMapBounds);
Core.startNewRound();
},
startNewRound: function () {
Core.rounds.push({ realPosition: null, guessPosition: null, realMarker: null, guessMarker: null, line: null });
Core.panorama.setVisible(false);
document.getElementById('loading').style.visibility = 'visible'; document.getElementById('loading').style.visibility = 'visible';
Core.getNewPosition();
},
getNewPosition: function () {
var xhr = new XMLHttpRequest(); var xhr = new XMLHttpRequest();
xhr.responseType = 'json'; xhr.responseType = 'json';
xhr.onreadystatechange = function () { xhr.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) { if (this.readyState == 4 && this.status == 200) {
Core.realPosition = this.response.position; Core.realPosition = this.response.position;
Core.rounds[Core.rounds.length - 1].realPosition = this.response.position;
Core.loadPositionInfo(this.response.position);
var sv = new google.maps.StreetViewService(); Core.saveToSession();
sv.getPanorama({ location: this.response.position, preference: google.maps.StreetViewPreference.NEAREST }, Core.loadPano);
} }
}; };
xhr.open('GET', 'getNewPosition.json', true); xhr.open('GET', 'getNewPosition.json', true);
xhr.send(); xhr.send();
}, },
loadPositionInfo: function (position) {
var sv = new google.maps.StreetViewService();
sv.getPanorama({ location: position, preference: google.maps.StreetViewPreference.NEAREST }, Core.loadPano);
},
loadPano: function (data, status) { loadPano: function (data, status) {
if (status !== google.maps.StreetViewStatus.OK) { if (status !== google.maps.StreetViewStatus.OK) {
Core.getNewPosition(); Core.getNewPosition();
@ -49,14 +127,111 @@
Core.panorama.setPano(data.location.pano); Core.panorama.setPano(data.location.pano);
}, },
evaluateGuess: function () {
var guessPosition = Core.guessMarker.getPosition().toJSON();
Core.rounds[Core.rounds.length - 1].guessPosition = guessPosition;
var distance = Util.calculateDistance(Core.realPosition, guessPosition);
var score = Core.calculateScore(distance);
Core.scoreSum += score;
Core.saveToSession();
Core.guessMarker.setMap(null);
Core.guessMarker = null;
document.getElementById('guess').style.visibility = 'hidden';
document.getElementById('result').style.visibility = 'visible';
Core.addRealGuessPair(Core.realPosition, guessPosition);
var resultBounds = new google.maps.LatLngBounds();
resultBounds.extend(Core.realPosition);
resultBounds.extend(guessPosition);
Core.resultMap.fitBounds(resultBounds);
document.getElementById('distance').innerHTML = Util.printDistanceForHuman(distance);
document.getElementById('score').innerHTML = score;
var scoreBarProperties = Core.calculateScoreBarProperties(score, Core.MAX_SCORE);
var scoreBar = document.getElementById('scoreBar');
scoreBar.style.backgroundColor = scoreBarProperties.backgroundColor;
scoreBar.style.width = scoreBarProperties.width;
if (Core.rounds.length == Core.NUMBER_OF_ROUNDS) {
document.getElementById('continueButton').style.display = 'none';
document.getElementById('showSummaryButton').style.display = 'block';
}
},
addRealGuessPair(realPosition, guessPosition) {
if (Core.rounds.length > 1) {
var lastRound = Core.rounds[Core.rounds.length - 2];
lastRound.realMarker.setVisible(false);
lastRound.guessMarker.setVisible(false);
lastRound.line.setVisible(false);
}
var round = Core.rounds[Core.rounds.length - 1];
round.realMarker = new google.maps.Marker({
map: Core.resultMap,
position: realPosition,
clickable: true,
draggable: false
});
round.realMarker.addListener('click', function () {
window.open('https://www.google.com/maps/search/?api=1&query=' + this.getPosition().toUrlValue(), '_blank');
});
round.guessMarker = new google.maps.Marker({
map: Core.resultMap,
position: guessPosition,
clickable: false,
draggable: false,
label: {
color: '#ffffff',
fontFamily: 'Roboto',
fontSize: '18px',
fontWeight: '500',
text: '?'
}
});
round.line = new google.maps.Polyline({
map: Core.resultMap,
path: [
realPosition,
guessPosition
],
geodesic: true,
strokeOpacity: 0,
icons: [{
icon: {
path: 'M 0,-1 0,1',
strokeOpacity: 1,
strokeWeight: 2,
scale: 2
},
offset: '0',
repeat: '10px'
}],
clickable: false,
draggable: false,
editable: false
});
},
calculateScore: function (distance) { calculateScore: function (distance) {
var goodness = 1.0 - distance / Math.sqrt(mapArea); var goodness = 1.0 - distance / Math.sqrt(mapArea);
return Math.round(Math.pow(Core.MAX_SCORE, goodness)); return Math.round(Math.pow(Core.MAX_SCORE, goodness));
}, },
calculateScoreBarProperties: function (score) { calculateScoreBarProperties: function (score, maxScore) {
var percent = Math.floor((score / Core.MAX_SCORE) * 100); var percent = Math.floor((score / maxScore) * 100);
var color; var color;
if (percent >= 90) { if (percent >= 90) {
@ -70,6 +245,39 @@
return { width: percent + '%', backgroundColor: color }; return { width: percent + '%', backgroundColor: color };
}, },
showSummary: function () {
var distanceInfo = document.getElementById('distanceInfo');
distanceInfo.children[0].style.display = 'none';
distanceInfo.children[1].style.display = 'block';
var scoreInfo = document.getElementById('scoreInfo');
scoreInfo.children[0].style.display = 'none';
scoreInfo.children[1].style.display = 'block';
document.getElementById('showSummaryButton').style.display = null;
document.getElementById('startNewGameButton').style.display = 'block';
var resultBounds = new google.maps.LatLngBounds();
for (var i = 0; i < Core.rounds.length; ++i) {
var round = Core.rounds[i];
round.realMarker.setVisible(true);
round.guessMarker.setVisible(true);
round.line.setVisible(true);
resultBounds.extend(round.realPosition);
resultBounds.extend(round.guessPosition);
}
Core.resultMap.fitBounds(resultBounds);
document.getElementById('scoreSum').innerHTML = Core.scoreSum;
var scoreBarProperties = Core.calculateScoreBarProperties(Core.scoreSum, Core.NUMBER_OF_ROUNDS * Core.MAX_SCORE);
var scoreBar = document.getElementById('scoreBar');
scoreBar.style.backgroundColor = scoreBarProperties.backgroundColor;
scoreBar.style.width = scoreBarProperties.width;
},
rewriteGoogleLink: function () { rewriteGoogleLink: function () {
if (!Core.googleLink) { if (!Core.googleLink) {
var anchors = document.getElementById('panorama').getElementsByTagName('a'); var anchors = document.getElementById('panorama').getElementsByTagName('a');
@ -86,6 +294,23 @@
Core.googleLink.title = 'Google Maps' Core.googleLink.title = 'Google Maps'
Core.googleLink.href = 'https://maps.google.com/maps' Core.googleLink.href = 'https://maps.google.com/maps'
}, 1); }, 1);
},
saveToSession: function () {
if (Core.rounds.length == Core.NUMBER_OF_ROUNDS && Core.rounds[Core.rounds.length - 1].guessPosition) {
sessionStorage.removeItem('rounds');
sessionStorage.removeItem('scoreSum');
return;
}
var roundsToSave = [];
for (var i = 0; i < Core.rounds.length; ++i) {
var round = Core.rounds[i];
roundsToSave.push({ realPosition: round.realPosition, guessPosition: round.guessPosition });
}
sessionStorage.setItem('rounds', JSON.stringify(roundsToSave));
sessionStorage.setItem('scoreSum', String(Core.scoreSum));
} }
}; };
@ -182,49 +407,7 @@
clickableIcons: false, clickableIcons: false,
}); });
Core.resultMarkers.real = new google.maps.Marker({ Core.initialize();
map: Core.resultMap,
clickable: true,
draggable: false
});
Core.resultMarkers.real.addListener('click', function () {
window.open('https://www.google.com/maps/search/?api=1&query=' + this.getPosition().lat() + ',' + this.getPosition().lng(), '_blank');
});
Core.resultMarkers.guess = new google.maps.Marker({
map: Core.resultMap,
clickable: false,
draggable: false,
label: {
color: '#ffffff',
fontFamily: 'Roboto',
fontSize: '18px',
fontWeight: '500',
text: '?'
}
});
Core.resultLine = new google.maps.Polyline({
map: Core.resultMap,
geodesic: true,
strokeOpacity: 0,
icons: [{
icon: {
path: 'M 0,-1 0,1',
strokeOpacity: 1,
strokeWeight: 2,
scale: 2
},
offset: '0',
repeat: '10px'
}],
clickable: false,
draggable: false,
editable: false
});
Core.getNewPosition();
document.getElementById('showGuessButton').onclick = function () { document.getElementById('showGuessButton').onclick = function () {
this.style.visibility = 'hidden'; this.style.visibility = 'hidden';
@ -241,56 +424,20 @@
return; return;
} }
var guessedPosition = Core.guessMarker.getPosition();
this.disabled = true; this.disabled = true;
Core.guessMarker.setMap(null);
Core.guessMarker = null;
var distance = Util.calculateDistance(Core.realPosition, { lat: guessedPosition.lat(), lng: guessedPosition.lng() }); Core.evaluateGuess();
document.getElementById('guess').style.visibility = 'hidden';
document.getElementById('result').style.visibility = 'visible';
var resultBounds = new google.maps.LatLngBounds();
resultBounds.extend(Core.realPosition);
resultBounds.extend(guessedPosition);
Core.resultMap.fitBounds(resultBounds);
Core.resultMarkers.real.setPosition(Core.realPosition);
Core.resultMarkers.guess.setPosition(guessedPosition);
Core.resultLine.setPath([
Core.realPosition,
guessedPosition
]);
document.getElementById('distance').innerHTML = Util.printDistanceForHuman(distance);
var score = Core.calculateScore(distance);
var scoreBarProperties = Core.calculateScoreBarProperties(score);
document.getElementById('score').innerHTML = score;
var scoreBar = document.getElementById('scoreBar');
scoreBar.style.backgroundColor = scoreBarProperties.backgroundColor;
scoreBar.style.width = scoreBarProperties.width;
} }
document.getElementById('continueButton').onclick = function () { document.getElementById('continueButton').onclick = function () {
document.getElementById('scoreBar').style.width = null; Core.prepareNewRound();
}
if (Core.adaptGuess) { document.getElementById('showSummaryButton').onclick = function () {
document.getElementById('guess').classList.remove('adapt'); Core.showSummary();
} }
document.getElementById('showGuessButton').style.visibility = null; document.getElementById('startNewGameButton').onclick = function () {
document.getElementById('guess').style.visibility = null; Core.startNewGame();
document.getElementById('result').style.visibility = null;
Core.guessMap.fitBounds(guessMapBounds);
Core.getNewPosition();
} }
})(); })();

View File

@ -20,13 +20,6 @@ class GameController implements ControllerInterface
$stmt->execute(); $stmt->execute();
$map = $stmt->get_result()->fetch_assoc(); $map = $stmt->get_result()->fetch_assoc();
// using RAND() for the time being, could be changed in the future
$stmt = $mysql->prepare('SELECT lat, lng FROM places WHERE map_id=? ORDER BY RAND() LIMIT 1');
$stmt->bind_param("i", $mapId);
$stmt->execute();
$place = $stmt->get_result()->fetch_assoc();
$realPosition = new Position($place['lat'], $place['lng']);
$bounds = Bounds::createDirectly($map['bound_south_lat'], $map['bound_west_lng'], $map['bound_north_lat'], $map['bound_east_lng']); $bounds = Bounds::createDirectly($map['bound_south_lat'], $map['bound_west_lng'], $map['bound_north_lat'], $map['bound_east_lng']);
$data = compact('bounds'); $data = compact('bounds');

View File

@ -27,17 +27,21 @@
<div id="result"> <div id="result">
<div id="resultMap"></div> <div id="resultMap"></div>
<div id="resultInfo"> <div id="resultInfo">
<div> <div id="distanceInfo">
<p>You were <span id="distance" class="bold"></span> close.</p> <p>You were <span id="distance" class="bold"></span> close.</p>
<p class="bold">Game finished.</p>
</div> </div>
<div> <div id="scoreInfo">
<p>You earned <span id="score" class="bold"></span> points.</p> <p>You earned <span id="score" class="bold"></span> points.</p>
<p>You got <span id="scoreSum" class="bold"></span> points in total.</p>
</div> </div>
<div> <div>
<div id="scoreBarBase"><div id="scoreBar"></div></div> <div id="scoreBarBase"><div id="scoreBar"></div></div>
</div> </div>
<div> <div>
<button id="continueButton">Continue</button> <button id="continueButton">Continue</button>
<button id="showSummaryButton">Show summary</button>
<button id="startNewGameButton">Start new game</button>
</div> </div>
</div> </div>
</div> </div>