diff --git a/android/build.gradle b/android/build.gradle index 6375e115da3157f109728b453ec932e7023f3f07..869e7d86409293a669301078d767af12a4b382fa 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -21,7 +21,7 @@ android { } defaultConfig { applicationId "com.wordbattle.game" - minSdkVersion 19 + minSdkVersion 24 targetSdkVersion 34 versionCode 1 versionName "1.0" diff --git a/android/google-services.json b/android/google-services.json index 04c1c3cb9b22e32e5a8605fbcd15fd1392447597..6a41ce54485a4f28876589f5fed2b09c45403529 100644 --- a/android/google-services.json +++ b/android/google-services.json @@ -1,6 +1,7 @@ { "project_info": { "project_number": "188857427405", + "firebase_url": "https://wordbattle-96156-default-rtdb.europe-west1.firebasedatabase.app", "project_id": "wordbattle-96156", "storage_bucket": "wordbattle-96156.appspot.com" }, diff --git a/android/src/com/wordbattle/game/AndroidInterfaceClass.java b/android/src/com/wordbattle/game/AndroidInterfaceClass.java index 20e1e5eb33a0e7ed459771902e1e7168f67f6693..c548c465291268674b04a09e35fc0917f07e5f8a 100644 --- a/android/src/com/wordbattle/game/AndroidInterfaceClass.java +++ b/android/src/com/wordbattle/game/AndroidInterfaceClass.java @@ -7,23 +7,32 @@ import com.google.firebase.database.DatabaseError; import com.google.firebase.database.DatabaseReference; import com.google.firebase.database.FirebaseDatabase; import com.google.firebase.database.ValueEventListener; +import com.wordbattle.game.model.Category; import com.wordbattle.game.model.LobbyModel; +import com.wordbattle.game.model.PlayerModel; +import com.wordbattle.game.model.Word; import com.wordbattle.game.network.FirebaseInterface; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.concurrent.atomic.AtomicBoolean; + public class AndroidInterfaceClass implements FirebaseInterface { FirebaseDatabase database; DatabaseReference myRef; - String lobbyID; - - public AndroidInterfaceClass() { - database = FirebaseDatabase.getInstance("https://wordbattle-96156-default-rtdb.europe-west1.firebasedatabase.app"); - myRef = database.getReference("message"); - myRef.setValue("Something"); + database = FirebaseDatabase.getInstance("https://wordbattle-96156-default-rtdb.europe-west1.firebasedatabase.app"); + myRef = database.getReference("message"); + myRef.setValue("Something"); } + @Override public void SomeFunction() { System.out.println("Something works"); @@ -31,10 +40,23 @@ public class AndroidInterfaceClass implements FirebaseInterface { @Override public void createNewLobby(String hostNickname, String pin) { - System.out.println("Gooooooood morning Vietnam"); - LobbyModel lobby = new LobbyModel(hostNickname, pin); DatabaseReference lobbyRef = database.getReference("lobbies").child(pin); - lobbyRef.setValue(lobby) + Map<String, Object> lobbyData = new HashMap<>(); + lobbyData.put("gameStarted", false); + lobbyData.put("hostNickname", hostNickname); + lobbyData.put("pin", pin); + + // Create a map to store players' scores and finished status + Map<String, Object> players = new HashMap<>(); + // Add the host player + players.put(hostNickname, new HashMap<String, Object>() {{ + put("score", 0); + put("finished", false); + }}); + // Add the players to the lobby data + lobbyData.put("players", players); + + lobbyRef.setValue(lobbyData) .addOnSuccessListener(aVoid -> { // This will be called if the lobby is successfully created in the database. // Here you could navigate to the lobby screen, update the UI, etc. @@ -46,58 +68,537 @@ public class AndroidInterfaceClass implements FirebaseInterface { System.err.println("Error creating lobby: " + e.getMessage()); }); } + @Override - public void joinLobby(String pin, String playerNickname, Runnable onSuccess, Runnable onFail) { + public void joinLobby(String pin, String playerNickname, Runnable onSuccess, Runnable onFail) { // Reference to the specific lobby by its pin DatabaseReference lobbyRef = database.getReference("lobbies").child(pin); // Get the current state of the lobby to add a new player lobbyRef.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + Map<String, Object> lobbyData = (Map<String, Object>) dataSnapshot.getValue(); + if (lobbyData != null) { + // Get the players map from the lobby data + Map<String, Object> players = (Map<String, Object>) lobbyData.get("players"); + if (players != null) { + // Add the new player to the players map + players.put(playerNickname, new HashMap<String, Object>() {{ + put("score", 0); + put("finished", false); + }}); + // Update the players map in the lobby data + lobbyData.put("players", players); + + // Save the updated lobby back to the database + lobbyRef.setValue(lobbyData).addOnSuccessListener(aVoid -> { + // Successfully joined the lobby + System.out.println(playerNickname + " joined the lobby with PIN: " + pin); + onSuccess.run(); + }).addOnFailureListener(e -> { + // Handle failure to join the lobby + System.err.println("Failed to join lobby: " + e.getMessage()); + }); + } else { + // Players map is null, something went wrong + System.err.println("Error: Players map is null in lobby " + pin); + onFail.run(); + } + } else { + // Lobby data is null, lobby does not exist + System.err.println("Error: Lobby with PIN " + pin + " does not exist."); + onFail.run(); + } + } + + + @Override + public void onCancelled(DatabaseError databaseError) { + // Handle cancellation + System.err.println("Error joining lobby: " + databaseError.getMessage()); + onFail.run(); + } + }); + }; + + + public void createNewCategory(Category category) { + DatabaseReference categoryRef = database.getReference("categories").child(category.getName()); + categoryRef.setValue(category) + .addOnSuccessListener(aVoid -> { + System.out.println("Category " + category.getName() + " created successfully."); + }) + .addOnFailureListener(e -> { + System.err.println("Error creating category " + category.getName() + ": " + e.getMessage()); + }); + } + + @Override + public void addWordToCategory(String categoryName, Word word) { + DatabaseReference wordsRef = database.getReference("categories").child(categoryName).child("words"); + wordsRef.child(word.getWord()).setValue(word) + .addOnSuccessListener(aVoid -> { + // Handle success + System.out.println("Word " + word.getWord() + " added to category " + categoryName + " successfully."); + }) + .addOnFailureListener(e -> { + // Handle failure + System.err.println("Error adding word " + word.getWord() + " to category " + categoryName + ": " + e.getMessage()); + }); + } + + @Override + public void addScoreToDatabase(String pin, String nickname) { + DatabaseReference scoreRef = FirebaseDatabase.getInstance().getReference("lobbies") + .child(pin).child("players").child(nickname).child("score"); + System.out.println("Inside addInitialScore"); + + // Initialize score to 0 for the nickname + scoreRef.setValue(0) + .addOnSuccessListener(aVoid -> { + System.out.println("Score for " + nickname + " initialized to 0."); + }) + .addOnFailureListener(e -> { + System.err.println("Failed to add score to database for " + nickname + ": " + e.getMessage()); + }); + } + + + + @Override + public void updateScoreInDatabase(String pin, String nickname, int scoreToAdd, ScoreUpdateCallback callback) { + DatabaseReference scoreRef = FirebaseDatabase.getInstance().getReference("lobbies") + .child(pin).child("players").child(nickname).child("score"); + + // First, read the current score + scoreRef.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot dataSnapshot) { + Integer currentScore = dataSnapshot.getValue(Integer.class); + if (currentScore == null) { + currentScore = 0; // Default to 0 if not set + } + int newScore = currentScore + scoreToAdd; + + // Now, update the score with the new value + scoreRef.setValue(newScore) + .addOnSuccessListener(aVoid -> { + System.out.println("Score for " + nickname + " updated successfully. New score: " + newScore); + if (callback != null) { + callback.onSuccess(); + } + }) + .addOnFailureListener(e -> { + System.err.println("Failed to update score for " + nickname + ": " + e.getMessage()); + if (callback != null) { + callback.onFailure(); + } + }); + } + + @Override + public void onCancelled(@NonNull DatabaseError databaseError) { + System.err.println("Failed to read current score for " + nickname + ": " + databaseError.getMessage()); + if (callback != null) { + callback.onFailure(); + } + } + }); + } + + + + + @Override + public void fetchScores(String lobbyPin, ScoreFetchCallback callback) { + DatabaseReference scoresRef = FirebaseDatabase.getInstance().getReference("lobbies").child(lobbyPin).child("scores"); + + scoresRef.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot snapshot) { + Map<String, Integer> scores = new HashMap<>(); + for (DataSnapshot scoreSnapshot : snapshot.getChildren()) { + scores.put(scoreSnapshot.getKey(), scoreSnapshot.getValue(Integer.class)); + } + callback.onScoresFetched(scores); + } + + @Override + public void onCancelled(@NonNull DatabaseError error) { + callback.onError(error.getMessage()); + } + }); + } + + + @Override + public void fetchPlayers(String pin, PlayerListUpdateCallback callback) { + DatabaseReference lobbyRef = database.getReference("lobbies").child(pin); + lobbyRef.addValueEventListener(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { LobbyModel lobby = dataSnapshot.getValue(LobbyModel.class); if (lobby != null) { - // Add the player's nickname to the lobby - lobby.addPlayerNickname(playerNickname); - - // Save the updated lobby back to the database - lobbyRef.setValue(lobby).addOnSuccessListener(aVoid -> { - // Successfully joined the lobby - System.out.println(playerNickname + " joined the damn lobby with PIN: " + pin); - onSuccess.run(); - }).addOnFailureListener(e -> { - // Handle failure to join the lobby - System.err.println("Failed to join lobby: " + e.getMessage()); - }); + List<String> playerNicknames = lobby.getPlayerNicknames(); + callback.onPlayerListUpdated(playerNicknames); + } + } + + @Override + public void onCancelled(@NonNull DatabaseError databaseError) { + callback.onError(databaseError.getMessage()); + } + }); + } + + + + public void startGame(String pin) { + DatabaseReference lobbyRef = database.getReference("lobbies").child(pin); + lobbyRef.child("gameStarted").setValue(true) + .addOnSuccessListener(aVoid -> { + System.out.println("The game has started for lobby with pin: " + pin); + }) + .addOnFailureListener(e -> { + System.err.println("Failed to start game for lobby: " + pin + ", error: " + e.getMessage()); + }); + } + + @Override + public void isHost(String pin, String nickname, HostCheckCallback callback) { + DatabaseReference lobbyRef = FirebaseDatabase.getInstance().getReference("lobbies").child(pin); + + lobbyRef.child("hostNickname").addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + String hostNickname = dataSnapshot.getValue(String.class); + if (nickname.equals(hostNickname)) { + // If the nicknames match, the given nickname is the host + callback.onHostCheckResult(true); } else { - onFail.run(); + // The given nickname is not the host + callback.onHostCheckResult(false); } } @Override public void onCancelled(DatabaseError databaseError) { - // Handle error on getting lobby data + // Handle possible errors System.err.println("Database error: " + databaseError.getMessage()); + callback.onError(databaseError.getMessage()); } }); } + public void startRound(String pin) { + DatabaseReference lobbyRef = database.getReference("lobbies").child(pin); + lobbyRef.child("roundStarted").setValue(true) + .addOnSuccessListener(aVoid -> { + System.out.println("Round started for lobby with pin: " + pin); + }) + .addOnFailureListener(e -> { + System.err.println("Failed to start round for lobby: " + pin + ", error: " + e.getMessage()); + }); + } + @Override - public void fetchPlayers(String pin, PlayerListUpdateCallback callback) { - /*DatabaseReference lobbyRef = database.getReference("lobbies").child(pin); + public void resetRoundFlag(String pin) { + DatabaseReference lobbyRef = database.getReference("lobbies").child(pin); + lobbyRef.child("roundStarted").setValue(false) + .addOnSuccessListener(aVoid -> { + System.out.println("Round flag reset for lobby with pin: " + pin); + }) + .addOnFailureListener(e -> { + System.err.println("Failed to reset round flag for lobby: " + pin + ", error: " + e.getMessage()); + }); + } + + + + public void listenForGameStart(String pin, GameStartCallback callback) { + DatabaseReference lobbyRef = database.getReference("lobbies").child(pin); + lobbyRef.child("gameStarted").addValueEventListener(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + Boolean gameStarted = dataSnapshot.getValue(Boolean.class); + if (gameStarted != null && gameStarted) { + callback.onGameStarted(); + lobbyRef.child("gameStarted").removeEventListener(this); + } + } + + @Override + public void onCancelled(DatabaseError databaseError) { + // Handle the error + } + }); + } + + @Override + public long getSeed() { + return 0; + // Should return seed, will be done later + } + + public void fetchWord(String pin, String category, WordFetchCallback callback) { + DatabaseReference wordsRef = database.getReference("categories").child(category).child("words"); + wordsRef.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + ArrayList<String> words = new ArrayList<>(); + for (DataSnapshot snapshot : dataSnapshot.getChildren()) { + words.add(snapshot.getKey()); // Assuming the words are stored as keys + } + + if (!words.isEmpty()) { + long seed = generateSeedFromPin(pin); + Collections.shuffle(words, new Random(seed)); + + String selectedWord = words.get(new Random().nextInt(words.size())); + callback.onWordFetched(selectedWord); + } + } + + @Override + public void onCancelled(DatabaseError databaseError) { + callback.onError(databaseError.getMessage()); + } + }); + } + + @Override + public boolean checkIfAllPlayersAreFinished(String pin) { + DatabaseReference lobbyRef = database.getReference("lobbies").child(pin); + AtomicBoolean allPlayersFinished = new AtomicBoolean(true); // Assume all players are finished initially + + lobbyRef.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + Map<String, Object> lobbyData = (Map<String, Object>) dataSnapshot.getValue(); + if (lobbyData != null) { + Map<String, Object> players = (Map<String, Object>) lobbyData.get("players"); + if (players != null) { + // Iterate through each player + for (Map.Entry<String, Object> entry : players.entrySet()) { + Map<String, Object> playerData = (Map<String, Object>) entry.getValue(); + boolean finished = false; + if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { + finished = (boolean) playerData.getOrDefault("finished", false); + } + if (!finished) { + // If any player is not finished, set the flag to false and break the loop + allPlayersFinished.set(false); + break; + } + } + } + } + } + + @Override + public void onCancelled(DatabaseError databaseError) { + // Handle cancellation + System.err.println("Error checking if all players are finished: " + databaseError.getMessage()); + } + }); + + return allPlayersFinished.get(); + } + + @Override + public void updateFinishedFlag(String nickname, String pin) { + // Reference to the specific lobby by its pin + DatabaseReference lobbyRef = database.getReference("lobbies").child(pin); + + // Get the current state of the lobby to update the player's flag lobbyRef.addListenerForSingleValueEvent(new ValueEventListener() { @Override public void onDataChange(DataSnapshot dataSnapshot) { LobbyModel lobby = dataSnapshot.getValue(LobbyModel.class); if (lobby != null) { - callback.onPlayerListUpdated(lobby.getPlayerNicknames()); + Map<String, PlayerModel> players = lobby.getPlayers(); + PlayerModel player = players.get(nickname); + if (player != null) { + player.setFinished(true); // Set the player's flag to true + lobbyRef.setValue(lobby).addOnSuccessListener(aVoid -> { + // Successfully updated the player's flag + System.out.println("Player's finished flag updated successfully."); + }).addOnFailureListener(e -> { + // Handle failure to update the player's flag + System.err.println("Failed to update player's finished flag: " + e.getMessage()); + }); + } } } @Override public void onCancelled(@NonNull DatabaseError databaseError) { - callback.onError(databaseError.getMessage()); + // Handle database error + System.err.println("Database error: " + databaseError.getMessage()); + } + }); + } + + @Override + public void getPlayerAndScore(String pin, PlayerScoreCallback callback) { + DatabaseReference playersRef = database.getReference("lobbies").child(pin).child("players"); + Map<String, Integer> playerScores = new HashMap<>(); // Initialize the map + + playersRef.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + for (DataSnapshot playerSnapshot : dataSnapshot.getChildren()) { + String playerName = playerSnapshot.getKey(); // Get player name + // Handle the case where score might not be an integer or could be null + Integer score = null; + try { + score = playerSnapshot.child("score").getValue(Integer.class); // Get player score + } catch (Exception e) { + System.out.println("Error parsing score for player " + playerName); + } + if (score != null) { + playerScores.put(playerName, score); // Add player score to the map + } + } + + // Invoke the callback with the retrieved player scores + callback.onPlayerScoresReceived(playerScores); + } + + @Override + public void onCancelled(DatabaseError databaseError) { + // Handle database error + System.out.println("Something is not okay"); + } + }); + } + + public void updateRound(String pin, RoundUpdateCallback callback) { + DatabaseReference roundsRef = FirebaseDatabase.getInstance().getReference("lobbies") + .child(pin).child("rounds"); + + // Listen for the current round value once + roundsRef.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot snapshot) { + Integer currentRound = snapshot.getValue(Integer.class); + if (currentRound == null) { + // If it's the first round, set to 1 + roundsRef.setValue(1).addOnSuccessListener(aVoid -> { + System.out.println("Round initialized successfully to 1"); + callback.onRoundUpdateSuccess(); + }).addOnFailureListener(e -> { + System.err.println("Failed to initialize round: " + e.getMessage()); + callback.onRoundUpdateFailure(); + }); + } else { + // Increment the round and set the new value + int newRound = currentRound + 1; + roundsRef.setValue(newRound).addOnSuccessListener(aVoid -> { + System.out.println("Round updated successfully to " + newRound); + callback.onRoundUpdateSuccess(); + }).addOnFailureListener(e -> { + System.err.println("Failed to update round: " + e.getMessage()); + callback.onRoundUpdateFailure(); + }); + } + } + + @Override + public void onCancelled(@NonNull DatabaseError error) { + System.err.println("Failed to fetch current round: " + error.getMessage()); + callback.onRoundUpdateFailure(); + } + }); + } + + + @Override + public void fetchRound(String pin, RoundCallback callback) { + DatabaseReference roundRef = FirebaseDatabase.getInstance().getReference("lobbies") + .child(pin).child("rounds"); + + roundRef.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + Integer currentRound = dataSnapshot.getValue(Integer.class); + if (currentRound != null) { + callback.onRoundFetched(currentRound); + } else { + // Handle case where "rounds" node does not exist or is null + callback.onRoundFetched(0); // Assuming 0 as the default round number + } + } + + @Override + public void onCancelled(DatabaseError databaseError) { + callback.onError(); + } + }); + } + + @Override + public void resetFlags(String pin) { + DatabaseReference playersRef = FirebaseDatabase.getInstance().getReference("lobbies") + .child(pin).child("players"); + + // Fetch all players under this pin + playersRef.addListenerForSingleValueEvent(new ValueEventListener() { + @Override + public void onDataChange(@NonNull DataSnapshot dataSnapshot) { + // Iterate over all players + for (DataSnapshot playerSnapshot : dataSnapshot.getChildren()) { + // Reset the "finished" flag for each player + playerSnapshot.getRef().child("finished").setValue(false) + .addOnSuccessListener(aVoid -> System.out.println("Reset finished flag for player " + playerSnapshot.getKey())) + .addOnFailureListener(e -> System.err.println("Failed to reset finished flag for player " + playerSnapshot.getKey() + ": " + e.getMessage())); + } + } + + @Override + public void onCancelled(@NonNull DatabaseError databaseError) { + System.err.println("Failed to fetch players for resetting flags: " + databaseError.getMessage()); } - });*/ + }); } + + @Override + public void listenForRoundStarted(String pin, Runnable onRoundStarted) { + DatabaseReference roundStartedRef = database.getReference("lobbies").child(pin).child("roundStarted"); + + ValueEventListener roundStartedListener = new ValueEventListener() { + @Override + public void onDataChange(DataSnapshot dataSnapshot) { + Boolean roundStarted = dataSnapshot.getValue(Boolean.class); + if (Boolean.TRUE.equals(roundStarted)) { + // Round started, trigger the provided Runnable + onRoundStarted.run(); + + // Optionally reset the flag to false if it should only trigger once per round + roundStartedRef.setValue(false); + + // Remove this listener to avoid it triggering again + roundStartedRef.removeEventListener(this); + } + } + + @Override + public void onCancelled(DatabaseError databaseError) { + System.err.println("Listening for round start cancelled: " + databaseError.getMessage()); + } + }; + + // Add the event listener to the roundStartedRef + roundStartedRef.addValueEventListener(roundStartedListener); + } + + + + private long generateSeedFromPin(String pin) { + return Long.parseLong(pin); + } + + + } diff --git a/assets/words.txt b/assets/words.txt new file mode 100644 index 0000000000000000000000000000000000000000..57e1149f4f1aa4e31aac1400d415406123fe452a --- /dev/null +++ b/assets/words.txt @@ -0,0 +1,9 @@ +Animals:Tiger,Eagle,Dolphin,Giraffe,Lion,Catfish,Dog,Mouse,Rabbit,Parrot,Squirrel,Penguin,Zebra,Spider,Hamster,Hedgehog,Jaguar,Koala,Beaver,Donkey,Ferret,Rabbit,Sheep,Skunk,Snake +Fruits:Apple,Banana,Orange,Mango,Kiwi,Grapes,Papaya,Cherry,Lemon,Melon,Peach,Pear,Plum,Fig,Guava,Lychee,Papaya,Berry,Lime,Grape,Raisin,Dates,Prune,Olive,Tamarind +Colors:Red,Blue,Green,Yellow,Orange,Purple,Pink,Brown,Black,White,Gray,Cyan,Amber,Olive,Indigo,Maroon,Magenta,Coral,Beige,Violet,Silver,Gold,Teal,Peach,Tan +Countries:USA,China,India,Brazil,Russia,Japan,Mexico,France,Italy,Canada,Spain,UK,Germany,Turkey,Iran,Iraq,Egypt,Peru,Chile,Nigeria,Kenya,Ghana,Uganda,Morocco,Cuba,Norway +Occupations:Doctor,Teacher,Engineer,Lawyer,Nurse,Artist,Pilot,Chef,Actor,Singer,Police,Farmer,Writer,Dentist,Driver,Sailor,Baker,Barber,Tailor,Editor,Porter,Singer,Pilot,Dancer +Sports:Soccer,Tennis,Boxing,Hockey,Golf,Rugby,Cricket,Bowling,Cycling,Fencing,Swimming,Running,Climbing,Jumping,Skiing,Skating,Rowing,Racing,Diving,Surfing,Gymnast,Archery,Sprinter,Jogging +Vehicles:Car,Truck,Plane,Train,Boat,Ferry,Scooter,Moped,Bike,Drone,Sled,Kayak,Yacht,Tram,Tank,Lorry,Buggy,Coach,Jet,Taxi,Van +Weather:Sunny,Rainy,Cloudy,Windy,Stormy,Snowy,Foggy,Hail,Freeze,Tornado,Blizzard,Drizzle,Monsoon,Drought,Flood,Thunder,Shower,Rainbow,Sunset,Sunrise,Misty,Frosty,Chilly +Emotions:Happy,Sad,Angry,Nervous,Calm,Brave,Proud,Shy,Grief,Guilt,Fear,Love,Hate,Hope,Trust,Jealous,Excited,Lonely,Bored,Content,Joyful,Ecstatic,Amused,Curious \ No newline at end of file diff --git a/build.gradle b/build.gradle index 7eb13d56d1a5936acdba28eb524274cd9da67a31..11fdf1fb0994e578499014194d912f33d07c5c7a 100644 --- a/build.gradle +++ b/build.gradle @@ -7,9 +7,8 @@ buildscript { google() } dependencies { - classpath 'com.android.tools.build:gradle:8.2.2' - + classpath 'com.android.tools.build:gradle:8.2.2' classpath 'com.google.gms:google-services:4.4.1' diff --git a/core/src/com/wordbattle/game/WordBattle.java b/core/src/com/wordbattle/game/WordBattle.java index 581a9a184ab79a5e072018d7ba2c9d24814db237..49e1336919f4156d23ac35473ef5a87d8dd99f2b 100644 --- a/core/src/com/wordbattle/game/WordBattle.java +++ b/core/src/com/wordbattle/game/WordBattle.java @@ -4,10 +4,12 @@ import com.badlogic.gdx.ApplicationAdapter; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.utils.ScreenUtils; -import com.wordbattle.game.manager.SoundManager; +import com.wordbattle.game.model.CreateWords; import com.wordbattle.game.network.FirebaseInterface; import com.wordbattle.game.states.MainMenuState; import com.wordbattle.game.states.StateManager; +import com.wordbattle.game.manager.SoundManager; +import com.wordbattle.game.manager.MusicManager; import com.wordbattle.game.manager.MusicManager; @@ -27,12 +29,14 @@ public class WordBattle extends ApplicationAdapter { _FBIC.SomeFunction(); batch = new SpriteBatch(); stateManager = new StateManager(); + // Make changes in assets/words.txt, and uncomment the two lines beneath to update database + // CreateWords createWords = new CreateWords(_FBIC); + // createWords.updateDB(); ScreenUtils.clear(1, 0, 0, 1); stateManager.setState(new MainMenuState(stateManager, _FBIC)); // Set the main menu as the initial state MusicManager.initialize(); MusicManager.playMusic(); SoundManager.initialize(); - } @Override public void render() { diff --git a/core/src/com/wordbattle/game/controller/CreateGameController.java b/core/src/com/wordbattle/game/controller/CreateGameController.java index aa89e8c8867186f47606f1e598d9886832497733..1491b8b022b2e3c78d83241dba29671f89adb3e6 100644 --- a/core/src/com/wordbattle/game/controller/CreateGameController.java +++ b/core/src/com/wordbattle/game/controller/CreateGameController.java @@ -11,6 +11,11 @@ import com.wordbattle.game.states.CreateGameState; import com.wordbattle.game.states.MainMenuState; import com.wordbattle.game.states.SettingsState; import com.wordbattle.game.view.CreateGameView; +import com.wordbattle.game.manager.SoundManager; +import com.wordbattle.game.states.MainMenuState; +import com.wordbattle.game.states.SettingsState; +import com.badlogic.gdx.math.Rectangle; + public class CreateGameController { private CreateGameState state; @@ -45,8 +50,21 @@ public class CreateGameController { } if (createGameView.getCreateGameBounds().contains(touchPos.x, touchPos.y)) { - state.getStateManager().setState(new LobbyState(state.getStateManager(), createGameView.getPin(), createGameView.getNickname(), _FBIC)); + if (confirmNickname()) { + state.getStateManager().setState(new LobbyState(state.getStateManager(), createGameView.getPin(), createGameView.getNickname(), _FBIC)); + } + else{ + createGameView.setNickNameMessage("Wrong pin"); + } + } + if (settingsBounds.contains(touchPos.x, touchPos.y)) { + System.out.println("Settings Pressed"); + state.getStateManager().setState(new SettingsState(state.getStateManager(), _FBIC)); + } + + if (createGameView.getGoBackButtonBounds().contains(touchPos.x, touchPos.y)) { + state.getStateManager().setState(new MainMenuState(state.getStateManager(), _FBIC )); } if (settingsBounds.contains(touchPos.x, touchPos.y)) { System.out.println("Settings Pressed"); @@ -59,6 +77,12 @@ public class CreateGameController { } } + public boolean confirmNickname(){ + String Nickname = createGameView.getNickname(); + //does not allow empty string or only whitespace + return !Nickname.trim().isEmpty(); + } + public void update(float dt) { handleInput(); @@ -69,6 +93,8 @@ public class CreateGameController { createGameView.render(sb); } + + public void dispose() { createGameView.dispose(); } diff --git a/core/src/com/wordbattle/game/controller/FinalLeaderBoardController.java b/core/src/com/wordbattle/game/controller/FinalLeaderBoardController.java index 2cf7d84a1345648fb51b6f4e870f8b314a564a7f..2b602023ca82316a497c1bf698cc22d6f1362515 100644 --- a/core/src/com/wordbattle/game/controller/FinalLeaderBoardController.java +++ b/core/src/com/wordbattle/game/controller/FinalLeaderBoardController.java @@ -4,8 +4,10 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.math.Vector3; import com.wordbattle.game.WordBattle; +import com.wordbattle.game.network.FirebaseInterface; import com.wordbattle.game.states.CreateGameState; import com.wordbattle.game.states.FinalLeaderboardState; +import com.wordbattle.game.states.MainMenuState; import com.wordbattle.game.view.FinalLeaderBoardView; public class FinalLeaderBoardController { @@ -15,14 +17,22 @@ public class FinalLeaderBoardController { private FinalLeaderBoardView finalLeaderBoardView; private int lenLeaderBordPage; + private String pin; + private FirebaseInterface _FBIC; + private String nickname; - public FinalLeaderBoardController(FinalLeaderboardState state) { + + public FinalLeaderBoardController(FinalLeaderboardState state, FirebaseInterface _FBIC, String pin, String nickname) { this.state=state; + this._FBIC = _FBIC; + this.pin = pin; + this.nickname = nickname; finalLeaderBoardView = new FinalLeaderBoardView(state.getCam()); lenLeaderBordPage=2400; //testing variable until firebase is implemented finalLeaderBoardView.setNumBackgroundRenders(calculateBackgroundRenders()); //Tells view how many backgroundTextures to load + getPlayerAndScore(); @@ -42,9 +52,7 @@ public class FinalLeaderBoardController { Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0); state.getCam().unproject(touchPos); // convert from screen coordinates to world coordinates if (finalLeaderBoardView.getBackToStartBounds().contains(touchPos.x, touchPos.y)){ -/* - state.getStateManager().setState(new CreateGameState(state.getStateManager())); //midlertidlig -*/ + state.getStateManager().setState(new MainMenuState(state.getStateManager(), _FBIC)); //midlertidlig } @@ -57,13 +65,18 @@ public class FinalLeaderBoardController { finalLeaderBoardView.getCam().translate(0,-scrollDistance); } - - } + } - - - + public void getPlayerAndScore() { + _FBIC.getPlayerAndScore(pin, playerScores -> { + Gdx.app.postRunnable(() -> { + if (finalLeaderBoardView != null) { + finalLeaderBoardView.setMap(playerScores); + System.out.println(playerScores); + } + }); + }); } public void render(SpriteBatch sb){ diff --git a/core/src/com/wordbattle/game/controller/GamePlayController.java b/core/src/com/wordbattle/game/controller/GamePlayController.java new file mode 100644 index 0000000000000000000000000000000000000000..68ebdf599f25e99a5adb5efaba3b6cf97fe1a22d --- /dev/null +++ b/core/src/com/wordbattle/game/controller/GamePlayController.java @@ -0,0 +1,242 @@ +package com.wordbattle.game.controller; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.math.Vector3; +import com.wordbattle.game.network.FirebaseInterface; +import com.wordbattle.game.states.GamePlayState; +import com.wordbattle.game.states.SettingsState; +import com.wordbattle.game.states.WaitingLobbyState; +import com.wordbattle.game.view.CreateGameView; +import com.wordbattle.game.view.GamePlayView; + +import java.util.Arrays; +import java.util.Stack; + +public class GamePlayController { + + private final GamePlayState state; + private final GamePlayView gamePlayView; + private FirebaseInterface _FBIC; + private String pin; + private String word; + private Character selectedLetter = null; + private int selectedIndex = -1; + private String nickname; + private int round; + + + + + + + + + public GamePlayController(GamePlayState state, FirebaseInterface _FBIC, String pin, String nickname) { + this.state = state; + this._FBIC = _FBIC; + this.pin = pin; + this.nickname = nickname; + this.gamePlayView = new GamePlayView(state.getCam(), _FBIC, pin); // Assuming you provide a getter for the camera in BaseState + + resetRoundFLag(); + + // Fetch the word using the PIN and the category + fetchWord(); + + } + + + public void handleInput() { + if (Gdx.input.justTouched()) { + Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0); + state.getCam().unproject(touchPos); // Adjusts the touch position to the game's coordinate system. + System.out.println("Clicked on the screen"); + Rectangle settingsBounds = gamePlayView.getSettingsBounds(); + if (settingsBounds.contains(touchPos.x, touchPos.y)) { + System.out.println("Settings Pressed"); + state.getStateManager().setState(new SettingsState(state.getStateManager(), _FBIC)); + } + for (int i = 0; i < gamePlayView.getLetterBounds().length; i++) { + if (gamePlayView.getLetterBounds()[i].contains(touchPos.x, touchPos.y)) { + // The i-th letter was clicked + // Handle the click, like selecting or deselecting a letter + selectedLetter = gamePlayView.getLetters().get(i); + System.out.println("Clicked on letter " + gamePlayView.getLetters().get(i)); + selectedIndex = i; + + // Try placing the selected letter in the next available box + boolean letterPlaced = false; + for (int j = 0; j < gamePlayView.getFilledBoxes().length; j++) { + if (gamePlayView.getFilledBoxes()[j] == null) { // Check if the box is empty + // Get the current filledBoxes + System.out.println("Before setting letter: " + Arrays.toString(gamePlayView.getFilledBoxes())); + + Character[] currentFilledBoxes = gamePlayView.getFilledBoxes(); + System.out.println(currentFilledBoxes.length); + + // Place the selected letter in the j-th box + currentFilledBoxes[j] = selectedLetter; + + // Update the filledBoxes in the view + gamePlayView.setFilledBoxes(currentFilledBoxes); + gamePlayView.getLetters().remove(i); + checkWordCompletion(); + + + // Log the action + System.out.println("Letter " + selectedLetter + " placed in box " + j); + System.out.println("After setting letter: " + Arrays.toString(gamePlayView.getFilledBoxes())); + + + letterPlaced = true; + break; // Exit the loop since we've placed the letter + } + } + + if (!letterPlaced) { + // All boxes are filled, handle accordingly. + System.out.println("All boxes are filled."); + } + + break; // Break from the loop checking letter bounds + } + } + for (int i = 0; i < gamePlayView.getLetterBoxBounds().length; i++) { + if (gamePlayView.getLetterBoxBounds()[i].contains(touchPos.x, touchPos.y)) { + Character letterToRemove = gamePlayView.getFilledBoxes()[i]; + gamePlayView.getFilledBoxes()[i] = null; // Clear the letter from the box + gamePlayView.getLetters().add(selectedIndex, letterToRemove); + System.out.println("Removed letter " + letterToRemove + " from box " + i); + break; // Exit the loop since we've handled the box click + + + + } + } + + + + + } + + } + + + private void resetRoundFLag() { + _FBIC.resetRoundFlag(pin); + } + + + + public void fetchWord() { + _FBIC.fetchRound(pin, new FirebaseInterface.RoundCallback() { + @Override + public void onRoundFetched(int fetchedRound) { + Gdx.app.postRunnable(new Runnable() { + @Override + public void run() { + round = fetchedRound; + // Now that we have the round, you can perform checks or update the state + } + }); + } + + @Override + public void onError() { + System.err.println("Error fetching round"); + // Handle error, perhaps retry or provide user feedback + } + }); + _FBIC.fetchWord(pin + round, "Animals", new FirebaseInterface.WordFetchCallback() { + @Override + public void onWordFetched(String word) { + gamePlayView.setCurrentWord(word.toUpperCase()); + System.out.println("Set word to " + word); + } + + @Override + public void onError(String error) { + // Handle the error here + System.err.println("Error fetching word: " + error); + } + }); + } + + + private void checkWordCompletion() { + Character[] filledBoxes = gamePlayView.getFilledBoxes(); + StringBuilder userWord = new StringBuilder(filledBoxes.length); + boolean isComplete = true; + + // Build the word from filled boxes and check if any box is still empty + for (Character letter : filledBoxes) { + if (letter == null) { + isComplete = false; // Found an empty box, so the word isn't complete + break; + } + userWord.append(letter); + } + + if (isComplete) { + if (userWord.toString().equals(gamePlayView.getCurrentWord())) { + gamePlayView.stopTimer(); + + System.out.println("Congratulations! The word is correct: " + userWord); + _FBIC.updateFinishedFlag(nickname, pin); + System.out.println("Score: " + calculateScore(gamePlayView.getTimeLeft(), gamePlayView.getMaxTime())); + state.getStateManager().setState(new WaitingLobbyState(state.getStateManager(), _FBIC, nickname, calculateScore(gamePlayView.getTimeLeft(), gamePlayView.getMaxTime()), pin)); + // Here you can handle the event when the user correctly completes the word + // For example, proceed to the next word, update score, etc. + + } else { + System.out.println("The word is incorrect: " + userWord + ". Try again!"); + // Here you can handle the event when the user fills all boxes but the word is incorrect + // For example, clear the boxes for another attempt, show an error message, etc. + } + } + } + + public void update(float dt) { + gamePlayView.update(dt); + handleInput(); + //Check if gameTimer is up. If so allert database, award player 0 points and go to waitingLobby. + if (!gamePlayView.isTimerRunning()){ + _FBIC.updateFinishedFlag(nickname, pin); + state.getStateManager().setState(new WaitingLobbyState(state.getStateManager(), _FBIC, nickname, 0, pin)); + } + + } + + + public int calculateScore(float timeLeft, float maxTime) { + // Parameters to shape the S-curve + float steepness = 10.0f; // Change this to make the curve steeper or shallower + float midpoint = maxTime / 2.0f; // Midpoint of the time where the curve will be centered + + // Convert timeLeft into a score between 0 and 1 using the sigmoid function + double scoreFraction = 1 / (1 + Math.exp(-steepness * ((timeLeft / maxTime) - midpoint / maxTime))); + + // Convert the fraction into an actual score value, let's say the maximum score is 1000 + int maxScore = 1000; + int score = (int)(scoreFraction * maxScore); + + return score; + } + + public void render(SpriteBatch sb) {gamePlayView.render(sb);} + + public void dispose() {gamePlayView.dispose();} + + public void enter() { + // Any initialization when entering this state + } + + public void exit() { + // Clean up when exiting this state + dispose(); + } +} + + diff --git a/core/src/com/wordbattle/game/controller/JoinGameController.java b/core/src/com/wordbattle/game/controller/JoinGameController.java index d3411cf4a265bab4a9e6c486da25bae6742e20c4..e252cd94d39339c25213259ad449e1bbdd2d817a 100644 --- a/core/src/com/wordbattle/game/controller/JoinGameController.java +++ b/core/src/com/wordbattle/game/controller/JoinGameController.java @@ -14,6 +14,7 @@ import com.wordbattle.game.states.WaitForHostState; import com.wordbattle.game.states.WaitingLobbyState; import com.wordbattle.game.view.JoinGameView; import com.wordbattle.game.view.MainMenuView; +import com.wordbattle.game.states.SettingsState; public class JoinGameController { @@ -24,6 +25,7 @@ public class JoinGameController { private String errorMsg; + public JoinGameController(JoinGameState state, FirebaseInterface _FBIC, String errorMsg) { this.state = state; this._FBIC = _FBIC; @@ -53,11 +55,9 @@ public class JoinGameController { // Stay on JoinGameState and display an error message if joining lobby failed Gdx.app.postRunnable(() -> joinGameView.setErrorMessage("Lobby does not exist")); }); - state.getStateManager().setState(new WaitForHostState(state.getStateManager(), _FBIC, pin, nickname)); - } else { // Stay on JoinGameState and display an error message if inputs are not valid - joinGameView.setErrorMessage("DB error"); + //joinGameView.setErrorMessage("DB error"); } } if (settingsBounds.contains(touchPos.x, touchPos.y)) { @@ -68,6 +68,7 @@ public class JoinGameController { state.getStateManager().setState(new MainMenuState(state.getStateManager(), _FBIC )); } } + }; diff --git a/core/src/com/wordbattle/game/controller/LeaderBoardController.java b/core/src/com/wordbattle/game/controller/LeaderBoardController.java index 3ebf4a85daff2fbb82c36da59765c6ebff9808ab..110da376f8db5d6a006fdce378292472600418a5 100644 --- a/core/src/com/wordbattle/game/controller/LeaderBoardController.java +++ b/core/src/com/wordbattle/game/controller/LeaderBoardController.java @@ -5,10 +5,14 @@ import com.badlogic.gdx.InputAdapter; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.math.Vector3; import com.wordbattle.game.WordBattle; +import com.wordbattle.game.network.FirebaseInterface; import com.wordbattle.game.states.CreateGameState; +import com.wordbattle.game.states.GamePlayState; import com.wordbattle.game.states.LeaderBoardState; import com.wordbattle.game.view.LeaderBoardView; +import java.util.Map; + public class LeaderBoardController { private LeaderBoardState state; @@ -16,36 +20,85 @@ public class LeaderBoardController { private LeaderBoardView leaderBoardView; private int lenLeaderBordPage; + private FirebaseInterface _FBIC; + private String pin; + private String nickname; + + public LeaderBoardController(LeaderBoardState state, FirebaseInterface _FBIC, String pin, String nickname ) { + this.state = state; + this._FBIC = _FBIC; + this.pin = pin; + this.nickname = nickname; - public LeaderBoardController(LeaderBoardState state) { - this.state=state; + resetFinishedFlagForAllPlayers(); leaderBoardView = new LeaderBoardView(state.getCam()); lenLeaderBordPage=2400; //testing variable until firebase is implemented leaderBoardView.setNumBackgroundRenders(calculateBackgroundRenders()); //Tells view how many backgroundTextures to load + getPlayerAndScore(); + listenForRoundStarted(); + checkHost(); + + } + + private void listenForRoundStarted() { + // Assuming _FBIC is your FirebaseInterface instance and pin is your game's pin + _FBIC.listenForRoundStarted(pin, () -> { + // This code will be executed when the round starts flag is set to true + Gdx.app.postRunnable(this::startNewRound); + }); + } + private void checkHost() { + _FBIC.isHost(pin, nickname, new FirebaseInterface.HostCheckCallback() { + @Override + public void onHostCheckResult(boolean isHost) { + if (isHost) { + leaderBoardView.setHost(true); + } else { + leaderBoardView.setHost(false); + } + } + @Override + public void onError(String error) { + // Handle error + } + }); } - int mouseYCoordinate; - public void handleInput(){ + private void startNewRound() { + System.out.println("A new round has started. Preparing game for the next round..."); + state.getStateManager().setState(new GamePlayState(state.getStateManager(), _FBIC, pin, nickname)); + // This is not working + } + private void resetFinishedFlagForAllPlayers() { + _FBIC.resetFlags(pin); + + } + + + int mouseYCoordinate; + + public void handleInput(){ if (Gdx.input.justTouched()){ mouseYCoordinate =Gdx.input.getY(); Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0); state.getCam().unproject(touchPos); // convert from screen coordinates to world coordinates - if (leaderBoardView.getNextRoundBounds().contains(touchPos.x, touchPos.y)){ -/* - state.getStateManager().setState(new CreateGameState(state.getStateManager())); //midlertidlig -*/ + if(leaderBoardView.isHost()) { + if (leaderBoardView.getNextRoundBounds().contains(touchPos.x, touchPos.y)) { + _FBIC.startRound(pin); // Stasrt the round + state.getStateManager().setState(new GamePlayState(state.getStateManager(), _FBIC, pin, nickname)); + } } @@ -58,15 +111,26 @@ public class LeaderBoardController { leaderBoardView.getCam().translate(0,-scrollDistance); } - - } + } + // Inside your controller class + + public void getPlayerAndScore() { + _FBIC.getPlayerAndScore(pin, playerScores -> { + Gdx.app.postRunnable(() -> { + if (leaderBoardView != null) { + leaderBoardView.setMap(playerScores); + System.out.println(playerScores); + } + }); + }); } + public void render(SpriteBatch sb){ leaderBoardView.render(sb); diff --git a/core/src/com/wordbattle/game/controller/LobbyController.java b/core/src/com/wordbattle/game/controller/LobbyController.java index 068d9f85c5823cce07959c35ae840ac19967a589..aae7891edee244af49f2725d4902712421ca8c1d 100644 --- a/core/src/com/wordbattle/game/controller/LobbyController.java +++ b/core/src/com/wordbattle/game/controller/LobbyController.java @@ -2,17 +2,22 @@ package com.wordbattle.game.controller; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector3; import com.wordbattle.game.model.LobbyModel; import com.wordbattle.game.network.FirebaseInterface; +import com.wordbattle.game.states.GamePlayState; import com.wordbattle.game.states.LobbyState; import com.wordbattle.game.view.LobbyView; +import java.util.List; + public class LobbyController { private LobbyState state; private LobbyView lobbyView; private String pin; private FirebaseInterface _FBIC; + private String hostNickname; @@ -20,16 +25,51 @@ public class LobbyController { this.state = state; this.pin = pin; this._FBIC = _FBIC; + this.hostNickname = hostNickname; this.lobbyView = new LobbyView(state.getCam(), pin); - _FBIC.createNewLobby(hostNickname, pin); + fetchPlayers(); } + private void fetchPlayers() { + _FBIC.fetchPlayers(pin, new FirebaseInterface.PlayerListUpdateCallback() { + @Override + public void onPlayerListUpdated(List<String> playerNames) { + System.out.println("Fetched players: " + playerNames); + lobbyView.setPlayerNames(playerNames); + } + @Override + public void onError(String error) { + System.err.println("Failed to fetch players: " + error); + } + }); + } + + public void setInitialScore() { + _FBIC.addScoreToDatabase(pin, hostNickname); + } + public void handleInput() { + Rectangle startGame = lobbyView.getStartGameButtonBounds(); + + if (Gdx.input.justTouched()) { + Vector3 touchPos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0); + state.getCam().unproject(touchPos); // convert from screen coordinates to world coordinates + + System.out.println(touchPos); + System.out.println(startGame.x); + System.out.println(startGame.y); + + if (startGame.contains(touchPos.x, touchPos.y)) { + _FBIC.startGame(pin); + setInitialScore(); + state.getStateManager().setState(new GamePlayState(state.getStateManager(), _FBIC, pin, hostNickname)); + } + } } diff --git a/core/src/com/wordbattle/game/controller/MainMenuController.java b/core/src/com/wordbattle/game/controller/MainMenuController.java index 82093b8afe7a956db0ad7a9281f0a0556557bc35..d23d16c37570f8c509d7f94a829e9dddf8ab4c2b 100644 --- a/core/src/com/wordbattle/game/controller/MainMenuController.java +++ b/core/src/com/wordbattle/game/controller/MainMenuController.java @@ -1,34 +1,28 @@ package com.wordbattle.game.controller; import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.math.Vector3; -import com.badlogic.gdx.utils.Null; -import com.wordbattle.game.manager.SoundManager; +import com.wordbattle.game.model.CreateWords; import com.wordbattle.game.network.FirebaseInterface; -import com.wordbattle.game.network.FirebaseManager; import com.wordbattle.game.states.CreateGameState; -import com.wordbattle.game.states.JoinGameState; import com.wordbattle.game.states.HowToPlayState; +import com.wordbattle.game.states.JoinGameState; import com.wordbattle.game.states.MainMenuState; -import com.wordbattle.game.states.SettingsState; -import com.wordbattle.game.states.StartState; -import com.wordbattle.game.states.StartingGameState; -import com.wordbattle.game.states.StateManager; import com.wordbattle.game.states.WaitForHostState; import com.wordbattle.game.view.MainMenuView; +import com.wordbattle.game.states.SettingsState; import com.badlogic.gdx.audio.Sound; +import com.wordbattle.game.manager.SoundManager; -import java.util.logging.Logger; - public class MainMenuController { private Sound clickSound; private MainMenuState state; private MainMenuView mainMenuView; FirebaseInterface _FBIC; + private Sound clickSound; public MainMenuController(MainMenuState state, FirebaseInterface _FBIC) { @@ -64,8 +58,6 @@ public class MainMenuController { if (joinGameButtonBounds.contains(touchPos.x, touchPos.y)) { System.out.println("Join Game Button Pressed, takning you to WaitForHost"); state.getStateManager().setState(new JoinGameState(state.getStateManager(), _FBIC, "")); - - } if (newGameButtonBounds.contains(touchPos.x, touchPos.y)) { System.out.println("New Game Button Pressed"); diff --git a/core/src/com/wordbattle/game/controller/SettingsController.java b/core/src/com/wordbattle/game/controller/SettingsController.java index 30678cf558e4cfb0925caeadefadbef03778be44..afddd274d25d88148b85eaa86693ebe5e5ba96e2 100644 --- a/core/src/com/wordbattle/game/controller/SettingsController.java +++ b/core/src/com/wordbattle/game/controller/SettingsController.java @@ -76,4 +76,4 @@ public class SettingsController { public void exit() { dispose(); } -} +} \ No newline at end of file diff --git a/core/src/com/wordbattle/game/controller/WaitForHostController.java b/core/src/com/wordbattle/game/controller/WaitForHostController.java index 9ce115c75eb4a073a27d6b3c5d4627949e49fa25..95d890cb31b684ebce27acd499709e314c62c1f2 100644 --- a/core/src/com/wordbattle/game/controller/WaitForHostController.java +++ b/core/src/com/wordbattle/game/controller/WaitForHostController.java @@ -7,6 +7,7 @@ import com.sun.org.apache.xerces.internal.util.SynchronizedSymbolTable; import com.wordbattle.game.WordBattle; import com.wordbattle.game.network.FirebaseInterface; import com.wordbattle.game.states.CreateGameState; +import com.wordbattle.game.states.GamePlayState; import com.wordbattle.game.states.JoinGameState; import com.wordbattle.game.states.WaitForHostState; import com.wordbattle.game.view.JoinGameView; @@ -34,8 +35,11 @@ public class WaitForHostController { this.nickname = nickname; this.pin = pin; this._FBIC = _FBIC; - fetchPlayers(); this.waitForHostView = new WaitForHostView(state.getCam(), _FBIC, nickname, pin); + fetchPlayers(); + listenForStart(); + _FBIC.addScoreToDatabase(pin, nickname); + } @@ -53,7 +57,17 @@ public class WaitForHostController { }); } - int mouseYCoordinate; + private void listenForStart() { + // Inside your listener method + _FBIC.listenForGameStart(pin, () -> { + Gdx.app.postRunnable(() -> { + System.out.println("Gameflag start triggered"); + state.getStateManager().setState(new GamePlayState(state.getStateManager(), _FBIC, pin, nickname)); + }); + }); + + } + private void handleInput(){ diff --git a/core/src/com/wordbattle/game/controller/WaitingLobbyController.java b/core/src/com/wordbattle/game/controller/WaitingLobbyController.java index 9672d01dcc573c96567da274886d94b9e7304334..96d282d6e2bb8d9d5196f4728c218d37b83fea21 100644 --- a/core/src/com/wordbattle/game/controller/WaitingLobbyController.java +++ b/core/src/com/wordbattle/game/controller/WaitingLobbyController.java @@ -3,34 +3,123 @@ package com.wordbattle.game.controller; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.wordbattle.game.network.FirebaseInterface; +import com.wordbattle.game.states.FinalLeaderboardState; import com.wordbattle.game.states.JoinGameState; +import com.wordbattle.game.states.LeaderBoardState; import com.wordbattle.game.states.MainMenuState; import com.wordbattle.game.states.WaitingLobbyState; import com.wordbattle.game.view.WaitingLobbyView; public class WaitingLobbyController { - WaitingLobbyState state; + private WaitingLobbyState state; + private WaitingLobbyView waitingLobbyView; + private String nickname; + private int score; + private FirebaseInterface _FBIC; + private String pin; + private float timer; + private boolean allPlayersFinished; + private boolean scoreUpdated = false; // Add this field + private boolean roundUpdated = false; + private int round; - WaitingLobbyView waitingLobbyView; - public WaitingLobbyController(WaitingLobbyState state) { + public WaitingLobbyController(WaitingLobbyState state, FirebaseInterface _FBIC, String nickname, int score, String pin) { this.state = state; + this._FBIC = _FBIC; + this.nickname = nickname; + this.score = score; + this.pin = pin; + updateScore(); + + updateRound(() -> { + roundUpdated = true; + }); + fetchRound(); + + waitingLobbyView= new WaitingLobbyView(state.getCam()); + + + + + } + + + + public void updateRound(Runnable onRoundUpdated) { + _FBIC.updateRound(pin, new FirebaseInterface.RoundUpdateCallback() { + @Override + public void onRoundUpdateSuccess() { + Gdx.app.postRunnable(onRoundUpdated); + } + + @Override + public void onRoundUpdateFailure() { + System.out.println("Failed to update round"); + } + }); } public void handleInput(){ - if (Gdx.input.justTouched()) { -/* - state.getStateManager().setState(new MainMenuState(state.getStateManager(), FirebaseInterface _FBIC)); -*/ - } + } + public void fetchRound() { + _FBIC.fetchRound(pin, new FirebaseInterface.RoundCallback() { + @Override + public void onRoundFetched(int fetchedRound) { + Gdx.app.postRunnable(() -> { + round = fetchedRound; + // Now that we have the round, you can perform checks or update the state + }); + } + + @Override + public void onError() { + System.err.println("Error fetching round"); + // Handle error, perhaps retry or provide user feedback + } + }); + } + + + public void updateScore() { + _FBIC.updateScoreInDatabase(pin, nickname, score, new FirebaseInterface.ScoreUpdateCallback() { + @Override + public void onSuccess() { + System.out.println("Score updated successfully."); + Gdx.app.postRunnable(() -> { + scoreUpdated = true; // This variable should be a class-level field + }); + } + @Override + public void onFailure() { + System.out.println("Score update failed."); + } + }); } - public void update(float dt){ - handleInput(); + + + public void update(float dt) { + timer += dt; + if (scoreUpdated) { + boolean allPlayersFinished = _FBIC.checkIfAllPlayersAreFinished(pin); + if (timer >= 10 && round < 3 && allPlayersFinished) { // This means 4 rounds, starting from 0 + Gdx.app.postRunnable(() -> { + state.getStateManager().setState(new LeaderBoardState(state.getStateManager(), _FBIC, pin, nickname)); + }); + } else if (timer >= 10 && round == 3) { + Gdx.app.postRunnable(() -> { + state.getStateManager().setState(new FinalLeaderboardState(state.getStateManager(), _FBIC, pin, nickname)); + }); + } + } + + handleInput(); + } public void render(SpriteBatch spriteBatch){ diff --git a/core/src/com/wordbattle/game/manager/MusicManager.java b/core/src/com/wordbattle/game/manager/MusicManager.java index 43c767ee29af6b74da06800f3c0de86d7506b3e6..dd7177219672d6bbb89cc394fedc2e14b74859ed 100644 --- a/core/src/com/wordbattle/game/manager/MusicManager.java +++ b/core/src/com/wordbattle/game/manager/MusicManager.java @@ -43,4 +43,4 @@ public class MusicManager { public static boolean isMusicOn() { return isMusicOn; } -} +} \ No newline at end of file diff --git a/core/src/com/wordbattle/game/manager/SoundManager.java b/core/src/com/wordbattle/game/manager/SoundManager.java index 11d1acb26cb590573adce08a132cb541f90639e3..48fee3d5588a5d4b6994969e1eb13cf6d5892d41 100644 --- a/core/src/com/wordbattle/game/manager/SoundManager.java +++ b/core/src/com/wordbattle/game/manager/SoundManager.java @@ -28,4 +28,4 @@ public class SoundManager { public static void dispose() { clickSound.dispose(); } -} +} \ No newline at end of file diff --git a/core/src/com/wordbattle/game/model/Category.java b/core/src/com/wordbattle/game/model/Category.java new file mode 100644 index 0000000000000000000000000000000000000000..659b063ad96567797c57101e928a3865694b5c83 --- /dev/null +++ b/core/src/com/wordbattle/game/model/Category.java @@ -0,0 +1,26 @@ +package com.wordbattle.game.model; + +import java.util.ArrayList; +import java.util.List; + +public class Category { + private String name; + private List<Word> words; + + public Category(String name) { + this.name = name; + this.words = new ArrayList<>(); + } + + public String getName() { + return name; + } + + public List<Word> getWords() { + return words; + } + + public void addWord(Word word) { + words.add(word); + } +} diff --git a/core/src/com/wordbattle/game/model/CreateWords.java b/core/src/com/wordbattle/game/model/CreateWords.java new file mode 100644 index 0000000000000000000000000000000000000000..2a668f9b27bc4903f5f9a4a40a4d3cc57284d622 --- /dev/null +++ b/core/src/com/wordbattle/game/model/CreateWords.java @@ -0,0 +1,44 @@ +package com.wordbattle.game.model; +import com.badlogic.gdx.Gdx; +import com.wordbattle.game.model.Category; +import com.wordbattle.game.model.Word; +import com.wordbattle.game.network.FirebaseInterface; + +import java.util.HashMap; +import java.util.Map; + +public class CreateWords { + Map<String, Category> categories; + FirebaseInterface _FBIC; + + public CreateWords(FirebaseInterface _FBIC) { + this.categories = new HashMap<>(); + this._FBIC = _FBIC; + } + + public void updateDB() { + try { + String wrds = Gdx.files.internal("words.txt").readString(); + + String[] lines = wrds.split("\n"); + + for (String line : lines) { + String[] parts = line.split(":"); + String categoryName = parts[0]; + String[] wordsArray = parts[1].split(","); + + System.out.println("Category: " + categoryName); + Category category = new Category(categoryName); + _FBIC.createNewCategory(category); + for (String word : wordsArray) { + System.out.println("Word: " + word); + Word newWord = new Word(word); + _FBIC.addWordToCategory(category.getName(), newWord); + } + } + + } + catch (Exception e) { + e.printStackTrace(); + } + }} diff --git a/core/src/com/wordbattle/game/model/LetterPool.java b/core/src/com/wordbattle/game/model/LetterPool.java new file mode 100644 index 0000000000000000000000000000000000000000..a3b17d78fa22bef15532b7202b5c73cd10a52de9 --- /dev/null +++ b/core/src/com/wordbattle/game/model/LetterPool.java @@ -0,0 +1,46 @@ +package com.wordbattle.game.model; + + +import com.badlogic.gdx.math.Rectangle; + +import org.w3c.dom.css.Rect; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Random; + +public class LetterPool { + private Long seed; + private String word; + private ArrayList<Character> letters; + private Random randomGenerator; + private Rectangle rectangle; + + public LetterPool(String word, int extraLettersCount, String pin) { + this.word = word.toUpperCase(); + letters = new ArrayList<Character>(); + seed = Long.parseLong(pin); + this.randomGenerator = new Random(seed); + + + + // Add the word's letters to the pool + for (char c : word.toCharArray()) { + letters.add(c); + } + + // Add extra random letters to the pool + for (int i = 0; i < extraLettersCount; i++) { + char randomChar = (char) ('A' + randomGenerator.nextInt(26)); + letters.add(Character.toUpperCase(randomChar)); + } + + // Shuffle the pool + Collections.shuffle(letters); + } + + public ArrayList<Character> getLetters() { + return letters; + } + +} diff --git a/core/src/com/wordbattle/game/model/LobbyModel.java b/core/src/com/wordbattle/game/model/LobbyModel.java index c3ab7ae431ece625a24eb664620110e4f5c05118..5b5acea948183f3abc611794bd32faa658c4aa74 100644 --- a/core/src/com/wordbattle/game/model/LobbyModel.java +++ b/core/src/com/wordbattle/game/model/LobbyModel.java @@ -2,28 +2,45 @@ package com.wordbattle.game.model; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; public class LobbyModel { private String hostNickname; private String pin; - private List<String> playerNicknames; + private boolean gameStarted; + private Map<String, PlayerModel> players; // Updated to use PlayerModel + private List<String> playerNicknames; // Optional, depending on usage + private Map<String, Integer> scores; // Optional, depending on usage + private int rounds; // Add this line for the rounds counter + private boolean roundStarted; - // Constructor for initializing a new Lobby with the host's nickname and PIN public LobbyModel() { // Initialize empty constructor to allow to create lobby from snapshot of DB playerNicknames = new ArrayList<>(); + scores = new HashMap<>(); + players = new HashMap<>(); } + public LobbyModel(String hostNickname, String pin) { this.hostNickname = hostNickname; this.pin = pin; - this.playerNicknames = new ArrayList<>(); // Initialize the list of player nicknames - this.playerNicknames.add(hostNickname); + this.gameStarted = false; + this.players = new HashMap<>(); + // Add the host player to the players map + this.players.put(hostNickname, new PlayerModel(0, false)); // Initialize with default values + this.rounds = 0; // Initialize the rounds counter + this.roundStarted = false; } - // Getters and setters public String getHostNickname() { return hostNickname; } @@ -36,21 +53,64 @@ public class LobbyModel { return pin; } + public int getRounds() { + return rounds; + } + + public void setRounds(int rounds) { + this.rounds = rounds; + } + public void setPin(String pin) { this.pin = pin; } + public boolean isGameStarted() { + return gameStarted; + } + + public void setGameStarted(boolean gameStarted) { + this.gameStarted = gameStarted; + } + + public Map<String, PlayerModel> getPlayers() { + return players; + } + + public void setPlayers(Map<String, PlayerModel> players) { + this.players = players; + } + public List<String> getPlayerNicknames() { - return playerNicknames; + return new ArrayList<>(players.keySet()); // Convert player names to a list } - public void setPlayerNicknames(List<String> playerNicknames) { - this.playerNicknames = playerNicknames; + public Map<String, Integer> getScores() { + return scores; } - public void addPlayerNickname(String nickname) { - this.playerNicknames.add(nickname); + public void setScores(Map<String, Integer> scores) { + this.scores = scores; } - // ... additional logic related to the lobby ... + public void addPlayer(String nickname, PlayerModel player) { + players.put(nickname, player); + } + + public void removePlayer(String nickname) { + players.remove(nickname); + } + + // Additional methods if needed + + @Override + public String toString() { + return "LobbyModel{" + + "hostNickname='" + hostNickname + '\'' + + ", pin='" + pin + '\'' + + ", gameStarted=" + gameStarted + + ", players=" + players + + ", scores=" + scores + + '}'; + } } diff --git a/core/src/com/wordbattle/game/model/Player.java b/core/src/com/wordbattle/game/model/Player.java deleted file mode 100644 index 9b3fe25fef918ba88c17b82792ed859288d707ac..0000000000000000000000000000000000000000 --- a/core/src/com/wordbattle/game/model/Player.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.wordbattle.game.model; - -public class Player { -} diff --git a/core/src/com/wordbattle/game/model/PlayerModel.java b/core/src/com/wordbattle/game/model/PlayerModel.java new file mode 100644 index 0000000000000000000000000000000000000000..be56c7072e8d494b3aa143af7ae24963cbdad46d --- /dev/null +++ b/core/src/com/wordbattle/game/model/PlayerModel.java @@ -0,0 +1,37 @@ +package com.wordbattle.game.model; + +public class PlayerModel { + private int score; + private boolean finished; + + // Default constructor + public PlayerModel() { + // Default values for the fields + this.score = 0; + this.finished = false; + } + + // Constructor with arguments + public PlayerModel(int score, boolean finished) { + this.score = score; + this.finished = finished; + } + + + public int getScore() { + return score; + } + + public boolean isFinished() { + return finished; + } + + public void setScore(int score) { + this.score = score; + } + + public void setFinished(boolean finished) { + this.finished = finished; + } +} + diff --git a/core/src/com/wordbattle/game/model/ScoreboardModel.java b/core/src/com/wordbattle/game/model/ScoreboardModel.java new file mode 100644 index 0000000000000000000000000000000000000000..2a4055015b9d9cb15b7872624ef37efbaaf97a92 --- /dev/null +++ b/core/src/com/wordbattle/game/model/ScoreboardModel.java @@ -0,0 +1,38 @@ +package com.wordbattle.game.model; + +import java.util.HashMap; +import java.util.Map; + +public class ScoreboardModel { + + private Map<String, Integer> scores; + + public ScoreboardModel() { + scores = new HashMap<>(); + } + + public void addPlayerToScoreboard(String nickname) { + scores.put(nickname, 0); // Start with 0 score + } + + // Call this when a player scores points + public void updateScore(String nickname, int points) { + if (scores.containsKey(nickname)) { + scores.put(nickname, scores.get(nickname) + points); + } + } + + // Call this to get the score of a player + public int getScore(String nickname) { + return scores.getOrDefault(nickname, 0); + } + + // Getter for the entire scores map + public Map<String, Integer> getScores() { + return scores; + } + + +} + + diff --git a/core/src/com/wordbattle/game/model/Word.java b/core/src/com/wordbattle/game/model/Word.java new file mode 100644 index 0000000000000000000000000000000000000000..ec378426cc8044a8e03e1bd8131c412a027a411b --- /dev/null +++ b/core/src/com/wordbattle/game/model/Word.java @@ -0,0 +1,58 @@ +package com.wordbattle.game.model; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Random; + +public class Word { + + private final String word; + + public Word(String word) { + this.word = word; + } + + public String getWord() { + return word; + } + + + public List<String> getLetters(int amount) { + List<String> letters = new ArrayList<>(); + + // Add letters from the word + for (char letter : word.toCharArray()) { + letters.add(String.valueOf(letter)); + } + + // Generate random letters + Random random = new Random(); + int maxLetters = 10; + if (amount > maxLetters) { + amount = maxLetters; + } + if (amount > 0) { + for (int i = 0; i < amount; i++) { + char randomLetter = (char) (random.nextInt(26) + 'a'); + letters.add(String.valueOf(randomLetter)); + } + } + + Collections.shuffle(letters, random); + + for (String letter : letters) { + System.out.print(letter + " "); + } + System.out.println(); + + return letters; + } + + public boolean checkWord(String guessedWord) { + return guessedWord.equalsIgnoreCase(word); + } + +} + + diff --git a/core/src/com/wordbattle/game/model/WordTest.java b/core/src/com/wordbattle/game/model/WordTest.java new file mode 100644 index 0000000000000000000000000000000000000000..74abf847035413f8b38a008d5b1416fa702e7825 --- /dev/null +++ b/core/src/com/wordbattle/game/model/WordTest.java @@ -0,0 +1,21 @@ +package com.wordbattle.game.model; + +// Denne skal slettes + +public class WordTest { + + public static void main(String[] args) { + // Create an instance of Word + Category category = new Category("Test"); + Word word = new Word("lemon"); + + // Test the getWord method + System.out.println("Word: " + word.getWord()); + + // Test the getLetters method + int numberOfRandomLetters = 3; + System.out.println("Letters:"); + word.getLetters(numberOfRandomLetters); + System.out.println(word.checkWord("lemon")); + } +} \ No newline at end of file diff --git a/core/src/com/wordbattle/game/network/FirebaseInterface.java b/core/src/com/wordbattle/game/network/FirebaseInterface.java index ea3cb7663a30c84f037dbe0a09c2f5679c8348d6..4ac43cad0e9a3d1a8b59114c433efeb964c59651 100644 --- a/core/src/com/wordbattle/game/network/FirebaseInterface.java +++ b/core/src/com/wordbattle/game/network/FirebaseInterface.java @@ -1,6 +1,10 @@ package com.wordbattle.game.network; +import com.wordbattle.game.model.Category; +import com.wordbattle.game.model.Word; + import java.util.List; +import java.util.Map; public interface FirebaseInterface { @@ -13,11 +17,94 @@ public interface FirebaseInterface { void fetchPlayers(String pin, PlayerListUpdateCallback callback); + void startGame(String pin); + + + void isHost(String pin, String nickname, HostCheckCallback callback); + + void startRound(String pin); + + void resetRoundFlag(String pin); + + interface HostCheckCallback { + void onHostCheckResult(boolean isHost); + void onError(String error); + } + + void listenForGameStart(String pin, GameStartCallback callback); + + long getSeed(); + + void fetchWord(String pin, String category, WordFetchCallback callback); + + boolean checkIfAllPlayersAreFinished(String pin); + + void updateFinishedFlag(String nickname, String pin); + + void getPlayerAndScore(String pin, PlayerScoreCallback callback); + + void updateRound(String pin, RoundUpdateCallback callback); + + void fetchRound(String pin, RoundCallback callback); + + void resetFlags(String pin); + + + void listenForRoundStarted(String pin, Runnable onRoundStarted); + + interface PlayerScoreCallback { + void onPlayerScoresReceived(Map<String, Integer> playerScores); + } + + interface RoundUpdateCallback { + void onRoundUpdateSuccess(); + void onRoundUpdateFailure(); + } + + + interface GameStartCallback { + void onGameStarted(); + } + // Callback interface interface PlayerListUpdateCallback { void onPlayerListUpdated(List<String> playerNames); + + void onError(String error); + } + + interface WordFetchCallback { + void onWordFetched(String word); void onError(String error); } + void createNewCategory(Category category); + + void addWordToCategory(String categoryName, Word word); + + void addScoreToDatabase(String pin, String nickname); + + void updateScoreInDatabase(String pin, String nickname, int newScore, ScoreUpdateCallback callback); + interface ScoreUpdateCallback { + void onSuccess(); + void onFailure(); + } + + interface RoundCallback { + void onRoundFetched(int round); + void onError(); + } + + + + void fetchScores(String pin, ScoreFetchCallback callback); + + interface ScoreFetchCallback { + void onScoresFetched(Map<String, Integer> scores); + void onError(String error); + } + + } + diff --git a/core/src/com/wordbattle/game/network/FirebaseManager.java b/core/src/com/wordbattle/game/network/FirebaseManager.java index 3ecae622510a050ac614881335d5c2af08655df4..f150e5f635de81185d57dd8a7f7face363129cf8 100644 --- a/core/src/com/wordbattle/game/network/FirebaseManager.java +++ b/core/src/com/wordbattle/game/network/FirebaseManager.java @@ -1,5 +1,8 @@ package com.wordbattle.game.network; +import com.wordbattle.game.model.Category; +import com.wordbattle.game.model.Word; + public class FirebaseManager implements FirebaseInterface { @@ -16,14 +19,108 @@ public class FirebaseManager implements FirebaseInterface { @Override public void joinLobby(String pin, String playerNickname, Runnable onSuccess, Runnable onFail) { + } + + public void createNewCategory(Category category) { + + } + + @Override + public void addWordToCategory(String categoryName, Word word) { } + @Override + public void addScoreToDatabase(String lobbyPin, String nickname) { + + } + + @Override + public void updateScoreInDatabase(String pin, String nickname, int newScore, ScoreUpdateCallback callback) { + + } + + + @Override + public void fetchScores(String pin, ScoreFetchCallback callback) { + + } + + @Override public void fetchPlayers(String pin, PlayerListUpdateCallback callback) { } + @Override + public void startGame(String pin){ + + } + + @Override + public void isHost(String pin, String nickname, HostCheckCallback callback) { + + } + + @Override + public void startRound(String pin) { + + } + + @Override + public void resetRoundFlag(String pin) { + + } + + + @Override + public void listenForGameStart(String pin, GameStartCallback callback) { + } + + @Override + public long getSeed() { + return 0; + } + + @Override + public void fetchWord(String pin, String category, WordFetchCallback callback) { + + } + + @Override + public boolean checkIfAllPlayersAreFinished(String pin) { + return false; + } + + @Override + public void updateFinishedFlag(String nickname, String pin) { + + } + + @Override + public void getPlayerAndScore(String pin, PlayerScoreCallback callback) { + + } + + @Override + public void updateRound(String pin, RoundUpdateCallback callback) { + + } + + @Override + public void fetchRound(String pin, RoundCallback callback) { + + } + + @Override + public void resetFlags(String pin) { + + } + + @Override + public void listenForRoundStarted(String pin, Runnable onRoundStarted) { + + } } diff --git a/core/src/com/wordbattle/game/states/FinalLeaderboardState.java b/core/src/com/wordbattle/game/states/FinalLeaderboardState.java index 9fa26af98dcf5d36c5f0bfa88304a3f350400243..310d67e39de9209dd1f09d55a48cfd37bad03874 100644 --- a/core/src/com/wordbattle/game/states/FinalLeaderboardState.java +++ b/core/src/com/wordbattle/game/states/FinalLeaderboardState.java @@ -3,13 +3,22 @@ package com.wordbattle.game.states; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.wordbattle.game.WordBattle; import com.wordbattle.game.controller.FinalLeaderBoardController; +import com.wordbattle.game.network.FirebaseInterface; +import com.wordbattle.game.network.FirebaseManager; public class FinalLeaderboardState extends BaseState { + private String pin; + private FirebaseInterface _FBIC; + private String nickname; + FinalLeaderBoardController controller; - public FinalLeaderboardState(StateManager gsm) { + public FinalLeaderboardState(StateManager gsm, FirebaseInterface _FBIC, String pin, String nickname) { super(gsm); - this.controller = new FinalLeaderBoardController(this); // 'this' provides context + this._FBIC = _FBIC; + this.pin = pin; + this.nickname = nickname; + this.controller = new FinalLeaderBoardController(this, _FBIC, pin, nickname); // 'this' provides context cam.setToOrtho(false, WordBattle.WIDTH, WordBattle.HEIGHT); } diff --git a/core/src/com/wordbattle/game/states/GamePlayState.java b/core/src/com/wordbattle/game/states/GamePlayState.java new file mode 100644 index 0000000000000000000000000000000000000000..58e705bf8d6bcec3dc2d3eca25a8f3b08acef038 --- /dev/null +++ b/core/src/com/wordbattle/game/states/GamePlayState.java @@ -0,0 +1,64 @@ +package com.wordbattle.game.states; + +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.wordbattle.game.controller.CreateGameController; +import com.wordbattle.game.controller.GamePlayController; +import com.wordbattle.game.network.FirebaseInterface; + +public class GamePlayState extends BaseState { + + private GamePlayController controller; + private FirebaseInterface _FBIC; + private String pin; + private String nickname; + + + public GamePlayState(StateManager gsm, FirebaseInterface _FBIC, String pin, String nickname) { + super(gsm); + this._FBIC = _FBIC; + this.pin = pin; + this.controller = new GamePlayController(this, _FBIC, pin, nickname); + this.nickname = nickname; + + } + + public GamePlayController getController() { + return this.controller; + } + + @Override + public void handleInput() { + + } + + @Override + public void update(float dt) { + controller.update(dt); + cam.update(); + } + + @Override + public void render(SpriteBatch sb) { + controller.render(sb); + } + + @Override + public void enter() { + + } + + @Override + public void exit() { + + } + + @Override + public void dispose() { + controller.dispose(); + } + + public StateManager getStateManager() { + return gsm; + } + +} diff --git a/core/src/com/wordbattle/game/states/LeaderBoardState.java b/core/src/com/wordbattle/game/states/LeaderBoardState.java index 7f3cbce4ebda7b540dfb3a7acc0d870624d2835e..3579dd95113e770bf56eb54473585edf88f9eb0f 100644 --- a/core/src/com/wordbattle/game/states/LeaderBoardState.java +++ b/core/src/com/wordbattle/game/states/LeaderBoardState.java @@ -4,13 +4,22 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.wordbattle.game.WordBattle; import com.wordbattle.game.controller.LeaderBoardController; import com.wordbattle.game.controller.MainMenuController; +import com.wordbattle.game.network.FirebaseInterface; +import com.wordbattle.game.network.FirebaseManager; public class LeaderBoardState extends BaseState { + private FirebaseInterface _FBIC; + private String pin; + private String nickname; + LeaderBoardController controller; - public LeaderBoardState(StateManager gsm) { + public LeaderBoardState(StateManager gsm, FirebaseInterface _FBIC, String pin, String nickname ) { super(gsm); - this.controller = new LeaderBoardController(this); // 'this' provides context + this._FBIC = _FBIC; + this.pin = pin; + this.nickname = nickname; + this.controller = new LeaderBoardController(this, _FBIC, pin, nickname); // 'this' provides context cam.setToOrtho(false, WordBattle.WIDTH, WordBattle.HEIGHT); } diff --git a/core/src/com/wordbattle/game/states/SettingsState.java b/core/src/com/wordbattle/game/states/SettingsState.java index 7b40611507d8256881b157a5ff0ab8fc42e99984..cca1579253176689a2236b4f7198a4fd611d6ac4 100644 --- a/core/src/com/wordbattle/game/states/SettingsState.java +++ b/core/src/com/wordbattle/game/states/SettingsState.java @@ -52,4 +52,4 @@ public class SettingsState extends BaseState{ public void dispose() { } -} +} \ No newline at end of file diff --git a/core/src/com/wordbattle/game/states/WaitingLobbyState.java b/core/src/com/wordbattle/game/states/WaitingLobbyState.java index 8fed142dbaa315359002e61d5e2cdd3acd7bc7ca..11c3e8b86525980acbaa3492524bb9418c905384 100644 --- a/core/src/com/wordbattle/game/states/WaitingLobbyState.java +++ b/core/src/com/wordbattle/game/states/WaitingLobbyState.java @@ -4,14 +4,24 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.wordbattle.game.WordBattle; import com.wordbattle.game.controller.MainMenuController; import com.wordbattle.game.controller.WaitingLobbyController; +import com.wordbattle.game.network.FirebaseInterface; public class WaitingLobbyState extends BaseState { + private String nickname; + private int score; + private FirebaseInterface _FBIC; + private String pin; + WaitingLobbyController controller; - public WaitingLobbyState(StateManager gsm) { + public WaitingLobbyState(StateManager gsm, FirebaseInterface _FBIC, String nickname, int score, String pin) { super(gsm); - this.controller = new WaitingLobbyController(this); // 'this' provides context + this._FBIC = _FBIC; + this.nickname = nickname; + this.score = score; + this.pin = pin; + this.controller = new WaitingLobbyController(this, _FBIC, nickname, score, pin); // 'this' provides context cam.setToOrtho(false, WordBattle.WIDTH, WordBattle.HEIGHT); } diff --git a/core/src/com/wordbattle/game/view/CreateGameView.java b/core/src/com/wordbattle/game/view/CreateGameView.java index a6dc778d0a7a75c4ff520f75b5c506d814b40d6e..5ad74486d42b4c79a723c2b89514d37481bc9d12 100644 --- a/core/src/com/wordbattle/game/view/CreateGameView.java +++ b/core/src/com/wordbattle/game/view/CreateGameView.java @@ -43,10 +43,13 @@ public class CreateGameView { private String pin; private String selectedLevel = "easy"; // default to easy + private String nickNameMessage; private Rectangle settingsBounds; private Rectangle goBackButtonBounds; + + public CreateGameView(OrthographicCamera cam) { this.cam = cam; stage = new Stage(new ScreenViewport(cam)); @@ -65,6 +68,21 @@ public class CreateGameView { textFieldStyle.fontColor = Color.WHITE; + goBackButtonBounds = new Rectangle( + 0, + WordBattle.HEIGHT - 100, + 100, + 100 + ); + + settingsBounds = new Rectangle( + WordBattle.WIDTH - 100, + WordBattle.HEIGHT - 100, + 100, + 100 + ); + + // Create the TextField for nickname input nicknameField = new TextField("", textFieldStyle); @@ -118,6 +136,8 @@ public class CreateGameView { nicknameField.setSize(nicknameBounds.width, nicknameBounds.height); stage.addActor(nicknameField); + nickNameMessage=""; + } public Rectangle getSettingsBounds() { return settingsBounds; } @@ -160,6 +180,10 @@ public class CreateGameView { font.draw(spriteBatch, "Easy", easyButtonBounds.x + (easyButtonBounds.width / 2) - 35, easyButtonBounds.y + (easyButtonBounds.height / 2) + 20); font.draw(spriteBatch, "Medium", mediumButtonBounds.x + (mediumButtonBounds.width / 2) - 60, mediumButtonBounds.y + (mediumButtonBounds.height / 2) + 20); font.draw(spriteBatch, "Hard", hardButtonBounds.x + (hardButtonBounds.width / 2) - 35, hardButtonBounds.y + (hardButtonBounds.height / 2) + 20); + if (!nickNameMessage.isEmpty()){ + font.draw(spriteBatch,nickNameMessage,nicknameBounds.x+120,nicknameBounds.y); + } + spriteBatch.end(); @@ -206,6 +230,13 @@ public class CreateGameView { public Rectangle getCreateGameBounds() { return createGameBounds; } + public Rectangle getSettingsBounds() { return settingsBounds; } + public Rectangle getGoBackButtonBounds() {return goBackButtonBounds;} + + + public void setNickNameMessage(String nickNameMessage) { + this.nickNameMessage = nickNameMessage; + } } diff --git a/core/src/com/wordbattle/game/view/FinalLeaderBoardView.java b/core/src/com/wordbattle/game/view/FinalLeaderBoardView.java index f328e1649013c8f256ccbaee45b9b93890c5d5d8..cb897b01ec478b5dfff8205392d8bd4201dcba55 100644 --- a/core/src/com/wordbattle/game/view/FinalLeaderBoardView.java +++ b/core/src/com/wordbattle/game/view/FinalLeaderBoardView.java @@ -11,6 +11,10 @@ import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator; import com.badlogic.gdx.math.Rectangle; import com.wordbattle.game.WordBattle; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + public class FinalLeaderBoardView { private OrthographicCamera cam; @@ -25,7 +29,7 @@ public class FinalLeaderBoardView { private Texture thirdPlaceTex; - private Texture BackToStartTex; + private Texture backToStartTex; private Rectangle backToStartBounds; @@ -34,6 +38,9 @@ public class FinalLeaderBoardView { private BitmapFont titleFont; + private Map<String, Integer> playerScoresMap; + + private int numBackgroundRenders; @@ -52,7 +59,7 @@ public class FinalLeaderBoardView { secondPlaceTex = new Texture("Nr2Emoji.png"); thirdPlaceTex = new Texture("Nr3Emoji.png"); - BackToStartTex = new Texture("BackToStartButton.png"); + backToStartTex = new Texture("BackToStartButton.png"); @@ -83,35 +90,76 @@ public class FinalLeaderBoardView { spriteBatch.begin(); for (int i = 0; i < numBackgroundRenders ; i++) { - spriteBatch.draw(background,0,0-(i* WordBattle.HEIGHT), WordBattle.WIDTH,WordBattle.HEIGHT); + spriteBatch.draw(background,0,0-(i*WordBattle.HEIGHT), WordBattle.WIDTH,WordBattle.HEIGHT); } - //spriteBatch.draw(purpleRectangle,10,- - spriteBatch.draw(BackToStartTex,backToStartBounds.x,backToStartBounds.y-10, backToStartBounds.getWidth(),backToStartBounds.getHeight()+20); + spriteBatch.draw(backToStartTex, getBackToStartBounds().x,getBackToStartBounds().y-10, getBackToStartBounds().getWidth(), getBackToStartBounds().getHeight()+20); + titleFont.draw(spriteBatch,"LeaderBoard", 40, 660); - titleFont.draw(spriteBatch,"Final Result", 40, 660); + if (playerScoresMap != null) { + int yPos = 490; // Initial Y position for the first player entry + int place = 1; // Initialize the place counter - spriteBatch.draw(pinkBubble,45,490,400,100); - spriteBatch.draw(firstPlaceTex,80,520,35,35); - playerFont.draw(spriteBatch,"Marcus",120,560); + // Sort the player scores by score (from high to low) + List<Map.Entry<String, Integer>> sortedScores = new ArrayList<>(playerScoresMap.entrySet()); + sortedScores.sort((e1, e2) -> e2.getValue().compareTo(e1.getValue())); + // Render each player entry + for (Map.Entry<String, Integer> entry : sortedScores) { + String playerName = entry.getKey(); + int score = entry.getValue(); - spriteBatch.draw(goldenBubble,45,410,400,100); - spriteBatch.draw(secondPlaceTex,80,440,35,35); + spriteBatch.draw(pinkBubble, 45, yPos, 400, 100); // Adjust X and Y positions as needed + spriteBatch.draw(getPlaceTexture(place), 80, yPos + 30, 35, 35); // Adjust X and Y positions as needed + playerFont.draw(spriteBatch, playerName, 120, yPos + 70); // Adjust X and Y positions as needed + playerFont.draw(spriteBatch, String.valueOf(score), 350, yPos + 70); // Render the score next to the player name - playerFont.draw(spriteBatch,"Askh",120,480); + // Update Y position for the next player entry + yPos -= 120; // Adjust this value as needed + // Increment the place counter + place++; + } + } + /*spriteBatch.draw(pinkBubble,45,490,400,100); + spriteBatch.draw(firstPlaceTex,80,520,35,35); + playerFont.draw(spriteBatch,"Marcus",120,560); + spriteBatch.draw(goldenBubble,45,410,400,100); + spriteBatch.draw(secondPlaceTex,80,440,35,35); + playerFont.draw(spriteBatch,"Askh",120,480); +*/ spriteBatch.end(); + } + private Texture getPlaceTexture(int place) { + switch (place) { + case 1: + return firstPlaceTex; + case 2: + return secondPlaceTex; + case 3: + return thirdPlaceTex; + default: + return null; + } + } + + public void setMap(Map<String, Integer> playerScores) { + this.playerScoresMap = playerScores; + if (!playerScores.isEmpty()) { + List<Integer> scores = new ArrayList<>(playerScores.values()); + int firstPlayerScore = scores.get(0); + System.out.println("Score of the first player: " + firstPlayerScore); + } } public OrthographicCamera getCam() { @@ -133,7 +181,7 @@ public class FinalLeaderBoardView { firstPlaceTex.dispose(); secondPlaceTex.dispose(); thirdPlaceTex.dispose(); - BackToStartTex.dispose(); + backToStartTex.dispose(); } diff --git a/core/src/com/wordbattle/game/view/GamePlayView.java b/core/src/com/wordbattle/game/view/GamePlayView.java new file mode 100644 index 0000000000000000000000000000000000000000..70410df4768b2caee85de85722e1eda77820d982 --- /dev/null +++ b/core/src/com/wordbattle/game/view/GamePlayView.java @@ -0,0 +1,274 @@ +package com.wordbattle.game.view; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Screen; +import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.GL30; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.BitmapFont; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator; +import com.badlogic.gdx.graphics.glutils.ShapeRenderer; +import com.badlogic.gdx.math.Rectangle; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.ui.TextField; +import com.badlogic.gdx.utils.viewport.ScreenViewport; +import com.sun.org.apache.xerces.internal.util.SynchronizedSymbolTable; +import com.wordbattle.game.WordBattle; +import com.wordbattle.game.model.LetterPool; +import com.wordbattle.game.network.FirebaseInterface; + +import org.w3c.dom.ranges.Range; + +import java.util.ArrayList; +import java.util.Stack; + +import jdk.internal.org.jline.terminal.Size; + +public class GamePlayView { + + private FirebaseInterface _FBIC; + private OrthographicCamera cam; + private Stage stage; + private String currentWord; + private ShapeRenderer shapeRenderer; + private Texture backgroundTexture; + private LetterPool letterPool; + private BitmapFont font; + private String pin; + private Stack<Character> selectedLetters = new Stack<>(); + private ArrayList<Character> letters; + private Rectangle[] letterBoxBounds; + private Rectangle[] letterBounds; + private Character[] filledBoxes; + private float timeLeft; + private float maxTime; + private boolean isTimerRunning; + private Rectangle settingsBounds; + + + + + public GamePlayView(OrthographicCamera cam, FirebaseInterface _FBIC, String pin) { + this._FBIC = _FBIC; + this.pin = pin; + this.cam = cam; + stage = new Stage(new ScreenViewport(cam)); + Gdx.input.setInputProcessor(stage); + + + settingsBounds = new Rectangle( + WordBattle.WIDTH - 100, + WordBattle.HEIGHT - 100, + 100, + 100 + ); + + // Load BG + backgroundTexture = new Texture("bgWithSettings.png"); + + + // Load and set up font + FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("Knewave-Regular.ttf")); + FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter(); + parameter.size = 120; + font = generator.generateFont(parameter); + generator.dispose(); + + // Initialize TextFieldStyle with the font + TextField.TextFieldStyle textFieldStyle = new TextField.TextFieldStyle(); + textFieldStyle.font = font; + textFieldStyle.fontColor = Color.WHITE; + + // Set timer + maxTime = 30.0f; + timeLeft = 30.0f; // Starting with 30 seconds for example + isTimerRunning = true; // Start with the timer running + + + + + } + + public Rectangle getSettingsBounds() { return settingsBounds; } + + // Update timer + public void update(float deltaTime) { + if (isTimerRunning) { + timeLeft -= deltaTime; + if (timeLeft <= 0) { + timeLeft = 0; + isTimerRunning = false; // Stop the timer when it reaches 0 + // Handle time out logic + + } + } + } + + public void setCurrentWord(String currentWord) { + this.currentWord = currentWord; + letterPool = new LetterPool(currentWord, 5, pin); // Or however you decide the number of extra letters + letterBoxBounds = new Rectangle[currentWord.length()]; + filledBoxes = new Character[currentWord.length()]; + } + + public void render(SpriteBatch sb) { + if (shapeRenderer == null) { + shapeRenderer = new ShapeRenderer(); + + } + if (letterPool != null) { + + + + letters = letterPool.getLetters(); + letterBounds = new Rectangle[letters.size()]; + + float letterSpacing = 100; + float totalWidthLetter = ((((float) letters.size() * letterSpacing)) / 2); + float letterStartX = ((cam.viewportWidth - totalWidthLetter) - 2*letterSpacing) / 2; + float letterStartY = cam.viewportHeight / 2; + sb.setProjectionMatrix(cam.combined); + sb.begin(); // Begin the SpriteBatch for other rendering + sb.draw(backgroundTexture, 0, 0, cam.viewportWidth, cam.viewportHeight); + float letterStartYBaseEven = 700; // Midpoint for range 500 to 900 + float letterStartYBaseOdd = -550; // Midpoint for range 300 to 800 + for (int i = 0; i < letters.size(); i++) { + // Calculate the position for each letter + float x = letterStartX + i * letterSpacing; + float y; + if (i % 2 == 0) { + // For even indices, use the range 500 to 900 + y = letterStartY + 700; // Alternate within the range + } else { + // For odd indices, use the range 300 to 800 + y = letterStartY - 400;// Alternate within the range + x -= letterSpacing; + } + + + // Draw each letter, here you might want to draw a background texture for the letter + font.setColor(Color.GREEN); + font.draw(sb, letters.get(i).toString(), x, y); + letterBounds[i] = new Rectangle(x, y-120, 120, 120); + } + + + // Draw time + font.draw(sb, "Time: " + String.format("%o", Math.round(timeLeft)), cam.viewportWidth / 2 - 200, cam.viewportHeight - 200); + + sb.end(); // End SpriteBatch + + // This is the rects around letters + shapeRenderer.setProjectionMatrix(cam.combined); + shapeRenderer.begin(ShapeRenderer.ShapeType.Line); // Begin ShapeRenderer + for (int i = 0; i < getLetterBounds().length; i++) { + Rectangle rect = getLetterBounds()[i]; + shapeRenderer.rect(rect.x, rect.y, rect.width, rect.height); + } + shapeRenderer.end(); // End ShapeRenderer + + + shapeRenderer.setProjectionMatrix(cam.combined); + shapeRenderer.begin(ShapeRenderer.ShapeType.Filled); + shapeRenderer.setColor(Color.WHITE); // Set the color for the boxes + + float boxWidth = 120; // Set the width for the boxes + float boxHeight = 120; // Set the height for the boxes + float spacing = 25; // Space between boxes + float totalWidth = currentWord.length() * (boxWidth + spacing) - spacing; + float startX = (cam.viewportWidth - totalWidth) / 2; // Center the boxes + float yPosition = cam.viewportHeight / 2; // Y position for the boxes + + + for (int i = 0; i < currentWord.length(); i++) { + float boxX = startX + i * (boxWidth + spacing); + shapeRenderer.rect(boxX, yPosition, boxWidth, boxHeight); + // Add a new box to arr + letterBoxBounds[i] = new Rectangle(boxX, yPosition, boxWidth, boxHeight); + + } + + shapeRenderer.end(); + sb.begin(); // Begin SpriteBatch again + + // This is letters being drawn in the boxes + for (int i = 0; i < filledBoxes.length; i++) { + if (filledBoxes[i] != null) { + // Draw the letter in the box + float y = getLetterBoxBounds()[i].y + 120; + float x = getLetterBoxBounds()[i].x + 10; + font.draw(sb, filledBoxes[i].toString(), x, y); + } + } + sb.end(); + + } + } + + + public Stack<Character> getSelectedLetters() { + return selectedLetters; + + } + + + + public ArrayList<Character> getLetters() { + return letters; + } + + + + public String getCurrentWord() { + return currentWord; + } + + public Rectangle[] getLetterBounds() { + return letterBounds; + } + + public Rectangle[] getLetterBoxBounds() { + return letterBoxBounds; + } + + public Character[] getFilledBoxes() { + return filledBoxes; + } + + public void setFilledBoxes(Character[] filledBoxes) { + this.filledBoxes = filledBoxes; + } + + public void dispose() { + shapeRenderer.dispose(); + } + + + // Timer control methods + public void startTimer() { + isTimerRunning = true; + } + + public void stopTimer() { + isTimerRunning = false; + } + + public boolean isTimerRunning() { + return isTimerRunning; + } + + public void resetTimer(float newTime) { + timeLeft = newTime; + } + + public float getTimeLeft() { + return timeLeft; + } + + public float getMaxTime() { + return maxTime; + } +} diff --git a/core/src/com/wordbattle/game/view/GameView.java b/core/src/com/wordbattle/game/view/GameView.java deleted file mode 100644 index 046bd973ac952085fd20d795a4d9fad19670b6b2..0000000000000000000000000000000000000000 --- a/core/src/com/wordbattle/game/view/GameView.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.wordbattle.game.view; - -public class GameView { -} diff --git a/core/src/com/wordbattle/game/view/JoinGameView.java b/core/src/com/wordbattle/game/view/JoinGameView.java index a5ccaa8e2280c08ece3702fbe54042e2e617b650..632dbfd2963afcbfd5363bc43e5dd01bc8d731fb 100644 --- a/core/src/com/wordbattle/game/view/JoinGameView.java +++ b/core/src/com/wordbattle/game/view/JoinGameView.java @@ -41,6 +41,8 @@ public class JoinGameView { private String nicknameMessage; private String errorMsg; private String errorMessage = ""; + private Rectangle settingsBounds; + private Rectangle goBackButtonBounds; private Rectangle settingsBounds; private Rectangle goBackButtonBounds; @@ -50,6 +52,8 @@ public class JoinGameView { stage = new Stage(new ScreenViewport(cam)); Gdx.input.setInputProcessor(stage); + + backgroundTexture = new Texture("bg_btn_settings.png"); nicknameTexture = new Texture("pink_long-01.png"); pinTexture = new Texture("pink_long-01.png"); @@ -177,6 +181,9 @@ public class JoinGameView { public String getNickname(){ return nicknameField.getText(); } + public Rectangle getGoBackButtonBounds() {return goBackButtonBounds;} + public Rectangle getSettingsBounds() { return settingsBounds; } + public void setPinMessage(String pinMessage) { diff --git a/core/src/com/wordbattle/game/view/LeaderBoardView.java b/core/src/com/wordbattle/game/view/LeaderBoardView.java index 2946585a3f92cffb6f325c2aeb32c00a1aa8079b..bf5331af1ccb4db1b6848b02005b3e7468510f1d 100644 --- a/core/src/com/wordbattle/game/view/LeaderBoardView.java +++ b/core/src/com/wordbattle/game/view/LeaderBoardView.java @@ -13,6 +13,10 @@ import com.wordbattle.game.WordBattle; import org.w3c.dom.Text; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; + public class LeaderBoardView { private OrthographicCamera cam; @@ -38,11 +42,12 @@ public class LeaderBoardView { private BitmapFont playerFont; private BitmapFont titleFont; + private int numBackgroundRenders; + private Map<String, Integer> playerScoresMap; + private boolean isHost; - private int numBackgroundRenders; - public LeaderBoardView(OrthographicCamera cam) { this.cam = cam; @@ -88,32 +93,63 @@ public class LeaderBoardView { spriteBatch.draw(background,0,0-(i*WordBattle.HEIGHT), WordBattle.WIDTH,WordBattle.HEIGHT); } + if (isHost) { + spriteBatch.draw(nextRoundTex,getNextRoundBounds().x,getNextRoundBounds().y-10, getNextRoundBounds().getWidth(),getNextRoundBounds().getHeight()+20); + spriteBatch.draw(ArrowTex,350,715,50,25); + } - //spriteBatch.draw(purpleRectangle,10,- - spriteBatch.draw(nextRoundTex,getNextRoundBounds().x,getNextRoundBounds().y-10, getNextRoundBounds().getWidth(),getNextRoundBounds().getHeight()+20); - spriteBatch.draw(ArrowTex,350,715,50,25); titleFont.draw(spriteBatch,"LeaderBoard", 40, 660); - spriteBatch.draw(pinkBubble,45,490,400,100); - spriteBatch.draw(firstPlaceTex,80,520,35,35); - playerFont.draw(spriteBatch,"Marcus",120,560); - + if (playerScoresMap != null) { + int yPos = 490; // Initial Y position for the first player entry + int place = 1; // Initialize the place counter - spriteBatch.draw(goldenBubble,45,410,400,100); - spriteBatch.draw(secondPlaceTex,80,440,35,35); - - playerFont.draw(spriteBatch,"Askh",120,480); + // Sort the player scores by score (from high to low) + List<Map.Entry<String, Integer>> sortedScores = new ArrayList<>(playerScoresMap.entrySet()); + sortedScores.sort((e1, e2) -> e2.getValue().compareTo(e1.getValue())); + // Render each player entry + for (Map.Entry<String, Integer> entry : sortedScores) { + String playerName = entry.getKey(); + int score = entry.getValue(); + spriteBatch.draw(pinkBubble, 45, yPos, 400, 100); // Adjust X and Y positions as needed + spriteBatch.draw(getPlaceTexture(place), 80, yPos + 30, 35, 35); // Adjust X and Y positions as needed + playerFont.draw(spriteBatch, playerName, 120, yPos + 70); // Adjust X and Y positions as needed + playerFont.draw(spriteBatch, String.valueOf(score), 350, yPos + 70); // Render the score next to the player name + // Update Y position for the next player entry + yPos -= 120; // Adjust this value as needed + // Increment the place counter + place++; + } + } + spriteBatch.end(); + } + private Texture getPlaceTexture(int place) { + switch (place) { + case 1: + return firstPlaceTex; + case 2: + return secondPlaceTex; + case 3: + return thirdPlaceTex; + default: + return null; + } + } - spriteBatch.end(); + public void setHost(boolean host) { + isHost = host; + } + public boolean isHost() { + return isHost; } public OrthographicCamera getCam() { @@ -127,6 +163,14 @@ public class LeaderBoardView { public void setNumBackgroundRenders(int backgroundRenders){ this.numBackgroundRenders=backgroundRenders; } + public void setMap(Map<String, Integer> playerScores) { + this.playerScoresMap = playerScores; + if (!playerScores.isEmpty()) { + List<Integer> scores = new ArrayList<>(playerScores.values()); + int firstPlayerScore = scores.get(0); + System.out.println("Score of the first player: " + firstPlayerScore); + } + } public void dispose(){ background.dispose(); diff --git a/core/src/com/wordbattle/game/view/LobbyView.java b/core/src/com/wordbattle/game/view/LobbyView.java index 5e4b1b69b4f0de756faa500bbf0963c63cf052e5..30162167ccc73a793abfcfb0461750a049f84802 100644 --- a/core/src/com/wordbattle/game/view/LobbyView.java +++ b/core/src/com/wordbattle/game/view/LobbyView.java @@ -11,13 +11,15 @@ import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator; import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.scenes.scene2d.Stage; -import com.badlogic.gdx.scenes.scene2d.ui.TextButton; import com.badlogic.gdx.utils.viewport.ScreenViewport; import com.wordbattle.game.WordBattle; import com.badlogic.gdx.scenes.scene2d.ui.ImageButton; import com.badlogic.gdx.scenes.scene2d.utils.TextureRegionDrawable; import com.badlogic.gdx.graphics.g2d.TextureRegion; +import java.util.ArrayList; +import java.util.List; + public class LobbyView { private Texture backgroundTexture; private BitmapFont font; @@ -28,6 +30,8 @@ public class LobbyView { private Texture startGameTexture; // Texture for the "START GAME" button background private Rectangle startTheGameBounds; + private List<String> playerNames = new ArrayList<>(); + public LobbyView(OrthographicCamera cam, String pin) { this.cam = cam; @@ -53,7 +57,6 @@ public class LobbyView { stage.addActor(startGameButton); startTheGameBounds = new Rectangle((WordBattle.WIDTH / 2) - (startGameTexture.getWidth() / 2), 100, startGameTexture.getWidth(), startGameTexture.getHeight()); - // Load background texture backgroundTexture = new Texture("bg2.png"); @@ -74,13 +77,23 @@ public class LobbyView { float waitingForWidth = "WAITING FOR".length() * 14; // Approximate width per character is 14 float playersToJoinWidth = "PLAYERS TO JOIN...".length() * 14; - // Draw "WAITING FOR" in the middle of the screen - font.draw(spriteBatch, "WAITING FOR", (WordBattle.WIDTH - waitingForWidth) / 2, 500); - // Draw "PLAYERS TO JOIN..." in the middle of the screen - font.draw(spriteBatch, "PLAYERS TO JOIN...", (WordBattle.WIDTH - playersToJoinWidth) / 2, 450); + if (playerNames.size() < 2 ) { + // Draw "WAITING FOR" in the middle of the screen + font.draw(spriteBatch, "WAITING FOR", (WordBattle.WIDTH - waitingForWidth) / 2, 500); + // Draw "PLAYERS TO JOIN..." in the middle of the screen + font.draw(spriteBatch, "PLAYERS TO JOIN...", (WordBattle.WIDTH - playersToJoinWidth) / 2, 450); + } + else { + // Draw the list of players + float startY = WordBattle.HEIGHT / 2f; // Adjust Y as necessary + for (String playerName : playerNames) { + font.draw(spriteBatch, playerName, WordBattle.WIDTH / 2f, startY); + startY -= font.getLineHeight(); // Space the player names out + } + } // Draw PIN - font.draw(spriteBatch, "PIN: " + pin, 160, 750); + font.draw(spriteBatch, "PIN: " + pin, 160, 750);; spriteBatch.end(); @@ -113,9 +126,12 @@ public class LobbyView { return startGameButton; } - public Rectangle getCreateGameBounds() { + public Rectangle getStartGameButtonBounds() { return startTheGameBounds; } + public void setPlayerNames(List<String> playerNames) { + this.playerNames = playerNames; + } } diff --git a/core/src/com/wordbattle/game/view/MainMenuView.java b/core/src/com/wordbattle/game/view/MainMenuView.java index ab208b8ac07a8fbc35685e9ed80972271941977b..41cd298f2d03f315dd50c088a6bc675a1e52f5f5 100644 --- a/core/src/com/wordbattle/game/view/MainMenuView.java +++ b/core/src/com/wordbattle/game/view/MainMenuView.java @@ -19,6 +19,7 @@ public class MainMenuView { private Rectangle howToPlayButtonBounds; private Rectangle settingsBounds; private OrthographicCamera cam; + private Rectangle settingsBounds; @@ -54,7 +55,6 @@ public class MainMenuView { howToPlayButton.getHeight() ); - settingsBounds = new Rectangle( WordBattle.WIDTH - 100, WordBattle.HEIGHT - 100, diff --git a/core/src/com/wordbattle/game/view/SettingsView.java b/core/src/com/wordbattle/game/view/SettingsView.java index 7401aa13406eb19d53e651e5150e1706a6dc8763..8e5457c59ecfa7c7468dfcb250631b3297ed2697 100644 --- a/core/src/com/wordbattle/game/view/SettingsView.java +++ b/core/src/com/wordbattle/game/view/SettingsView.java @@ -136,4 +136,4 @@ public class SettingsView { switchOnSoundTexture.dispose(); switchOffSoundTexture.dispose(); } -} +} \ No newline at end of file diff --git a/core/src/com/wordbattle/game/view/WaitForHostView.java b/core/src/com/wordbattle/game/view/WaitForHostView.java index cc5006cb93af4e60d421de9079829396c8613aa0..d604886d11fbbfb75634186a86daa028e580f4e6 100644 --- a/core/src/com/wordbattle/game/view/WaitForHostView.java +++ b/core/src/com/wordbattle/game/view/WaitForHostView.java @@ -80,7 +80,18 @@ public class WaitForHostView { spriteBatch.begin(); spriteBatch.draw(backgroundTexture, 0, 0, WordBattle.WIDTH, WordBattle.HEIGHT); - font.draw(spriteBatch, "Test123", 300, 300); + // Text on screen + font.draw(spriteBatch, "Pin: " + pin, WordBattle.WIDTH / 2f, WordBattle.HEIGHT - 50); + + font.draw(spriteBatch, "Waiting for host to start the game...", WordBattle.WIDTH / 2f, 50); + + // Draw the list of players + float startY = WordBattle.HEIGHT / 2f; // Adjust Y as necessary + for (String playerName : playerNames) { + font.draw(spriteBatch, playerName, WordBattle.WIDTH / 2f, startY); + startY -= font.getLineHeight(); // Space the player names out + } + spriteBatch.end(); } diff --git a/desktop/src/com/wordbattle/game/DesktopInterfaceClass.java b/desktop/src/com/wordbattle/game/DesktopInterfaceClass.java index c28ec5ef8c925becd0699bf8aa37bb135fca2ea1..6aca15e58124994c185abd6b7bcaa4acbfef52cb 100644 --- a/desktop/src/com/wordbattle/game/DesktopInterfaceClass.java +++ b/desktop/src/com/wordbattle/game/DesktopInterfaceClass.java @@ -1,6 +1,8 @@ package com.wordbattle.game; +import com.wordbattle.game.model.Category; +import com.wordbattle.game.model.Word; import com.wordbattle.game.network.FirebaseInterface; @@ -27,4 +29,99 @@ public class DesktopInterfaceClass implements FirebaseInterface{ } + @Override + public void startGame(String pin) { + + } + + @Override + public void isHost(String pin, String nickname, HostCheckCallback callback) { + + } + + @Override + public void startRound(String pin) { + + } + + @Override + public void resetRoundFlag(String pin) { + + } + + @Override + public void listenForGameStart(String pin, GameStartCallback callback) { + + } + + @Override + public long getSeed() { + return 0; + } + + @Override + public void fetchWord(String pin, String category, WordFetchCallback callback) { + + } + + @Override + public boolean checkIfAllPlayersAreFinished(String pin) { + return false; + } + + @Override + public void updateFinishedFlag(String nickname, String pin) { + + } + + @Override + public void getPlayerAndScore(String pin, PlayerScoreCallback callback) { + + } + + @Override + public void updateRound(String pin, RoundUpdateCallback callback) { + + } + + @Override + public void fetchRound(String pin, RoundCallback callback) { + + } + + @Override + public void resetFlags(String pin) { + + } + + @Override + public void listenForRoundStarted(String pin, Runnable onRoundStarted) { + + } + + @Override + public void createNewCategory(Category category) { + + } + + @Override + public void addWordToCategory(String categoryName, Word word) { + + } + + @Override + public void addScoreToDatabase(String pin, String nickname) { + + } + + @Override + public void updateScoreInDatabase(String pin, String nickname, int newScore, ScoreUpdateCallback callback) { + + } + + @Override + public void fetchScores(String pin, ScoreFetchCallback callback) { + + } + }