Score.java - Score Display

The Score class manages the game scoreboard, tracking points for both players and rendering the score display with a center divider line.

Purpose: Tracks player scores and renders the scoreboard display with proper formatting and visual design.

Source Code

 1import java.awt.*;
 2
 3public class Score extends Rectangle{
 4    static int GAME_WIDTH;
 5    static int GAME_HEIGHT;
 6    int player1;
 7    int player2;
 8
 9    Score(int GAME_WIDTH, int GAME_HEIGHT){
10        Score.GAME_WIDTH = GAME_WIDTH;
11        Score.GAME_HEIGHT = GAME_HEIGHT;
12    }
13    
14    public void draw(Graphics g){
15        g.setColor(Color.white);
16        g.setFont(new Font("Consolas", Font.PLAIN, 60));
17        g.drawLine(GAME_WIDTH/2, 0, GAME_WIDTH/2, GAME_HEIGHT);
18        g.drawString(String.valueOf(player1/10)+String.valueOf(player1%10), (GAME_WIDTH/2)-85, 50);
19        g.drawString(String.valueOf(player2/10)+String.valueOf(player2%10), (GAME_WIDTH/2)+20, 50);
20    }
21}

Code Analysis

Class Design

Static Field Usage
1static int GAME_WIDTH;
2static int GAME_HEIGHT;

Static Fields for Dimensions:

  • Shared State: All Score instances use same game dimensions
  • Memory Efficiency: Only one copy of dimensions needed
  • Global Access: Can be accessed without instance reference
  • Initialization: Set once in constructor, used in drawing

Constructor Assignment:

1Score(int GAME_WIDTH, int GAME_HEIGHT){
2    Score.GAME_WIDTH = GAME_WIDTH;    // Assign to static field
3    Score.GAME_HEIGHT = GAME_HEIGHT;  // Using class name prefix
4}
Score Storage
1int player1;  // Player 1's current score
2int player2;  // Player 2's current score

Score Management:

  • Integer Counters: Simple increment system
  • Default Initialization: Both start at 0
  • Public Access: GamePanel directly modifies these fields
  • No Upper Limit: Scores can increment indefinitely

Rendering System

Visual Layout Design
 1public void draw(Graphics g){
 2    g.setColor(Color.white);
 3    g.setFont(new Font("Consolas", Font.PLAIN, 60));
 4    
 5    // Center divider line
 6    g.drawLine(GAME_WIDTH/2, 0, GAME_WIDTH/2, GAME_HEIGHT);
 7    
 8    // Player scores positioned relative to center
 9    g.drawString(player1Score, (GAME_WIDTH/2)-85, 50);  // Left of center
10    g.drawString(player2Score, (GAME_WIDTH/2)+20, 50);  // Right of center
11}

Layout Elements:

  1. Center Line: Vertical divider separating player sides
  2. Font Choice: “Consolas” monospace font for consistent character width
  3. Font Size: Large 60pt for clear visibility during gameplay
  4. Positioning: Scores positioned symmetrically around center line
Score Formatting Logic
1String.valueOf(player1/10) + String.valueOf(player1%10)

Two-Digit Display System:

  • Tens Digit: player1/10 - Integer division gives tens place
  • Ones Digit: player1%10 - Modulo gives remainder (ones place)
  • Always 2 Digits: Ensures “05” instead of “5” for single digits
  • String Concatenation: Combines digits into display string

Examples:

1Score = 7:  7/10=0, 7%10=7   "0" + "7" = "07"
2Score = 15: 15/10=1, 15%10=5  "1" + "5" = "15"
3Score = 23: 23/10=2, 23%10=3  "2" + "3" = "23"

Graphics Programming Concepts

Font and Typography
1g.setFont(new Font("Consolas", Font.PLAIN, 60));

Font Configuration:

  • Font Family: “Consolas” - monospace font for digital aesthetic
  • Font Style: Font.PLAIN - no bold or italic styling
  • Font Size: 60 points - large enough for game visibility
  • Monospace Advantage: All digits have same width for consistent alignment

Alternative Font Options:

1new Font("Arial", Font.BOLD, 60);        // Bold sans-serif
2new Font("Courier New", Font.PLAIN, 60); // Alternative monospace
3new Font(Font.MONOSPACED, Font.PLAIN, 60); // System default monospace
Coordinate System
1// Center line coordinates
2g.drawLine(GAME_WIDTH/2, 0, GAME_WIDTH/2, GAME_HEIGHT);
3
4// Score positioning
5g.drawString(score, (GAME_WIDTH/2)-85, 50);  // Player 1
6g.drawString(score, (GAME_WIDTH/2)+20, 50);  // Player 2

Positioning Strategy:

  • Center Reference: All positioning relative to GAME_WIDTH/2
  • Vertical Line: From top (y=0) to bottom (y=GAME_HEIGHT)
  • Text Baseline: Y=50 positions text near top of screen
  • Horizontal Offset: -85 and +20 create symmetric spacing around center

Integration with Game System

Score Updates

The GamePanel updates scores directly when goals occur:

 1// In GamePanel.checkCollision():
 2if(ball.x <= 0) {
 3    score.player2++;  // Player 2 scores
 4    newPaddles();
 5    newBall();
 6    System.out.println("Player 2: " + score.player2);
 7}
 8if(ball.x >= GAME_WIDTH - BALL_DIAMETER) {
 9    score.player1++;  // Player 1 scores  
10    newPaddles();
11    newBall();
12    System.out.println("Player 1: " + score.player1);
13}

Scoring Logic:

  • Left Goal: Ball exits left side → Player 2 scores
  • Right Goal: Ball exits right side → Player 1 scores
  • Immediate Update: Score incremented directly
  • Game Reset: New ball and paddles created after each goal

Design Patterns and Architecture

Observer Pattern (Implicit)

  • Score Display: Automatically reflects current game state
  • No Notifications: Direct field access instead of events
  • Simple Coupling: GamePanel modifies, Score displays

Utility Class Pattern

  • Single Responsibility: Only handles score display
  • Stateless Rendering: Draw method has no side effects
  • Configuration Storage: Holds display parameters

Enhancement Ideas

Advanced Score Features
 1public class EnhancedScore extends Rectangle {
 2    private int player1, player2;
 3    private int winningScore = 11;
 4    private long lastScoreTime;
 5    private boolean gameWon = false;
 6    private String winnerName = "";
 7    
 8    public void incrementPlayer1() {
 9        player1++;
10        lastScoreTime = System.currentTimeMillis();
11        checkForWin();
12    }
13    
14    public void incrementPlayer2() {
15        player2++;
16        lastScoreTime = System.currentTimeMillis();
17        checkForWin();
18    }
19    
20    private void checkForWin() {
21        if(player1 >= winningScore) {
22            gameWon = true;
23            winnerName = "Player 1";
24        } else if(player2 >= winningScore) {
25            gameWon = true;
26            winnerName = "Player 2";
27        }
28    }
29    
30    public void draw(Graphics g) {
31        // Draw normal score
32        drawScore(g);
33        
34        // Flash recent scores
35        if(System.currentTimeMillis() - lastScoreTime < 1000) {
36            g.setColor(Color.YELLOW);
37            // Highlight recent score
38        }
39        
40        // Display winner
41        if(gameWon) {
42            g.setColor(Color.GREEN);
43            g.setFont(new Font("Arial", Font.BOLD, 40));
44            g.drawString(winnerName + " Wins!", GAME_WIDTH/2 - 100, 150);
45        }
46    }
47}
Visual Improvements
 1public void draw(Graphics g) {
 2    // Gradient background for score area
 3    Graphics2D g2d = (Graphics2D) g;
 4    GradientPaint gradient = new GradientPaint(
 5        0, 0, Color.BLACK,
 6        0, 80, new Color(30, 30, 30)
 7    );
 8    g2d.setPaint(gradient);
 9    g2d.fillRect(0, 0, GAME_WIDTH, 80);
10    
11    // Animated center line
12    g.setColor(Color.WHITE);
13    for(int i = 0; i < GAME_HEIGHT; i += 20) {
14        if((System.currentTimeMillis() / 100 + i) % 40 < 20) {
15            g.fillRect(GAME_WIDTH/2 - 2, i, 4, 10);
16        }
17    }
18    
19    // Shadow effect for text
20    g.setFont(new Font("Consolas", Font.BOLD, 60));
21    g.setColor(Color.DARK_GRAY);
22    g.drawString(player1String, (GAME_WIDTH/2)-83, 52); // Shadow
23    g.setColor(Color.WHITE);
24    g.drawString(player1String, (GAME_WIDTH/2)-85, 50); // Main text
25}

Study Questions

  1. Memory Management: Why use static fields for game dimensions?
  2. String Formatting: What’s the purpose of the complex score formatting logic?
  3. Architecture: How could you implement score limits or win conditions?
  4. Performance: Is creating new Font objects every frame efficient?

Common Issues and Solutions

Potential Issues:

  1. Large Numbers: Score formatting breaks for scores > 99
  2. Font Loading: Font may not be available on all systems
  3. Performance: String concatenation in drawing loop
  4. Positioning: Hard-coded offsets may not work with different fonts

Solutions:

  1. Use String.format("%02d", score) for better formatting
  2. Check font availability and provide fallbacks
  3. Pre-format score strings outside draw method
  4. Calculate text bounds for dynamic positioning

Summary: This completes the Pong game architecture! The Score class demonstrates simple state management, string formatting, and graphics programming concepts essential for game UI development.