Skip to content
Snippets Groups Projects
Commit b55a128e authored by Sixten Müller's avatar Sixten Müller
Browse files

feat: working on score. Non workin atm

parent 480e237d
Branches
No related tags found
2 merge requests!22Resolve "Create game model",!18Draft: Resolve "Create game model"
Showing
with 325 additions and 27 deletions
package com.wordbattle.game;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.MutableData;
import com.google.firebase.database.Transaction;
import com.google.firebase.database.ValueEventListener;
import com.wordbattle.game.model.Category;
import com.wordbattle.game.model.LobbyModel;
......@@ -14,6 +17,8 @@ import com.wordbattle.game.network.FirebaseInterface;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
public class AndroidInterfaceClass implements FirebaseInterface {
......@@ -37,7 +42,6 @@ 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)
......@@ -114,7 +118,74 @@ public class AndroidInterfaceClass implements FirebaseInterface {
});
}
@Override
public void addScoreToDatabase(String pin, String nickname) {
DatabaseReference lobbyRef = FirebaseDatabase.getInstance().getReference("lobbies").child(pin).child("scores");
System.out.println("Inside addInitialScore");
// Initialize score to 0 for the nickname
lobbyRef.child(nickname).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) {
DatabaseReference lobbyRef = FirebaseDatabase.getInstance().getReference("lobbies").child(pin).child("scores").child(nickname);
// Read the current score and update it with the new score
lobbyRef.runTransaction(new Transaction.Handler() {
@NonNull
@Override
public Transaction.Result doTransaction(@NonNull MutableData mutableData) {
Integer currentScore = mutableData.getValue(Integer.class);
if (currentScore == null) {
mutableData.setValue(scoreToAdd); // If there's no score yet, set the new score
} else {
mutableData.setValue(currentScore + scoreToAdd); // Otherwise, add to the current score
}
return Transaction.success(mutableData);
}
@Override
public void onComplete(@Nullable DatabaseError databaseError, boolean committed, @Nullable DataSnapshot dataSnapshot) {
if (committed) {
System.out.println("Score for " + nickname + " updated successfully.");
} else {
System.err.println("Failed to update score for " + nickname + (databaseError != null ? ": " + databaseError.getMessage() : "."));
}
}
});
}
@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
......
......@@ -39,11 +39,18 @@ public class CreateGameController {
}
if (createGameView.getCreateGameBounds().contains(touchPos.x, touchPos.y)) {
if (confirmNickname()) {
state.getStateManager().setState(new LobbyState(state.getStateManager(), createGameView.getPin(), createGameView.getNickname(), _FBIC));
}
}
}
}
public boolean confirmNickname(){
String Nickname = createGameView.getNickname();
//does not allow empty string or only whitespace
return !Nickname.trim().isEmpty();
}
public void update(float dt) {
......
......@@ -6,6 +6,7 @@ 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.WaitingLobbyState;
import com.wordbattle.game.view.CreateGameView;
import com.wordbattle.game.view.GamePlayView;
......@@ -21,16 +22,18 @@ public class GamePlayController {
private String word;
private Character selectedLetter = null;
private int selectedIndex = -1;
private String nickname;
public GamePlayController(GamePlayState state, FirebaseInterface _FBIC, String pin) {
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
// Fetch the word using the PIN and the category
......@@ -70,6 +73,7 @@ public class GamePlayController {
// Update the filledBoxes in the view
gamePlayView.setFilledBoxes(currentFilledBoxes);
gamePlayView.getLetters().remove(i);
checkWordCompletion();
// Log the action
......@@ -94,8 +98,14 @@ public class GamePlayController {
for (int i = 0; i < gamePlayView.getLetterBoxBounds().length; i++) {
if (gamePlayView.getLetterBoxBounds()[i].contains(touchPos.x, touchPos.y)) {
// The i-th box was clicked
// Handle the click, like selecting or deselecting a letter
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
}
}
......@@ -122,8 +132,58 @@ public class GamePlayController {
});
}
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();
int score = calculateScore(gamePlayView.getTimeLeft(), gamePlayView.getMaxTime());
System.out.println("Congratulations! The word is correct: " + userWord);
state.getStateManager().setState(new WaitingLobbyState(state.getStateManager(), _FBIC, nickname, score, 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();
}
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);}
......
......@@ -17,6 +17,7 @@ public class LobbyController {
private LobbyView lobbyView;
private String pin;
private FirebaseInterface _FBIC;
private String hostNickname;
......@@ -24,6 +25,7 @@ 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();
......@@ -45,6 +47,9 @@ public class LobbyController {
});
}
public void setInitialScore() {
_FBIC.addScoreToDatabase(pin, hostNickname);
}
public void handleInput() {
Rectangle startGame = lobbyView.getStartGameButtonBounds();
......@@ -59,7 +64,8 @@ public class LobbyController {
if (startGame.contains(touchPos.x, touchPos.y)) {
_FBIC.startGame(pin);
state.getStateManager().setState(new GamePlayState(state.getStateManager(), _FBIC, pin));
setInitialScore();
state.getStateManager().setState(new GamePlayState(state.getStateManager(), _FBIC, pin, hostNickname));
}
......
......@@ -38,6 +38,7 @@ public class WaitForHostController {
this.waitForHostView = new WaitForHostView(state.getCam(), _FBIC, nickname, pin);
fetchPlayers();
listenForStart();
_FBIC.addScoreToDatabase(pin, nickname);
}
......@@ -58,7 +59,7 @@ public class WaitForHostController {
private void listenForStart() {
_FBIC.listenForGameStart(pin, () -> {
state.getStateManager().setState(new GamePlayState(state.getStateManager(), _FBIC, pin));
state.getStateManager().setState(new GamePlayState(state.getStateManager(), _FBIC, pin, nickname));
});
}
......
......@@ -10,24 +10,31 @@ import com.wordbattle.game.view.WaitingLobbyView;
public class WaitingLobbyController {
WaitingLobbyState state;
WaitingLobbyView waitingLobbyView;
public WaitingLobbyController(WaitingLobbyState state) {
private WaitingLobbyState state;
private WaitingLobbyView waitingLobbyView;
private String nickname;
private int score;
private FirebaseInterface _FBIC;
private String pin;
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();
waitingLobbyView= new WaitingLobbyView(state.getCam());
}
public void handleInput(){
if (Gdx.input.justTouched()) {
/*
state.getStateManager().setState(new MainMenuState(state.getStateManager(), FirebaseInterface _FBIC));
*/
}
public void handleInput(){
}
public void updateScore() {
_FBIC.updateScoreInDatabase(pin, nickname, score);
System.out.println("Score was updated for "+ nickname+ ", score this round: " + score);
}
public void update(float dt){
handleInput();
......
......@@ -2,19 +2,25 @@
package com.wordbattle.game.model;
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 = false;
private Map<String, Integer> scores;
// 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<>();
}
public LobbyModel(String hostNickname, String pin) {
this.hostNickname = hostNickname;
......@@ -22,8 +28,17 @@ public class LobbyModel {
this.playerNicknames = new ArrayList<>(); // Initialize the list of player nicknames
this.playerNicknames.add(hostNickname);
this.gameStarted = false;
this.scores = new HashMap<>(); // Initialize the scores map
scores.put(hostNickname, 0);
}
public Map<String, Integer> getScores() {
return scores;
}
public void setScores(Map<String, Integer> scores) {
this.scores = scores;
}
// Getters and setters
......
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;
}
}
......@@ -4,6 +4,7 @@ import com.wordbattle.game.model.Category;
import com.wordbattle.game.model.Word;
import java.util.List;
import java.util.Map;
public interface FirebaseInterface {
......@@ -44,5 +45,17 @@ public interface FirebaseInterface {
void addWordToCategory(String categoryName, Word word);
void addScoreToDatabase(String pin, String nickname);
void updateScoreInDatabase(String pin, String nickname, int newScore);
void fetchScores(String pin, ScoreFetchCallback callback);
interface ScoreFetchCallback {
void onScoresFetched(Map<String, Integer> scores);
void onError(String error);
}
}
......@@ -30,6 +30,21 @@ public class FirebaseManager implements FirebaseInterface {
}
@Override
public void addScoreToDatabase(String lobbyPin, String nickname) {
}
@Override
public void updateScoreInDatabase(String lobbyPin, String nickname, int newScore) {
}
@Override
public void fetchScores(String pin, ScoreFetchCallback callback) {
}
@Override
public void fetchPlayers(String pin, PlayerListUpdateCallback callback) {
......
......@@ -10,16 +10,22 @@ 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) {
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);
this.controller = new GamePlayController(this, _FBIC, pin, nickname);
this.nickname = nickname;
}
public GamePlayController getController() {
return this.controller;
}
@Override
public void handleInput() {
......
......@@ -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);
}
......
......@@ -41,9 +41,9 @@ public class GamePlayView {
private Rectangle[] letterBoxBounds;
private Rectangle[] letterBounds;
private Character[] filledBoxes;
private float timeLeft;
private float maxTime;
private boolean isTimerRunning;
......@@ -56,7 +56,7 @@ public class GamePlayView {
Gdx.input.setInputProcessor(stage);
// Load BG
backgroundTexture = new Texture("bg2.png");
......@@ -73,9 +73,28 @@ public class GamePlayView {
textFieldStyle.fontColor = Color.WHITE;
shapeRenderer = new ShapeRenderer();
// Set timer
maxTime = 30.0f;
timeLeft = 30.0f; // Starting with 30 seconds for example
isTimerRunning = true; // Start with the timer running
}
// 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) {
......@@ -88,6 +107,7 @@ public class GamePlayView {
public void render(SpriteBatch sb) {
if (letterPool != null) {
letters = letterPool.getLetters();
letterBounds = new Rectangle[letters.size()];
......@@ -119,6 +139,10 @@ public class GamePlayView {
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("%.1f", timeLeft), cam.viewportWidth / 2 - 200, cam.viewportHeight - 200);
sb.end(); // End SpriteBatch
// This is the rects around letters
......@@ -170,8 +194,11 @@ public class GamePlayView {
public Stack<Character> getSelectedLetters() {
return selectedLetters;
}
public ArrayList<Character> getLetters() {
return letters;
}
......@@ -201,4 +228,26 @@ public class GamePlayView {
public void dispose() {
shapeRenderer.dispose();
}
// Timer control methods
public void startTimer() {
isTimerRunning = true;
}
public void stopTimer() {
isTimerRunning = false;
}
public void resetTimer(float newTime) {
timeLeft = newTime;
}
public float getTimeLeft() {
return timeLeft;
}
public float getMaxTime() {
return maxTime;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment