Welcome to Part 4! We're now going to add some dynamic interactivity to your digital pet simulator. In this part, you'll learn about functions, asynchronous operations using
async
and
await, and how to handle potentially null values using Dart's null safety features. This will make your pet simulator more engaging and robust.
Step 1: Creating Functions – feed and play#
Instead of directly modifying the pet's hunger and happiness levels within the
main
function, let's create separate functions for feeding and playing. This makes our code more organized and reusable. Add these functions below your
main
function:
Future<void> feed(int hungerLevel, int happinessLevel) async {
print('Your pet is eating...');
await Future.delayed(Duration(seconds: 2)); // Simulate eating time
print('Your pet finished eating!');
return;
}
Future<void> play(int hungerLevel, int happinessLevel) async {
print('You are playing with your pet...');
await Future.delayed(Duration(seconds: 3)); // Simulate playtime
print('You finished playing with your pet!');
return;
}
Notice the use of
Future<void>. This indicates that the functions are asynchronous and don't return a value.
await Future.delayed()
simulates a delay, making the actions feel more realistic. This illustrates Dart’s asynchronous programming capabilities.
Step 2: Calling Functions from main#
Now, let's call these new functions from your
main
function. Replace the existing hunger and happiness modification code with these calls:
// Inside your main function, after getting the pet's name and hunger/happiness levels:
await feed(petHunger, petHappiness); // Call the feed function
await play(petHunger, petHappiness); // Call the play function
// Update the hunger and happiness levels (You'll need to adjust the values based on feeding/playing):
petHunger -=2;
petHappiness += 3;
The
await
keyword ensures that the
main
function waits for the
feed
and
play
functions to complete before continuing. These will be significantly improved in later steps.
Step 3: Handling Null Values – Robust Input#
Recall that
stdin.readLineSync()
can return
null. Let's add more robust null handling in a more sophisticated way. Replace your existing
petName
assignment with this improved version:
String? petName = stdin.readLineSync()?.trim();
petName ??= 'Buddy'; //Null-aware assignment operator provides a default value if petName is null
The
?.
operator performs a null-aware method call. If
stdin.readLineSync()
returns
null, the
trim()
method won't be called, preventing a potential error. The
??=
operator provides a default value ('Buddy') if
petName
is still null after the null-aware call. This method elegantly handles the null case without multiple if statements.
Step 4: Putting it All Together#
Here’s how your
main
function should look after integrating these changes. Note that at this stage the hunger and happiness levels aren’t dynamically updated. This will be completed in the next part.
import 'dart:io';
Future<void> feed(int hungerLevel, int happinessLevel) async {
print('Your pet is eating...');
await Future.delayed(Duration(seconds: 2));
print('Your pet finished eating!');
}
Future<void> play(int hungerLevel, int happinessLevel) async {
print('You are playing with your pet...');
await Future.delayed(Duration(seconds: 3));
print('You finished playing with your pet!');
}
void main() async {
stdout.write('What would you like to name your pet? ');
String? petName = stdin.readLineSync()?.trim();
petName ??= 'Buddy';
print('Hello, $petName!');
int petHunger = 5;
int petHappiness = 7;
print('${petName}\'s Hunger: $petHunger');
print('${petName}\'s Happiness: $petHappiness');
await feed(petHunger, petHappiness);
await play(petHunger, petHappiness);
if (petHunger > 7) {
print('$petName is very hungry!');
} else if (petHunger > 3) {
print('$petName is a little hungry.');
} else {
print('$petName is not hungry.');
}
if (petHappiness < 3) {
print('$petName is sad.');
} else if (petHappiness < 7) {
print('$petName is okay.');
} else {
print('$petName is happy!');
}
}
Run your code! Now you can interact with your pet through functions and see the simulated delays.
What's Next?#
In the next part, "Advanced Pet Care: Object-Oriented Programming and Class Structure," we will introduce the concept of classes to improve the organization and reusability of our code further, creating a
DigitalPet
class to encapsulate our pet's data and behaviors. Get ready to take your pet simulation to the next level!
