This commit is contained in:
ipvg 2024-08-11 22:35:04 -04:00
parent 32ed18870c
commit 8d6b17b617
7 changed files with 592 additions and 0 deletions

View File

@ -0,0 +1,297 @@
# Challenge project
## Create a mini-game
Demonstrate your ability to create and use different methods to develop
features for a console mini-game.
### Learning objectives
- Develop a C# console application that uses methods to implement logical
workflows.
- Understand existing code and make informed changes to design.
- Create return values as well as required and optional parameters in methods.
## Introduction
Creating your own game is an exciting way to practice your programming skills.
Games rely heavily on processing user input to make dynamic decisions. Every
game must also have a set of defined rules that determine actions and events in
the game.
Suppose you want to create your own game. You might not be ready to develop a
fully featured game, so you decide to start as small as possible. You want to
move a character across the screen and make it consume an object. The object
consume can affect the state of the player. To keep the game going, you wanted
to regenerate the object in a new location once it has been consumed. You
decide that you'll need to use methods to keep your game code organized.
In this module, you'll develop the following features of a mini-game
application:
- A feature to determine if the player consumed the food
- A feature that updates player status depending on the food consumed
- A feature that pauses movement speed depending on the food consumed
- A feature to regenerate food in a new location
- An option to terminate the game if an unsupported character is pressed
- A feature to terminate the game if the Terminal window was resized
By the end of this module, you'll create a playable mini-game application!
> Note
> This is a challenge project module where you'll complete an end-to-end
project from a specification. This module is intended to be a test of your
skills; theres little guidance and no step-by-step instructions.
#### Learning objectives
In this module, you'll demonstrate your ability to:
- Use Visual Studio Code to develop a C# console application that uses methods
to implement logical workflows.
- Understand existing code and make informed changes to design.
- Create return values and methods with required and optional parameters.
---
## Prepare for challenge
You'll be using Visual Studio Code to develop a small mini-game. Your
application should establish the basics of the game, including updating player
state, manipulating player movement, and consuming and regenerating a food
object. You'll develop each of those features and run a simplified game test.
### Project specification
The Starter code project for this module includes a Program.cs file with the
following code features:
```txt
- The code declares the following variables:
- Variables to determine the size of the Terminal window.
- Variables to track the locations of the player and food.
- Arrays `states` and `foods` to provide available player and food appearances
- Variables to track the current player and food appearance
- The code provides the following methods:
- A method to determine if the Terminal window was resized.
- A method to display a random food appearance at a random location.
- A method that changes the player appearance to match the food consumed.
- A method that temporarily freezes the player movement.
- A method that moves the player according to directional input.
- A method that sets up the initial game state.
- The code doesn't call the methods correctly to make the game playable. The following features are missing:
- Code to determine if the player has consumed the food displayed.
- Code to determine if the food consumed should freeze player movement.
- Code to determine if the food consumed should increase player movement.
- Code to increase movement speed.
- Code to redisplay the food after it's consumed by the player.
- Code to terminate execution if an unsupported key is entered.
- Code to terminate execution if the terminal was resized.
```
Your goal in this challenge is to use the existing features and create the
missing features to make the game playable.
### Setup
Use the following steps to prepare for the Challenge project exercises:
To download a zip file containing the Starter project code, select the
following link:
[Lab Files](https://github.com/MicrosoftLearning/Challenge-project-Create-methods-in-CSharp/archive/refs/heads/main.zip).
Unzip the download files.
You're now ready to begin the Challenge project exercises. Good luck!
---
## Exercise - Add code to end the game
Your goal is to develop a mini-game application. You need the game to end if
the user resized the Console window the game is running in. You also want to
add an option for the game to end if the user enters any nondirectional
character.
### Specification
In this challenge exercise, you need to update the existing code to support an
option to terminate the gameplay if a nondirectional character is entered. You
also want to terminate the game if the terminal window was resized. You need to
locate the correct methods for your code to use.
#### Terminate on resize
This feature must:
- Determine if the terminal was resized before allowing the game to continue
- Clear the Console and end the game if the terminal was resized
- Display the following message before ending the program: Console was resized. Program exiting.
#### Add optional termination
- Modify the existing `Move` method to support an optional parameter
- If enabled, the optional parameter should detect nondirectional key input
- If nondirectional input is detected, allow the game to terminate
### Check your work
To validate that your code satisfies the specified requirements, complete the
following steps:
At the Terminal command prompt, resize the window.
Enter a directional key.
Verify that the program ends after displaying the following message:
```txt
Console was resized. Program exiting.
```
Run the app again.
At the Terminal command prompt, press directional keys to move the player.
Press a nondirectional key.
Verify that the program ends.
Disable the optional parameter, then build and run the app.
At the Terminal command prompt, press directional keys to move the player.
Press a nondirectional key.
Verify that the program continues.
Resize the Terminal window.
Verify that the program ends.
Once you've validated the results for this exercise, proceed to the next
exercise in this challenge.
---
## Exercise
### Make the player consume food
Your goal is to develop a mini-game application. The mini-game displays food
that the player can consume. You need to detect if the player has successfully
consumed the food, and if so, redisplay the food. You also want to change the
player appearance depending on what food was consumed.
### Specification
In this challenge exercise, you need to create a method that determines if the
player has consumed the food that was displayed. If the food was consumed, you
want to update the player's appearance and redisplay the food.
#### Check if the player consumed the food
- Create a method that uses the existing position variables of the player and food
- The method should return a value
- After the user moves the character, call your method to determine the following:
- Whether or not to use the existing method that changes player appearance
- Whether or not to use the existing method to redisplay the food
### Check your work
To validate that your code satisfies the specified requirements, complete the
following steps:
At the Terminal command prompt, press directional keys to move the player.
Move the player across the displayed food string.
Verify that a new food string is displayed.
Verify that the player appearance changes depending on which food string was
consumed.
Once you've validated the results for this exercise, proceed to the next
exercise in this challenge.
---
## Exercise
### Add code to modify movement
Your goal is to develop a mini-game application. Currently, your mini-game has
some basic gameplay capabilities! It terminates correctly, detects when the
player consumes food, changes the player appearance, and displays more food.
Now you want the food the player consumes to affect the player's ability to
move.
### Specification
In this challenge exercise, you need to create a method that determines if the
player has consumed the food that affects their movement. When the player
consumes the food string with value `#####,` the appearance is updated to
`(X_X)`. You'll add a feature to detect if the player appearance is `(X_X)`, and
if so, temporarily prevent the player from moving.
You also want to add an optional feature that detects if the player appearance
is `(^-^)` and if so, increase or decrease the right and left movement speeds
by a value of `3` while that appearance is active. When the player state is
`('-')`, you want the speed to return to normal. You want to make this feature
optional since consuming food in this state requires more collision detection
than you want to develop for now.
#### Check if the player should freeze
- Create a method that checks if the current player appearance is `(X_X)`
- The method should return a value
- Before allowing the user to move the character, call your method to determine the following:
- Whether or not to use the existing method that freezes character movement
- Make sure the character is only frozen temporarily and the player can still move afterwards
#### Add an option to increase player speed
- Modify the existing `Move` method to support an optional movement speed
parameter
- Use the parameter to increase or decrease right and left movement speed by `3`
- Create a method that checks if the current player appearance is `(^-^)`
- The method should return a value
- Call your method to determine if `Move` should use the movement speed
parameter
### Check your work
To validate that your code satisfies the specified requirements, complete the
following steps:
Enable the optional parameters.
At the Terminal command prompt, press directional keys to move the player.
Move the player across the displayed food string.
Verify that a new food string is displayed.
Verify that the player appearance changes depending on which food string was
consumed.
Verify that movement is temporarily stopped when the player appearance is
`(X_X)`.
Verify that left and right movement is faster in the correct directions when
the player appearance is `(^-^)`.
Press a nondirectional key to terminate the program.
Disable the optional movement speed parameter and rerun the app.
Verify that movement is normal when the player appearance is `(^-^)`.
Congratulations if you succeeded in this challenge!
---

View File

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@ -0,0 +1,144 @@
using System;
Random random = new Random();
Console.CursorVisible = false;
int height = Console.WindowHeight - 1;
int width = Console.WindowWidth - 5;
bool should_exit = false;
// Console position of the player
int player_x = 0;
int player_y = 0;
// Console position of the food
int food_x = 0;
int food_y = 0;
// Available player and food strings
string[] states = { "('-')", "(^-^)", "(X_X)" };
string[] foods = { "@@@@@", "$$$$$", "#####" };
// Current player string displayed in the Console
string player = states[0];
// Index of the current food
int food = 0;
initialize_game();
while (!should_exit) {
if (terminal_resized()) {
Console.Clear();
Console.Write("Console was resized. Program exiting.");
should_exit = true;
} else {
if (player_is_faster()) {
move(1, false);
} else if (player_is_sick()) {
freeze_player();
} else {
move(otherKeysExit: false);
}
if (got_food()) {
change_player();
show_food();
}
}
}
// Returns true if the Terminal was resized
bool terminal_resized() {
return height != Console.WindowHeight - 1 ||
width != Console.WindowWidth - 5;
}
// Displays random food at a random location
void show_food() {
// Update food to a random index
food = random.Next(0, foods.Length);
// Update food position to a random location
food_x = random.Next(0, width - player.Length);
food_y = random.Next(0, height - 1);
// Display the food at the location
Console.SetCursorPosition(food_x, food_y);
Console.Write(foods[food]);
}
// Returns true if the player location matches the food location
bool got_food() {
return player_y == food_y && player_x == food_x;
}
// Returns true if the player appearance represents a sick state
bool player_is_sick() {
return player.Equals(states[2]);
}
// Returns true if the player appearance represents a fast state
bool player_is_faster() {
return player.Equals(states[1]);
}
// Changes the player to match the food consumed
void change_player() {
player = states[food];
Console.SetCursorPosition(player_x, player_y);
Console.Write(player);
}
// Temporarily stops the player from moving
void freeze_player() {
System.Threading.Thread.Sleep(1000);
player = states[0];
}
// Reads directional input from the Console and moves the player
void move(int speed = 1, bool otherKeysExit = false) {
int last_x = player_x;
int last_y = player_y;
switch (Console.ReadKey(true).Key) {
case ConsoleKey.UpArrow:
player_y--;
break;
case ConsoleKey.DownArrow:
player_y++;
break;
case ConsoleKey.LeftArrow:
player_x -= speed;
break;
case ConsoleKey.RightArrow:
player_x += speed;
break;
case ConsoleKey.Escape:
should_exit = true;
break;
default:
// Exit if any other keys are pressed
should_exit = otherKeysExit;
break;
}
// Clear the characters at the previous position
Console.SetCursorPosition(last_x, last_y);
for (int i = 0; i < player.Length; i++) {
Console.Write(" ");
}
// Keep player position within the bounds of the Terminal window
player_x = (player_x < 0) ? 0 : (player_x >= width ? width : player_x);
player_y = (player_y < 0) ? 0 : (player_y >= height ? height : player_y);
// Draw the player at the new location
Console.SetCursorPosition(player_x, player_y);
Console.Write(player);
}
// Clears the console, displays the food and player
void initialize_game() {
Console.Clear();
show_food();
Console.SetCursorPosition(0, 0);
Console.Write(player);
}

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2023 Microsoft Learning
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,109 @@
using System;
Random random = new Random();
Console.CursorVisible = false;
int height = Console.WindowHeight - 1;
int width = Console.WindowWidth - 5;
bool should_exit = false;
// Console position of the player
int player_x = 0;
int player_y = 0;
// Console position of the food
int food_x = 0;
int food_y = 0;
// Available player and food strings
string[] states = { "('-')", "(^-^)", "(X_X)" };
string[] foods = { "@@@@@", "$$$$$", "#####" };
// Current player string displayed in the Console
string player = states[0];
// Index of the current food
int food = 0;
initialize_game();
while (!should_exit) {
move();
}
// Returns true if the Terminal was resized
bool terminal_resized() {
return height != Console.WindowHeight - 1 ||
width != Console.WindowWidth - 5;
}
// Displays random food at a random location
void show_food() {
// Update food to a random index
food = random.Next(0, foods.Length);
// Update food position to a random location
food_x = random.Next(0, width - player.Length);
food_y = random.Next(0, height - 1);
// Display the food at the location
Console.SetCursorPosition(food_x, food_y);
Console.Write(foods[food]);
}
// Changes the player to match the food consumed
void change_player() {
player = states[food];
Console.SetCursorPosition(player_x, player_y);
Console.Write(player);
}
// Temporarily stops the player from moving
void freeze_player() {
System.Threading.Thread.Sleep(1000);
player = states[0];
}
// Reads directional input from the Console and moves the player
void move() {
int last_x = player_x;
int last_y = player_y;
switch (Console.ReadKey(true).Key) {
case ConsoleKey.UpArrow:
player_y--;
break;
case ConsoleKey.DownArrow:
player_y++;
break;
case ConsoleKey.LeftArrow:
player_x--;
break;
case ConsoleKey.RightArrow:
player_x++;
break;
case ConsoleKey.Escape:
should_exit = true;
break;
}
// Clear the characters at the previous position
Console.SetCursorPosition(last_x, last_y);
for (int i = 0; i < player.Length; i++) {
Console.Write(" ");
}
// Keep player position within the bounds of the Terminal window
player_x = (player_x < 0) ? 0 : (player_x >= width ? width : player_x);
player_y = (player_y < 0) ? 0 : (player_y >= height ? height : player_y);
// Draw the player at the new location
Console.SetCursorPosition(player_x, player_y);
Console.Write(player);
}
// Clears the console, displays the food and player
void initialize_game() {
Console.Clear();
show_food();
Console.SetCursorPosition(0, 0);
Console.Write(player);
}

View File

@ -0,0 +1,10 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@ -35,3 +35,4 @@ Following
28. [Methods with parameters](./028_method_parameters/028_csharp.md) 28. [Methods with parameters](./028_method_parameters/028_csharp.md)
29. [Methods that return values](./029_return_value_method/029_csharp.md) 29. [Methods that return values](./029_return_value_method/029_csharp.md)
30. [Guided project - Plan a Petting Zoo](./030_project_petting_zoo/030_csharp.md) 30. [Guided project - Plan a Petting Zoo](./030_project_petting_zoo/030_csharp.md)
31. [Challenge project - Create a mini-game](./031_Challenge_mini_game/031_csharp.md)