LogoDart Beginner Tutorials

Advanced Controls switch Statements while Loops and Encapsulation

This part introduces switch statements for menu-driven interaction while loops to keep the game running and encapsulation by creating private variables and public getters.

Welcome to Part 5! We're nearing the completion of our Digital Pet simulator. In this part, we'll enhance user interaction and refine our code organization using switch statements, while loops, and the concept of encapsulation.

Understanding switch Statements

switch statements provide a more structured way to handle multiple conditional branches compared to a series of if/else if/else statements, especially when checking a single variable against several possible values. The syntax is as follows:

switch (expression) {
  case value1:
    // Code to execute if expression == value1
    break;
  case value2:
    // Code to execute if expression == value2
    break;
  default:
    // Code to execute if expression doesn't match any case
}

Understanding while Loops

while loops execute a block of code repeatedly as long as a specified condition is true. This is perfect for creating a game loop that continues until the player chooses to exit. The structure is:

while (condition) {
  // Code to execute repeatedly while the condition is true
}

Encapsulation: Protecting Data

Encapsulation is a core OOP principle that involves bundling data (variables) and methods (functions) that operate on that data within a class and controlling access to that data. This improves code organization and prevents accidental modification of internal data. We achieve this in Dart by using underscores before private variable names.

Step 1: Encapsulating hunger and happiness

Let's encapsulate the hunger and happiness variables in our DigitalPet class by making them private:

class DigitalPet {
  // ... other code ...
  int _hunger; // Private variable
  int _happiness; // Private variable
  // ... rest of the class
  int get hunger => _hunger;
  int get happiness => _happiness;
}

The underscore (_) before the variable names indicates that they are private members, only accessible from within the DigitalPet class. We've also added getter methods (hunger and happiness) to provide controlled access to these values from outside the class. These getters simply return the values of the private variables.

Step 2: Implementing a while Loop for the Main Game Loop

Next, we'll restructure our main function to use a while loop to create the main game loop:

void main() async {
  // ... get pet name ...

  DigitalPet myPet = DigitalPet(petName, 5, 5);

  while (true) { // The main game loop continues indefinitely
    // ... add the game logic inside the while loop ...
  }
}

Step 3: Using a switch Statement for User Input

Let's replace our series of if/else if statements with a switch statement to process user input:

  while (true) {
    myPet.displayStatus();

    // ... print menu options ...

    stdout.write('Enter your choice: ');
    String? choice = stdin.readLineSync();

    switch (choice) {
      case '1':
        await myPet.feed();
        break;
      case '2':
        await myPet.play();
        break;
      case '3':
        await myPet.timePasses();
        break;
      case '4':
        print('Goodbye!');
        return;
      default:
        print('Invalid choice.');
    }

    await Future.delayed(Duration(milliseconds: 500));
  }

Now the user can enter a number to select an action.

Step 4: Adding an Exit Condition (Optional)

We can also add an if condition to gracefully exit the loop if certain conditions are met. For instance, your pet might be too sad to continue. In the example code, this is handled in step 6.

Step 5: (Optional) Adding a needsAttention() Method

To make the game more challenging, we can add a method that checks if the pet needs attention. This method will be part of the DigitalPet class. We will check the private variables here.

  bool needsAttention() {
    return _hunger >= 10 || _happiness <= 0;
  }

Step 6: (Optional) Integrating needsAttention()

Now, let's integrate the needsAttention() method into the main function to check the pet's condition and issue warnings.

if (myPet.needsAttention()) {
  print('Warning: ${myPet.name} really needs your attention!');
}

Congratulations! You've successfully implemented advanced control structures and improved code organization using encapsulation! In the final part, Part 6, we'll add some final touches using string interpolation, explore importing libraries, and refine our code for better readability.