Vol.10 NOV
2017
Contents:
Participants in FabCafe Bangkok
PLAY
New games out this month! Community Polls - Favourite video game conference
LEARN
Design & Development with filmote - Pipes (Part 4)
Steve the Jumping Dinosaur (Part 1) with filmote Good coding habits (Part 1) with Pharap
EXPLORE
Questions with Game Developer
Events - Gamestart Asia Events - Portland Retro Gaming Expo Workshop - Arduboy x Fabcafe Bangkok Workshop - Arduboy x Fabcafe Singapore #arduboy
Page 2 of 46
A welcome note: After last month being packed with activities, this month was busy with workshops - organised independently by Fab Cafes in Bangkok and Singapore. Reach out to the Arduboy team if you are planning to host a workshop and need some resources. If the workshops are a little too far away from you, and you’ve already finished crait’s 7 lessons on the community, you’d be happy to know that filmote has written a two part series - Steve the jumping Dinosaur. This lesson guide you as you make your known chrome-like dinosaur jumping game! Have a great Make-vember. -celinebins
Do you wish to contribute? Have an interesting article you wish to share with the Arduboy community? A cool project you did, your experience on working on it? A funny joke? We want to hear it! Send arduboymag a message through the Arduboy community page or a DM on Twitter! Page 3 of 46
Thank you to this months contributors! @filmote: In between writing articles for this magazine, Simon Simon is currently developing a dungeon crawling game called Dark & Under and hope to release it this November.
@JO3RI: Better known as TEAM a.r.g, some of Arduboy’s community favorite games are written by them, as well as their own Arduboy Game Loader, where you can easily upload your favorite Team a.r.g games without using the Arduino IDE. http://www.team-arg.com/
@Pharap: Feel free to ask Pharap for help with things. He believes the three great programming virtues are laziness, impatience and hubris. https://github.com/Pharap
@TheArduinoGuy: Author of the ArduBoy games - Jet Pac & Arcodia.. Author of ‘Beginning Arduino’. Medway Makers. Maidstone Hackspace. http://thearduinoguy.org/
@Your name: This could be you.. Help contribute to the Arduboy Magazine!
Page 4 of 46
Arduboy
Company
news:
What’s happening at headquarters?
@Celinebins
Shipping
Delayed shipping from the Arduboy store - We are currently overwhelmed with orders and are in a hurry to catch up by mid November.
New Packaging
In the next few months, our new packaging will be rolled out at our store, and across our distributors. It is more compact and would be able to withstand damages from shipping.
Where to buy Arduboy? In order to better deliver the Arduboy to you, a distribution model for sales has been currently implemented. You can now purchase the Arduboy from a variety of different retailers from around the world!
New!
New!
Talk to us!
Page 5 of 46
W
ES AM G
by @Celinebins So many new games were released this month! If you missed them on the community pages, here they are.
FR ES H
N E
PLAY:
That will get you hooked
Ardulem Lemmings on Arduboy
@Iswbanban Ardulem is an attempt to bring the legendary “Lemmings” puzzle platformer game to the Arduboy. Move the cursor over the Lems and press the B button to give them orders to lead them to the exit door marked with a flag to win.
DanceRow
@madya121 An Audition Ayodance clone for Arduboy. With your arrow keypad, match the arrow on the screen! Music has been added!
Fire
place
demo
@Schuemi Developer Schuemi wants to say “hello” to the community with this first little test. So, get romantically with your very own Arduboy fireplace! Page 6 of 46
Hopper
@obono Hollow Seeker developer obono is back with - Hopper! There are square panels around you. Like trampolines, you must jump on them and go up, earning more points the higher you go. If you miss the panel and fall toward bottom, the game is over. How high can you go?
Ninja
fuzzgrawth
@Hundestrasse Guide the Fuzzgrawth up the three towers to collect the three ‘things’! It’s a fast paced platformer against the clock with randomly ordered levels. Can’t get past the fish? Visit the community thread for a useful hint!
Saru Gorira Chinpanji
@taniguchi SARU, GORIRA, CHINPANJI- is famous song poetry in Japan. It is a parody of Colonel Bogey March. Children often sing. SARU is monkey. GORIRA is gorilla. CHINPANJI- is Chimpanzee. Lyrics have no meaning.
Want us to feature your game? Write in to us with your game, how you made it, and anything else you want the community to know! Page 7 of 46
Community POLLs! by @Celinebins
We asked the community conferences, and why... The E-Sports? The indie g These are The Portland Retro Gaming Expo
Location: Portland, Oregon, USA Date: 19 - 21 October 2017 Website: http://retrogamingexpo.com/ What the community thinks: - Collectables and sweet merch @Androck
Penny Arcade Expo (PAX)
Locations: Seattle, WA (PAX West), San Antonio, TX (PAX South), Philadelphia, PA (PAX Unplugged) Date: 1 - 4 Sept 2017, 12 - 14 Jan 2018, 17 - 19 Nov 2017 Respectively Website: http://www.paxsite.com/ What the community thinks: - Current gen stuff/upcoming games - Tickets sell out fast @Androck
Geek End
Location: Savannah, GA, USA Date: 2 - 3 Feb 2018 Website: http://www.geek-end.com/ What the community thinks: Not just games, but a bit of everything “geek” Might speak about Arduboy at the upcoming one! @luxregina
Favourite video game conference
y recently attended game e games? The cosplay? The games? New games? the results! Game Developer Conference (GDC) Location: San Francisco, California, USA Date: 19 - 23 March 2018 Website: http://www.gdconf.com/ What the community thinks: - Interesting talks - Location: San Francisco @luxregina
E3
Location: Los Angeles, California, USA Date: 12 - 14 June 2018 Website: https://www.e3expo.com/ What the community thinks: - Fun but overwhelmed and less focused than GDC @luxregina
EGX/Eurogamer expo
Location: Birmingham, England Date: 20 - 23 Sept 2018 Website: https://www.egx.net/egx What the community thinks: - Playing the old consoles that were around ‘before my time’ @Pharap - enjoyed playing R-Type on a PC-Engine @ Keyboard_Camper - Trying out the upcoming games @Pharap The discussion is still open, let us know what you usually attend, and if you’d like to see Arduboy there! Page 9 of 46
Level: Intermediate
Laying Pipes
- Part 4
by @filmote In the last article we enabled the multi-level game play and the game is almost finished – all it needs is some polish to make it look a little professional.
In this article, we will add some animation to the splash screen and some sound effects before packaging the application ready for publication.
Splash screen animation When I originally designed the artwork for the splash screen, I made individual sprites for each of the pipe pieces rather than one large graphic allowing me to ‘animate’ the pipes being laid.
In the previous article, the drawSplash() routine clears the screen and renders all of the pipes in one action.
arduboy.clear(); sprites.drawOverwrite(112, sprites.drawOverwrite(112, sprites.drawOverwrite(96, sprites.drawOverwrite(96, ... arduboy.display();
0, 16, 16, 0,
logo_straight_TB_noflange, frame); logo_elbow_TL, frame); logo_elbow_TR, frame); logo_elbow_LB, frame);
The code below shows the modified version of the drawSplash() routine. It is similar to that original except it uses a helper function, splashAnimation(), to render the pipes individually. As you will see in a moment, the splashAnimation() routine takes the original parameters as the original
sprites.drawOverwrite() function it replaces but adds an additional one that allows the functionality to be skipped. After seeing the animation once or twice, most players will be happy to skip straight to the game play.
bool skipSplash = false; arduboy.clear(); arduboy.display(); skipSplash skipSplash skipSplash skipSplash
= = = =
splashAnimation(112, splashAnimation(112, splashAnimation(96, splashAnimation(96,
0, 16, 16, 0,
logo_straight_TB_noflange, frame, skipSplash); logo_elbow_TL, frame, skipSplash); logo_elbow_TR, frame, skipSplash); logo_elbow_LB, frame, skipSplash);
... splashWaitForever(); to be continued next page >> Page 10 of 46
The splashAnimation() function is shown below. As mentioned, it accepts a new parameter, skip, and if detected to be true causes the function to immediately return. Otherwise, the requested sprite is rendered to the screen and the routine loops 20 times, pausing for 15 milliseconds at the end of each loop. #define ANIMATION_DELAY_SHORT
If the player has pressed the ‘A’ button, the function returns true and all subsequent calls to the function from the drawSplash() routine effectively skip the animation.
20
bool splashAnimation(byte x, byte y, const uint8_t *bitmap, uint8_t frame, bool skip) { if (skip) return true; int i = ANIMATION_DELAY_SHORT; sprites.drawOverwrite(x, y, bitmap, frame); arduboy.display(); while (i >= 0) { arduboy.pollButtons(); if (arduboy.justPressed(A_BUTTON)) { return true; } arduboy.delayShort(15); i--; } return false; }
We will revisit these two functions in a moment to add some sound effects and additional functionality that will allow the player to turn the sound effects on or off.
Adding sound effects The Arduboy has a number of sound options including the basic tone() function of the Arduboy2 library and the more functional ArduboyTones library maintained by @ MLXXXp. The ArduboyTones library provides methods to play single notes or sequences that can be stored in PROGMEM. It also plays these tunes asynchronously, allowing you code to continue executing.
The Arduboy2 library also contains code that other libraries, such as ArduboyTones, can utilize to save and retrieve audio settings providing a consistent model across the different libraries. The sample code below shows how the ArduboyTones library and the standard Arduboy2 libraries combine.
#include <ArduboyTones.h> ArduboyTones sound(arduboy.audio.enabled); sound.tone(NOTE_C1,50, NOTE_D1,50, NOTE_C1,50);
to be continued next page >> Page 11 of 46
After importing the library, an instance of the sound class is instantiated. The constructor of the ArduboyTones class has a parameter to indicate whether sounds should be played (true) or not (false). Here we have used a function in the base Arduboy2 class to retrieve the audio setting from the EEPROM setting while instantiating the class.
Other functions of the Arduboy2 class allow the setting to be changed and saved to the EEPROM allowing a player to mute the game and have that setting honored when they next turn the device on. The tone() method comes in three variants, as shown below, that play one, two and three notes respectively.
static void tone(uint16_t freq, uint16_t dur = 0); static void tone(uint16_t freq1, uint16_t dur1, uint16_t freq2, uint16_t dur2); static void tone(uint16_t freq1, uint16_t dur1, uint16_t freq2, uint16_t dur2, uint16_t freq3, uint16_t dur3);
The function takes ‘pairs’ of parameters which represent the frequency of the note followed by a duration. The notes are enumerated as #defines in the class itself and span nine octaves, ranging from a very low C to a very high B. The naming convention for these is NOTE_{tone, A - G}{octave, 0 – 8}. #define #define #define #define … #define #define #define
NOTE_C0 NOTE_CS0 NOTE_D0 NOTE_DS0
16 17 18 19
NOTE_A9 NOTE_AS9 NOTE_B9
14080 14917 15804
The duration is specified in 1/1024th of a second – close enough to milliseconds. Omitting the duration or specifying a duration of 0 will result in the For more tone being played information, check forever.
out the following “Callouts” article
The library also defines a second set of notes that are the equivalent to the previous ones but they are played at a higher volume. These have the same naming convention as the normal notes but are suffixed with an ‘H’. #define #define #define #define … #define #define #define
NOTE_C0H NOTE_CS0H NOTE_D0H NOTE_DS0H
(NOTE_C0 + TONE_HIGH_VOLUME) (NOTE_CS0 + TONE_HIGH_VOLUME) (NOTE_D08 + TONE_HIGH_VOLUME) (NOTE_DS0 + TONE_HIGH_VOLUME)
NOTE_A9H NOTE_AS9H NOTE_B9H
(NOTE_A9 + TONE_HIGH_VOLUME) (NOTE_AS9 + TONE_HIGH_VOLUME) (NOTE_B9 + TONE_HIGH_VOLUME)
The three tone() variants are great for short sound effects and I have created four small functions that make appropriate sounds while pipes are being laid in the splash screen or the play selects and matches nodes while playing the game.
I will leave it to you to search for these within the game play code itself.
to be continued next page >> Page 12 of 46
void playSplashTune()
{ sound.tone(NOTE_C1,50, NOTE_D1,50, NOTE_C1,50); }
void playClearSelectionTune() { sound.tone(NOTE_C2,50, NOTE_D2,50, NOTE_E2,50); } void playSelectNodeTune()
{ sound.tone(NOTE_C4, 50); }
void playMatchNodeTune()
{ sound.tone(NOTE_C4,50, NOTE_D4,50, NOTE_E4,50); }
The ArduboyTones library also allows sequences of tones to be stored in an array in PROGMEM in much the same way sprites are defined. This caters for longer sequences than the tone() method can handle. An example of the declaration and use is shown below. const uint16_t puzzleSolved[] NOTE_C4, 50, NOTE_D4, 50, NOTE_C4, 50, NOTE_D4, 50, NOTE_C4, 50, NOTE_D4, 50, TONES_END };
Two things to note are the use of the TONES_ END constant is used to signify the end of the sequence and the use of the tones() - with an ‘s’ - method.
PROGMEM = { NOTE_E4, 50, NOTE_E4, 50, NOTE_E4, 50,
void playPuzzleSolved() { sound.tones(puzzleSolved); }
Toggling Sound On and Off I think it is a good design practice for all games to allow players to mute the sound as soon as the game starts up and to have that setting be honoured next time the Arduboy is turned on. This prevents those awkward situations where you are at, say, a funeral and decide to play a quick game while the eulogy rambles on and on. The high pitched sounds of the Arduboy can be hard to muffle as you desperately try to turn the machine off.
The audio state – on or off – is saved in the EEPROM at position 2 and its value can be retrieved using the arduboy.audio.enabled() function. When rendering the splash screen, I have included a sprite in the bottom right corner to indicate the current sound status. The modified drawSplash() function below shows the code in action.
Obviously the authors of the Arduboy2 library thought so as well and they have included a standardized way to save and retrieve sound settings that can be utilised across games. void drawSplash() { arduboy.clear(); sprites.drawOverwrite(120, 56, (arduboy.audio.enabled() ? sound_icon : no_sound_icon), frame); arduboy.display(); … }
The splashAnimation() function has also been updated to detect if the user has pressed the ‘B’ button.
If pressed, the value in the EEPROM is overwritten using a wrapper function that coordinates the calls to the base Arduboy2 functions.
to be continued next page >> Page 13 of 46
bool splashAnimation(byte x, byte y, const uint8_t *bitmap, uint8_t frame, bool skip) { ... if (arduboy.justPressed(B_BUTTON)) { toggleSoundSettings(); sprites.drawOverwrite(120, 56, (arduboy.audio.enabled() ? sound_icon : no_sound_icon), frame); arduboy.display(); } ... } void toggleSoundSettings() { if (arduboy.audio.enabled()) { arduboy.audio.off(); arduboy.audio.saveOnOff(); } else { arduboy.audio.on(); arduboy.audio.saveOnOff(); } }
At this point, our application has a funky splash screen, sound effects and an ability for the player to turn the sounds on or off. The complete code is included in my repository at https://github.com/filmote/LayingPipe and I encourage you to download it and look at
some of the other little additions I have made to make the level and puzzle selection and game over banners nicer. This complete version has 30 puzzles per level for you to try out.
Packaging a game for Distribution Once your game is complete and testing finished, you will probably want to share the code with the world. There are three ways to do this and I suggest you do them all! Publishing the code to GitHub The Arduboy is an open-source project and is supported by a community who will offer assistance and guidance free of charge. As member of the community, you can contribute by publishing your source code for others to learn from.
Publishing an application is simple and I have documented it using the web interface only. Once you are familiar with the concepts, I would recommend you download the GitHub Desktop application. Among other things, it compares the files on your desktop against the repository to determine which ones to update thus minimizing the chance that a change will go unpublished or an incomplete change that spans multiple files is published.
GitHub is an open-source, web-based version control system that will allow people to view and comment on your code and â&#x20AC;&#x201C; if you allow them to â&#x20AC;&#x201C; suggest changes that you can incorporate back into the code set. to be continued next page >> Page 14 of 46
To publish an application: Step 1: Create a user profile if you do not have one. Visit https://github.com/ to get started. Step 2: Log in to GitHub using the credentials created in Step 1. Select New Repository from the menu in the top right hand corner of the screen, as shown on the right side.
Step 3: Give the repository a name and, optionally, a description. Select the ‘Public’ repository option and check the Initialize this repository with a README checkbox. Click the Create Repository to complete the creation of the repository.
Step 4: Give the repository a name and, optionally, a description. Select the ‘Public’ repository option and check the Initialize this repository with a README checkbox. Click the Create Repository to complete the creation of the repository.
to be continued next page >> Page 15 of 46
Step 5: Once the repository has been created, the actual source files can be added to the project. From the repository view, click Upload Files button to begin adding files. Files can be dragged onto the window from Windows Explorer or OS X’s Finder. The image below shows how the files are accumulated under the drag-and-drop window as they are added. Provide a description of the files being committed and click the Commit Changes button.
Step 6: The repository is shown again with the files added. You can add new files as needed or update the existing ones using the Upload Files button. Other people can retrieve a copy of the code using the Clone or Download option.
Creating a Hex file A .hex file is a compiled, binary version of your program that some game uploaders, such as @crait’s Arduboy Manager, @shdwwzrd’s Arduboy Center or @ereid’s Arduboy Uploader can directly load onto an Arduboy. A compiled binary saves the user the hassle of downloading your code and any prerequisite libraries and having to compile the code and upload it themselves.
Step 1: Once the program is complete and compiles properly, create the .hex file by selecting the Export compiled Binary option from the Sketch menu as shown below. The images are from a Macintosh but the menu options are identical on the Windows version of the Arduino IDE.
Creating a binary file is simple and can be achieved following these steps.
to be continued next page >> Page 16 of 46
Step 2: Once complete, select the Show Sketch Folder option from the Sketch menu. This will open Windows Explorer or OS X’s Finder at the folder in which the new binary file was created.
Step 3: The file is named after the primary INO file in your application and the platform or board selected when compiled. Rename this file and shorten it to {your game name}.hex, e.g. in the example below the file might get renamed to Pipes.hex. This file can now be shared around to the various game sites.
Creating an Arduboy file An .arduboy file is an archive file (zip file) that contains the .hex file created in the previous step along with a metadata file that describes the program in a standard format. Optionally, the archive can contain a banner image and one or more screenshots of the game in action. The .arduboy format was developed by the community to allow game loaders, such as @crait’s Arduboy Manager, TeamARG’s Game Loader or @ereid’s Arduboy Uploader, to be able to catalogue and display a library of games in a nice format. An .arduboy archive at a minimum must contain the .hex file along with a metadata file named info.json. The format of the info.json file can be found at the Team ARG site, here http://www.team-arg.org/AGL-technical.html The file can be created by hand or you can use Jeremy Dorn’s web-based JSON editor which allows you to build one simply by filling in a form. The tool can be accessed via the TinyURL http://tinyurl.com/jkw9vpf24 Amongst the options you can fill in are two important ones for promoting your application. The first is a banner which is a 700 x 192 pixel, black and white image in PNG, BMP, JPG
or GIF format. Team ARG have some nice tools for converting colour images to 1-bit black and white ones at https://teamarg. github.io/arduboy-image-converter/. I have made banner logos by finding appropriate artwork on the web and cropping it down to the correct size and adding a heading using the text tools in Paint / Paintshop. Once complete, I have then used Team ARG’s tool to convert it into the correct, 1 bit format. The second option is for screenshots showing you game in action. These are again 1 bit, black and white images but are 128 x 64 pixels in size. You can use @crait’s Arduboy Manager to capture screenshots following the instructions found here https://community. arduboy.com/t/screen-mirroring-guide-howto-screenshot-your-game/2800. In the latest version of the info.json schema, the screenshots can be named anything but by convention and as a prerequisite from earlier schema versions, they are named screenshot00 and sequentially numbered. As with the banner, these images can be PNG, BMP, JPG or GIF format.
to be continued next page >> Page 17 of 46
Once the JSON form is complete, the output of the file can be seen on the right-hand side of the screen. Once the form is completed, copy and paste the output into a text file named info.json. A sample info.json file can be seen below: {
}
“schemaVersion”: 2, “title” : “Pipes”, “description” : “The classic pipe laying game for the Arduboy.”, “version” : “1.0.0”, “device” : “Arduboy”, “author” : “Filmote”, “url” : “https://github.com/filmote/LayingPipe”, “sourceUrl” : “https://github.com/filmote/LayingPipe”, “genre” : “Puzzle”, “date” : “2017-06-28”, “idea” : “Filmote”, “code” : “Filmote”, “publisher” : “Filmote”, “banner”: “banner.png”, “screenshots”: [ { “title”: “Title Screen”, “filename”: “screenshot00.png” }, { “title”: “Level Select 1”, “filename”: “screenshot01.png” }, { “title”: “Level Select 2”, “filename”: “screenshot02.png” }, { “title”: “Simple Game”, “filename”: “screenshot03.png” }, { “title”: “Complex Game 1”, “filename”: “screenshot04.png” }, { “title”: “Complex Game 2”, “filename”: “screenshot05.png” } ], “buttons”: [ { “control”: “Down”, “action”: “Down” }, { “control”: “Up”, “action”: “Up” }, { “control”: “Left”, “action”: “Left” }, { “control”: “Right”, “action”: “Right” }, { “control”: “A”, “action”: “Select” }, { “control”: “B”, “action”: “Back” } ]
The actual .arduboy file can be created by adding the info.json file, the .hex file and all of the image files into a single zip or compressed folder. Once done, rename your file to {your game name}.arduboy. The Window’s command ‘Send to Compressed Folder’ will do the job perfectly. However, if you are using OS X’s ‘Compress’ option from Finder you will run into trouble as it includes a .ds_store and __MACOSX file automatically in the archive and these are unknown to the game loaders. If you are using a Macintosh, follow these steps to create a proper .arduboy file.
Step 1: Copy the info.json file, the .hex file and all of the image files into a new folder on the desktop or under the documents directory. Step 2: Open the Terminal application. It is usually hidden in the Utilities folder under the Applications folder in the dock. If you cannot find it, search for Terminal using Spotlight. Step 3: Navigate to the directory using the cd command. The file structure is hierarchical and you will probably start in a directory called /Users/{your user name}. You can confirm this by using the command pwd.
to be continued next page >> Page 18 of 46
If your folder new folder is on the desktop, you can probably navigate to it using the command cd Desktop/NewFolderName. If you created your new folder in the Documents directory, you can probably navigate to it using the command cd Documents/NewFolderName.
Step 4: Create a zip file using the command zip -r dir.zip . -x “.*” -x “__MACOSX” Note that the name of the file is specified as dir.zip but this can be changed to any appropriate name. Also note that there are two leading underscores on __MACOSX.
Next Month Actually, there is no next month for ‘Pipes’ anymore. I hope you enjoyed this series and learnt something!
Laying Pipes -
If you have any troubles understanding a section, please ask a question via the Arduboy Community website.
Part 4 (Callouts)
by @filmote
Constants vs #define vs enum When writing code in C / C++ - or anyone other language for that matter – your code often becomes littered with hard-coded values that only you, the programmer, understands. These values are often referred to as ‘magic numbers’ as their use and derivation is a mystery to other programmers. The use of a constant in your code allows you to assign a more textual and descriptive value to your magic number.
Which is more readable, the value 52 or the constant NUMBER_OF_CARDS_IN_DECK ? Constants in C/ C++ can be handled a number of ways, each with their own pros and cons. These include: • the const qualifier for a variable • the #definepreprocessor directive • the enum keyword
The Const Qualifier Adding the const qualifier to a variable declaration tells the compiler that the variable cannot be modified by code. Any attempt to update the value of the variable will result in a compile time error.
Declaring a variable as a constant allows the compiler to optimise the code as it knows in advance that no updates are possible.
to be continued next page >> Page 19 of 46
const int cards_in_deck = 52; cards_in_deck = 53;
< this will result in a compile time error.
The const keyword can also be used when specifying parameters to a function. When calling a function in C / C++, all parameters are passed by value unless you pass the pointer to the variable so adding the const keyword does is not used to prevent updates to the calling parameter outside of
the function but instead to ensure that the parameter is not updated within the function. Again, the use of the const keyword allows the compiler to optimize the code knowing that the variable is immutable.
int cards_in_deck = 52; shuffleCards(cards_in_deck); cards_in_deck = 53; a constant.
< This will compile correctly as the cards_in_deck variable is not
void shuffleCards(const int cards_to_shuffle) { < This will fail to compile as the parameter is defined as a
cards_to_shuffle--; constant. }
The #define Preprocessor Directive Before compiling an application, the C / C++ compiler runs a preprocessing that looks for compiler directives and acts on them first. Preprocessing directives can be used to define constants and to include / exclude sections of code based on the platform the compilation is targeting or to remove debugging code from a release build. The directives can also define simple macro functions as described in my article on debugging in the 6th issue of the Arduboy Magazine. More information on preprocessing directives can be found here. #define CAT #define DOG #define MOUSE
1 2 3
#define CAT_NAME #define DOG_NAME #define MOUSE_NAME
“Leo” “Fido” “Mickey”
The simple #define directive instructs the preprocessor to look for the first operand and replace it within the code using the second operand. In the example below, I have created constants for three animal types, as numeric values, and three name constants as strings. One thing to note though is that the preprocessor will not check the validity of the substitutions it makes and can result in compilation errors.
int myAnimal = CAT; String myAnimalName = CAT_NAME; String myOtherCat = DOG; < This will fail to compile as the variable is defined as a string but an attempt is being made to initialize it with a numeric value.
to be continued next page >> Page 20 of 46
One nice thing about the #define directive is that it allows you to combine values together, like those shown below. I have used this functionality in the Pipes game to define the EEPROM settings used when saving and retrieving player settings where all memory positions are defined relative to the EEPROM_ STORAGE_SPACE_START constant. #define SMALL #define MEDIUM #define LARGE
1 2 3
#define CAT #define DOG #define MOUSE
10 20 30
#define CAT_SMALL #define CAT_MEDIUM #define CAT_LARGE
CAT + SMALL CAT + MEDIUM CAT + LARGE
#define DOG_SMALL #define DOG_MEDIUM #define DOG_LARGE
DOG + SMALL DOG + MEDIUM DOG + LARGE
#define MOUSE_SMALL #define MOUSE_MEDIUM #define MOUSE_LARGE
MOUSE + SMALL MOUSE + MEDIUM MOUSE + LARGE
The same techniques are used in the ArduboyTones library to construct the high volume notes that add the original note value plus a TONE_HIGH_VOLUME constant
int myCat = CAT; int myLargeCat = CAT_LARGE;
Enumerations In C / C++, an enumeration is a data type consisting of a set of named values of type integer. Enumerations can be named or anonymous as shown below. Note in the first example, I have nominated that the first element, cat, is assigned the numeric value 10. Dog will automatically be assigned the value of 11 and mouse, 12.
In the second example where no starting number is specified, the items are numbered from zero onwards.
enum Pet { cat = 10, dog, mouse }; enum { horse, cow, sheep };
The following declarations are all valid. int aHorse = horse; Pet aCat = cat; Pet aDog = Pet::dog; to be continued next page >> Page 21 of 46
Named enumerations can be used when defining parameters to a function. As you can see from the sample calls, the declaration will not prevent you from passing any other enumeration type or even an integer. void printPetDetails(Pet thePet) { switch (thePet) { case Pet::cat: Serial.println(“cat”); break; case Pet::dog: Serial.println(“dog”); break; case Pet::mouse: Serial.println(“mouse”); break; default: Serial.println(“other”); break; } } printPetDetails(aCat); printPetDetails(aDog); printPetDetails(aHorse); printPetDetails(2);
< prints “cat” < prints “dog” < prints “other” but is illogical as it isn’t a Pet < prints “other” but is illogical as it isn’t a Pet
Enumerations can also include the class keyword as shown below.
This overcomes the limitations in the previous example by ensuring that references to a Pet are checked in both the declarations and passing of variables to a function.
enum class Pet { cat = 10, dog, mouse }; enum class FarmAnimal { horse, cow, sheep }; Pet aCat = Pet::cat; Pet aDog = dog; < Will not compile. The elements of Pet must be specified as Pet::{element} FarmAnimal aHorse = FarmAnimal.horse; printPetDetails(aCat); printPetDetails(aDog); printPetDetails(aHorse); Pet. printPetDetails(2);
< prints “cat” < prints “dog” < will not compile as the compiler cannot convert a FarmAnimal to a < will not compile as the compiler cannot convert an integer to a Pet. to be continued next page >> Page 22 of 46
However, enumerations declared with the class scope are not viewed as simple integers anymore. The following code illustrates this: Serial.println(aCat); Serial.println((int)aCat);
< will not compile as there is no overload Serial.println(&Pet) function. < casting the number back to an integer allows it to compile.
You can use any or all three of these techniques in your code. I prefer to use #defines when the number actually means something, such as #define ARRAY_SIZE 100, but would opt for enumerations where the number is irrelevant. Use whatever you feel comfortable with!
Circuit Dude is a top-down, tile-based puzzler with 100 levels. Help Circuit Dude build his ultimate secret invention by plugging in chips, moving blocks, rotating walls, and much more!
Get it on Steam here!
Page 23 of 46
Level: Beginner
Steve the Jumping Dinosaur
- Part 1
by @filmote The following article describes how to build a simple game based on the Google browser game that is available if you are offline. Other versions of this game are available on iOS and Android and are called Steve the Jumping Dinosaur. This article assumes you have read Crait’s series of articles that describe the process of setting up an Arduboy environment, writing simple applications and culminating in the writing of your first game – the classic Pong! If you haven’t already read Crait’s articles, stop reading this and do that first.
Make your own Arduboy Game: Part 1 - Setting Up Your Computer Part 2 - Printing Text Part 3 - Storing Data & Loops Part 4 - Questions & Button Input Part 5 - Your First Game! Part 6 - Graphics! Part 7 - Make Pong From Scratch! Crait’s articles do a great job of detailing the structure of an Arduboy program. This article adds some additional concepts including enumerations, structures and arrays of images to build a more advanced game than Pong. If I haven’t already said it, make sure you read Crait’s articles first.
Creating Steve the Jumping Dinosaur Steven the Jumping Dinosaur is an endless runner where you jump oncoming cacti and duck under low-flying pterodactyls. The longer you run, the higher your score!
Before we jump (all puns intended) in to writing some code, we need to look at a few new concepts:
Structures A structure is a way of grouping related variables together into a single construct. A structure can be passed to a function or referred to as a single unit. struct byte byte byte };
An example of a structure is shown below. It represents a node and contains three variables that hold the coordinates and node value respectively.
Node { x; y; value;
to be continued next page >> Page 24 of 46
Once defined, a new variable can be created using it as a datatype as shown below. The members of the structure can be referenced directly to assign or retrieve their values. Node aNode; aNode.x = 3; aNode.y = 4; int x = calc(aNode); int calc(Node theNode) { return theNode.x * theNode.y; }
The declaration and initialization code above could have been expressed in a single line as shown below. The members of the structure must be initialised in the sequence they were declared in the structure definition.
Not all members must be initialized and the second example is also valid and the value member would be initialised to 0.
Node myNewNode = {3, 4, 5}; Node myNewNode = {3, 4};
Enumerations An enumerations is a data type consisting of a set of named values. Under the covers, the values are all of type integer but the programmer may not ever need to know or care what the values are.
Enumerations can be named or anonymous as shown below. Note in the first example, I have nominated that the first element, Cat, is assigned the numeric value 10. Dog will automatically be assigned the value of 11 and Mouse, 12. In the second example where no starting number is specified, the items are numbered from zero onwards.
enum Pet { Cat = 10, Dog, Mouse }; enum { Horse, Cow, Sheep };
Once an enumeration is declared, it can be used as shown in the valid declarations below. int aHorse = Horse; Pet aCat = Cat; Pet aDog = Pet::Dog;
Named enumerations can be used when defining parameters of a function. As you can see from the sample calls, the declaration will not prevent you from passing any other enumeration type or even an integer. to be continued next page >> Page 25 of 46
void printPetDetails(Pet thePet) { switch (thePet) { case Pet::Cat: Serial.println(“cat”); break; case Pet::Dog: Serial.println(“dog”); break; case Pet::Mouse: Serial.println(“mouse”); break; default: Serial.println(“other”); break; } } printPetDetails(aCat); < prints printPetDetails(aDog); < prints printPetDetails(aHorse); < prints printPetDetails(2); < prints
‘cat’ ‘dog’ ‘other’ but is illogical as it isn’t a Pet ‘other’ but is illogical as it isn’t a Pet
Sprites A sprite is an image or graphic that represents a player, an enemy or even background elements of your game and can be drawn or moved around as a single object. The Arduboy library provides a number of functions to render sprites to the screen. In this tutorial, we will concentrate on two functions drawOverwrite() and drawExternalMask().
But before we get into those, let’s recap how we define a sprite. The image below shows Steve in his upright, ready-to-run position. The array definition for this sprite is shown below.
const byte PROGMEM dinosaur_still[] = { 18, 21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF, 0xFB, 0xFF, 0xFF, 0xBF, 0xBF, 0x3F, 0x3E, 0x3F, 0x7C, 0xF8, 0xF0, 0xF0, 0xF8, 0xFC, 0xFE, 0xFF, 0xFF, 0xFF, 0x7F, 0x3F, 0x04, 0x0C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x1F, 0x17, 0x03, 0x01, 0x03, 0x1F, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, };
I have formatted the array to make it a little more readable. The first line contains the width and height of the array, in this case 18 pixels wide by 21 pixels. The remaining rows contain the pixel data of the actual image.
I am not going to describe how the image data is calculated in this article – it has been described in detail in other articles in this magazine including this one on Page 23 of the Arduboy Magazine (Vol 7). to be continued next page >> Page 26 of 46
Team ARG have a great online tool that allows you to drop a black and white image on to the page and calculate the image data. It can be found here. The following code will render Steve at position x = 4, y = 5. Sprites::drawOverwrite(3, 4, dinosaur_still, 0);
The last parameter â&#x20AC;&#x201C; the zero â&#x20AC;&#x201C; is the frame number. We will cover that in a few moments.
When rendering an image using drawOverwrite(), it overwrites whatever is on the screen with the image specified. There is no concept of transparent pixels so the entire rectangle that the sprite covers is affected.
Masks The Arduboy library also provides some nice masking utilities that allow you to render a sprite over a background without clearing the entire rectangle that the sprite occupies. In a sense it allows you to mark areas of a sprite as solid (black or white) and transparent.
Consider the following image and mask: As mentioned above, drawOverwrite() simply draws the sprite and overwrites what was already there. In the example below, the black corners of the ball are visible as the ball passes into the white area.
As the name implies, the drawExternalMask() function allows the image and mask to be nominated when rendering. Bits set to 1 in the mask indicate that the pixel will be set to the value of the corresponding image bit. Bits set to 0 in the mask will be left unchanged.
This can be seen clearly as the ball moves into the right hand side of the background. The top-left and bottom-right corners of the image are rendered as black as the mask is set to 1 in these areas which in turn ensures that the images pixels (both zeroes and ones) are rendered on the background.
A second article on Page 33 of the Arduboy Magazine (Vol 7) describes the various other mask options available and contains a link to a project that demonstrates the various techniques.
The sample code below shows a call to the drawExternalMask() function. As with the drawOverwrite() function, it has specifies the frame for each image.
Sprites::drawExtnerlaMask(3, 4, dinosaur_still, dinosaur_mask, 0, 0); to be continued next page >> Page 27 of 46
Frames One challenge when writing a game is to ensure that the speed of the game is not affected by the amount of activity that is going on. The Arduboy supports a concept called frames which allows activity to be coordinated - paused even – so that game play speed is constant. Think of it like a traffic cop that slows down fast processes and waits until it’s time for the next round of activity.
The Arduboy allows you to specify the number of frames you want per second. A large number will result in many frames per second and therefore the period between frames is very short. A small number will result in a larger gap between frames. The code below shows a typical setup:
void setup() {
}
arduboy.boot(); arduboy.setFrameRate(75);
void loop() {
}
if (!(arduboy.nextFrame())) return; …
The first line of code in the loop() is crucial. It induces a delay if it is not time to process the next frame. Frames can also be used as a basic counter and to animate graphics.
Later when we look at rendering Steve, we will use the frame count to alternate between an images where his left foot is down to a second where his right foot is down.
Moving the ground The illusion of movement in an endless runner is important to game play. To provide a little variety, I have designed three separate graphics which include flat land, a bump and a pot-hole. The variations are irrelevant to the game play.
These are enumerated in an enum called GroundType, as shown below. The first element in an enumeration is implicitly assigned a value of zero and subsequent elements increase in value by one. An array of images has also been declared with the images arranged in the same order as the enumeration allowing us to use the enumeration elements as index values to retrieve the images.
enum GroundType { Flat, Bump, Hole, }; const byte *ground_images[] = { ground_flat, ground_bump, ground_hole };
The ‘ground’ itself is made up of five images that are 32 pixels wide to give a combined width of 160 pixels. As you will see in a moment, the array of images will be rendered across the page overlapping the 128 pixels of the screen width. Moving the images a pixel
to the left and re-rendering them will provide the illusion that the ground is moving. The array is declared and initialised as shown on the next page:
to be continued next page >> Page 28 of 46
GroundType ground[5] = { GroundType::Flat, GroundType::Flat, GroundType::Hole, GroundType::Flat, GroundType::Flat, };
When rendering the ground for the first time, the first four images are rendered at X position 0, 32, 64 and 96 respectively. The fifth image is also rendered but as its X position is 128 it is not visible off to the right of the screen.
The following code renders the ground. It loops through the ground array and draws the five elements 32 pixels apart.
for (byte i = 0; i < 5; i++) { Sprites::drawSelfMasked((i * 32) - groundX, GROUND_LEVEL, ground_images[ground[i]], frame); }
In the code above, the variable groundX is used as an offset and is initially set to zero so has no affect. To scroll the ground to the left, the ground variable is incremented. Assuming the value is now one, this results in the five images being rendered at X positions -1, 31, 63, 95, and 127 respectively. The left most pixels of the first image are no longer visible and the left most pixels of the right are now rendered on the right most side of the screen. The ground can be continued to be scrolled until the offset equals 32 (our image width) at which point the images are being rendered at the X positions -32, 0, 32, 64 and 96 respectively. At this point the first image is completely off screen. At this point, we need to move the elements of the ground array to
the left one position and randomly select an image for the fifth position. The code below detects when the offset has reached the 32 and randomly selects a number between 0 and 5 and assigns the ground type accordingly. One thing to note about the random() function is that the lower bound is inclusive whereas the upper bound is inclusive. A value of 3 or lower results in a flat section of ground whereas the values 4 and 5 are mapped to a bump and a pothole. This approach ensures that many more flat sections of ground are generated. Finally, the elements of the array are shuffled to the left and the newly generated ground type is assigned to the fifth element.
if (groundX == 32) { groundX = 0; byte type = random(0, 6); switch (type) { case 0 ... 3: type = GroundType::Flat; break; case 4: type = GroundType::Bump; break; case 5: type = GroundType::Hole; break; } ground[0] = ground[1]; ground[1] = ground[2]; ground[2] = ground[3]; ground[3] = ground[4]; ground[4] = (GroundType)type; } groundX++; to be continued next page >> Page 29 of 46
Moving and rendering Steve When Steve is not standing around waiting for the game to begin he may be running, ducking or simply be dead. These various states or stances are shown below:
These stances are enumerated in an enum called Stance. As with the ground types detailed above, a matching array of dinosaur images has been declared with the images arranged in the same order as the Stance enumeration. A second array of masks has also been declared – again with the masks in the same order as the Stance enumeration – to allow us to use the Stance values as indexes.
enum Stance { Standing, Running1, Running2, Ducking1, Ducking2, Dead1, Dead2, }; const byte *steve_images[] = { dinosaur_still, dinosaur_running_1, dinosaur_running_2, dinosaur_ducking_1, dinosaur_ducking_2, dinosaur_dead_1, dinosaur_dead_2 }; const byte *steve_masks[] = { dinosaur_still_mask, dinosaur_running_1_mask, dinosaur_running_2_ mask, dinosaur_ducking_1_mask, dinosaur_ducking_2_mask, dinosaur_dead_2_mask, dinosaur_dead_2_ mask };
All of the details relating to Steve’s position and current stance are stored in a single structure.
Note that in structures, we can include fields using the common data types (integers, Booleans and so forth) and ones that refer to the enumerations we have already defined.
struct Steve { int x; int y; Stance stance; bool jumping; byte jumpIndex; const byte *image; const byte *mask; };
Once the structure has been declared, we can create an instance of it and initialise all of the elements in a single line as shown below. We now have a container to track changes in Steve’s position. Steve steve = {0, STEVE_GROUND_LEVEL, Stance::Standing, false, false, dinosaur_still, dinosaur_ still_mask };
to be continued next page >> Page 30 of 46
Our Steve structure has two fields that point to the image and mask that represent his current stance. Later we will use these to determine whether Steve has crashed into a cactus or pterodactyl. For now, we can populate these by looking up looking up the image and mask from the array of images using Steve’s current stance as an index.
Steve can then be rendered using the Sprites::drawExternalMask() function with Steve’s current position and the two image references. As Steve can be standing or ducking, I have assumed that his coordinates represent the lower left position. By default, images are rendered from the top left position and therefore I have subtracted the height of the image from Steve’s Y position to accommodate this.
void drawSteve() { steve.image = steve_images[steve.stance]; steve.mask = steve_masks[steve.stance]; Sprites::drawExternalMask(steve.x, steve.y - getImageHeight(steve.image), steve.image, steve. mask, frame, frame); }
Now that we can draw Steve on the screen, we need to be able to move him around. Our structure includes an X and Y coordinates plus fields that represent his current stance and whether or not he is jumping. Handling user input is generally handled in the main loop of the program. The code below tests first whether Steve is jumping and, if not, allows the player to control him. The Arduboy library provides four commands for detecting the pressing and releasing of buttons justPressed(), justReleased(), pressed() and notPressed(). The first two commands are used in conjunction with the command pollButtons().
A call to pollButtons() at the start of the main loop captures the current state of the Arduboy’s buttons. The justPressed()and justReleased() commands will return true if the user has pressed a button since the last time pollButtons() was called. The pressed() command returns true if the nominated button is pressed or remains pressed over a period of time. You can see that I am using the justPressed()command to detect a jump as it is a one off event whereas I am allowing the user to hold the left and right buttons to move continuously by using the pressed() command .
arduboy.pollButtons(); … if (!steve.jumping) { if (arduboy.justPressed(A_BUTTON)) { steve.jumping = true; steve.jumpIndex = 0; } if (arduboy.justPressed(B_BUTTON)) { if (steve.stance != Stance::Ducking2) { steve.stance = Stance::Ducking1; }; } if (arduboy.pressed(LEFT_BUTTON) && steve.x > 0) { steve.x--; } if (arduboy.pressed(RIGHT_BUTTON) && steve.x < 100) { steve.x++; } to be continued next page >> Page 31 of 46
if (arduboy.notPressed(B_BUTTON) && (steve.stance == Stance::Ducking1 || steve.stance == Stance::Ducking2)) { steve.stance = Stance::Running1; } }
The last clause of the code above detects whether the player has let go of the B button (the duck button) and returns Steve to a running stance if he was already ducking. The second part of the condition is important as the notPressed() command - as the name suggests - will return true when the user is not pressing the button and we do not want Steve’s stance to be changed unless he was actually ducking.
At the end of each loop, we need to update Steve’s position if he is jumping or change the image displayed to give the illusion of his feet moving.
Jumping Previously, we detected if the user had pressed the A button and set the jumping flag to true. If it is true we want Steve to jump an over oncoming obstacles in an arc that somewhat simulates the effects of gravity – fast acceleration at the start of the jump, deceleration as he reaches full height followed by acceleration as he falls to earth,
The array below describes the Y positions of Steve as his jump progresses. It starts and ends at Y = 55 (or ground level) and reaches a height of 19 in the middle.
unsigned char jumpCoords[] = {55, 52, 47, 43, 40, 38, 36, 34, 33, 31, 30, 29, 28, 27, 26, 25, 24, 24, 23, 23, 22, 22, 21, 21, 20, 20, 20, 20, 19, 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, 25, 26, 27, 28, 29, 30, 31, 33, 34, 36, 38, 40, 43, 47, 51, 55 };
The code below updates Steve’s position when jumping. In addition to the jumping flag, the data structure that maintains Steve’s details also includes an array index, named jumpIndex, which is used to keep track of the current position in the array. On each pass of the main loop, adjust Steve’s height to the value within the array that the index points to.
We then increment the array index up until the last value of the array is reached at which point Steve has returned to the ground and the jump is over. Steve’s jumping property is set to false and the array index is set to zero in anticipation of his next jump.
void updateSteve() { if (steve.jumping) { steve.y = jumpCoords[steve.jumpIndex]; steve.jumpIndex++; if (steve.jumpIndex == sizeof(jumpCoords)) { steve.jumping = false; steve.jumpIndex = 0; steve.y = STEVE_GROUND_LEVEL; }
}
} else { ... }
to be continued next page >> Page 32 of 46
Running or Ducking The illusion of running is achieved by alternating the images used when rendering Steve. If we alternate the images every frame (or every time we pass through the main loop), Steve’s legs will appear as a blur as this is too fast. To slow this down, we can use an Arduboy library function called everyXFrames(n) which returns true on every nth frame.
The code below alternates Steve’s stance every 3 frames. If his current stance is Stance::Running1 then it becomes Stance::Running2 – if it was already Stance::Running2 then it reverts back to the original value. This is true of the ducking images but not true of the dead images – once you are dead, you remain dead.
void updateSteve() { if (steve.jumping) { ... } else { if (arduboy.everyXFrames(3)) { switch (steve.stance) { case Stance::Running1: steve.stance = Stance::Running2; break; case Stance::Running2: steve.stance = Stance::Running1; break; case Stance::Ducking1: steve.stance = Stance::Ducking2; break; case Stance::Ducking2: steve.stance = Stance::Ducking1; break; case Stance::Dead1: steve.stance = Stance::Dead2; break; default: break;
}
}
}
}
Now that we have Steve running, jumping and ducking we can move on to the obstacles he will need to avoid.
Stay tuned for next month’s article, where launching obstacles will be discussed!
Page 33 of 46
Level: Beginner
Good Coding Habits
Part 1 - Meaningful Names by @Pharap Foreword
Hello readers. I’ve never actually written a magazine article before and I usually have a bit of an odd writing style, so this will be interesting to say the least. (I was also going to say I’ll try not to write a text-wall, but in a way that’s what magazine articles are supposed to be, right?) While this article is aimed mainly at beginners, I’d recommend reading it even if you aren’t a beginner. Even the smartest of people can write code that’s hard to follow, and I doubt there is someone out there who wouldn’t benefit from being reminded about some good coding habits.
This article is going to be all about ‘good coding habits’, which means it’s going to be full of tips that should make your code easier to read, easier to work with and easier to maintain. Writing good code does involve some effort, but others will thank you for it, and hopefully you’ll also see the benefits. As an added bonus, most of these techniques are transferable skills that will help you when programming things other than the Arduboy and in other programming languages. Anyway, here goes my first ever article.
Introduction This first part is about using meaningful names. I’ve noticed that beginners (and sometimes even experienced programmers) have a habit of not giving their variables very good names.
In fairness, it’s widely accepted by programmers that naming things can be really hard, but it is important for writing readable code so it deserves care and attention.
Sometimes people get lazy and can’t be bothered to type out long words so they just use shortened versions. Sometimes people just don’t know what to call their variable.
So I’m going to try my best to offer some advice on what makes a good name and how you can become a better namer.
Tip 1: Use Nouns and Verbs To start with, there’s one very easy way you can improve the readability of your code. Make sure all your variables are nouns (or ‘thing words’) and all your functions are verbs (or ‘doing words’). In programming, a variable is by its very nature a ‘thing’. It’s some sort of object, a block of data, maybe a number or a representation of a sprite. Variables don’t ‘do’ anything, they just sit there. For a variable to ‘do’ anything is has to be altered by an operator (e.g. =, +, - etc.) or by a function. For example, say I want to add 5 to an integer: variable = variable + 5;
The variable doesn’t do the adding, the variable is just the place where the number is stored. Instead, the addition operator + is used to take the variable’s value and add 5 to it to create a new value and then the assignment operator = takes that value and puts that value back into the variable. So naturally, since variables are in fact ‘things’ it makes sense that variables should be named with ‘thing’ words, e.g. player, enemy, entity, gameState. Functions on the other hand, should be named with ‘doing’ words, e.g. update, draw, addHealth, checkForWin.
to be continued next page >> Page 34 of 46
Tip 2: Use Descriptive Names For beginners, it’s especially common to think about what a variable is rather than thinking about what it’s used for. I’ve seen quite a few beginners working on their first attempt at doing some maths in code and decide to call their variable number or number1. That’s fine for a first attempt, but you shouldn’t be doing that in production code. When picking a name for something, you should pick a name that reflects what the purpose of that thing is. For example, call your Arduboy2 variable arduboy, because that’s what it represents. If you’ve got a variable to store the player’s name, call it playerName. If you have an object representing the player, don’t call it myHero, call it player. If you’re calculating the distance between a player and an enemy then distance is probably a good name, although distanceToEnemy would be much more descriptive even if it’s a bit more typing. If you’ve got a boolean variable, you should try to name it with words like ‘is’ or ‘can’, for example isOnGround or canFly. Likewise you shouldn’t use ‘is’ or ‘can’ for things that aren’t boolean variables, for example if you have a counter that you use to do something special when it reaches zero, that shouldn’t
be a canDoSomething variable because that isn’t an accurate description of what it does, a better name would be something like framesUntilSomething – it’s a counter, not a condition. Another example, although this one is a bit more of a grey area: if you’re writing an asteroids game and you’re representing the ship’s direction as an angle, don’t call it shipDirection, call it shipAngle so it’s clearer that it’s just an angle and not some other way of representing direction (e.g. a vector). Using descriptive names gets more and more important as you start to write more advanced code, and sometimes it gets more difficult too. There are some incredibly complicated topics in programming so it really pays to be as clear as possible. Remember, at some point you will stop working on a project and start doing other things. If you decide to come back to that project later and find you’ve forgotten everything and you haven’t used very good names then you’re going to be struggling to understand it. There’s nothing worse than reading some code, wanting to scream “what moron wrote this? I can’t understand any of it” and then suddenly realising “oh wait, it was me... oops”, and I’ll freely admit I’ve been there, as I suspect many others have.
Tip 3: Avoid Short Names Historically programming used short names because back ‘ye olden days’ computers didn’t have much memory for storing source code and there weren’t any fancy newfangled auto-complete systems. Also most programmers were mathematicians who were doing serious business ‘computer science’, so they had the mathematicians’ habit of singleletter variables. One of the biggest reasons I never got on very well with algebra (or mathematics in general) is that mathematicians love to give their variables single-letter names and it’s not very helpful for understanding an equation. Take a random mathematical equation using single letters for variables and show it to a
non-mathematician and they won’t have the slightest clue what it’s used for. The same is true for programming. If most of your variables have one-letter names then your code will generally look confusing. For example, Einstein’s famous equation could be written in code as: float e = pow(m * c, 2);
but it could be written much more descriptively as: float energy = (mass * lightSpeed) * (mass * lightSpeed); to be continued next page >> Page 35 of 46
Before the rewrite, most people would recognise the equation but not have a clue what it means, but after the rewrite it’s more obvious that it’s calculating the energy of something by multiplying the mass of something and the speed of light, then multiplying that value by itself. Programming need not be rocket science! (Or in this case theoretical physics.) There are a few exceptions to this rule. For example, using x and y as coordinates and using i and j as loop variables are well established. Also in some cases where mathematical constants are involved (like Euler’s number e or the speed of light c) the recognised mathematical letter is acceptable. Using contractions of larger words is a bit of a grey area.
Some people are fine with contracting sprite to spr, width to w and height to h. Personally I am against doing this because I think using the full names makes code easier to read because fully fledged words are easier to recognise. (If you shorten arduboy to ab, know that I am frowning at you right now, and also ducking under my desk to dodge the internet projectiles you’re probably throwing at me.) Importantly, remember that modern text editors and IDEs have auto-completion of words, so being too lazy to type long names is a poor excuse. Also, using smaller variable or function names doesn’t actually save space – it might make your source code smaller but it won’t affect the compiled code at all.
Tip 4: Keep naming consistent Lastly, when naming things it’s important to keep your naming choices consistent. For example, if you were writing some functions involving USB communication, it’s important to be consistent with the capitalisation of USB. If you wrote a function called openUSB, it would be confusing to then have another function called closeUsb because you’d be using two different approaches to capitalisation. Using acronyms in code is another one of those awkward grey areas. Sometimes people prefer putting the letters all in capitals, such as openUSB and closeUSB, and sometimes people prefer treating an acronym as its own word, like in openUsb and closeUsb.
Neither is right or wrong, but it’s important that when you pick a naming pattern, you stick to it. Similarly, it is important to keep the order of naming consistent. By which I mean don’t mix openUSB and usbClose, stick to using either openUSB and closeUSB or usbOpen and usbClose. When your names follow a distinct pattern it makes it much harder to make mistakes and much easier to remember names.
Summary Naming might be hard at times, but it’s worth the effort to get it right. Whether you code alone or in a team, giving your variables, functions and classes good meaningful names can be very helpful. Even if you do code alone, you might take a break from your project and forget all about it. Then six weeks down the line you rediscover your project and want to work on it again – that’s going to be a lot easier if everything’s clearly named. The less time you have to spend understanding your code, the more time you can spend writing games.
Then there’s the matter of asking for help. Everyone needs help with their code sometimes, and when that time comes you wouldn’t want the person helping you to have a hard time trying to understand your code. If your code is easy to read and easy to understand, that person helping you will be able to sort your problem a lot quicker than they would if your code was full of confusing names.
to be continued next page >> Page 36 of 46
I think I’d like to end this with a relevant and somewhat profound quote from a well known programming book (that I’ve heard of but never read): “Names are deeply meaningful to your brain, and misleading names add chaos to your code.” - Andrew Hunt, ‘The Pragmatic Programmer’.
Did this article help you as a beginner, or reminded you of good coding practices? Start a discussion in our community! Keep an eye out for Part 2 in the next issue!
We are looking for Pixel artists to feature! Are you a pixel artist? Done some Arduboy Fan art? Wish to have your work shared with the Arduboy community? Send arduboymag a message through the Arduboy community page or a DM on Twitter!
Page 37 of 46
EXPLORE:
In this section we’ll ask the same 10 questions to a different developer in every new issue.
Questions with game developers by @Celinebins
Always quick to offer help in the community pages, this issue we interview @Pharap, author of his first Arduboy Magazine article above!
1. Tell us a little bit about yourself.. Taken from the community page: Feel free to ask me for help with things. The three great programming virtues are laziness, impatience and hubris.
2. Where did you find out about Arduboy the first time? @noel_abercrombie (who I know in person) told me about it after backing the kickstarter. The Arduboy I’m currently using is actually one of his kickstarter units, but I’ll be able to ‘un-borrow’ it when the Arduventure units ship.
3. What is the first program/game you created for Arduboy? That’s a tough one since I tend to write a lot of throwaway code to try things out. I think the first game I worked on was the dungeon crawler Loot which kind of evaporated. Though looking at my Arduboy projects folder, aparently the oldest project I have (last modified 07/11/2015) is actually a prototype FixedPoint class. That’s a spooky coincidence.
4. Did you have app / game development experience before Arduboy? Yes. I have a BTEC in Game Design and a HND in Computing and have been programming for roughly 5-6 years now. The first game I made (which I still have the code for) was a sort of dungeon crawler written during my BTEC with the Windows forms API in Visual Basic using Visual Studio 2008. Despite how awful that sounds, the game itself wasn’t too bad for a first game. I also made a Java version of asteroids during my HND which had decent rigidbody physics simulation. Usually I spend more time writing throwaway utility programs and libraries than games though.
5. What do you read to learn how to code for Arduboy? Generally I don’t need to because of my prior programming experience. At most I’ll read the code or documentation for the libraries I’m using. to be continued next page >> Page 38 of 46
For people with less experience though, I’d recommend looking around the forums at questions other people have asked, reading library documentation, reading code from other people’s games and of course reading articles in the Arduboy magazine. It also pays to read C++ tutorials on other sites as well though, there’s no substitute for good knowledge of the language you’re using to program.
FixedPoints library, so I’d like to release that eventually (even though @taniguchi just released a really good Minesweeper clone). Apart from that I’ve also got another (currently secret) project I’ve started working on, which isn’t really a game per se, but if I can get it working the way I want it then it will certainly help with making certain games.
6. What app/game do you currently have on your Arduboy.
9. What app/game would you love to see on the Arduboy?
A work-in-progress version of the game @Dreamer2345 is making (Rouge Boy). Though it could have easily been @ luxregina and @filmote’s work-in-progress game Dark & Under, since I’ve been acting as a tester and advisor for both.
I really like tile-based games so I’d like to see some more tile-based games being made. I’d also like to see more games with stories and more humourous games.
7. What app/program is your favorite? That’s a tough one. Truthfully I spend more time developing and testing Arduboy games than I actually do playing them. Obviously I’m fond of @filmote’s 1943 because I was the tester for it (and it’s currently the only game using my FixedPoints library). And both the unpublished games I’ve been helping with are pretty cool. And I liked the zoo jam games… I like lots of different games, I don’t have a particular favourite.
8. What is the next app/program for Arduboy we can expect? Well, obviously Dark & Under and RougeBoy are just around the corner, and Arduventure is out next year. If you mean me specifically, I’ve got a version of Minesweeper that I started back in July before I got sidetracked with my
10. What is your best tip for other people who want to start creating apps/games for Arduboy? This is the hardest question, I’ve got so many tips that, it’s hard to pick just one. I’ve had to rewrite my answer for this several times now because it’s so hard to decide. I suppose really when it comes down to it the most important thing is to keep trying. Programming is hard. To be a good programmer you need to know an awful lot of things and it can be very daunting at times. But no matter how hard it may seem, if you keep trying you’ll get there eventually. If you’re stuck, read some articles, practise some more, stop and ask for help, but whatever you do - don’t give up. Get inspired at @Pharap’s Github page: https://github.com/Pharap Are you a developer and want to be featured here? Reach out to the Magazine through Twitter DM @arduboymag Page 39 of 46
Gamestart is Southeast Asia’s premier game convention, and Arduboy was part of it on 14 & 15 October 2017! This year brought back annual favourites as well as new and exciting content for everyone, including game showcases and previews, esports, indie games, retro gaming, cosplay and more! Read more on our experience below.
Arduboy was at Founder’s Base.. Right next to the main stage! Special events = special prices
There was a Cosplay “Catwalk” competition on Sunday, and all Cosplayers enter for free! Page 40 of 46
Playstation had a sponsored stage at the corner of the hall, where Street Fighter and other PS E-sports competitions were held throughout the weekend.
There was also an area dedicated to Table top gaming.
Next to founder’s base was ‘Doujin Market’ where talented artists displayed their work and some even did live drawing.
There were indie games from the International Game Developers Association of Singapore, and there were also huge booths from the big boys.
Watch the official Gamestart Asia 2017 video here
Images taken from: Dejiki.com https://dejiki.com/2017/10/gamestart2017-gaming-convention-highlights/ Page 41 of 46
Retro Gaming Expo, Inc. is a Portland, Oregon-based 501(c)4 non-profit cooperative organization dedicated to creating awareness of, and appreciation for classic video and arcade games through the presentation of events and conventions that celebrate the historic contribution video games have made and continue to make in popular culture.
Thank you everyone from Portland and beyond who attended the expo and dropped by the Arduboy booth! Community member and Circuit Dude developer Jonathan Holmes (@crait) was invited to take part. Who managed to meet him and Kevin?
Page 42 of 46
Workshop: Make a retro style game in Bangkok by Gearwalker
Date: 22 October 2017 Time: 10:30 - 16:00 Where: Fab Cafe, Bangkok, Thailand Thai maker, Gearwalker, held a game making workshop in one of Bangkokâ&#x20AC;&#x2122;s trendy cafes, FabCafe. Participants brought their laptops and were provided an Arduboy for the course. Everyone had a lot of fun learning how to program for their Arduboy.
If you missed this one - sign up for the next workshop on 26th November in FabCafe Bangkok here! Page 43 of 46
Workshop: Play n code your own epic games with Clouduboy by @Flaki
Date: 5 November 2017 Time: 11:00 - 13:00 Where: Fab Cafe, Singapore Talented firefox developer @flaki walked participants through gme creation on his online Clouduboy platform - where you do not need to download Arduino. If you are interested in how Clouduboy works, visit the page here. It is still in Beta testing so you would not be able to use it immediately, but you can reach out to @flaki via twitter for a user key.
Missed the workshop? Like their page to get notifications for the next one early next year!
Page 44 of 46
#arduboy:
Arduboy
Adventure!
“Arduboy Mate by @mockfrog and clone of @eried collection made the perfect #Arduboy Roadtrip.” He got to play got to play @ZappedCow ‘s “CastleBoy” in a medieval castle, @TEAMarg_org’s SIRÈNE in an under water world, and @crait’s “Chicken Cross” with some naughty chickens....
@Keyboard_Camper
Post your photos with Arduboy on Instagram and Twitter with #arduboy. We want to feature them in this segment!
Page 45 of 46
Thank
you!
Thank you for reading the Magazine! Hope you enjoyed it as much as we did putting it together. We want to know how to make Volume 11 better than the last, so write in to us to tell us what you think!
https://twitter.com/arduboymag