Categories
Game Design Game Development Geek / Technical

Toytles: Leaf Raking Progress Report – Refactoring, Testing, and Vacationing

Last week’s report indicated that I didn’t get as much done as I would have liked. I managed to add a bunch of new random dialogs for weekends, but I didn’t get to grumpy client dialogs, which I pushed into the next sprint.

Sprint 5: More personality injections; streamline waiting for rain

Last week’s sprint plan was:

  • Give each neighbor unique text as unhappy clients
  • Streamline “Wait for Rain” option

In the last report, I said:

So this week’s sprint I will definitely get to the unhappy client dialog. I have some marketing screenshots to update, partly due to the copyright date, and I want to streamline the way you wait for rain to end so you can get back to raking as it is currently a bit clunky.

I did 2.25 hours of game development, but I did not actually work on any of the above.

So what did I do? Well, last week’s report also said:

I am kicking my Past Self for not spending more time on automated tests so I didn’t have to verify that I didn’t break anything each time I make a change. I’m slowly improving the code as I go along so that it is easier for Future Self, but Past Self is a short-sighted jerk.

This codebase is a few years old, and it has gotten fairly unwieldy. When I work on a 48-hour game development competition such as Ludum Dare, it’s fine for almost all of my game code to be in a single file. It is quick and dirty, and so long as I am mindful and focused, as I would be in a concentrated weekend development effort, I can make a game and then be done with it.

But when I have a commercial project that I am maintaining for years, something I come back to once in awhile, I need to break it up into well-tested pieces so that I don’t need to worry about forgetting how it works.

So I invested in my code quality last week. The rest of this report gets fairly technical, so feel free to skip to the end for my plans for the next sprint.

Code quality and its improvement

To give an idea of what I am dealing with, I have a class called InGameState which handles all of the game play logic and rendering. The class itself only has six functions:

virtual void onEnter();
virtual void update(int timeElapsed);
virtual GBLib::IRenderCommand * draw(); 
virtual void onExit(); 
virtual void onSuspend();
virtual void onUnsuspend();

This class is the workhorse of pretty much all of my games. That is, when you start a new game, the Main Menu state changes to the In Game state. It calls onEnter(), which is where things get initialized, including loading saved games or creating default values for variables.

Then update() and draw() get called over and over until the player exits, which calls onExit(), and the state machine calls onEnter() on whatever other state, either the main menu state again or the exit state in preparation for shutting down the game.

But as I said, I like to throw as much as I can into a single file when I work on a quick game project. If you looked at InGameState.cpp from nine months ago, it was 4,148 lines of code, and my work in the last month has added another 100 lines of code or so.

In a well-written codebase, I’d argue that most class implementations shouldn’t be more than a few hundred lines of code.

Now onSuspend() and onUnsuspend() are meant to help with pausing and unpausing, usually by delegating to a different state, but in this game, they merely set a boolean value to true and false respectively, so they aren’t very interesting. So how are over 4,000 lines of code distributed among four functions?

Well, they aren’t really. There may be four major class member functions, but each one is implemented using inline code as well as non-member functions strewn throughout the file.

I don’t know offhand how many of those non-member functions are in the code base. There’s a lot. But I know my bias is towards lots of small, well-named functions. But this codebase is also a few years old, so some of those functions are not as small as I would like.

So why didn’t I add them to InGameState.h and make them part of the class? Well, as with my protoytpe projects, it is a lot easier to delete all of the .cpp file and copy the header into a new project than it is to remember which functions to keep and which ones are project-specific.

Why didn’t I create a project-specific class and leave InGameState as a generic class to be used across projects? Because I didn’t.

In any case, there is so much code in this class that handles everything from initializing variables, dialog management, time and date changes, weather updates, input processing, screen updates and changes, and more.

An example: generateNeighborhoodScreenBG()

There’s an entire function dedicated to figuring out how to render a particular part of the neighborhood.

This function is over 50 lines long. What may not be obvious is that it takes what is called a NeighborhoodScreen, iterates over the tiles at the x and y positions, and adds the sprite that corresponds with the tile to the spriteWidget.

Ostensibly, that is ALL it does. But when you look at the code, it looks like it is doing a lot more. In fact, most of the code was actually figuring out how to put sidewalks down based on where streets are located.

void generateNeighborhoodScreenBG(SpriteWidget * spriteWidget, NeighborhoodScreen * screen)
{
	for (int x = 0; x < MAX_NEIGHBORHOOD_TILE_WIDTH; ++x)
	{
		for (int y = 0; y < MAX_NEIGHBORHOOD_TILE_HEIGHT; ++y)
		{
			int tileType(screen->tiles.at(x).at(y));
			SpriteWidget * tileWidget = new SpriteWidget(TileTypesToSprites[tileType], Point(x * TILE_WIDTH, y * TILE_HEIGHT, ZORDER::BG));
			if (STREET_TILE == tileType)
			{
				if (y != 0 && screen->tiles.at(x).at(y-1) != STREET_TILE)
				{
					tileWidget->add(new SpriteWidget(SideWalkHorizontalSprite, Point(0, 0, ZORDER::FG)));
				}
				else 
				{
					tileWidget->add(new SpriteWidget(SideWalkCornerSprite, Point(0, 0, ZORDER::FG)));
					tileWidget->add(new SpriteWidget(SideWalkCornerSprite, Point(TILE_WIDTH - 27, 0, ZORDER::FG)));
				}

				if (y != MAX_NEIGHBORHOOD_TILE_HEIGHT - 1 && screen->tiles.at(x).at(y + 1) != STREET_TILE)
				{
					tileWidget->add(new SpriteWidget(SideWalkHorizontalSprite, Point(0, TILE_HEIGHT - 27, ZORDER::FG)));
				}
				else
				{
					tileWidget->add(new SpriteWidget(SideWalkCornerSprite, Point(0, TILE_HEIGHT - 27, ZORDER::FG)));
					tileWidget->add(new SpriteWidget(SideWalkCornerSprite, Point(TILE_WIDTH - 27, TILE_HEIGHT - 27, ZORDER::FG)));
				}

				if (x != 0 && screen->tiles.at(x - 1).at(y) != STREET_TILE)
				{
					tileWidget->add(new SpriteWidget(SideWalkVerticalSprite, Point(0, 0, ZORDER::FG)));
				}
				else
				{
					tileWidget->add(new SpriteWidget(SideWalkCornerSprite, Point(0, 0, ZORDER::FG)));
					tileWidget->add(new SpriteWidget(SideWalkCornerSprite, Point(0, TILE_HEIGHT - 27, ZORDER::FG)));
				}

				if (x != MAX_NEIGHBORHOOD_TILE_WIDTH - 1 && screen->tiles.at(x + 1).at(y) != STREET_TILE)
				{
					tileWidget->add(new SpriteWidget(SideWalkVerticalSprite, Point(TILE_WIDTH - 27, 0, ZORDER::FG)));
				}
				else
				{
					tileWidget->add(new SpriteWidget(SideWalkCornerSprite, Point(TILE_WIDTH - 27, 0, ZORDER::FG)));
					tileWidget->add(new SpriteWidget(SideWalkCornerSprite, Point(TILE_WIDTH - 27, TILE_HEIGHT - 27, ZORDER::FG)));
				}
			}
			spriteWidget->add(tileWidget);
		}
	}
}

There isn’t anything wrong with this function. It does what is intended. Well, presumably. Since I have no tests around it, who knows what that intention was originally or if it continues to work when I’m changing code or even sneezing near it. But let’s assume with maybe only a little anxiety that the code works.

What I hate about it is that this code mixes levels of abstraction. I’m iterating through tile types and adding corresponding tile sprites to some parent sprite. But in one special case, I suddenly need to figure out how to add child sprites to the tile sprite. It’s important, but not so important that it takes up the lion’s share of the function! It just makes the entire thing harder to comprehend. So, a quick “refactor” changes the above code to:

void generateNeighborhoodScreenBG(SpriteWidget * spriteWidget, NeighborhoodScreen * screen)
{
	for (int x = 0; x < MAX_NEIGHBORHOOD_TILE_WIDTH; ++x)
	{
		for (int y = 0; y < MAX_NEIGHBORHOOD_TILE_HEIGHT; ++y)
		{
			int tileType(screen->tiles.at(x).at(y));
			SpriteWidget * tileWidget = new SpriteWidget(TileTypesToSprites[tileType], Point(x * TILE_WIDTH, y * TILE_HEIGHT, ZORDER::BG));
			if (STREET_TILE == tileType)
			{
				addSidewalksToTileWidget(tileWidget, screen, x, y);
			}
			spriteWidget->add(tileWidget);
		}
	}
}

I simply extracted that giant collection of if/else chunks into a separate function called addSidewalksToTileWidget().

Sidewalks on streets

Now, you’ll note I said “refactor” above. Why the quotes? Well, as said, there are no tests around most of these non-member functions. I have no idea if I subtly broke something with this change. I think it looks fine, and when I play test the game, it still seems to be rendering sidewalks on streets as expected, but does it do the exact same thing as it did before? I have no way of verifying it. So it’s not really refactoring, because refactoring requires that I know with some confidence that I didn’t change the behavior when I changed the structure of the code.

You might also wonder what the above change bought me. Did I not just add more lines of code to InGameState.cpp?

Yes, yes I did. But as I said, the original function mixed layers of abstraction and was hard to read. It is now easier to read and understand. Future Me will be so pleased that Current Me didn’t get in his way when it comes to future updates.

Another example: getTimeText()

Ok, how about one that actually shrunk InGameState AND resulted in an increase in testing, giving me more confidence that the code works and will continue to work correctly in the future?

getTimeText() takes a TimeOfDay object and produces a string that I can render in the clock at the top left of the screen.

TimeOfDay handles dates, but for the purposes of this function, know that it has two important members: hour and minute. TimeOfDay uses 24 hours, and so based on the hour, getTimeText() needs to show a 12-hour clock and let you know if it is AM or PM.

The minute isn’t an actual count of minutes. Time passes in Toytles: Leaf Raking in 10 minute increments, so TimeOfDay’s minute can have values 0 through 5. So getTimeText() will need to convert minute to one of the 10 minute increments to render.

For example, if getTimeText() takes a TimeOfDay object with an hour of 14 and a minute of 3, it will return the string “2:30 PM”.

The TimeOfDay struct was already in a separate file called Gamedata.h, mixed with other miscellaneous classes. But the following code was in InGameState.cpp:

std::string getTimeText(const TimeOfDay & timeOfDay)
{
	std::stringstream timeText;
	int currentHour = (timeOfDay.hour == 0) ? 12 : timeOfDay.hour;
	std::string periodString = (timeOfDay.hour >= 12 ) ? "PM" : "AM";
	
	if (currentHour > 12)
	{
		timeText << currentHour - 12;
	}
	else
	{
		timeText << currentHour;
	}

	if (timeOfDay.minute == 0)
	{
		timeText << ":00";
	}
	else
	{
		timeText << ":" << timeOfDay.minute * 10;
	}

	timeText << " " << periodString;

	return timeText.str();
}

Since it is so intimately tied to TimeOfDay, I decided to make it a member, and I wanted to be able to test this class, so I put it in its own .h and .cpp files.

There was a bit of hesitation on my part to add this function as a member of TimeOfDay. The struct is just a value, and getTimeText() outputs a particular rendering of that value in a certain way. How it gets rendered should be independent of what it represents, much like how CSS can let you style the same HTML differently based on your needs. What if a future project needs a 24-hour clock rendered? Or what if I don’t want to render text but will instead render an analog clock?

So good design tells me that getTimeText() is more of a rendering helper than an intrinsic part of the TimeOfDay struct, and therefore it should be separate.

But incremental and iterative change tells me that I can move it into the struct, then add tests to it, as well as other TimeOfDay functionality that wasn’t related to rendering, and I can worry about creating separate renderer utilities in the future. Future Me might wish he had them, but he’ll be appreciative that the improved test quality allows him the option to create them much more easily.

I have a function that generates the store’s hours that makes use of getTimeText(). It changed from

hoursOfOperationText << getTimeText(openingTime) << " - " << getTimeText(closingTime);

to

hoursOfOperationText << openingTime.getTimeText() << " - " << closingTime.getTimeText();

It’s not a big difference, which is part of the point. I wanted it to be an easy change that improved things, a simple step forward.

I don’t like that TimeOfDay is in charge of figuring out how to render its time, but for now, I’ll take well-tested, refactorable code over trying to fix all of the design problems at once without a test suite to catch breaking changes.

Oh, and TimeofDay.cpp is 63 lines of code. It’s super easy to read and understand.

I frankly don’t have the hours to spend trying to remember everything I might break while making a large change, so I make smaller changes that I can handle in a single session between the day job and taking care of the kids.

Also, I went on vacation

I meant to work on actual features to continue to inject personality into the project, but I spent almost 2 hours writing a blog post and an email newsletter to announce the most recent update to Toytles: Leaf Raking, and the remainder of my time on changes like the ones above to make future changes easier and safer.

And then I left town for a birthday vacation at a log cabin in northeastern Iowa. It’s easy to social distance when you are living in a forest with no AC. I had a great time with my family.

But that vacation is also why I haven’t written up this report for Monday like I planned. Next week’s report should be on the regularly scheduled day.

Next time, less random work

So my previous sprint got cut short, and my current sprint started late. I should probably commit to less getting done as a result.

I should ALSO stop myself from working on random “improvements” unrelated to what I committed to working on. I want more automated tests to give me confidence in what I am changing. I want to make the code easier to work within. I want to make Future Me happy.

But I also need to recognize that I didn’t get anything player-facing accomplished. I didn’t even address any bugs. I just restructured some code. There’s no actual value in doing so. In fact, Future Me might not even find any improvement in his situation from the changes I did make since I made them without any thought toward what he was going to work on next.

On the one hand, I’m the boss. I can give myself time to work on nothing but code quality improvement. No one is going to give me a hard time about slowing down my next release. On a whim, I can decide to work on a completely different project if I wanted, or not work on a project at all if I need the break.

But on the other hand, I’m the boss, and I need to keep my eye on continually adding value for players. No one else is responsible for ensuring that what I’m working on is the highest priority, and I need to hold myself to a higher standard. I need to be more deliberate.

You might think that I am chastising myself, but I’m not. I’m just taking this opportunity to analyze how the past sprint went and how I would like to change things going forward to improve future sprints. Future Me is going to have the benefit of hindsight, as well as a project that has steadily been improving in quality both from a game play perspective as well as a codebase perspective.

So going forward, code quality improvements should always correlate to work that adds value to the game in the eyes of my customers.

InGameState.cpp has a lot of low-hanging fruit along the lines of long functions I can shorten and classes I can pull out into their own files, so the temptation is going to be to tackle these all at once. I love refactoring code, even if I am just “refactoring” code carefully without the benefit of tests. And ultimately I’d like to get most of the code covered by tests, which requires pulling out more and more into separate modules.

But I’m also running an indie game development business. No one is going to be convinced to purchase a game because its internal code is easier for the developer to work with. There is value in Future Me having an easier time supporting and updating this and other projects, but Future Me is smart and capable enough to make the changes he needs when he needs them. Current Me will make the changes I need as I need them today.

I’ll waste less time on guessing what might be useful and actually work on what I see would be useful now.

Toytles: Leaf Raking Player's Guide

Want to learn when I release updates to Toytles: Leaf Raking or about future games I am creating? Sign up for the GBGames Curiosities newsletter, and get the 24-page, full color PDF of the Toytles: Leaf Raking Player’s Guide for free!

Categories
Game Design Game Development Geek / Technical

Toytles: Leaf Raking Progress Report – A Little More Conversation

Last week, I reported on the progress of my first few sprints to create updates for my leaf-raking business simulation Toytles: Leaf Raking.

Sprint 4: More personality injections

Last week’s sprint plan included:

  • Give each neighbor unique text as unhappy clients
  • Add variation to weekend flavor text

I was able to work 5.25 hours, but unfortunately part of that time was used to create the v1.4.1 release for both the App Store and Google Play.

Unfortunately, it’s not yet an automated process. Well, the Android build is mostly automated. I can run a single command and have a release APK ready to install on my own devices to test with or to upload.

But due to Apple changing requirements every so often, breaking old scripts and how-tos, I unfortunately can only get so far before I need to fiddle with things in Xcode in order to create a publishable release for iOS.

I have it mostly down to only a few manual steps related to getting the app icons setup at this point, but it’s still tedious and annoying that I need to do so.

I decided to work on the weekend flavor text, which is all I finished for this sprint unfortunately.

There were originally two random dialog sequences that occurred when you woke up on a weekend, telling you about a dream you had. Now there are 11 more.

New dream

Part of the time was rewriting some of the code so it was easier for me to add a dialog sequence. I think ultimately it would be best if I could change the code to load the scripts from a text file. For now, I’m adding the scripts in code, which requires a recompile to test each time. But it works.

None of these events make a difference to the game play. That is, they don’t help or hinder your progress towards earning enough money to purchase the Ultimate Item(tm).

So why do it? It’s all part of my attempt to inject some personality into the game.

And eventually I would like to add weekend events that allow the player to make a decision that could, in fact, make a difference. So for now, I’m laying the groundwork.

Until next sprint

So this week’s sprint I will definitely get to the unhappy client dialog. I have some marketing screenshots to update, partly due to the copyright date, and I want to streamline the way you wait for rain to end so you can get back to raking as it is currently a bit clunky.

I’d also like to invest in getting the release builds a bit more automated, and I am kicking my Past Self for not spending more time on automated tests so I didn’t have to verify that I didn’t break anything each time I make a change. I’m slowly improving the code as I go along so that it is easier for Future Self, but Past Self is a short-sighted jerk.

Toytles: Leaf Raking Player's Guide

Want to learn when I release updates to Toytles: Leaf Raking or about future games I am creating? Sign up for the GBGames Curiosities newsletter, and get the 24-page, full color PDF of the Toytles: Leaf Raking Player’s Guide for free!

Categories
Game Design Game Development Geek / Technical

Toytles: Leaf Raking Progress Report – Having a Dialog

A few weeks ago, I started working on a new set of updates for my leaf-raking business simulation Toytles: Leaf Raking, originally released in 2016.

I wanted to focus on making the neighborhood come to life by giving it some personality and character. I plan to do so by allowing your neighbors to talk about story lines happening in their lives.

My current project plan is in a spreadsheet I manage through LibreOffice, and with the COVID-19 pandemic, it took me quite a few months before I could focus on it. It mostly came together in June.

The original plan was broken down into weekly sprints, and I decided to continue to do so despite not having nearly as much capacity to get much done in a given sprint. Still, having a plan did wonders for my productivity.

What follows is a quick report on how the last few weeks have been.

Sprint 1: Start of personality injection

The first sprint was from June 21st to June 27th, and I wanted to get a few things done:

  • Give player option to accept a client when visiting a neighbor
  • Update copyright date on title screen
  • Chat w/ Mr. Matt at General Store
  • Give each neighbor unique chat text

Before that sprint, visiting a neighbor was the same as asking for work. Effectively, it meant you never visited anyone because you didn’t want to take on too many clients, which meant most of the neighborhood was pointless. This change should open up the way towards future work which will allow the neighbors to have more personality and give the player a reason to chat with them that doesn’t involve cold calling them for business.

I wanted to add the ability to talk to the store owner for the same reason. He doesn’t even exist in the game except for his name being on the store, and I want to make him a living, breathing character, too.

I wanted to update the copyright date to make it dynamic instead of baked into the title screen art, which should make it easier to update in the future. It was a fairly straightforward change.

And once you can visit a neighbor without asking for work, I wanted the ability to hear each neighbor say something unique when you call upon them. This change should mean that the neighbors are no longer essentially interchangeable numbers in a simulation, even if it is only one piece of dialog.

For that sprint, I did 2.5 hours of game development. It may not sound like much, but…well, it isn’t much. But again, we’re in a pandemic, I have kids, and there was some turmoil at my day job, so all in all, I think 2.5 hours sounds like plenty. Well, not really. I still worry when I don’t get much done in any given week, lamenting that if I was focused full time on it that I could probably get it all done in a day, but I’m trying not to dwell on it.

Unfortunately, I only got the copyright update and the visit option done.

Sprint 2: Start of personality injection (continued)

It took the next sprint to get the other two pieces of work accomplished, and that took me 7.75 hours of work, which included putting together the v1.4.0 release for both Android and iOS.

Mr. Cardinal's greeting

Sprint 3: Start of personality injection (continued)

Ok, so my first update to Toytles: Leaf Raking has introduced the tiniest amount of personality to the neighbors. To build upon it, last week’s sprint from July 5th to July 11th focused on writing more dialog:

  • Give each neighbor unique text as clients
  • Give each neighbor unique text as ex-clients

There are 19 neighbors currently in the game. The v1.4.0 release has the neighbors say something unique, and now I wanted them to say one thing as a prospective client, one thing as a client, and one thing if they become an ex-client.

For example, Mrs. Smith is a sweet neighbor who loves it when you visit, so she says, “It’s always a pleasure to see you.”

Once she hires you, she says, “I’m so proud of you. It’s a joy to see you work hard. I’m sure you’ll go far in life.”

And if she has to fire you for doing a poor job of raking her leaves, she says, “Well, not everything works out. I’m sure you’ll bounce back.”

Not all the neighbors are so nice.

Last week I did 3.75 hours of game development, finishing the sprint very late on Saturday night. Considering I also spent 2 hours writing a blog post and a newsletter mailing to announce the published update from earlier in the week, I felt like I did well to make time for the project, all things considered.

I also gained a greater appreciation for the work of game writers.

Sprint 4: More personality injections

Which brings me to this week’s sprint:

  • Give each neighbor unique text as unhappy clients
  • Add variation to weekend flavor text

Currently, if a client is not happy with you, you will learn about it in the morning from your mother. She will inform you which clients are worried that their lawns are not being taken care of, often when over half of the lawn is covered in leaves.

Mom about to tell you bad news

But if you talk to those clients, they will continue to say the same thing they said before. Giving them something to say when they are still clients but are also concerned about your work is once again adding a little more personality and character into the game. Eventually I’d like to get to the point where the way they say something is impacted by your reputation with them, the weather, and possibly anything that is happening in their lives unrelated to your work.

Another area of the game that could use some variety is the weekend text. On weekdays, you wake up, go to school, and then come home to start your day. On weekends, however, you currently get to hear about one of two dreams you have. I want to add at least one more weekend dialog for each week.

Eventually that weekend dialog should have random events, such as a neighbor willing to pay double for getting to their lawn that day, or perhaps you learn that a client has a nephew in town who raked their leaves for them so you aren’t needed that day. But that kind of feature will be for a future update.

Until next sprint

I hope you enjoyed this behind-the-scenes report of my progress on Toytles: Leaf Raking’s Personality Injection updates. I plan to provide a weekly report going forward.

While I would love to have a huge big bang update to release with a ton of changes, I will instead be working slowly but surely, adding a little character each time. Eventually, the game will feel completely different, but I will get there one step at a time.

Toytles: Leaf Raking Player's Guide

Want to learn when I release updates to Toytles: Leaf Raking or about future games I am creating? Sign up for the GBGames Curiosities newsletter, and get the 24-page, full color PDF of the Toytles: Leaf Raking Player’s Guide for free!

Categories
Geek / Technical Politics/Government

Books I Have Read: Tools and Weapons

A colleague at my day job lent me a copy of the book Tools and Weapons by Brad Smith and Carol Ann Browne.

Tools and Weapons book cover

The main premise of the book is that technology is a double-edged sword.

On the one hand, it has the potential to do so much good for individuals, organizations, and societies. It can ease our lives by automating drudgery, help us make and keep connections with friends and family, and assist us in solving some huge problems in healthcare, conservation, and business.

On the other hand, technology has the potential to do a lot of harm, especially in the area of human rights. It makes it easier for totalitarian governments to identify and spy on political enemies. Our privacy is at risk as organizations find ways to take disparate pieces of data and find correlations that give insights into who we are. Inequality can get exacerbated.

I found myself impressed with Smith and Browne’s ability to tie modern day conundrums back to analogous situations in the past. The late 1800s gave birth to the modern U.S. government when it started to regulate railroads, an interstate technology with a scale and scope that was unheard of in an era when states were almost exclusively the ones doing the regulating. What does our modern Internet require?

In the early 1900s, combustion engine technology put horses out of work in firehouses all over the country. The need for food to feed these horses also dropped, which had knock-on effects for other areas of the economy, from farming to packaging to shipping. What will AI do to today’s workforce, and how much can we reliably predict?

When it comes to making broadband Internet available for rural residents, what can we learn about the initiatives to spread the benefits of electricity throughout small towns and farms?

And as Smith is an executive at Microsoft, I also enjoyed getting quite a bit of insight into the company’s approach to dealing with the world and governments over the last few decades, especially when juxtaposed with newer tech companies such as Facebook.

While I don’t doubt Microsoft led some initiatives to work with governments, I did find myself rolling my eyes at reading how moral the company supposedly was and is. There was a lot of name-dropping, including U.S. presidents and major figures in technology and political science, and I appreciate that there were discussions about how a large and influential tech company such as Microsoft needed to create policies to ensure that they did as little harm as possible to society, but then again, this is the same company that for years liked to spin their monopoly as natural.

But now I also know that this is the same company that provided their technology to organizations such as ICE. I mentioned the name-dropping earlier because I wanted to emphasize how weird this one passage was:

A glimpse of what lies ahead emerged suddenly in the summer of 2018, in relation to one of the hottest political topics of the season. In June, a gentleman in Virginia, a self-described “free software tinkerer”, also clearly had a strong interest in broader political issues. He posted a series of tweets about a contract Microsoft had with the US Immigration and Customs Enforcement, or ICE, based on a story posted on the company’s marketing blog in January. It was a post that frankly everyone at the company had forgotten. But it says that Microsoft’s technoloygy for ICE passed a high security threshold and will be deployed by the agency. It says the company is proud to support the agency’s work, and it includes a sentence about the resulting potential for ICE to use facial recognition.

The next paragraph goes on to talk about how that supposedly forgotten marketing post took on different meaning in the context of the Trump administration’s decision to separate children from parents at the US border, and it goes on to talk about employee activism, but wait…

A gentleman from Virginia? Why didn’t we name this individual like we did everyone else? Well, there was an endnote:

Taotetek (@taotetek), “It looks like Microsoft is making quite a bit of money from their cozy relationship with ICE and DHS,” Twitter, June 17, 2018, 9:20 a.m. https://twitter.com/taotetek/status/1008383982533259269.

While Smith makes it sound like the relationship between Microsoft and ICE/DHS was this forgotten quirk, here’s a thread in which this “gentleman from Virginia” gives more context to this section of the book, including pointing out that a Microsoft executive got a job at DHS and shortly after a number of contracts between Microsoft and DHS were established.

https://twitter.com/taotetek/status/1173338647673933825

All this is to say that while I found a lot of insight into how major tech companies are starting to recognize that great power requires great responsibility and how they are doing more to work together with governments and society to make it happen, I’m also taking the “we’re trying to do right by everyone because it’s the right thing to do” line with a huge grain of salt. When big companies seek out regulations, it is often to make it easier for them to compete and not out of some moral character.

Still, the book tackled privacy, the ethics of AI, inequality, cybersecurity, and modern society’s dependence on technology to live and work while discussing the repercussions of data moving across borders into data centers and the laws that regulate them.

In the end, even while Smith talks about the needs of a “Digital Geneva Convention” to protect civilians against cyberattacks by nation-states, and privacy regulations to protect people against rogue companies (it sounds like Europe is way ahead of the world in terms of pushing technology companies to respect individuals and their privacy rights), I worry about a world in which most of our technology is seemingly dependent upon Microsoft, Google, Apple, and Facebook doing the right thing by everyone. In each case, they’ve shown that there is a priority for them, and it isn’t my or your interests.

Categories
Game Development Geek / Technical Linux Game Development

Screenshots Made Easy with Window Resizing Tool wmctrl

I needed to create screenshots for the iOS port of Toytles: Leaf Raking, my leaf-raking business simulation. My game doesn’t have a built-in screenshot shortcut key, and I needed screenshots that were 2688×1242, 2208×1242, and 2732×2048.

Immediately I knew I didn’t want to resize windows by hand, as it would be annoying and error-prone. Was there a tool that let me do it in a much more controlled manner?

I did a search, and I came across this Ask Ubuntu question about resizing windows to a particular width and height.

That’s when I learned about wmctrl. It is a tool that allows you to interact with the X window manager, which is the main windowing system used by GNU/Linux desktops.

I ran the following command to find the window of the running game:

wmctrl -l

It output a bunch of windows and showed me that I had:

0x0320000f 2 [machine name] Toytles: Leaf Raking

And then I used the ID corresponding to the game to resize that window:

wmctrl -i -r 0x0320000f -e 0,10,10,2688,1242
wmctrl -i -r 0x0320000f -e 0,10,10,2732,2048
wmctrl -i -r 0x0320000f -e 0,10,10,2208,1242

And then I just navigated around my game, found a good spot to take a screenshot, pressed Ctrl+PrtScn to take the screenshot, then resized and repeated for the various iOS sizes.

I then used Gimp to remove the top 30 pixels which was just the title bar of the window. I think I should be able to take screenshots without the window decorations, but I haven’t researched it yet.

I think I’d like to create a script to handle resizing, taking the screenshot, cropping the top 30 pixels, and placing into the appropriate screenshot folder, but I’ll probably create it next time I need to make screenshots, which might be sooner than I think.

Categories
Game Design Geek / Technical

10 Years Later: Look Inside the Source of Terry Cavanagh’s VVVVVV

Last week, Terry Cavanagh made an announcement with the post VVVVVV’s source code is now public, 10 year anniversary jam happening now!

Collectors of commercial indie game source code have another project to add alongside games such as Aquaria and Gish.

And people are swarming all over it.

A lot has been made of the apparently low quality of the code, with people remarking on the very large case switch statement. To be fair, this is code that was converted from Flash to C++, but it’s apparently quite horrifying and fascinating to read through.

Others are more pragmatic about it:

https://twitter.com/mikeBithell/status/1215939170079821824

In contrast, and as a personal story, I just found some old notebooks of mine from around 2005, and I was very concerned about writing code “the right way.” Now, I wasn’t demanding perfection, but I did have in mind that I didn’t want to just hack together something and hope it worked. I wanted to know it would work. And I apparently wanted to learn UML.

I never shipped that project. But I was also pretty early in my career as a programmer, and I didn’t know much of anything.

Today, I know that I would put something together that works, and then I would iterate and build upon it. I mean, I believe in creating high quality code and using test-driven development to help get me there, but I also don’t spend a lot of time focused on up-front design so much as ensuring my code base is easy to refactor and modify without a lot of pain.

And I know that years of not learning UML hasn’t hurt me.

Cavanagh went on to say:

A decade on, I still feel the same way. I’m incredibly proud of VVVVVV, and grateful for everything. I want to thank everyone who helped me along the way – Magnus for his incredible soundtrack, Ethan and Simon for all their work to bring the game to more people, Bennett for naming the rooms, Stephen for helping me get that mac build out late in launch day. This game is special to me – thank you to everyone who played it and supported me over the past ten years. It’s meant so much. <3

Congratulations, Terry!

Categories
Game Development Geek / Technical General Personal Development

Derek Yu’s Updated Pixel Art Tutorial

In ancient times, around 2005, Derek Yu of Spelunky fame created a 10-step pixel art tutorial. It took you through the process of creating a cartoonish lucha lawyer, including brief discussions on lines, shading, dithering, and more.

Derek Yu's pixel art luchador
As seen in archive.org’s history of Derek’s old site.
Also, Derek, please don’t sue me.

Yu recently tweeted that he’s rebooted the tutorial, which can now be found at https://derekyu.com/makegames/pixelart.html and takes you through drawing an orc.

Derek Yu's orc from start to finish
Who would win, this orc or the law?

It’s a more detailed tutorial, and it shows what Yu has learned about teaching pixel art with almost 15 years more experience since the original was created.

There’s also a tutorial about common pixel art mistakes to go with it, so you can see what you’re doing wrong as you try to follow along.

Thanks for contributing to the world of game making, Derek Yu!

Categories
Geek / Technical

Fixed SDL2 Android App Issue When Suspending and Resuming

Months ago, I needed to update the SDL2 libraries I was using in order to gain access to a new piece of functionality in SDL2 that lets me load SVG vector graphic file and create textures out of them. But then I found a problem was introduced. The app would hang whenever I would leave it to look at a different app. I posted about it on the libSDL Discourse site, but I did not receive a response. I finally had a chance to investigate this issue and I think I have solved it.

When an SDL2-based Android app needs to suspend and resume, there are events that need to be handled immediately, before your main event loop: SDL_APP_WILLENTERBACKGROUND and SDL_APP_DIDENTERFOREGROUND.

So you create an event filter, register it with SDL_SetEventFilter(), and it is here that you need to handle things like music. If your app enters the background, but music is still playing, the app will crash. So, in your event filter, you would have code that looks something like the following:

int EventHandler::eventFilter(void * userData, SDL_Event * event)
{
    int whatToDoWithThisEvent(ADD_TO_QUEUE);

    IHardwareLayer * hardwareLayer = static_cast<IHardwareLayer *>(userData);
    if (hardwareLayer != 0) 
    { 
        switch(event->type)
        {
            case SDL_APP_WILLENTERBACKGROUND:
                {
                    hardwareLayer->pauseMusic();
                    whatToDoWithThisEvent = DO_NOT_ADD_TO_QUEUE;
                }
                break;

            case SDL_APP_DIDENTERFOREGROUND:
                { 
                    hardwareLayer->resumeMusic();
                    whatToDoWithThisEvent = DO_NOT_ADD_TO_QUEUE;
                }
                break;
        }
    }

    return whatToDoWithThisEvent;
}

In my case, I have a wrapper around SDL that I call IHardwareLayer, and it will delegate the calls to SDL as well as do some other useful things.

The above code worked fine. Before I added this event filtering, my music-playing Android app would become unresponsive whenever the app would get suspended. With SDL2 and SDL2_mixer, the music plays on a separate thread, but most of the time you don’t need to know about it. In this case, however, you need to stop the music before your app gets suspended in order to prevent it from trying to play music in a bad state.

Ok, great! But then I updated my libraries in order to handle the ability to load SVGs, and the above code started failing. Except suspending worked just fine. It was the resume functionality that was broken now. How bizarre!

So the symptom is that when the app is suspended, everything is fine, but bringing the app back to the foreground would cause it to become unresponsive.

By adding logs and using adb logcat, I could trace the code all the way until it called Mix_ResumeMusic(), and it never returned from the call. What gives?

After trying a number of different approaches, including updating SDL2_mixer to the latest release, I finally tried to resume the music in the main event loop.
I presume the issue has to do with threading, as I learned I couldn’t call functions that would let me query the pause state of the music in the event filter without the app becoming unresponsive.

The way the event filter works, it gets called before your main event loop, giving you a chance to handle an event beforehand. You can, of course, ignore an event, and in my code above, the default return value ADD_TO_QUEUE is an int that has a value of 1, which has the effect of allowing the event to get handled later in my main event loop when I call SDL_PollEvent().

So I changed the above code so that it no longer tries to resume music and it no longer returns DO_NOT_ADD_TO_QUEUE (otherwise known as the return value of 0) when the filter receives the event SDL_APP_DIDENTERFOREGROUND. Then I added the following code to my main event loop, which is in my HardwareLayer wrapper class:

SDL_Event event;
while (1 == SDL_PollEvent(&event))
{
    switch (event.type)
    {
        case SDL_APP_DIDENTERFOREGROUND:
            {
                resumeMusic(); 
            }
            break;

...

So now I pause the music when handling the SDL_APP_WILLENTERBACKGROUND event in the event filter, and I resume music once my app is up and running the main event loop again. No more crashes or unresponsive app!

I am a bit bothered by the lack of symmetry in terms of how to handle suspending and resuming an app, but software development is often about compromise. B-)

Categories
Geek / Technical Personal Development

Come See Me Speak at dsmAgile on September 28th

dsmAgile is a one day Agile conference in Des Moines, Iowa, and I’ll be presenting at it this year.

On Friday, September 28, 2018 from 8:30 AM to 4:30 PM, you can discuss, discover, and learn more about Agile software development from people who have been practicing and living it. And it only costs $100, a great deal.

My presentation is called “You’re Not a Code Monkey, So Stop Acting Like One!” You can read more about in the dsmAgile session descriptions, but the main idea is that software developers can and should do more than write code.

You are responsible for not only creating value through technology but also for maintaining that capability, and you don’t get to pretend that “they won’t let me” is a valid excuse.

Merely slinging code is not enough. You are not a code monkey following orders. You are a first-class citizen in the organization, more than capable of driving value as well as delivering it. Let’s discuss how you (and your organization) can start acting like it.

I have enjoyed attending dsmAgile in the last few years, and I look forward to being part it. Will I see you there?

Categories
Game Development Geek / Technical

Book Review: Behavioral Mathematics for Game AI by Dave Mark

Behavioral Mathematics for Game AI Book

Intrinsic Algorithm’s Dave Mark, a fixture at the Game Developer Conference’s AI Summit, is also the author of Behavioral Mathematics for Game AI.

Most game AI literature covers the basics in a general way, such as finite state machines, flocking and steering to control movement, pathfinding algorithms such as Djikstra’s or A*, goal-oriented action planning (or GOAP), and more.

Mark’s book, however, covers a specific topic in great depth: game AI decision-making.

You might have a character that can do interesting things such as hunt, flee, eat, track, alert nearby allies, etc, but if you don’t create a good system that allows that character to make decisions between those behaviors, it may not convince your players that it is intelligent at all.

The goal is to create behavioral algorithms to get computer-controlled agents responding to their environment in believable and sensible ways. To get there involves a journey through the subjects of psychology, decision theory, utilitarian philosophy, and probability and statistics, among others.

Mark was great at walking you through each step of this journey, combining theory with detailed explanations and examples, including code. Sometimes I felt the detailed explanations were a bit too detailed, but at no point did I feel like I was lost.

He never made a leap in logic that left me behind because he was holding my hand at every step of the way. Sometimes I appreciated that hand-holding, especially for the more involved statistics, but there were a couple of times when I found myself getting a bit impatient and wanting to run ahead.

And it is probably partly due to the fact that it’s a long journey. At one point, I realized I was over 300 pages into the book without feeling like I knew how to integrate and apply all of the individual tools I was learning into a cohesive system.

The examples he used to illustrate his point were sometimes bizarrely relatable. I have never tried to create a model of my behavior related to when I decide to replace my older razor blades with newer ones, but Mark did, and I actually found myself nodding with recognition that I do tend to use my last blade in the refill pack for way longer than my other blades.

Other examples demonstrate how his utility-based decision-making system can address problems with past games, such as the strategy game AI that kept sending its attack force towards the most vulnerable target. Savvy players can keep defensive forces outside of city walls, then place them in the city at the last moment and moving units out of a city far away. By doing so, they could keep the AI units moving back and forth, unable to carry out an attack, for as long as they want.

Solving this issue involves giving the AI the ability to have decision momentum by making decisions include all of the relevant information. The AI isn’t just deciding what city to attack. A single decision is what city to move to AND attack, which incorporates the time it takes to travel to a target city. Suddenly, the decision to change course in order to attack a different city is a bit more painful, and so the current target is more likely to be maintained.

I appreciated that he covered the problem of having the AI always making the best decision. While academic researchers might love that result, players are likely to find such AI as unrealistic and, worse, uninteresting. And if there are multiple AI agents that do exactly the same thing simultaneously, it’s even more of a problem. So there’s an entire chapter on ways to ensure that the game AI can be reasonable yet still interesting from one play session to the next.

The book was published in 2009, and so you would think it means that any information you could glean out of it would be obsolete after almost 10 years of advances and progress in the field. And yet, the basic decision-making system that drives behaviors is still relevant.

One of the benefits of reading an older book is seeing the ideas of that book illustrated in front of you in other media.

You can see Mark’s talks with Kevin Dill from GDC 2010 and 2012 in the GDC Vault. Improving AI Decision Modeling through Utility Theory and Embracing the Dark Art of Mathematical Modeling in AI both introduce the use of this utility-based system in games.

In 2013, Mark’s portion of the panel Architecture Tricks: Managing Behaviors in Time, Space, and Depth introduced the Infinite Axis Utility System, which takes the concepts from the book and puts them together into a simple yet powerful architecture.

In 2015, Mark and Mike Lewis presented Building a Better Centaur: AI at Massive Scale, in which they describe the Infinite Axis Utility System that was the architecture behind an MMO.

I’ve seen these videos before, but having now read the book, I found that upon rewatching them that I understand the sections on response curves and how they apply to the actions the IAUS chooses.

Behavioral Mathematics for Game AI is not a beginner’s book at all, but if you are interested in learning how to give your AI powerful reasoning abilities that produce rich, believable behaviors for your players and want it to be easy to understand and design with, I’m not aware of another book on the subject that is as accessible as this one.