public void onEndGame() { if (!GameSettings.isOwner()) { if (hasEnded) return; hasEnded = true; } // The host updates the high scores if (travelledDistance > GameSettings.getProfile().getHighscore()) { dataServer.sendRequest( ServerCommand.SET_HIGHSCORE, ImmutableMap.of( "id", GameSettings.getPlayerId(), "token", GameSettings.getPlayerToken(), "highscore", String.valueOf(Math.round(travelledDistance))), new HttpConnector.Callback() { @Override public void handleResult(String data) { showWinner(); } }); } else { showWinner(); } }
/** * Tell all of the players and the server that the game has ended * * @param winner The winner of the game */ public void notifyEndGame(String winner) { // Tell the other players that the game has ended // The players show the winner when they receive this message gameUpdateHandler.sendWinner(winner); // Tell the server that the game has ended ImmutableMap query = ImmutableMap.of( "gameId", String.valueOf(GameSettings.getGameId()), "token", GameSettings.getGameToken(), "winnerId", winner); dataServer.sendRequest( ServerCommand.END_GAME, query, new HttpConnector.Callback() { @Override public void handleResult(String data) { try { JSONObject result = new JSONObject(data); // TODO check for errors // The host shows the winner here onEndGame(); } catch (JSONException e) { e.printStackTrace(); } } }); }
/** * Is called when another player has died * * @param playerName The name of the player that died * @param killerId The id of the killer * @param killerName The name of the killer */ public void playerDied(String playerName, String killerId, String killerName) { if (killerId.equals("")) { // The player died because he went to far from the road showNotification( getString(R.string.player_died_text).replaceAll("%name", playerName), Toast.LENGTH_SHORT); } else { // The player crossed a wall // The killer gets a bonus score if (GameSettings.getPlayerId().equals(killerId)) { addScore(KILL_SCORE); showNotification( getString(R.string.player_killed_text) .replaceAll("%name", playerName) .replaceAll("%killer", "you") + " " + getString(R.string.score_received_text) .replaceAll("%score", String.valueOf(KILL_SCORE)), Toast.LENGTH_SHORT); } else { showNotification( getString(R.string.player_killed_text) .replaceAll("%name", playerName) .replaceAll("%killer", killerName), Toast.LENGTH_SHORT); } } if (GameSettings.isOwner()) { // There is one less player alive now playersAliveCount -= 1; // If there is only one player left : end the game if (!IMMORTAL && playersAliveCount <= 1) endGame(); } }
/** Is called by the host when either the time runs out or when there are no players left */ public void endGame() { if (hasEnded) return; hasEnded = true; // The host stores his own score and initializes all of the other scores to -1 playerScores = new HashMap<>(); for (Integer player : GameSettings.getPlayersInGame()) { if (player == GameSettings.getUserId()) playerScores.put(String.valueOf(player), travelledDistance); else playerScores.put(String.valueOf(player), -1.0); } // Tell the other players that the game has ended gameUpdateHandler.sendEndGame(); // Wait for the final scores of the other players before ending the game new Handler() .postDelayed( new Runnable() { @Override public void run() { winner = processFinalScores(); notifyEndGame(winner); } }, FINAL_SCORE_TIMEOUT * 1000); }
/** * Called when the start/stop wall button is pressed or when the proximity sensor detects * something */ public void createWall() { if (!isAlive) return; // Is the player currently creating a wall if (!creatingWall) { // Start creating a wall creatingWall = true; // The player is now creating a wall // Create the wall object Wall wall = new Wall( "W" + GameSettings.generateUniqueId(), GameSettings.getPlayerId(), GameSettings.getWallColor(), context); wallId = wall.getId(); // Store the wall id map.addMapItem(wall); // Add the wall to the map // Tell the other devices that a new wall has been created gameUpdateHandler.sendCreateWall( GameSettings.getPlayerId(), wallId, new ArrayList<LatLng>(), GameSettings.getWallColor()); // Show the "creating wall" notification showNotification(getString(R.string.wall_on_notification), Toast.LENGTH_SHORT); } // The wall is never turned off // else { // // Stop creating the wall // creatingWall = false; // The player is no longer creating a wall // wallId = null; // Forget about the current wall // // // Show the "stopped creating wall" notification // showNotification(getString(R.string.wall_off_notification), Toast.LENGTH_SHORT); // } }
/** * Is called when the player himself has died * * @param killerId The user id of the killer of the player * @param killerName The name of the killer */ public void onDeath(String killerId, String killerName) { // For debugging purposes if (IMMORTAL) return; // Hide all wall controls Button breakWallButton = (Button) findViewById(R.id.breakWallButton); breakWallButton.setVisibility(View.GONE); // Stop creating the wall creatingWall = false; wallId = null; // Tell the applications that the player has died showNotification(getString(R.string.you_died_text), Toast.LENGTH_SHORT); gameUpdateHandler.sendDeathMessage(killerId, killerName); if (GameSettings.isOwner()) { // There is one less player alive now playersAliveCount -= 1; // If there is only one player left : end the game if (playersAliveCount <= 1) endGame(); } isAlive = false; }
public void handleBellDetected() { // TODO: avoid calling this when the map is not yet ready if (hasEnded) return; if (isBellRinging) return; // Wait for the bell to stop ringing isBellRinging = true; gameUpdateHandler.sendBellSound(GameSettings.getPlayerId()); bellCount += 1; if (currentEvent != null && currentEvent instanceof BellEvent) { ((TextView) findViewById(R.id.eventValue)) .setText(getString(R.string.bell_event_text).replaceAll("%value", "" + bellCount)); } // After 3 seconds, disable the bell. new Handler() .postDelayed( new Runnable() { @Override public void run() { isBellRinging = false; } }, 3000); }
@Override public void onSaveInstanceState(Bundle savedInstanceState) { super.onSaveInstanceState(savedInstanceState); // Save UI state changes to the savedInstanceState. // This bundle will be passed to onCreate if the process is // killed and restarted. // Store game settings GameSettings.storeInBundle(savedInstanceState); savedInstanceState.putDouble("travelledDistance", travelledDistance); // TODO maybe add more data (at least it won't crash now) }
/** Quit game activity */ public void quitGame() { // Clear data from GameSettings GameSettings.setGameId(-1); GameSettings.setGameName(null); GameSettings.setGameToken(null); GameSettings.setCanBreakWall(false); GameSettings.setTimeLimit(-1); GameSettings.setLastPlayTime((System.currentTimeMillis() - startTime) / 1000); if (countdown != null) { countdown.removeCallbacks(countdownRunnable); countdownRunnable = null; countdown = null; } // Start Lobby activity while destroying RoomActivity and HostActivity Intent intent = new Intent(this, LobbyActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP); startActivity(intent); // Pause the socket Log.d("Socket", "quitting socket"); connection.pause(); // Close the GameActivity finish(); }
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_lobby); gameToJoin = getIntent().getIntExtra(JOIN_GAME_EXTRA, -1); if (gameToJoin != -1) { // We started from a notification => make sure basic initializations, normally // made in MainActivity are performed here: GameSettings.setProfile(Profile.Load(PreferenceManager.getDefaultSharedPreferences(this))); DrawableManager.InitializeCache(5); } dataServer = new HttpConnector(getString(R.string.dataserver_url)); ListView lobbyList = (ListView) findViewById(R.id.mainList); checkBoxView = (CheckBox) findViewById(R.id.spectatorCheckboxView); lobbyList.setClickable(true); listGames(); if (GameSettings.getLastPlayTime() != -1) { // A game has been played, push new playtime to server dataServer.sendRequest( ServerCommand.SET_PLAYTIME, ImmutableMap.of( "id", String.valueOf(GameSettings.getUserId()), "token", GameSettings.getPlayerToken(), "playtime", String.valueOf( GameSettings.getProfile().getPlaytime() + GameSettings.getLastPlayTime())), new HttpConnector.Callback() { @Override public void handleResult(String data) {} }); GameSettings.resetLastPlaytime(); } }
private void joinGame(LobbyListItem item) { if (!checkBoxView.isChecked() && item.getPlayerCount() >= item.getMaxPlayersAsInteger()) { Toast.makeText(this, getString(R.string.too_many_players), Toast.LENGTH_SHORT).show(); return; } String gameName = item.getGamename(); GameSettings.setGameName(gameName); GameSettings.setGameId(roomIds.get(gameName)); GameSettings.setOwnerId(item.getHostId()); GameSettings.setCanBreakWall(item.getCanBreakWall()); GameSettings.setTimeLimit(item.getTimeLimit()); GameSettings.setMaxDistance(item.getMaxDist()); GameSettings.setMaxPlayers(item.getMaxPlayersAsInteger()); GameSettings.setSpectate(checkBoxView.isChecked()); showToast(R.string.joinging_message, gameName); if (!GameSettings.getSpectate()) { Map<String, String> query = ImmutableMap.of( "gameId", String.valueOf(roomIds.get(gameName)), "id", String.valueOf(GameSettings.getPlayerId()), "token", GameSettings.getPlayerToken()); dataServer.sendRequest( ServerCommand.JOIN_GAME, query, new HttpConnector.Callback() { @Override public void handleResult(String data) { try { JSONObject result = new JSONObject(data); // TODO check for errors showRoomActivity(); } catch (JSONException e) { e.printStackTrace(); } } }); } else { showRoomActivity(); } }
/** * Most of the game functionality happens in this function. It is called when a location update is * snapped to the road by the snappedPointHandler * * @param result The snapped location * @return does not matter */ @Override public boolean handleApiResult(ArrayList<LatLng> result) { // Get the snapped location from the result (result is a list with one item) LatLng newSnappedGpsLoc = result.get(0); // Calculate the distance between the snapped location and the actual location // So this is basically the distance to the road double snappedDistance = LatLngConversion.getDistancePoints(gpsLoc, newSnappedGpsLoc); // Log.d("VALUE", "Snapped Distance "+String.valueOf(snappedDistance)); if (isAlive && mapCenter != null && GameSettings.getMaxDistance() > 0) { if (LatLngConversion.getAccurateDistancePoints(mapCenter, newSnappedGpsLoc) > GameSettings.getMaxDistanceInMeters()) { showNotification(getString(R.string.crossed_border), Toast.LENGTH_SHORT); onDeath("//", "Map Border"); } if (LatLngConversion.getAccurateDistancePoints(mapCenter, newSnappedGpsLoc) > GameSettings.getMaxDistanceInMeters() - WARNING_DISTANCE_TO_WALL) { showNotification(getString(R.string.close_to_border), Toast.LENGTH_SHORT); } } // Check is the player is (almost) on the road if (snappedDistance < MAX_ROAD_DISTANCE) { // Update the player marker and the camera map.updatePlayer(GameSettings.getPlayerId(), newSnappedGpsLoc); map.updateCamera(newSnappedGpsLoc); // Send the player location gameUpdateHandler.sendMyLocation(newSnappedGpsLoc); // If the player is alive the interactions with the wall can be checked // Add the travelled distance to the score // Check if the player is to close to or has crossed a wall // Update the wall if (isAlive) { // Add the travelled distance to the score // --------------------------------------- double distance = 0.0; if (!(snappedGpsLoc.longitude == 0 && snappedGpsLoc.latitude == 0)) { // This checks if there has been a previous location update distance = LatLngConversion.getDistancePoints(snappedGpsLoc, newSnappedGpsLoc); } addScore(LatLngConversion.latLngDistanceToMeter(distance)); if (!creatingWall && travelledDistance >= WALL_DELAY_DISTANCE) createWall(); // Check if the player is to close to or has crossed a wall // --------------------------------------------------------- ArrayList<Wall> walls = map.getWalls(); for (Wall wall : walls) { // Check if the player hasn't crossed a wall if (wall.hasCrossed( snappedGpsLoc, newSnappedGpsLoc, MIN_WALL_DISTANCE, IGNORE_WALL_DISTANCE, GameSettings.getPlayerId())) { // The player has crossed the wall and has therefore died showNotification(getString(R.string.wall_crossed), Toast.LENGTH_SHORT); Player killer = (Player) map.getItemById(wall.getOwnerId()); String killerName = ""; if (killer != null) killerName = killer.getName(); onDeath(wall.getOwnerId(), killerName); } else { // Check if the player isn't to close to a wall if (wall.getDistanceTo( newSnappedGpsLoc, MIN_WALL_WARNING_DISTANCE, GameSettings.getPlayerId()) < MIN_WALL_WARNING_DISTANCE) { // Show the "player to close to wall" notification showNotification(getString(R.string.wall_too_close), Toast.LENGTH_SHORT); } } } // Update the wall // --------------- Wall wall = (Wall) map.getItemById(wallId); // Update the wall (this must happen after the "player to close to wall" check if (creatingWall) { wall.addPoint(newSnappedGpsLoc); // Add the new point to the wall gameUpdateHandler.sendUpdateWall(newSnappedGpsLoc, wallId); map.redraw(wall.getId()); // Redraw the wall on the map } } snappedGpsLoc = newSnappedGpsLoc; // update the snapped location } else { // Player is to far from the road map.updatePlayer( GameSettings.getPlayerId(), gpsLoc); // Draw the player on the actual location instead map.updateCamera(gpsLoc); // Zoom to there as well // Send the player location gameUpdateHandler.sendMyLocation(gpsLoc); if (isAlive) { // Show the "player to far from road" notification showNotification(getString(R.string.road_too_far), Toast.LENGTH_SHORT); onDeath("", ""); } } return false; // This is used by the snappedPointHandler }
public void startGame(LatLng startPos) { // Tell the other players that the game has started if (GameSettings.isOwner()) gameUpdateHandler.sendStartGame(startPos); // Start sensor tracking // Listen to proximity updates sensorDataObservable.startSensorTracking( SensorFlag.PROXIMITY, new SensorDataObserver() { /** * Is called when the proximity sensor detects something * * @param observable The observable that has changed * @param data Extra data attached by observable */ @Override public void updateSensor(SensorDataObservable observable, Object data) { // Check whether it was the proximity sensor that detected something if (observable != sensorDataObservable) return; sensorDataObservable.resetSensorData( SensorFlag.PROXIMITY); // This was moved from within SensorDataObservable if (GameSettings.getCanBreakWall()) breakWall(null); // Activiate break wall button } /** * The amount of times the sensor can detect useful information before updateSensor is * called */ @Override public int getCountLimit() { return 1; } }); // Listen to accelerometer updates sensorDataObservable.startSensorTracking( SensorFlag.ACCELEROMETER, new SensorDataObserver() { @Override /** * Is called when the accelerometer sensor detects something * * @param observable The observable that has changed * @param data Extra data attached by observable */ public void updateSensor(SensorDataObservable observable, Object data) { // Check whether it was the proximity sensor that detected something if (observable != sensorDataObservable) return; if (data instanceof HorizontalAccelerationDataHolder) { HorizontalAccelerationDataHolder holder = (HorizontalAccelerationDataHolder) data; acceleration += holder.getAccelerationMagnitude(); accelerationCount += 1; } if (currentEvent != null && currentEvent instanceof ShowOffEvent) { ((TextView) findViewById(R.id.eventValue)) .setText( getString(R.string.show_off_event_text) .replaceAll("%value", "" + Math.floor(acceleration))); } } /** * The amount of times the sensor can detect useful information before updateSensor is * called */ @Override public int getCountLimit() { return -1; } }); // Listen to gyroscope sensorDataObservable.startSensorTracking( SensorFlag.GYROSCOPE, new SensorDataObserver() { @Override public void updateSensor(SensorDataObservable observable, Object data) { // Check whether it was the proximity sensor that detected something if (observable != sensorDataObservable) return; if (data instanceof GyroscopeDataHolder) { GyroscopeDataHolder holder = (GyroscopeDataHolder) data; turns = holder.getCount(); } if (currentEvent != null && currentEvent instanceof TurnEvent) { ((TextView) findViewById(R.id.eventValue)) .setText( getString(R.string.turn_event_text) .replaceAll("%value", "" + Math.floor(turns))); } } @Override public int getCountLimit() { return 1; } }); // Listen to microphone frequencyListener = new FrequencyListener( new Handler( new Handler.Callback() { @Override public boolean handleMessage(Message msg) { handleBellDetected(); return false; } }), 44100, 1650, 2450, 16384); frequencyListener.run(); // Start the FrequencyListener // Set the correct buttons to visible if (!GameSettings.getSpectate()) { if (GameSettings.getCanBreakWall()) { // TODO hide the breakWall button when there is a proximity sensor Button wallBreaker = (Button) findViewById(R.id.breakWallButton); wallBreaker.setVisibility(View.VISIBLE); } LinearLayout travelledDistanceContainer = (LinearLayout) findViewById(R.id.travelledDistanceContainer); travelledDistanceContainer.setVisibility(View.VISIBLE); TextView travelledDistance = (TextView) findViewById(R.id.travelledDistance); travelledDistance.setVisibility(View.VISIBLE); TextView travelledDistanceHead = (TextView) findViewById(R.id.travelledDistanceHead); travelledDistanceHead.setVisibility(View.VISIBLE); } // Set start time (in order to measure total playtime) startTime = System.currentTimeMillis(); if (GameSettings.isOwner()) // Set the amount of players that are alive playersAliveCount = GameSettings.getPlayersInGame().size(); // Set the initial location mapCenter = startPos; if (GameSettings.getMaxDistance() > 0) // Draw the border on the map // The distance is GameSettings.getMaxDistance() - WARNING_DISTANCE_TO_WALL so that the // player won't die right away after crossing the wall on the map. map.drawBorder(mapCenter, GameSettings.getMaxDistanceInMeters()); // Activate end game timer if (GameSettings.getTimeLimit() >= 0) { if (GameSettings.isOwner()) { // End the game in FINAL_SCORE_TIMEOUT seconds new Handler() .postDelayed( new Runnable() { @Override public void run() { endGame(); } }, 1000 * GameSettings.getTimeLimit() * 60); } // Update countdown endTime = startTime + 1000 * GameSettings.getTimeLimit() * 60; countdown = new Handler(); countdownRunnable = new Runnable() { @Override public void run() { TextView countdownText = (TextView) findViewById(R.id.countdown); if (endTime > System.currentTimeMillis()) { countdownText.setText(formatTime(endTime - System.currentTimeMillis())); countdown.postDelayed(this, 1000); } else { countdownText.setText(formatTime(0)); countdownText.setVisibility(View.GONE); } } }; countdown.postDelayed(countdownRunnable, 1000); findViewById(R.id.countdown).setVisibility(View.VISIBLE); } // Start the events if (GameSettings.isOwner() && HAS_EVENTS) gameEventHandler.start(); // Set the player to alive if (!GameSettings.getSpectate()) isAlive = true; else isAlive = false; hasEnded = false; showNotification(getString(R.string.game_started), Toast.LENGTH_SHORT); }
// region Initialization // --------------------------------------------------------------------------------------------- @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState != null) { // If the application closed accidentally the player is set to spectator mode // At this point the game is corrupt and a lot of problems will arise // If this happens to the host it is extremely problematic // TODO make the host end the game if his game is corrupt GameSettings.loadFromBundle(savedInstanceState); GameSettings.setSpectate(true); Toast.makeText(this, getString(R.string.game_activity_closed), Toast.LENGTH_SHORT).show(); } // Content of Activity // ----------------------------------------------------------------------------------------- setContentView(R.layout.activity_game); // Sensor tracking // ----------------------------------------------------------------------------------------- // Initialize sensorDataObservable and proximityObserver acceleration = 0; accelerationCount = 0; turns = 0; sensorDataObservable = new SensorDataObservable(this); isBellRinging = false; // Location tracking // ----------------------------------------------------------------------------------------- // Initialize the stored locations to 0,0 snappedGpsLoc = new LatLng(0, 0); gpsLoc = new LatLng(0, 0); if (savedInstanceState != null) travelledDistance = savedInstanceState.getDouble("travelledDistance", 0.0); else travelledDistance = 0.0; // Initialize location listener locationListener = new CustomLocationListener( this, // The activity that builds the google api this, // The LocationObserver 1500, // Normal update frequency of the location 500, // Fastest update frequency of the location LocationRequest.PRIORITY_HIGH_ACCURACY // Accuracy of the location ); // Create the context used by the google api (just stores the google key) context = new GeoApiContext().setApiKey(getString(R.string.google_maps_key_server)); // Permissions // ----------------------------------------------------------------------------------------- // Request permissions before doing anything else (after initializing the location listener!) requestPermissions(); // Map Object // ----------------------------------------------------------------------------------------- // Create the map object MapFragment mapFragment = (MapFragment) getFragmentManager().findFragmentById(R.id.map); map = new Map(mapFragment); // Player objects // ----------------------------------------------------------------------------------------- // Create the player map.addMapItem( new Player(GameSettings.getPlayerId(), GameSettings.getPlayerName(), new LatLng(0.0, 0.0))); // Networking // ----------------------------------------------------------------------------------------- // Create the gameUpdateHandler object connection = new SocketIoConnection("testA1", String.valueOf(GameSettings.getGameId())); gameUpdateHandler = new GameUpdateHandler(this, connection, map, context); gameEventHandler = new GameEventHandler(connection, this); if (savedInstanceState != null) // When the game is corrupt, you are considered dead. gameUpdateHandler.sendDeathMessage("//", "A corrupted game"); // Create the data server dataServer = new HttpConnector(getString(R.string.dataserver_url)); // Setup the game ui if (!GameSettings.isOwner()) { Button startButton = (Button) findViewById(R.id.start_game_button); startButton.setVisibility(View.GONE); } Button wallBreaker = (Button) findViewById(R.id.breakWallButton); wallBreaker.setVisibility(View.GONE); LinearLayout travelledDistanceContainer = (LinearLayout) findViewById(R.id.travelledDistanceContainer); travelledDistanceContainer.setVisibility(View.GONE); TextView travelledDistance = (TextView) findViewById(R.id.travelledDistance); travelledDistance.setVisibility(View.GONE); TextView travelledDistanceHead = (TextView) findViewById(R.id.travelledDistanceHead); travelledDistanceHead.setVisibility(View.GONE); findViewById(R.id.eventContainer).setVisibility(View.GONE); findViewById(R.id.countdown).setVisibility(View.GONE); }