This article compares a game written in Scratch to the same game written in C#. The objective is to show the difference between a visual block language to a common professional computer language.
Introduction
Anyone with school kids in their family have heard about the Scratch - the visual programming language for children. The language was developed by the MIT Media Lab to encourage young people to develop computer skills. The Scratch website has over 64,000,000 registered users. Many of them when they grow up will join CodeProject. Having my own grandchildren, I downloaded the Scratch application from the MIT website. I purchased the “Coding Games in Scratch” book by Jon Woodcock. Together with my grandson, we tried some of the games. One of the games is “Tropical Tunes”. I modified it to my liking. Then I decided to rewrite it in C#. My objective was to show the difference between a visual block language to a common professional computer language. This article highlights the extra development effort involved in writing a C# type language.
The Tropical Tunes Game
The Tropical Tunes is a memory game. There are four drums. Each has a different tune. The program plays a random sequence of drums (or tunes). The player must repeat the sequence. The game starts with a sequence of one tune and ends with seven tunes. If the player is successful, the next sequence is played. If the player makes an error, the game ends. Each correct response adds one to the score. With seven games from one to seven tunes, the perfect score is 28.
The Scratch Program
My version of the Scratch program TropicalTunes.sb3 is attached to this article. The program code is shown later in the article. To see the Scratch version of the game in action, go to the Scratch MIT website, select Create and run it in your web browser. Or go to Scratch download website and install the scratch app to your machine. In both cases, click on File and Load from your computer and navigate to the TropicalTunes.sb3 file.
If you find it hard to memorize seven notes, as I do, press up arrow and the list of notes will be displayed. Pressing down arrow will hide the list. Just don’t tell anyone.
A note to hackers. The .sb3 file is a .zip file. If you change the extension to .zip, you can see the incorporated files. The names of the files are random sequence of hex digits. The file list is made of resources files and one project.json file. The resources file extensions are what you would expect. If you double click on any of them, you will see or hear the resource content. For .svg files, you will need vector graphics editor such as Inkscape. If you open the project.json file with Visual Studio and go to Edit, Advanced and Format Document, you can read it.
Developing Tropical Tunes in C#
The main difference between C# development and Scratch development is the availability of image and audio resources. The Scratch environment provides many choices of background images (called stages), sprites images, and audio clips. To develop a similar game with C#, you need to create or acquire these images and audio clips yourself. Images will typically be .jpg, .bmp, or .png files and audio clips will be .wav files. Sometimes, it is convenient to create an image in vector format .svg. However, at the end, the image must be exported as a .png file.
Background Image or Stage in Scratch Lingo
For background image, I wanted an image with aspect ratio of 16:9 and resolution of 2560 by 1440. If you go to Google Images and type “tropical Paradise 2560 by 1440”, you will find many image files to choose from. My choice was this picture from Pinterest website.
Drums
For drums, the program needs eight images. Four normal size drums each with a different color scheme and four matching larger drums. When a drum is played, the program replaces the normal size with a larger drum. I found it convenient to look for one vector graphics drum that can be easily modified by a vector graphics editor to produce all the eight drums. Vector graphics images have .svg extensions. My vector graphics editor is Inkscape. For more information, go to inkscape website. I found suitable drum at FREE*SVG website. For each drum, I saved the modified vector graphics image and exported a .png file as the resource file. The vector graphics files are attached even though they are not needed to run the program.
Original drum | |
Normal drum | |
Active drum | |
Audio Clips Resources
Unlike images, audio samples are not easily available on the Internet. I was not able to find suitable .wav files for this project. The Scratch application has Add Extension option. One of the choices is Music Play instruments and drums. I wrote a four lines program to play four drum notes. I downloaded Audacity, a free audio editing program, from Audacity website. While Scratch was playing the four notes, Audacity was recording the sound. Next, I used Audacity to break the sound clip into four distinct .wav files. One for each note.
Audacity four drum notes
Embedding Image and Audio files into the Executable File
Once you have your image files and audio files resources, you want to embed them into the executable file.
- Load the resources files into the Resources directory of your project
- In Solution Explorer, right click the project and select Properties.
- Select Resources.
- In the first tab, select Images.
- In the second tab, Add Resources, select Add Existing File.
- Select all image files.
- Go back to the first tab and select Audio.
- Repeat the previous two steps for audio files.
- Open the Resources folder in Solution Explorer. All your resource files should be there.
- Select all the files in the Resources folder.
- Right click on the selection and click on Properties.
- Change Build Action to Embedded Resource.
- To access the resource from the C# program type:
Properies.Resources.<resource-name>
. For example, Bitmap BGImageFile = Properties.Resources.Background;
- Image resources will be returned as
Bitmap
class. Audio resources will be returned as Stream
class.
Resizing the Application Frame
When the Tropical Tunes application starts, it will occupy 90% of the computer screen. The user can resize the frame by dragging the sides or the corners. The user can click on the full screen icon, or on the maximize button. In all cases, the background image will be displayed with the correct aspect ratio.
Display Images to Fit the Screen
This method displays the background image with the correct aspect ratio to fit the client size of the frame. It is a two-step process. In step one, we create a memory image of the background and four normal sized drums. In step two, we draw the combined image to the screen. The reason for using two-steps is to avoid the DPI AWARENESS issue with running the program on notebooks with higher DPI than 96 dpi. We use the memory image to restore the image after a large drum was displayed. We draw the normal sized drum and the area around it over the large drum.
internal void DrawBackground()
{
BGImageWidth = Parent.ClientSize.Width;
BGImageHeight = BGImageFile.Height * BGImageWidth / BGImageFile.Width;
if(BGImageHeight > Parent.ClientSize.Height)
{
BGImageHeight = Parent.ClientSize.Height;
BGImageWidth = BGImageFile.Width * BGImageHeight / BGImageFile.Height;
}
BGPosX = (Parent.ClientSize.Width - BGImageWidth) / 2;
BGPosY = (Parent.ClientSize.Height - BGImageHeight) / 2;
if(BGMemoryImage != null) BGMemoryImage.Dispose();
BGMemoryImage = new Bitmap(BGImageWidth, BGImageHeight);
Graphics ImageGraph = Graphics.FromImage(BGMemoryImage);
ImageGraph.DrawImage(BGImageFile, 0, 0, BGImageWidth, BGImageHeight);
for(int Index = 0; Index < 4; Index++) Parent.DrumArray[Index].DrawNormalDrum(ImageGraph);
ImageGraph.Dispose();
Graphics ScreenGraph = Parent.CreateGraphics();
ScreenGraph.FillRectangle(Brushes.LightGray, 0, 0,
Parent.ClientSize.Width, Parent.ClientSize.Height);
ScreenGraph.DrawImageUnscaled(BGMemoryImage, BGPosX, BGPosY);
ScreenGraph.Dispose();
return;
}
internal void DrawNormalDrum(Graphics ImageGraph)
{
BGPosX = Parent.BGImage.BGPosX;
BGPosY = Parent.BGImage.BGPosY;
int BGImageWidth = Parent.BGImage.BGImageWidth;
int BGImageHeight = Parent.BGImage.BGImageHeight;
NormalDrumWidth = (int) Math.Floor(NormalDrumScale * BGImageWidth);
NormalDrumHeight = NormalDrumWidth * NormalImage.Height / NormalImage.Width;
LargeDrumWidth = (int) Math.Floor(LargeDrumScale * BGImageWidth);
LargeDrumHeight = LargeDrumWidth * LargeImage.Height / LargeImage.Width;
DrumPosX = (int) (RelPosX * BGImageWidth);
DrumPosY = (int) (RelPosY * BGImageHeight);
NormalRect = new Rectangle(DrumPosX - NormalDrumWidth / 2,
DrumPosY - NormalDrumHeight / 2, NormalDrumWidth, NormalDrumHeight);
LargeRect = new Rectangle(DrumPosX - LargeDrumWidth / 2,
DrumPosY - LargeDrumHeight / 2, LargeDrumWidth, LargeDrumHeight);
ImageGraph.DrawImage(NormalImage, NormalRect);
return;
}
Scratch Program Game Logic
The Tropical Tunes program is divided into two sections overall control (the background) and drum control. Since there are four drums, in total, there are five independent execution paths. Looking at the code, it is easy to see the main building blocks of any software program: assignment statements, conditional statements, loops, and control statements.
Background control program
Drum control program
C# Program Game Logic
The heart of the C# program, the game control logic, is a loop controlled by game state logic. There are six states.
GameState.Off
- Off state. The program is waiting for the user to press the Go (green) icon. GameState.Init
- Game initialization. Reset the score and set the game number to game 1. GameState.StartSequence
- Start a sequence of notes for one game. GameState.PlayNote
- Play a single random drum or note to the player. The game logic method exits the loop and waits for the note playing to end. GameState.PlayNoteDone
- Control returns to this state after a note was played. The program will continue to the next note in the sequence (back to GameState.PlayNote
. If it is the last note in the sequence, the program will wait for the user to repeat the full sequence. GameState.UserNote
- Control will return to this state after each drum or note was played by the user. If the user did not click any drum for 10 seconds, the game stops. If the correct drum was played, the program waits for the next drum in the sequence. If it is the last drum of the sequence, we go back to GameState.StartSequence
. If it is the last sequence, game number seven, it is perfect score. If the user did not hit the correct drum, game is over.
Each state ends with either continue
or return
. Block ending with continue
means that transition to the next state is immediate. Block ending in return
means that the program will return to the game logic after a timer event or mouse click event.
private void GameLoop()
{
for(;;) switch(State)
{
case GameState.Off:
default:
ActiveDrum = 0;
NoteTimer.Enabled = false;
TimeoutTimer.Enabled = false;
return;
case GameState.Init:
Score = 0;
ScoreArea.DrawScore(Score);
GameNo = 1;
State = GameState.StartSequence;
continue;
case GameState.StartSequence:
Array.Clear(DrumSequence, 0, MaxGames);
NoteNo = 0;
State = GameState.PlayNote;
continue;
case GameState.PlayNote:
SetActiveDrumNo();
DrumSequence[NoteNo] = ActiveDrum;
if(ShowList) ListArea.DrawList();
DrumArray[ActiveDrum - 1].PlayDrum();
State = GameState.PlayNoteDone;
NoteTimer.Enabled = true;
return;
case GameState.PlayNoteDone:
if(++NoteNo < GameNo)
{
State = GameState.PlayNote;
continue;
}
ActiveDrum = 0;
NoteNo = 0;
State = GameState.UserNote;
TimeoutTimer.Enabled = true;
return;
case GameState.UserNote:
TimeoutTimer.Enabled = false;
if(ActiveDrum == 0)
{
MessageArea.DisplayMessage("Timeout");
State = GameState.Off;
continue;
}
if(ActiveDrum == DrumSequence[NoteNo])
{
ScoreArea.DrawScore(++Score);
ActiveDrum = 0;
if(++NoteNo < GameNo)
{
TimeoutTimer.Enabled = true;
return;
}
if(++GameNo <= MaxGames)
{
State = GameState.StartSequence;
NoteTimer.Enabled = true;
return;
}
PerfectSound.Play();
MessageArea.DisplayMessage("Perfect Score");
GameNo = 0;
State = GameState.Off;
return;
}
GameOverSound.Play();
MessageArea.DisplayMessage("Wrong note");
ActiveDrum = 0;
State = GameState.Off;
return;
}
}
Conclusion
There is no question in my mind that Scratch is an excellent tool at introducing anyone young or old to computer programming. It is visually simple to see the basic programming building block. It is a very good educational tool. The Scratch language is very effective in putting together a simple game. Developing the same game in C# code is an order of magnitude more complicated. But it was real fun for me. It is rather obvious that the Scratch language has its limitation going further than a simple game.
History
- 27th January, 2021: Version 1.0 Original version