24 February 2023

Introduction to Game Design, Prototyping, and Development: From Concept to Playable Game with Unity and C#

Introduction to Game Design, Prototyping, and Development: From Concept to Playable Game with Unity and C#
 by Jeremy Gibson Bond is a great book to start with game development. Whereas other books focus on Unity development, Bond shows his academic experience with an overall focus that includes both theoretical concepts and technical ones. It's well thought structure has an academic smell indeed, but this one is for good and will give a knowledge that won't fade in few years or few versions of your specific game engine.

The first part of the book is focused in theoretical topics beginning with a high abstraction level and descending afterwards to detail step by step. In fact, it begins describing the concept of what we know as a game and which are its elements and structure. Take note that I've said game and not specifically computer game. This book part concepts are so general that author encourages to practice them with pencil and papers. It's evident that Bond is a great board and role playing games fan, starting with D&D, by his several references to that kind of games and its mechanics. This part goal is that the reader can model the game in his head, focusing in the mechanic development needed to make it appealing to be played. In this part has been specially suggestive the layered structure for the different games kinds that are inside a game: there is the game intended by its creators when they designed its rules, there is the game that rises when the game is played at the table, and then there is a game than appears when people start to mod the game and evolves it beyond what its creators thought (modding fan will really enjoy this part).

The second part deals with game design. Starting from theoretical concepts different parts of a game are defined, first with paper prototypes played by different tester rings. Here is specially interesting the part where the subtle ways to guide player are covered. In this part event Agile and Scrum is covered. 

I think this two first part will be the most interesting for seasoned Unity developers.

The third part implement paper prototypes in technical prototypes, more similar to the end game. Here is where Unity basic topics start, from the very beginning starting from editor layout setup and later with C# Unity development. Those who already know about C# and Unity probably will read fast these pages, although I don't recommend to skip them because you ca still learn useful tips. I've developed a lot in Unity and I'v still learned one or two things.   

The fourth part is focused in prototype development to cover some of the basic game kinds. They are like mini tutorials being each of them a different game. Those who are starting with Unity development will find here and excellent way to advance learning even good practices. 

So, it is a complete book, well structured and didactic, with a lot of links and book references to continue after ending this book. I recommend it both to those who already know Unity and want to start with game design, and to those who are starting and want to learn Unity from the scratch.

20 January 2022

How to parse console arguments in your Rust application with Clap

In a previous article I explained how to use ArgParse module to read console arguments in  your Python applications. Rust has it's own crates to parse consoles arguments too. In this article I'm going to explain how to use clap crate for that.

One wonderful thing about Rust is that inside its hard rustacean shell it uses to have a pythonista heart. Using clap you'll find many of ArgParse features. Actually concept are quite similar: while you called verbs as subparsers in ArgParser, here in clap you're going to call them subcommands, and ArgParse arguments are simply named at clap like arg. So if you're used to ArgParser you'll likely feel at home using clap. I'm going to assume you read my ArgParse article to not to repeat myself explaining the same concepts. 

Like any other Rust crate you need to include clap in your Cargo.toml file:

After that you can use clap in your source code. To illustrate explanations, I'm going to use as an example the command parsing I use in my project cifra-rust

As you can see there, you can use clap directly in you main() function but I like to abstract it in a generic function that returns my own defined Configuration struct type. That way if I switch from clap to any other parser crate change will be smoother for my app (reduce coupling). So, as I do at python I define a parse_arguments() function that returns a Configuration type.

There you can see that root parser is defined at clap using App::new(). As other rust crates, clap makes heavy use of builder pattern to configure its parsing. That way you can configure command version, author or long description ("long_about"), between other options, as you can see from lines 277 to 280:

Clap behaviour can be customized with setting() call. A typical parameter for that call is AppSettings::ArgRequiredElseHelp, to show help if command is called with no arguments:

A subparser is created calling subcommand() and passing it a new App instance:

With call about() you can define a short description, about the command or arguments, that will appear when --help is called.

Usually parser (and subparsers) will need arguments. Arguments are defined calling arg() in the parser they belong to. Here you have an example:

In last example you can see that subparser create (line 285) has two arguments: dictionary_name (line 287) and initial_words_file (line 292). Note that every arg() call uses as a parameter and Arg instance. Argument configuration is done using builder pattern over Arg instances.

Argument dictionary_name is required because it is configured as required(true) at line 288. Be aware that although you can use a flag here you are discouraged to do so. By definition, all required arguments should be positional (i.e. require no flag), the only time a flag could be used in required arguments is when called operation is destructive and user is required to prove he knows what he is doing providing that extra flag. When a positional argument is used you may call index() to specify the position of this argument relative to other positional arguments. Actually, I've found out later that you can leave off index() and in that case index will be assigned in order of evaluation. What index() allows you is setting indexes out of order.

When you call takes_value(true) on an argument, the value provided by user is stored in a key called like the argument. For instance, the takes_value(true) at line 290 makes the provided value to be stored in a key called dictionary_name. If your are using an optional flag with no value (i.e. a boolean flag) you could call takes_value(false) or just omit it.

The call to value_name() is equivalent to metavar parameter at python's argparse. It lets you define the string you want to be used to represent this parameter when help is called with --help argument.

Oddly, arguments don't use about() to define their help strings but help() instead.

You can find an optional argument definition from line 292 to 298. There, long version of flag is defined with long() and short one with short() call. In this example, this argument could be called both "--initial_words_file <PATH_TO_FILE_WITH_WORDS>" and "-i <PATH_TO_FILE_WITH_WORDS>".

It can be useful call validator(), as it let you define a function to be called over provided argument to assert it is what you expect to receive. Provided function should receive an string parameter with provided argument and it should return a Result<(), String>. If you make your checks and find correct the argument the function should return an Ok(()), or an Err("Here you write your error message") instead.

Chaining methods on nested arguments and subcommands you can define an entire command tree. Once you finish you have to make one final call to get_matches_from() to the root parser. You pass a vector of strings to that method, with every individual command argument:

Usually you'll pass a vector of strings from args() which returns a vector with every command argument given by user when application was called from console.

Note that my main() function is almost empty. That is because that way I can call _main() (note the underscore) from my integration tests, entering my own argument vector, to simulate a user calling the application from console.

What get_matches_from() returns is a ArgMatches type. That type retuns every argument value if be search by its key name. From line 149 to 245 we implement a method to create a Configuration type using an ArgMatches contents.

Be aware that when you only have a parser you can get values directly using value_of() method. But if you have subcommands you have first to get the specific ArgMatches for that subcommand branch doing a call to subcommand_matches():

In last example you can see the usual workflow:
  • You go deep getting the ArgMatches of the branch you are interested in. (lines 160-161)
  • Once you have the ArgMatches you want, you use value_of() to get an specific argument value. (line 164)
  • For optionals parameters you can make a is_present() call to check if that one was provided or not. (line 165). 
Using those methods, you can retrieve every provided value and build up your configuration to run your application.

As you can see you can make really powerful command parser with clap getting every functionality you are used at ArgParse but in a rustacean environment.