From 939b0425b02a773c062cd2f6a2ed4f45b4112c84 Mon Sep 17 00:00:00 2001 From: Alexander Doerflinger Date: Tue, 3 Feb 2026 10:38:54 +0100 Subject: [PATCH] Added rudimentary "Bust" Animation --- app/build.gradle.kts | 4 + .../aldo/apps/ochecompanion/GameActivity.java | 80 +++++++++++++++++-- app/src/main/res/layout/activity_game.xml | 11 ++- 3 files changed, 87 insertions(+), 8 deletions(-) diff --git a/app/build.gradle.kts b/app/build.gradle.kts index a688c31..10ec71b 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -33,6 +33,10 @@ android { } } +base { + archivesName.set("OcheCompanion") +} + dependencies { implementation(libs.appcompat) implementation(libs.material) diff --git a/app/src/main/java/com/aldo/apps/ochecompanion/GameActivity.java b/app/src/main/java/com/aldo/apps/ochecompanion/GameActivity.java index d8c86bc..ff59e88 100644 --- a/app/src/main/java/com/aldo/apps/ochecompanion/GameActivity.java +++ b/app/src/main/java/com/aldo/apps/ochecompanion/GameActivity.java @@ -123,6 +123,12 @@ public class GameActivity extends BaseActivity { */ private boolean mIsTurnOver = false; + /** + * Flag indicating the current turn resulted in a bust. + * Used to prevent UI from subtracting bust darts from the score display. + */ + private boolean mIsBustedTurn = false; + /** * Helper class to track dart hit details for statistics. */ @@ -183,6 +189,11 @@ public class GameActivity extends BaseActivity { * Visible when score ≤170 and route is available. */ private LinearLayout layoutCheckoutSuggestion; + + /** + * The Container for displaying the current score. + */ + private LinearLayout mScoreContainer; /** * Button for selecting single (1×) multiplier. @@ -199,6 +210,16 @@ public class GameActivity extends BaseActivity { */ private View btnTriple; + /** + * Overlay to be shown when the player busted. + */ + private View mBustOverlay; + + /** + * The Button to submit a turn. + */ + private MaterialButton mSubmitTurnBtn; + /** * The Button to open the stats view. */ @@ -329,6 +350,7 @@ public class GameActivity extends BaseActivity { outState.putInt("startingScore", mStartingScore); outState.putString("matchUuid", mMatchUuid); outState.putBoolean("isTurnOver", mIsTurnOver); + outState.putBoolean("isBustedTurn", mIsBustedTurn); // Save current turn darts int[] dartsArray = new int[mCurrentTurnDarts.size()]; @@ -382,6 +404,7 @@ public class GameActivity extends BaseActivity { mStartingScore = savedInstanceState.getInt("startingScore", DartsConstants.DEFAULT_GAME_SCORE); mMatchUuid = savedInstanceState.getString("matchUuid"); mIsTurnOver = savedInstanceState.getBoolean("isTurnOver", false); + mIsBustedTurn = savedInstanceState.getBoolean("isBustedTurn", false); // Restore current turn darts mCurrentTurnDarts.clear(); @@ -443,6 +466,9 @@ public class GameActivity extends BaseActivity { tvDartPills[0] = findViewById(R.id.tvDart1); tvDartPills[1] = findViewById(R.id.tvDart2); tvDartPills[2] = findViewById(R.id.tvDart3); + mBustOverlay = findViewById(R.id.bust_pulse_overlay); + mSubmitTurnBtn = findViewById(R.id.btnSubmitTurn); + mScoreContainer = findViewById(R.id.scoreContainer); glKeyboard = findViewById(R.id.glKeyboard); @@ -458,7 +484,7 @@ public class GameActivity extends BaseActivity { }); - findViewById(R.id.btnSubmitTurn).setOnClickListener(v -> submitTurn()); + mSubmitTurnBtn.setOnClickListener(v -> submitTurn()); findViewById(R.id.btnUndoDart).setOnClickListener(v -> undoLastDart()); } @@ -540,10 +566,11 @@ public class GameActivity extends BaseActivity { updateTurnIndicators(); mIsTurnOver = true; + mIsBustedTurn = true; if (mIsAudioEnabled) { mSoundEngine.playBustedSound(); } - Toast.makeText(this, "BUST!", Toast.LENGTH_SHORT).show(); + triggerBustSequence(); // In a pro interface, we usually wait for "Submit" or auto-submit after a short delay } else if (scoreAfterDart == 0 && isDouble) { // VICTORY CONDITION @@ -571,6 +598,39 @@ public class GameActivity extends BaseActivity { setMultiplier(DartsConstants.MULTIPLIER_SINGLE); } + private void triggerBustSequence() { + mIsTurnOver = true; + mIsBustedTurn = true; + + // Visual feedback: Shake scoreboard + Animation shake = AnimationUtils.loadAnimation(this, R.anim.shake); + mScoreContainer.startAnimation(shake); + + // Change scoreboard to Red + mScoreContainer.setBackgroundColor(Color.parseColor("#33FF3B30")); + tvScorePrimary.setTextColor(ContextCompat.getColor(this, R.color.double_red)); + + // Pulsing red overlay on input + mBustOverlay.setVisibility(View.VISIBLE); + Animation pulse = new AlphaAnimation(0.2f, 0.5f); + pulse.setDuration(500); + pulse.setRepeatMode(Animation.REVERSE); + pulse.setRepeatCount(Animation.INFINITE); + mBustOverlay.startAnimation(pulse); + + mSubmitTurnBtn.setText("NEXT PLAYER (BUST)"); + updateTurnIndicators(); + } + + private void resetVisuals() { + mScoreContainer.setBackgroundColor(ContextCompat.getColor(this, R.color.surface_primary)); + tvScorePrimary.setTextColor(ContextCompat.getColor(this, R.color.volt_green)); + mBustOverlay.clearAnimation(); + mBustOverlay.setVisibility(View.GONE); + mSubmitTurnBtn.setText(R.string.txt_game_btn_submit); + } + + /** * Handler for Bull button tap. Delegates to onNumberTap with base value 25. * @@ -659,6 +719,7 @@ public class GameActivity extends BaseActivity { * Updates player score (unless bust), rotates to next player, resets turn state. */ private void submitTurn() { + resetVisuals(); // Don't submit if no darts thrown if (mCurrentTurnDarts.isEmpty()) return; @@ -694,10 +755,9 @@ public class GameActivity extends BaseActivity { } } - // Re-check logic for non-double finish or score of 1 - int lastDartValue = mCurrentTurnDarts.get(mCurrentTurnDarts.size() - 1); - // Note: this check is redundant but safe for manual "Submit" actions - boolean isBust = (finalScore < 0 || finalScore == 1 || (finalScore == 0 && !isFinishDart(mCurrentTurnDarts.size() - 1))); + // Use the mIsBustedTurn flag that was set in onNumberTap when the bust was detected + // This is more reliable than recalculating since it tracks the actual multiplier used + boolean isBust = mIsBustedTurn; // Update score only if not bust if (!isBust) { @@ -717,6 +777,7 @@ public class GameActivity extends BaseActivity { mCurrentTurnDarts.clear(); mCurrentTurnDartHits.clear(); mIsTurnOver = false; + mIsBustedTurn = false; // Update UI for next player updateUI(); @@ -756,10 +817,12 @@ public class GameActivity extends BaseActivity { // Allow turn to continue mIsTurnOver = false; + mIsBustedTurn = false; // Update displays updateTurnIndicators(); updateUI(); + resetVisuals(); } } @@ -782,8 +845,11 @@ public class GameActivity extends BaseActivity { tvLegAvg.setText(String.format("AVG: %.1f", avg)); // Calculate current target (remaining score minus current turn darts) + // If it's a busted turn, don't subtract the bust darts from the display int turnPointsSoFar = 0; - for (int d : mCurrentTurnDarts) turnPointsSoFar += d; + if (!mIsBustedTurn) { + for (int d : mCurrentTurnDarts) turnPointsSoFar += d; + } int currentTarget = active.remainingScore - turnPointsSoFar; int dartsRemaining = 3 - mCurrentTurnDarts.size(); diff --git a/app/src/main/res/layout/activity_game.xml b/app/src/main/res/layout/activity_game.xml index b7b1dbc..9c06492 100644 --- a/app/src/main/res/layout/activity_game.xml +++ b/app/src/main/res/layout/activity_game.xml @@ -157,6 +157,15 @@ + + @@ -198,7 +208,6 @@ android:id="@+id/player_stats_view" android:layout_width="match_parent" android:layout_height="match_parent" - android:layout_marginTop="15dp" android:visibility="gone"/> \ No newline at end of file