From c2df9b77135b15b4a701c82c1f63112ec356cc2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bal=C3=A1zs=20Vigh?= Date: Thu, 20 May 2021 20:55:44 +0200 Subject: [PATCH] MAPG-235 timelimit restriction per round functionality implemented for challenges --- public/static/js/game.js | 88 ++++++++++++++++++--------- src/Controller/GameFlowController.php | 67 ++++++++++++-------- 2 files changed, 101 insertions(+), 54 deletions(-) diff --git a/public/static/js/game.js b/public/static/js/game.js index 4fe154d..718efe1 100644 --- a/public/static/js/game.js +++ b/public/static/js/game.js @@ -20,6 +20,7 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 }); adaptGuess: false, googleLink: null, history: [], + restrictions: null, readyToContinue: true, timeoutEnd: null, @@ -304,17 +305,7 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 }); } else { - if (this.response.restrictions) { - Game.panorama.setOptions({ - clickToGo: !this.response.restrictions.noMove, - linksControl: !this.response.restrictions.noMove, - scrollwheel: !this.response.restrictions.noZoom - }); - - if (this.response.restrictions.noPan) { - document.getElementById('panningBlockerCover').style.display = 'block'; - } - } + Game.restrictions = this.response.restrictions; Game.panoId = this.response.place.panoId; Game.pov = this.response.place.pov; @@ -327,6 +318,40 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 }); }); }, + enableRestrictions: function () { + if (!Game.restrictions) { + return; + } + + Game.panorama.setOptions({ + clickToGo: !Game.restrictions.noMove, + linksControl: !(Game.restrictions.noMove || Game.restrictions.noPan), + scrollwheel: !Game.restrictions.noZoom + }); + + if (Game.restrictions.noPan) { + document.getElementById('panningBlockerCover').style.display = 'block'; + } + + if (Game.restrictions.timeLimit) { + Game.startCountdown(Game.restrictions.timeLimit, function() { + Game.guess(); + }); + } + }, + + disableRestrictions: function () { + Game.panorama.setOptions({ + clickToGo: true, + linksControl: true, + scrollwheel: true + }); + + document.getElementById('panningBlockerCover').style.display = null; + + Game.startCountdown(0); + }, + transitToResultMap: function () { // TODO: refactor - it is necessary for mobile if (window.getComputedStyle(document.getElementById('guess')).visibility === 'hidden') { @@ -452,11 +477,8 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 }); // needs to be set visible after the show guess map hid it in mobile view document.getElementById("navigation").style.visibility = 'visible'; - Game.panorama.setOptions({ - clickToGo: true, - linksControl: true, - scrollwheel: true - }); + Game.disableRestrictions(); + document.getElementById('panningBlockerCover').style.display = null; Game.initialize(); @@ -511,6 +533,8 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 }); // update the compass const heading = Game.panorama.getPov().heading; document.getElementById("compass").style.transform = "translateY(-50%) rotate(" + heading + "deg)"; + + Game.enableRestrictions(); }, handleErrorResponse: function (error) { @@ -625,22 +649,24 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 }); }, guess: function () { - if (!Game.guessMarker) { - return; - } + + Game.disableRestrictions(); - var guessPosition = Game.guessMarker.getPosition().toJSON(); - Game.rounds[Game.rounds.length - 1].guessPosition = guessPosition; + var data = new FormData(); + + if (Game.guessMarker) { + var guessPosition = Game.guessMarker.getPosition().toJSON(); + Game.rounds[Game.rounds.length - 1].guessPosition = guessPosition; + + data.append('lat', String(guessPosition.lat)); + data.append('lng', String(guessPosition.lng)); + } document.getElementById('guessButton').disabled = true; document.getElementById('panoCover').style.visibility = 'visible'; - - var data = new FormData(); - data.append('lat', String(guessPosition.lat)); - data.append('lng', String(guessPosition.lng)); - document.getElementById('loading').style.visibility = 'visible'; var url = Game.getGameIdentifier() + '/guess.json'; + MapGuesser.httpRequest('POST', url, function () { document.getElementById('loading').style.visibility = 'hidden'; @@ -650,6 +676,7 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 }); } Game.history = this.response.history; + Game.restrictions = this.response.restrictions; Game.receiveResult(this.response.position, guessPosition, this.response.result, this.response.allResults); @@ -851,7 +878,7 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 }); }, 1); }, - startCountdown: function (timeout) { + startCountdown: function (timeout, timedOutHandler) { if (Game.countdownHandler) { clearInterval(Game.countdownHandler); } @@ -873,7 +900,12 @@ const GameType = Object.freeze({ 'SINGLE': 0, 'MULTI': 1, 'CHALLENGE': 2 }); Game.setCountdownTime(timeLeft); if (timeLeft <= 0) { - document.getElementById('panoCover').style.visibility = 'visible'; + if (typeof timedOutHandler === 'function') { + timedOutHandler(); + } else { + document.getElementById('panoCover').style.visibility = 'visible'; + } + clearInterval(Game.countdownHandler); } }, 1000); diff --git a/src/Controller/GameFlowController.php b/src/Controller/GameFlowController.php index 668e895..02b6df4 100644 --- a/src/Controller/GameFlowController.php +++ b/src/Controller/GameFlowController.php @@ -150,6 +150,7 @@ class GameFlowController $currentPlace = $this->placeRepository->getByRoundInChallenge($challenge, $currentRound); if (!isset($currentPlace) || $withHistory) { + $withRelations = [User::class, PlaceInChallenge::class, Place::class]; foreach ($this->guessRepository->getAllInChallenge($challenge, $withRelations) as $guess) { $round = $guess->getPlaceInChallenge()->getRound(); @@ -171,6 +172,22 @@ class GameFlowController ]; } } + + // setting default values for rounds without guesses (because of timeout) + for ($i = 0; $i < $currentRound; ++$i) { + if (!isset($response['history'][$i]) || !isset($response['history'][$i]['result'])) { + $response['history'][$i]['result'] = [ + 'guessPosition' => null, + 'distance' => null, + 'score' => 0 + ]; + + $response['history'][$i]['position'] = + $this->placeRepository->getByRoundInChallenge($challenge, $i)->getPosition()->toArray(); + } + } + + $response['history']['length'] = $currentRound; } if (!isset($currentPlace)) { // game finished @@ -196,7 +213,7 @@ class GameFlowController } $response['restrictions'] = [ - 'timeLimit' => $challenge->getTimeLimit(), + 'timeLimit' => $challenge->getTimeLimit() * 1000, 'noMove' => $challenge->getNoMove(), 'noPan' => $challenge->getNoPan(), 'noZoom' => $challenge->getNoZoom() @@ -339,39 +356,37 @@ class GameFlowController $currentPlace = $currentPlaceInChallenge->getPlace(); $map = $currentPlace->getMap(); - - $guessPosition = new Position((float) $this->request->post('lat'), (float) $this->request->post('lng')); - $result = $this->evaluateGuess($currentPlace->getPosition(), $guessPosition, $map->getArea()); - - // save guess - $guess = new Guess(); - $guess->setUserId($userId); - $guess->setPlaceInChallenge($currentPlaceInChallenge); - $guess->setPosition($guessPosition); - $guess->setDistance($result['distance']); - $guess->setScore($result['score']); - $this->pdm->saveToDb($guess); - - - - // update round + // creating response $nextRound = $currentRound + 1; + $response = $this->prepareChallengeResponse($userId, $challenge, $nextRound); + $response['position'] = $currentPlace->getPosition()->toArray(); + + if ($this->request->post('lat') && $this->request->post('lng')) { + $guessPosition = new Position((float) $this->request->post('lat'), (float) $this->request->post('lng')); + $result = $this->evaluateGuess($currentPlace->getPosition(), $guessPosition, $map->getArea()); + + // save guess + $guess = new Guess(); + $guess->setUserId($userId); + $guess->setPlaceInChallenge($currentPlaceInChallenge); + $guess->setPosition($guessPosition); + $guess->setDistance($result['distance']); + $guess->setScore($result['score']); + $this->pdm->saveToDb($guess); + + $response['result'] = $result; + + } else { + // user didn't manage to guess in the round in the given timeframe + $response['result'] = ['distance' => null, 'score' => 0]; + } $userInChallenge->setCurrentRound($nextRound); $this->pdm->saveToDb($userInChallenge); - - // creating response - $response = $this->prepareChallengeResponse($userId, $challenge, $nextRound); - - $response['position'] = $currentPlace->getPosition()->toArray(); - $response['result'] = $result; - if(isset($response['history'][$currentRound]['allResults'])) { $response['allResults'] = $response['history'][$currentRound]['allResults']; } - - $this->saveVisit($currentPlace->getId());