The code version of the “How to Draw an Owl” meme

I’ve been reading the Unity manual during my morning commute on BART… because the life of a game developer is non-stop excitement. Today I read something that made me burst out laughing in the middle of a crowded train, a single short bullet pointed list page entitled: Converting a Single Player Game to Multiplayer

If you’ve never made a multiplayer game from a code base someone else has made, attempting to follow these tutorial instructions is the programmer equivalent of the old art meme:
owl

At first I thought it was extremely funny that all you’d need to do to convert a single player designed game to multiplayer is “Make important member variables into SyncVars” and “Create Lobby Scene” but as I thought about it more I began to be worried that seeing something like this might make a student think it was an easy process that they can do “later.” Trying to oversimplify networking by talking about it being a matter of syntax instead of needing to understand concepts like everything needing to be asynchronous is making the process more mysterious, not less. I understand the one to one correlations between the class names could be useful, but I think manuals should take more care when they switch from showing best practices to showing “worst practices” as trying to shoehorn in networking clearly is.

For the most part if a student programmer does find themselves in the position of needing to put multiplayer into a fundamental single player game I look forward to hearing all the rants about rewrites due to discovering something else that is fundamentally unsyncable due to the way it was written and assumptions made.

Good luck with “Converting a Single Player Game to Multiplayer”
cry

Molly’s GaymerX3 talks

This year for GaymerX I did two different talks “Not just a Queer in Gaming” and “Localizing Games for a Worldwide Audience” (slides) (videos) As I gain experience I’m trying to do less panels that just focus on my own existence as a gay/women game programmer and more things on specific topics, so this con was a good step towards that goal. I think the existence panels are good for total new people. However, there are enough of a backlog where there is nothing new to say that a new person couldn’t easily find online and they don’t cause me to think and grow when writing them.

Not Just a Queer in Gaming I was invited on last minute with the famous David Gaider of BioWare fame, Wes Schneider of Pathfinder and Gordon Bellamy moderated. It was a casually moderated panel on motivations, career paths, and minimum bars for portfolios. Since GaymerX is an older crowd than something like PAX ( 18+ required ) it can focus less on school requirements. The main takeaway I had from this panel is the fairly obvious, being on a panel with famous names who have accomplished awesome stuff gets audiences to show up and is super cool.

The second panel being “Localizing Games for a Worldwide Audience” with Gordon Brown with Carbine Games, was one I had been thinking about for awhile. The idea was to get people from the typical “how to make your first game” talk to showing best practice steps for an area of game development not shown much to ship a real product. It had a secondary goal of exploring “English speaking” as an under examined privilege and bias I believe people should be more aware of. One immediate problem with this panel was scheduled for the early first slot 10AM on a Sunday at the same time as a Dragon Age panel, I’m not sure how to ensure better timeslots I believe this had but a strong negative impact on attendance. In addition, localization is inherently a niche topic, one that is so hidden people aren’t aware that they don’t know they don’t know. GaymerX is a very unique venue in that there are both a significant amount of gamer fans and developers of all levels so you can appeal to both. I was hoping this would pique the average gamers curiosity by talking about both why games from Japan were hard to bring over and teach something about how much work games were, but it didn’t quite work out that way. The good thing is that localizers themselves are very supportive of each other and we ended up having an interesting conversation with others working in various aspects of localization.

I started attempting to overcome my stage fright about 2.5 years ago and after about 6 small talks or so I no longer suffer from nervous fear of public speaking about a subject I know. Your mileage will vary but I found numbers comforting when I was first starting out on what seemed like an impossible goal of overcoming nerves. I’ll be moving onto bigger conferences next.

Ludum Dare 33 “You are the Monster” Entry

I wasn’t really inspired by the theme this Ludum Dare and I think that always tends to show. You can see the game here and vote on it here. Since it’s just html, css, and non-obfuscated js feel free to look at the code.

My main takeaways were:

  1. Keeping a blog makes me significantly better and showing my progress.
  2. CSS animations have gotten WAY easier to work with since I last did them.
  3. Kind of obvious but when making games in niche genres it’s easier to get attention from the hardcore fans. My game got a fair amount of hits from the clicker/idle subreddit.
  4. I managed to finish something even after I sort of lost motivation and had several other things to do during the weekend, so that’s a big improvement over previous jams.

Tools:

  • Visual Studio Express 2012 Web
  • jQueryUI

A few in progress shots of the order I did things in:

  1. Skeleton layout
  2. 1Layout

  3. Button Handcursor And Satisfying number animation complete with formatting of dummy info
  4. 2HandcursorAndNumberAnimation

  5. Stats Popup
  6. 3StatsPopup

  7. Dynamic Button inserts and Tooltips
  8. 4DynamicButtonInsertAndTooltips

  9. Button content updates
  10. 5ButtonContentLiveSite

  11. Logic working on everything
  12. 6LogicWorksCostsGrayedTitleBarUpdates

  13. Real art
  14. 7RealArtIsFun

  15. Floaty Text!!!!!!
  16. 8FloatyTextInAllBrowsers

  17. Toast Popups and Save load
  18. 9ToastPopupsAndSaveLoad

  19. Win condition
  20. 10WinMenu

  21. Final  including weird css bug fixes.
  22. 11Final

 

 

What happens when you’re really tired and google for transparent images because you’re trying to figure out a really dumb IE fading bug:
DumbShitToGoogleFor

Waves of Rocket League Games

Whenever a game becomes an unexpected hit there’s a flurry of “Well it’s like (recent hit game) but with…”
Partially this happens because it’s an easy way for people to understand/pitch a new concept in relation to a known idea and partially because people who fund games easily fall into the trap that they can compete with an existing product by having their own. It’s different than cloning in the sense that there is a value add, but usually not enough to really stand out and usually years later consumers only remember the one that made it big.

The hit game doesn’t need to be innovative enough to found a new genre, Everquest was around before World of Warcraft but not many companies were rushing to crank out their own spin on that. It’s hard to think about social games before simulation-Ville games and the spin-offs that followed.

Rocket League spin-offs just strike me as something that could get more comical.
I’m hoping in a few months we end up:

  • Cars play Basketball
  • Cars play Volleyball
  • Cars play Baseball
  • Cars play Poker ( vs dogs and cats or licensed characters from Telltale Games )
  • Cars do synchronized swimming
  • Cars do dressage ( Stephan Colbert’s Sport of the summer 2012 )
  • Cars do track and field ( including foot sprint races! )
    • bonus if this variant features surgeon simulator/QWOP style controls

… Actually after typing all those I’m fairly sure I would enjoy a gamejam with this theme.

Local flash game leaderboard tutorial

Update I’m stopping updating my whole blog and don’t have time to fix the confusing points of this post so if you get stuck there are some questions about this post answered on This StackOverflow question.

This tutorial is about how to create a local leaderboard in ActionScript 3, the principles will work on mobile in AIR or on the web. See completed project at the end of the post.

In AS3 ais used to store data to the player’s computer. In the case of a local leaderboard we want to store high score’s between games and then display them in a sorted order. Note since we’re only storing data locally ( as opposed to networked ) this will only show score’s on that machine and more complex methods would require a server component.

1. Initialize where data will be saved

Main.as 

private var m_FlashCookie:SharedObject;
private function init(e:Event = null):void
{
  //...
  m_FlashCookie = SharedObject.getLocal("LeaderboardExample");
  //...
}

2. “Play Game” and store the results of that player’s session. In the case of the example this is simply done using static variables in the Main document class.

StateGame.as 

Main.EntryScore = parseInt(m_InputBoxScore.text);
Main.EntryName = m_InputBoxName.text;

3. Fetch our saved leaderboard object of high scores. shared_object.data[“KEY_NAME”] will return null if nothing has been stored with that key.

StateLeaderboard.as

// Shared Objects store everything as untyped objects so we cast it back to an array as we will store it later
var arr:Array = Main.Inst.getSaved("TopScores") as Array;
if ( arr == null)
  arr = new Array();

//----------------------------

Main.as
public function getSaved(key:String):Object
{
  return m_FlashCookie.data.key;
}

4. Push the latest score that the last gameplay session added into the array storing the leaderboard data

StateLeaderboard.as 

// create the object that stores the data that just got created from our last gamestate
// we can add multiple stats in here if we wanted, for example "enemies killed" and "coins collected"
// in this case we just use score as an example so we have only one number to sort on
var latest_score_object:Object = {
  name: Main.EntryName,
  score: Main.EntryScore
};
// push the last score onto the list
arr.push( latest_score_object );

Note: this means that we might now have 11 scores in the array instead of the top 10.

5. Sort the leaderboard so it’s in the order we want it to be in

StateLeaderboard.as 

// sort the list from highest to lowest based on the "score" figure.
// the key here can be anything stored in the lastest_score_object entry.
arr.sortOn("score", Array.NUMERIC | Array.DESCENDING);

6. Remove extra entries in the array so we only save the “top 10”

StateLeaderboard.as 

// if adding the score from the last game made it so there were more than 10 items of the list, remove the last #11.
// since the array was sorted on the line above that means that the last score will be in the right place regardless
if ( arr.length < NUM_SCORES_SAVED )
{
  arr.pop();
}

7. Flush/Save the new leaderboard This makes it correct for next time.

StateLeaderboard.as 

// This key name must match the name we used above in step 3.
Main.Inst.saveData("TopScores", arr);

//--------------------

Main.as

// Function to store data by key.
public function saveData(key:String, dataToSave:Object):void
{
  m_FlashCookie.data.key = dataToSave;
  var flushStatus:String = null;
  try
  {
    flushStatus = m_FlashCookie.flush(10000);
  }
  catch (error:Error)
  {
    trace("Error...Could not write SharedObject to disk\n");
  }
  if (flushStatus != null)
  {
    switch (flushStatus)
    {
      case SharedObjectFlushStatus.PENDING:
        trace("Requesting permission to save object...\n");
        m_FlashCookie.addEventListener(NetStatusEvent.NET_STATUS, onFlushStatus);
        break;
      case SharedObjectFlushStatus.FLUSHED:
        trace("Value flushed to disk.\n");
      break;
      }
    }
}

8. Loop through all the leaderboard data and display it in a human readable way.

StateLeaderboard.as 

// In this example implementation we display all our data in a single textfield.
// In a real game we'd probably work with an artist to put these on seperate lines or a grid
var myHTML:String = "";
var total_stored_scores:int = arr.length;
for (var i:int = 0; i < total_stored_scores; ++i)
{
  // loop through every entry, every entry has a "name" and "score" field as that's what we save.
  var leaderboard_entry:Object = arr[i];
				
  // is this the last score that was just entered last gamestate?
  if ( leaderboard_entry == latest_score_object )
  {
    myHTML += (i+1) + ". <b><font color=\"#0002E5\">"+ leaderboard_entry.name + " " + leaderboard_entry.score +"</font></b><br>";
  }
  else
  {
    myHTML += (i+1) + ". "+ leaderboard_entry.name + " " + leaderboard_entry.score +"<br>";
  }
}
m_TF.htmlText = myHTML;

9. Rinse, repeat and observe.

DOWNLOAD EXAMPLE:
Flash Develop or Flash Pro CC project source of the complete example.