<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">

 <title>The Artillery Blog</title>
 <link href="http://blog.artillery.com/atom.xml" rel="self"/>
 <link href="http://blog.artillery.com"/>
 <updated>2013-03-17T20:38:30-07:00</updated>
 <id>http://blog.artillery.com</id>
 <author>
   <name>Artillery</name>
 </author>

 
 <entry>
   <title>Browser Garbage Collection and Frame Rate</title>
   <link href="http://blog.artillery.com/2012/10/browser-garbage-collection-and-framerate.html"/>
   <updated>2012-10-27T00:00:00-07:00</updated>
   <id>http://blog.artillery.com/2012/10/browser-garbage-collection-and-framerate</id>
   <content type="html">&lt;p&gt;Realtime games are a different breed of software than data-driven websites. A harsh constraint for game developers is that, in order to get 60 frames per second, your game loop needs to execute in less than 16.66ms. If you know your target CPU and your execution time budget, you can work within this constraint. But when you&amp;#8217;re writing a game for the browser, you have one more thing to worry about: the Javascript VM needs to pause periodically to collect garbage and manage the memory heap.&lt;/p&gt;

&lt;p&gt;The good news is that modern browsers have vastly improved the efficiency and common-case runtime of their garbage collection phases. But are they good enough to make games with smooth animation today? How much garbage can your game safely create? Once your game loop fits into the CPU-time budget, can you know that it will be scheduled fast enough? Are you going to meet some target frame rate for the 99th percentile rendering time? The answers depend strongly on the client (hardware and browser), but we can make some measurements on typical computers and make some useful generalizations.&lt;/p&gt;

&lt;h3 id='methodology'&gt;Methodology&lt;/h3&gt;

&lt;p&gt;Let&amp;#8217;s assume a typical game will have an animation loop which is gated by &lt;code&gt;window.requestAnimationFrame()&lt;/code&gt;, with the hope that the browser will schedule the loop at a stable 60fps. Also, assume that there is a single function which computes the next game state and &amp;#8220;draws&amp;#8221; it (to the DOM and Canvas). If we monitor the inter-arrival times of these &lt;code&gt;requestAnimationFrame()&lt;/code&gt; calls while watching the JS heap size we can see if garbage collection pauses are responsible for dropped frames.&lt;/p&gt;

&lt;p&gt;The following example runs in Chrome, which supplies &lt;code&gt;window.performance.now()&lt;/code&gt; and &lt;code&gt;window.performance.memory.usedJSHeapSize&lt;/code&gt; (when invoked with &lt;code&gt;--enable-memory-info&lt;/code&gt;). Similar affordances exist in Firefox and Safari.&lt;/p&gt;
&lt;script src='https://gist.github.com/3961866.js'&gt; &lt;/script&gt;&lt;!--
function() {
  var lastHeapSize = null;
  var lastFrameTime = null;

  var runGame = function() {
    requestAnimationFrame(runGame);
    var frameTime = window.performance.now();
    var heapSize = window.performance.memory.usedJSHeapSize;

    if (lastHeapSize == null) {
      lastHeapSize = heapSize;
    }
    if (lastFrameTime == null) {
      lastFrameTime = frameTime;
    }

    var dt = frameTime - lastFrameTime;
    var dh = heapSize - lastHeapSize

    frameDataList.push([dt, dh]);

    lastHeapSize = heapSize;
    lastFrameTime = frameTime;

    computeNextGameStateAndPaint();
  }
}();
--&gt;
&lt;p&gt;We can also make some adjustments to the implementation of &lt;code&gt;computeNextGameStateAndPaint()&lt;/code&gt; to see the effect of different amounts of garbage generation.&lt;/p&gt;
&lt;script src='https://gist.github.com/3961918.js'&gt; &lt;/script&gt;&lt;!--
var makeSimulatedGameLoop = function(n) {

  /* Pre-initialize an array with distinct simple objects */
  var g = new Array(1000*n);
  var count = 0;
  for (i=0; i&lt; g.length; i++) {
    g[i] = {count: count++};
  }

  var _work = function() {
    var i;
    for (i=0; i &lt; g.length; i++) {
      /* For every game variable, double it's count property. */
      /* Implicitly create a new object, garbaging the old one. */
      g[i] = { count: g[i].count * 2 };
    };
  };

  return _work;
};

computeNextGameStateAndPaint = makeSimulatedGameLoop(20);  //  Try 2, 20, 200
--&gt;
&lt;p&gt;After this runs for a while, &lt;code&gt;frameDataList&lt;/code&gt; will contain a list of samples which are easy to analyze:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&amp;gt; window.frameDataList
[16.672734, 133128],
[16.183574, 128228],
[39.847293, -12158528],
[16.974714, 119222],
[16.672734, 140248]&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id='correlation_between_slow_frames_and_gc_events'&gt;Correlation between slow frames and GC events&lt;/h3&gt;

&lt;p&gt;Garbage collection events aren&amp;#8217;t explicitly announced by the VM, but we can infer that one has just happened whenever the JS heap size decreases between two samples. We might undercount the number of garbage collection events by sampling too slowly, but we can&amp;#8217;t overcount it this way.&lt;/p&gt;

&lt;p&gt;Here are some plots showing the inter-arrival times of a series of animation frames, along with some decoration indicating changes to the size of the JS Heap. The bubble radius is proportional to the magnitude of the heap size change in the last frame, and color indicates the sign. This data was collected using Chrome 22 running on a high end laptop.&lt;/p&gt;

&lt;p&gt;Here&amp;#8217;s an example of an absurdly high amount of garbage generation with 200,000 anonymous objects becoming unreachable every frame. While this is an artificial and unrealistic memory-use profile, it still produces thought-provoking results. Notice how bi-modal the frame times are when there&amp;#8217;s a lot of garbage being generated inside &lt;code&gt;computeNextGameStateAndPaint()&lt;/code&gt;. It&amp;#8217;s clear that the slow frames which do occur almost always occur in conjunction with a garbage collection pass.&lt;/p&gt;
&lt;div class='plot-target' id='chart2'&gt;If you can read this, jqplot failed to run. Sorry!  &lt;/div&gt;
&lt;p&gt;As we dial down the rate of garbage generation, the situation improves materially. GC pauses start to fit inside the gaps between frames, and predictable 30fps is within reach.&lt;/p&gt;
&lt;div class='plot-target' id='chart1'&gt;If you can read this, jqplot failed to run. Sorry!  &lt;/div&gt;
&lt;p&gt;At 2,000 objects/tick, 60fps is looking rock-solid.&lt;/p&gt;
&lt;div class='plot-target' id='chart0'&gt;If you can read this, jqplot failed to run. Sorry!  &lt;/div&gt;
&lt;h3 id='conclusion'&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;Too much garbage will certainly cause stalls that impact frame rate, but the critical amount of garbage is discoverable early in the development cycle of your application. It &lt;strong&gt;is possible&lt;/strong&gt; to get stable &lt;strong&gt;fast frame rates&lt;/strong&gt; provided you stay inside your per-frame CPU budget and keep the rate of garbage generation under control.&lt;/p&gt;

&lt;h3 id='further_reading'&gt;Further Reading&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href='http://ejohn.org/blog/accuracy-of-javascript-time' title='Accuracy of Javascript Time'&gt;Accuracy of Javascript Time&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='https://www.scirra.com/blog/76/how-to-write-low-garbage-real-time-javascript' title='How to write low garbage real time JavaScript'&gt;How to write low garbage real time JavaScript&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://updates.html5rocks.com/2012/08/When-milliseconds-are-not-enough-performance-now' title='WHEN MILLISECONDS ARE NOT ENOUGH: PERFORMANCE.NOW('&gt;Context around the window.performance.now() interface&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</content>
 </entry>
 
 <entry>
   <title>Play Powderkeg!</title>
   <link href="http://blog.artillery.com/2012/10/play-powderkeg-html5-multiplayer.html"/>
   <updated>2012-10-04T00:00:00-07:00</updated>
   <id>http://blog.artillery.com/2012/10/play-powderkeg-html5-multiplayer</id>
   <content type="html">&lt;p&gt;We&amp;#8217;re very proud to announce Powderkeg, a synchronous, real-time, action-packed multiplayer browser game! Give it a try at &lt;a href='http://powderkeg.artillery.com/'&gt;powderkeg.artillery.com&lt;/a&gt;! (Google Chrome or Firefox is required.)&lt;/p&gt;

&lt;p&gt;Powderkeg represents the first step in building the Artillery Platform, which will enable game developers to easily build high-quality games that run in the browser without plugins. When speaking with developers the feature which is most attractive is easy multiplayer integration.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://powderkeg.artillery.com/'&gt;&lt;img src='/images/powderkeg-screenshot.jpg' alt='screenshot' /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Imagine building a game where player input all looked the same even if players were on separate continents, like a game console whose controllers had really long wires. Now imagine if you didn&amp;#8217;t host servers yourself and you never needed to write a line of lobby or matchmaking code. This is what we want to offer as part of the platform.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;ll present the details of our platform later on. In the meantime, go ahead and &lt;a href='http://powderkeg.artillery.com/'&gt;play a few rounds&lt;/a&gt;, and let us tell you about how it works.&lt;/p&gt;

&lt;h3 id='network_synchronization'&gt;Network Synchronization&lt;/h3&gt;

&lt;p&gt;Powderkeg works by running the game simulation in exactly the same way on each client. This is accomplished by initializing each client&amp;#8217;s pseudo-random number generator with a server-provided seed and transmitting the same input to each client. Clients send their input to the server, the server quantizes all input into frames (or &amp;#8220;ticks&amp;#8221;), and over time each frame is sent to each client which replays the input in its own simulation, resulting in the game you see.&lt;/p&gt;

&lt;p&gt;If the client waited for input before showing any kind of player movement, you&amp;#8217;d notice a delay between pressing an arrow key and your player moving. That&amp;#8217;s why the Powderkeg simulator supports &amp;#8220;hinting&amp;#8221; &amp;#8211; when you press a key, the runtime asks the simulator if your player can actually move in that direction and moves him if it can. The result is very responsive game which mixes strategy with split-second skill.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/powderkeg-action.jpg' alt='action' /&gt;&lt;/p&gt;

&lt;h3 id='dealing_with_lag'&gt;Dealing with Lag&lt;/h3&gt;

&lt;p&gt;Latency is problematic for all networked, multiplayer games. Everyone always wants to connect to a nearby gameserver with a low ping, and players with high pings incur hatred and pitchfork mobs. TCP, which WebSockets are built upon, compounds the problem due to its packet-ordering guarantee.&lt;/p&gt;

&lt;p&gt;We thought it would be a good idea to provide information about each players&amp;#8217; connection, just as you&amp;#8217;d find in any large multiplayer game, so that players can easily identify who is slowing down the game. On each player&amp;#8217;s info square you&amp;#8217;ll see a &amp;#8220;signal meter&amp;#8221; that represents that players&amp;#8217; connection quality. If you mouseover the meter you&amp;#8217;ll see some more details:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/powderkeg-lagmeter.png' alt='lag' /&gt;&lt;/p&gt;

&lt;p&gt;The tooltip shows information collected during the last run of the network latency test. &amp;#8220;Noise&amp;#8221; is the percent of messages which took longer than the standard deviation, &amp;#8220;ping&amp;#8221; is the average ping time of non-noisy packets, and &amp;#8220;max&amp;#8221; is the longest sample collected.&lt;/p&gt;

&lt;p&gt;Powderkeg performs a network latency test when you open the game to test the delay between you and our five game-serving regions around the globe. When you click &amp;#8220;Find a Match,&amp;#8221; your latency is used to match you with people closest to you geographically to ensure low lag and a glitch-free experience.&lt;/p&gt;

&lt;h3 id='graphics'&gt;Graphics&lt;/h3&gt;

&lt;p&gt;Most of the game art is laid out in 10 sprite sheets &amp;#8211; explosions, powerups, environment, one for each color player, and a few more. The UI is mostly HTML and CSS, when integrates with our game&amp;#8217;s runtime easily. Artwork and UI assets are loaded intelligently so that anyone opening &lt;a href='http://powderkeg.artillery.com/'&gt;powderkeg.artillery.com&lt;/a&gt; will see a menu as quickly as possible.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/powderkeg-sprites.jpg' alt='sprites' /&gt;&lt;/p&gt;

&lt;p&gt;Powderkeg should display at a constant 60 frames per second on Chrome and Firefox. You shouldn&amp;#8217;t see any jitter despite the hundreds of entities used to make the map and explosion tiles. Because of our focus on multiplayer support, we didn&amp;#8217;t spend a lot of time on building our own graphics engine or WebGL, and it turned out that using the canvas element is fast enough.&lt;/p&gt;

&lt;p&gt;All of the art in the game was produced by &lt;a href='http://www.adamdegrandis.com/'&gt;Adam deGrandis&lt;/a&gt;, a multi-talented artist and all around awesome person. If you&amp;#8217;re looking for an artist for your next game, we recommend him with the highest of honors.&lt;/p&gt;

&lt;h3 id='sound'&gt;Sound&lt;/h3&gt;

&lt;p&gt;We found high-quality sound effects and music from &lt;a href='http://www.soundrangers.com/'&gt;Soundrangers&lt;/a&gt; and &lt;a href='http://audiojungle.net/'&gt;AudioJungle&lt;/a&gt;. Since we built the game targeting Chrome and Firefox, getting all of that audio into the game was pretty easy. The HTML5 audio tag works well in the latest versions of Firefox, but the &lt;a href='http://www.html5rocks.com/en/tutorials/webaudio/intro/'&gt;Web Audio API&lt;/a&gt; in Chrome is even more straightforward.&lt;/p&gt;

&lt;h3 id='whats_next'&gt;What&amp;#8217;s Next&lt;/h3&gt;

&lt;p&gt;We&amp;#8217;re pretty excited about what we&amp;#8217;ve accomplished with Powderkeg so far, and we&amp;#8217;re even more exited about what&amp;#8217;s next. We&amp;#8217;&lt;/p&gt;

&lt;p&gt;If any of this interests you, please &lt;a href='https://artillery.com/signup'&gt;sign up&lt;/a&gt; for our mailing list to receive beta invitations as our platform becomes available. If this is so interesting that you&amp;#8217;d like to work with us, great news! &lt;a href='https://artillery.com/jobs'&gt;We&amp;#8217;re hiring.&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href='http://powderkeg.artillery.com/'&gt;&lt;img src='/images/powderkeg-winner.jpg' alt='winner' /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Have fun!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Welcoming Our New Investors</title>
   <link href="http://blog.artillery.com/2012/08/welcoming-our-new-investors.html"/>
   <updated>2012-08-03T00:00:00-07:00</updated>
   <id>http://blog.artillery.com/2012/08/welcoming-our-new-investors</id>
   <content type="html">&lt;p&gt;At Artillery, we are committed to an ambitious, long-term vision. We believe that it could take five to ten years to truly achieve our goal of building the world’s best gaming platform inside the browser. We know the path to get there is difficult, and we know that we need a world-class team of investors, advisors and employees.&lt;/p&gt;

&lt;p&gt;That said, we’re thrilled to welcome our new venture investors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;First Round Capital&lt;/li&gt;

&lt;li&gt;Signia Ventures&lt;/li&gt;

&lt;li&gt;Lowercase Capital&lt;/li&gt;

&lt;li&gt;CrunchFund&lt;/li&gt;

&lt;li&gt;General Catalyst&lt;/li&gt;

&lt;li&gt;Andreessen Horowitz&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We also appreciate the support of the many great angels that have helped us build our company so far: Ben Ling, Kevin Colleran, Alison Rosenthal, Tim Ferris, and too many others to list here.&lt;/p&gt;

&lt;p&gt;Kent Goldman of First Round Capital and Rick Thompson of Signia Ventures will be joining our board of directors.&lt;/p&gt;

&lt;p&gt;We feel lucky to have such a strong group of supporters who share our vision. To all of you: Thank you for your support. We will make you proud.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Six Impossible Problems</title>
   <link href="http://blog.artillery.com/2012/07/six-impossible-problems.html"/>
   <updated>2012-07-09T00:00:00-07:00</updated>
   <id>http://blog.artillery.com/2012/07/six-impossible-problems</id>
   <content type="html">&lt;blockquote&gt;
&lt;p&gt;Alice laughed: &amp;#8220;There&amp;#8217;s no use trying,&amp;#8221; she said; &amp;#8220;one can&amp;#8217;t believe impossible things.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8220;I daresay you haven&amp;#8217;t had much practice,&amp;#8221; said the Queen. &amp;#8220;When I was younger, I always did it for half an hour a day. Why, sometimes I&amp;#8217;ve believed as many as six impossible things before breakfast.&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8211; Lewis Carroll&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We&amp;#8217;re pretty optimistic about the possibility of bringing console-quality gaming to the browser. There are already lots of turn-based resource-collection/&amp;#8221;click-and-wait&amp;#8221; games and plenty of casual puzzle games, but we believe the platform is ready to take a step forward. We&amp;#8217;re talking about real-time, multiplayer gaming &amp;#8211; specifically high-quality graphics, content-rich game worlds, and everything else that gamers expect from a console or native PC game. In fact, most of the individual pieces have been proven possible in the dozens of brilliant HTML5 demos that appear every month.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/sc2-f2p.png' alt='hero' /&gt;&lt;/p&gt;

&lt;p&gt;Despite these wonderful demos there are some really hard problems in front of us. We&amp;#8217;re excited but a little daunted by what needs to be done. At Artillery, we know we can do it, but we know we also need to build a really great team. The following is a taste of what we want to accomplish. If this stuff excites you, get in touch with us.&lt;/p&gt;

&lt;p&gt;Without further ado, here are &lt;strong&gt;six impossible problems&lt;/strong&gt; we need to solve over the next few years to make our vision a reality:&lt;/p&gt;

&lt;h3 id='1_let_players_begin_playing_rich_triplea_games_seconds_after_clicking_a_link'&gt;1. Let players begin playing rich, triple-A games seconds after clicking a link.&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;&amp;#8220;Impossible! Games today are multi-gigabyte affairs. You can&amp;#8217;t download that much in seconds!&amp;#8221;&lt;/p&gt;

&lt;p&gt;&amp;#8211;Anonymous Gaming Industry Executive&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This is not an easy problem. But is it impossible? Consider two things: First, you probably don&amp;#8217;t need all of a game&amp;#8217;s assets to render the opening scene of the game. Second, there&amp;#8217;s plenty of ways that the server could compress and/or gracefully degrade game assets depending on client bandwidth. Here are just a few of the things we&amp;#8217;ll do if necessary to make content-rich games load in seconds:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Build an asset streaming system that can look at a game, figure out exactly which assets a player will require at each point in the game, and get them there just in time.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Build tools to automatically create degraded versions of assets, and have the client download the degraded assets first, so the player can start playing the game immediately. Then, stream the high quality assets as quickly as possible, and swap them in as they finish downloading. Some of these techniques are simple: You can get nearly a 10x reduction in PNG file size by converting a 24-bit image to a 64 or 256 color paletted image. For 3D games you could ship lower-poly meshes, lower-resolution textures, and round off significant digits from mesh vertex positions. This would all need to be done with minimal effort on the part of the artist, of course.&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Invent custom compression techniques. Can we take advantage of the inherent redundancy of animation sprite sheets to get better compression ratios than a general-purpose image compressor can achieve? Can we do better 3D mesh compression by exploiting the spatial structure of the mesh?&lt;/p&gt;
&lt;/li&gt;

&lt;li&gt;
&lt;p&gt;Build tools for procedural content generation that work for game designers. What if game designers could procedurally generate a map that they mostly like, and then make tweaks to it as needed? The client would download both the inputs to the procedural map generator and the tweaks, instead of an entire raw map file.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id='2_help_game_designers_create_realtime_multiplayer_games_without_knowing_anything_about_networking'&gt;2. Help game designers create real-time, multi-player games without knowing anything about networking.&lt;/h3&gt;

&lt;p&gt;If you look at all the &lt;a href='http://www.humblebundle.com/'&gt;brilliant indie games&lt;/a&gt; being produced these days, it starts to look like it&amp;#8217;s a new golden age of gaming. But why are there so few &lt;em&gt;multiplayer&lt;/em&gt; indie games? We believe it&amp;#8217;s because indie developers don&amp;#8217;t have the time or resources to design, debug, and operate networked, multiplayer games. We&amp;#8217;re working on building a JavaScript game runtime which allows developers to build multiplayer, networked games as though they were building a non-networked multiplayer console game.&lt;/p&gt;

&lt;p&gt;This is easy to do for turn-based games, or for games that are more forgiving of network latency, like tower-defense games, but it&amp;#8217;s a lot harder to do for latency-sensitive, arcade-style games. We believe we can do it in a way that allows game designers to forget about networking and focus on perfecting their gameplay, and yet makes the game feel perfectly responsive to players even when there&amp;#8217;s 100ms of latency or more between them and their opponents.&lt;/p&gt;

&lt;p&gt;For this to really work, we also need to make it totally effortless for developers to build games that can run in the browser and on our servers. Otherwise, we don&amp;#8217;t have a way to prevent elementary cheating techniques from working.&lt;/p&gt;

&lt;p&gt;Sound difficult enough? We&amp;#8217;re already working on solving this problem for one type of game (more on this later), but different types of games require different techniques for multiplayer networking, client-side prediction, and lag compensation. We will eventually support FPS games, RTS games, MMO games, and any other type of game you care to mention. If you&amp;#8217;ve got experience in multiplayer game networking or distributed systems, and are curious about how we plan to do this, we&amp;#8217;d love to talk with you about these problems.&lt;/p&gt;

&lt;h3 id='3_create_a_hosting_service_for_the_most_latencysensitive_web_applications_ever_built'&gt;3. Create a hosting service for the most latency-sensitive web applications ever built.&lt;/h3&gt;

&lt;p&gt;The engineering involved in creating a multiplayer networked game is not easy. In addition to the difficult programming involved there&amp;#8217;s the loathsome task of operating a cluster of servers. That&amp;#8217;s not an attractive prospect for most small game studios.&lt;/p&gt;

&lt;p&gt;We want to build a game hosting system that allows studios to publish multiplayer games onto our platform with one click. We&amp;#8217;ll host the game servers, we&amp;#8217;ll serve game code and assets to players, and we&amp;#8217;ll connect players to the games through lobbying. We&amp;#8217;ll be running the lowest-latency web applications &lt;em&gt;ever built&lt;/em&gt;. Google returns search results in about 250ms, but 250ms is an eternity when it comes to competitive multiplayer gaming. To keep latency down, we&amp;#8217;ll obviously have to make our backend code as fast as possible, but we&amp;#8217;ll also have to put servers near players, and scale game servers automatically to handle increased load.&lt;/p&gt;

&lt;h3 id='4_build_game_development_tools_that_allow_designers_artists_engineers_and_playtesters_to_collaborate_in_a_way_that_works_for_everyone'&gt;4. Build game development tools that allow designers, artists, engineers, and play-testers to collaborate in a way that works for everyone.&lt;/h3&gt;

&lt;p&gt;There are amazing tools available for game developers: engines, integrated development environments, level editors, etc. Unfortunately, few of them let you target the browser platform natively, and individual libraries still need to be strung together. What&amp;#8217;s missing is a single, hosted integrated environment that makes game development and collaboration as easy as possible.&lt;/p&gt;

&lt;p&gt;We need to build a game development environment that does it all: asset management, collaboration and version control, a short feedback-and-iteration cycle, and the ability to easily publish a game to Facebook, standalone sites and Steam. It should give you everything that&amp;#8217;s available in professional engines, but it needs to be hosted and run in the browser &amp;#8211; no software to install, seamless collaboration with your team, and fast updates so that bugs are fixed and features are improved.&lt;/p&gt;

&lt;h3 id='5_make_highfidelity_resourcehungry_games_run_perfectly_in_javascript'&gt;5. Make high-fidelity, resource-hungry games run perfectly in JavaScript.&lt;/h3&gt;

&lt;p&gt;We know that there&amp;#8217;s always going to be a performance edge available to game developers who build native games in C/C++, and we know there will probably always be developers who want to get close to the metal so they can squeeze out every last drop of performance. But really great games are still being made in Flash, and we&amp;#8217;re confident that the games eventually built in JavaScript + WebGL will be even better. V8 is &lt;em&gt;insanely&lt;/em&gt; fast and WebGL is clearly a viable way to do hardware accelerated graphics in the browser. You&amp;#8217;ve seen the &lt;a href='http://www.chromeexperiments.com/'&gt;demos&lt;/a&gt;. The games are coming.&lt;/p&gt;

&lt;p&gt;So does that mean we can just sit back and wait for Google to keep making Chrome and V8 faster? Nope. Our platform will still have to be the fastest available. It&amp;#8217;ll need to provide 2D and 3D graphics, collision detection/physics, and whatever else game developers need to make great games in the browser. All that code is going to have to run as fast as possible. It might, for example, have to be garbage-free to avoid triggering garbage collection pauses, or we might need to figure out the best way to let developers run path-finding or AI logic in WebWorkers.&lt;/p&gt;

&lt;p&gt;We will also need to take advantage of new browser standards and APIs as they become available, including the Gamepad API, Pointer Lock, WebRTC, and whatever else we need to use to make our vision a reality. We&amp;#8217;ll be as close to the bleeding edge as we can get while still having a large-enough installed base of players. (We&amp;#8217;re especially psyched to be developing for the browser without have to worry about IE8 compatibility.)&lt;/p&gt;

&lt;h3 id='6_increase_the_speed_of_light_to_reduce_network_latency'&gt;6. Increase the speed of light to reduce network latency.&lt;/h3&gt;

&lt;p&gt;Ok, this one we&amp;#8217;ll admit is impossible.&lt;/p&gt;

&lt;p&gt;Just kidding.&lt;/p&gt;

&lt;p&gt;Maybe.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;&lt;em&gt;If you find yourself salivating at the prospects of working on these problems, &lt;strong&gt;we are hiring&lt;/strong&gt;. If you think we&amp;#8217;re crazy, and want to tell us exactly why, we&amp;#8217;d still love to talk to you and try to convince you that yes, we really &lt;strong&gt;are&lt;/strong&gt; crazy, but that we&amp;#8217;ve also got a shot at solving all these problems. Let us see if we can &lt;a href='https://artillery.com/jobs'&gt;convince you&lt;/a&gt; to help us solve them.&lt;/em&gt;&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Consoles Are Dead</title>
   <link href="http://blog.artillery.com/2012/06/consoles-are-dead.html"/>
   <updated>2012-06-27T00:00:00-07:00</updated>
   <id>http://blog.artillery.com/2012/06/consoles-are-dead</id>
   <content type="html">&lt;p&gt;Consoles are dead. It’s time to lay down the controller, and pay our respects.&lt;/p&gt;

&lt;p&gt;For the last 25 years, I’ve owned almost every single console that there was. From the original Nintendo, to the Playstation 3, I count over 15 consoles and portables. Many were epic, like the Nintendo 64, while others wore out their welcome a little too soon.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/xbox-rose.jpg' alt='xboxrose' /&gt;&lt;/p&gt;

&lt;p&gt;Some of my favorite memories were when my friends and family would gather around a new game and we’d duke it out for hours. The really great games and consoles usually nailed one thing really well: Multiplayer. There was nothing like the thrill and competitive spirit of nailing the perfect Dragon Punch or getting the red shells in Mario Kart’s battle mode. Twenty years later, my friend Yuji and I still fire up Street Fighter II on an original SNES.&lt;/p&gt;

&lt;p&gt;Lately, it seems like some things have gotten lost. Games sometimes resemble movies more than they resemble games. Gameplay has been replaced with cut scenes. Fancy graphics and recycled sequels turned into fancier graphics and fancier sound. Gamers like myself were seduced back to the computer to play games like Counterstrike and StarCraft while I waited for the next Halo to come out.&lt;/p&gt;

&lt;p&gt;Unfortunately, as a gamer on the go, these don’t meet my needs anymore either. I’m looking for something rich yet something that I can pull up when I want. Something that I can play with my friends and something that is as accessible as pulling up a website. Millions of people are playing social games, but most of them are still just isometric resource-collecting games. We’re not faulting anybody — we all need to make money. However, we see a better world out there.&lt;/p&gt;

&lt;p&gt;It’s time to kill the console… or better yet, build a better one. One that lives in a browser and can be accessed from any device. One where I can play against my brother just by sending him a link and we’re dropped into an experience together. We’ve assembled a team to bring back that joy back again.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Experiments with WebSocket Performance</title>
   <link href="http://blog.artillery.com/2012/06/websocket-performance.html"/>
   <updated>2012-06-12T00:00:00-07:00</updated>
   <id>http://blog.artillery.com/2012/06/websocket-performance</id>
   <content type="html">&lt;p&gt;Networking is one of the biggest obstacles facing HTML5 game developers. While WebSockets provide a TCP-like communication mechanism, game networking often relies on UDP, and there&amp;#8217;s no way to do UDP-like communication in the browser without a plug-in.&lt;/p&gt;

&lt;p&gt;Why do games often rely on UDP? Imagine you need your server to send a small message to a player every 100ms. In a perfect world there&amp;#8217;s relatively little difference between using UDP and TCP for such a task. You send the player a message, and some amount of time later, the player gets it.&lt;/p&gt;

&lt;p&gt;Of course, we don&amp;#8217;t live in a perfect world, and in our imperfect world packets occasionally get dropped. If you&amp;#8217;re using UDP, and a message gets dropped, the player only has to wait an additional 100ms to get the next message (assuming that it isn&amp;#8217;t dropped as well). That is, new messages are sent out every 100ms, and the loss of one message can&amp;#8217;t delay the arrival of the next.&lt;/p&gt;

&lt;p&gt;With TCP, the player&amp;#8217;s computer will receive the packet containing the next message 100ms after the missing message, but the operating system won&amp;#8217;t send that data to the game program, because it will have detected a gap in the TCP transmission. That gap needs to be filled in before the game program gets to see any new data. How does it get filled in? The sender will wait a certain amount of time (see &lt;a href='http://www.ietf.org/rfc/rfc2988.txt'&gt;Computing TCP&amp;#8217;s Retransmission Timer&lt;/a&gt; for more information) for the receiver to send an acknowledgement of the missing packet. After that time has elapsed and no acknowledgement has been received, the server will retransmit the packet that was dropped. Depending on how long the retransmission timeout is, this can add up to a sizeable delay, which in turn can cause a noticeable blip in the responsiveness of your game. Worse still, subsequent messages can&amp;#8217;t be received by the game code until after this retransmission has happened, so one dropped packet can slow down several others.&lt;/p&gt;

&lt;p&gt;But what&amp;#8217;s the real effect of all this in practice?&lt;/p&gt;

&lt;h3 id='methodology'&gt;Methodology&lt;/h3&gt;

&lt;p&gt;Let&amp;#8217;s take some really simple measurements. We&amp;#8217;ll run a server that accepts WebSocket connections, and bounces every message it gets back to the client. Now, we can write some javascript that establishes a connection, sends a bunch of messages to the server, and measures how long it takes for each message to be sent back. Once we&amp;#8217;ve gathered this data, we can make a histogram. We&amp;#8217;ll do this in a way that resembles the situation I described above, in which messages are sent out periodically, without waiting for a reply first.&lt;/p&gt;

&lt;p&gt;In the tests below, I used &lt;code&gt;ipfw&lt;/code&gt; (Mac OS X&amp;#8217;s firewall/router tool) to model different amounts of latency and packet loss, and took 250 samples.&lt;/p&gt;

&lt;h3 id='measurements'&gt;Measurements&lt;/h3&gt;

&lt;p&gt;What should we expect to see when we run this experiment? Most of the measurements will be clustered around a single value, specifically the round-trip-time between the client and the server. But if any packets get dropped during our test, we&amp;#8217;ll see a few messages that take longer to return.&lt;/p&gt;

&lt;p&gt;So the two parameters most significant to our results are the baseline round-trip-time, and the packet loss rate.&lt;/p&gt;

&lt;p&gt;Before I show you all the data I gathered, go ahead and run these measurements from your own machine: (Note: you&amp;#8217;ll need to be using Chrome or Firefox for this to work. If you don&amp;#8217;t have a recent browser, scroll down to see the measurements I&amp;#8217;ve already taken for you.)&lt;/p&gt;
&lt;div class='plot-target' id='user-chart'&gt;
  &lt;button class='btn btn-primary' id='run-user-measurement'&gt;Go!&lt;/button&gt;
  &lt;span id='waiting-message'&gt;Collecting latency data: &lt;span id='received'&gt;0&lt;/span&gt;/&lt;span id='total'&gt;250&lt;/span&gt;&lt;/span&gt;
&lt;/div&gt;
&lt;p&gt;Hopefully, your connection doesn&amp;#8217;t have any packet loss right now, and so you&amp;#8217;ll just see one bar in the above histogram. But we&amp;#8217;d like to see the impact of varying rates of packet loss, so we&amp;#8217;ll have to somehow induce the packet loss ourselves.&lt;/p&gt;

&lt;p&gt;On OS X, it&amp;#8217;s easy to model latency and packet loss rate with the &lt;code&gt;ipfw&lt;/code&gt; tool. First, I&amp;#8217;ve simulated some different packet loss rates on a low latency connection. First, I ran these commands (as root):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ipfw add pipe 1 ip from any to any out
$ ipfw add pipe 2 ip from any to any in
$ ipfw pipe 1 config delay 12ms
$ ipfw pipe 2 config delay 12ms&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will result in a round trip time of about 50ms. (The packet is delayed by 12 ms twice in each direction, for a total of 48ms, which is pretty close to 50.) After I ran these commands, I measured the message latency at a variety of different packet loss rates, and made histograms from the results.&lt;/p&gt;
&lt;div class='plot-target' id='chart1' style='display: none'&gt;If you can read this, jqplot failed to run. Sorry!&lt;/div&gt;
&lt;h3 id='50ms_latency_01_packet_loss'&gt;50ms Latency, 0.1% Packet Loss&lt;/h3&gt;

&lt;p&gt;Now, let&amp;#8217;s add some packet loss.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ipfw pipe 2 config delay 12ms plr 0.0005&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This will mean about 0.1% of messages will get dropped. It&amp;#8217;s 0.1% because they have a 0.05% chance of getting dropped on the way out and 0.05% on the way back. (Yes, I know it&amp;#8217;s actually &lt;code&gt;100 × (1 - .9995²)&lt;/code&gt; percent. 0.1% is close enough.)&lt;/p&gt;
&lt;div class='plot-target' id='chart2'&gt;If you can read this, jqplot failed to run. Sorry!&lt;/div&gt;
&lt;h3 id='50ms_latency_1_packet_loss'&gt;50ms Latency, 1% Packet Loss&lt;/h3&gt;

&lt;p&gt;Now we bump it up a little further.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ipfw pipe 2 config delay 12ms plr 0.005&lt;/code&gt;&lt;/pre&gt;
&lt;div class='plot-target' id='chart3'&gt;If you can read this, jqplot failed to run. Sorry!&lt;/div&gt;
&lt;h3 id='50ms_latency_5_packet_loss'&gt;50ms Latency, 5% Packet Loss&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ ipfw pipe 2 config delay 12ms plr 0.025&lt;/code&gt;&lt;/pre&gt;
&lt;div class='plot-target' id='chart4'&gt;If you can read this, jqplot failed to run. Sorry!&lt;/div&gt;&lt;div class='plot-target' id='chart5' style='display: none'&gt;If you can read this, jqplot failed to run. Sorry!&lt;/div&gt;
&lt;h3 id='100ms_latency'&gt;100ms Latency&lt;/h3&gt;

&lt;p&gt;I ran the same experiments again, with 100ms of latency.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ipfw pipe 1 config delay 50ms
$ ipfw pipe 2 config delay 50ms&lt;/code&gt;&lt;/pre&gt;
&lt;div class='plot-target' id='chart6' style='display: none'&gt;If you can read this, jqplot failed to run. Sorry!&lt;/div&gt;
&lt;h3 id='100ms_latency_01_packet_loss'&gt;100ms Latency, 0.1% Packet Loss&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ ipfw pipe 2 config delay 25ms plr 0.0005&lt;/code&gt;&lt;/pre&gt;
&lt;div class='plot-target' id='chart7'&gt;If you can read this, jqplot failed to run. Sorry!&lt;/div&gt;
&lt;h3 id='100ms_latency_1_packet_loss'&gt;100ms Latency, 1% Packet Loss&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ ipfw pipe 2 config delay 25ms plr 0.005&lt;/code&gt;&lt;/pre&gt;
&lt;div class='plot-target' id='chart8'&gt;If you can read this, jqplot failed to run. Sorry!&lt;/div&gt;
&lt;h3 id='100ms_latency_5_packet_loss'&gt;100ms Latency, 5% Packet Loss&lt;/h3&gt;

&lt;pre&gt;&lt;code&gt;$ ipfw pipe 2 config delay 25ms plr 0.025&lt;/code&gt;&lt;/pre&gt;
&lt;div class='plot-target' id='chart9'&gt;If you can read this, jqplot failed to run. Sorry!&lt;/div&gt;&lt;div class='plot-target' id='chart10' style='display: none'&gt;If you can read this, jqplot failed to run. Sorry!&lt;/div&gt;
&lt;h3 id='conclusion'&gt;Conclusion&lt;/h3&gt;

&lt;p&gt;The most useful plots to look at above are probably the ones for 0.1% packet loss - a connection with 1% packet loss is already verging on unusable for most people. Even at that low rate, we see that about 3% of messages arrive late.&lt;/p&gt;

&lt;p&gt;Look at the percentage of messages that arrive &amp;#8220;on time&amp;#8221; in each plot. It&amp;#8217;s far lower than you might naively expect based on the packet loss rates. For instance, at 1% packet loss, only about 95% of messages arrive on time. This is because one dropped packet delays not only the message that was in that packet, but also several subsequent messages. This is exactly why TCP isn&amp;#8217;t the right choice for certain types of multiplayer games.&lt;/p&gt;

&lt;p&gt;We&amp;#8217;ll be working hard to make multiplayer html5 games a reality, despite these obstacles. Stay tuned!&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Reducing Polygon Counts and File Sizes</title>
   <link href="http://blog.artillery.com/2012/05/reducing-polygon-count-and-file-sizes.html"/>
   <updated>2012-05-29T00:00:00-07:00</updated>
   <id>http://blog.artillery.com/2012/05/reducing-polygon-count-and-file-sizes</id>
   <content type="html">&lt;p&gt;One of the reasons we built &lt;a href='http://airhockey.artillerygames.com/'&gt;Air Hockey&lt;/a&gt; was to test how easily we could use a professionally-made 3D model in WebGL. I grabbed the &lt;a href='http://www.turbosquid.com/3d-models/3d-max-air-hockey/430629'&gt;best-looking air hockey model&lt;/a&gt; off of TurboSquid, imported it into &lt;a href='http://www.blender.org/'&gt;Blender&lt;/a&gt;, and separated the table, mallet and puck into their own models. I converted each model into ThreeJS JSON format using the &lt;a href='https://github.com/mrdoob/three.js/tree/master/utils/exporters/blender'&gt;ThreeJS Blender exporter&lt;/a&gt;, loaded them into our scene, and ka-pow! It looked like a real air hockey game.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://www.turbosquid.com/3d-models/3d-max-air-hockey/430629'&gt;&lt;img src='/images/airhockey-tablemodel.jpg' alt='airhockey' /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At some point we noticed that the model file sizes were really big. The three JSON model files were 1.3 MB combined, not including the JPEG for the table&amp;#8217;s surface. At some point I was tweaking the puck in Blender and it dawned on me that these models were high-detail, photographic-quality models! The air hockey meshes were much more complex than we needed them to be, and I figured that by making the models simpler (and exporting fewer vertices) I could reduce file size, speed up load time and maybe increase performance of the game. It turns out that there&amp;#8217;s a whole category of 3D models called &lt;a href='http://en.wikipedia.org/wiki/Low_poly'&gt;low-poly models&lt;/a&gt;, i.e. models that are specifically designed to have far fewer faces/vertices/polygons.&lt;/p&gt;

&lt;p&gt;So, how do you reduce the complexity of the models? If you&amp;#8217;re using Maya, I&amp;#8217;m told that there&amp;#8217;s a &lt;em&gt;Reduce&lt;/em&gt; menu item under the &lt;em&gt;Mesh&lt;/em&gt; menu. I&amp;#8217;ve been using &lt;a href='http://www.blender.org/'&gt;Blender&lt;/a&gt; (because it&amp;#8217;s free) which allows you to add &amp;#8220;modifiers&amp;#8221; to objects, including one called &lt;a href='http://wiki.blender.org/index.php/Doc:2.6/Manual/Modifiers/Generate/Decimate'&gt;&amp;#8220;Decimate&amp;#8221;&lt;/a&gt;. The Decimate modifier lets you easily reduce the complexity of a model. It does this by letting you control a ratio which scales down the number of faces in the model, and you can keep decreasing the ratio until you are no longer happy with its appearance.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/decimation.jpg' alt='decimation' /&gt;&lt;/p&gt;

&lt;p&gt;The original mallet model has 9,504 faces. Setting the decimation ratio to 0.004 reduces this down to only 38 faces, but the model looks more like modern art than an air hockey mallet. A reasonable ratio turned out to be 0.15, which resulted in 1,424 (≈ 9,504 × 0.15) faces. However, Blender&amp;#8217;s decimation sometimes results in strange choices of polygon removal &amp;#8211; an artifact can be seen on the mallet where some vertices were merged, but nobody seemed to notice this while we were testing it.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/mallet-artifact.png' alt='mallet-artifact' /&gt;&lt;/p&gt;

&lt;p&gt;I also exported each sample using the ThreeJS exporter and gzipped the result. It turned out that the file size also scales linearly with the number of faces in the model:&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/decimation-filesize.png' alt='decimation-filesize' /&gt;&lt;/p&gt;

&lt;p&gt;In Blender, you don&amp;#8217;t need to decimate the entire model. For example, just decimating the corners, legs and trim (but not the blue sides) of the table reduced the number of faces and the file size by around 50%.&lt;/p&gt;

&lt;p&gt;This was a really easy way to make our game load faster, and we know optimizing load-time is going to be a huge problem in bringing great games to the browser. However, the Decimate modifier probably won&amp;#8217;t produce as attractive a model as a human could with the same polygon count. We&amp;#8217;re confident that, for our next game, the right thing to do is work with an artist who is great at building low-poly models. But if you&amp;#8217;ve found a model you really love and want a way to get the file size down, this should do the trick.&lt;/p&gt;</content>
 </entry>
 
 <entry>
   <title>Real-time synchronous multiplayer 3D gaming with HTML5</title>
   <link href="http://blog.artillery.com/2012/05/realtime-multiplayer-3d-gaming-html5.html"/>
   <updated>2012-05-14T00:00:00-07:00</updated>
   <id>http://blog.artillery.com/2012/05/realtime-multiplayer-3d-gaming-html5</id>
   <content type="html">&lt;p&gt;Six weeks ago we set out to see if we could build a real-time, “twitch” 3D game in the browser using HTML5. We built a few games and were pleasantly surprised with what we achieved.&lt;/p&gt;

&lt;p&gt;You can test one of our creations here: &lt;a href='http://airhockey.artillerygames.com/'&gt;Air Hockey&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href='http://airhockey.artillerygames.com/'&gt;&lt;img src='/images/airhockey.jpg' alt='airhockey' /&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id='graphics'&gt;Graphics&lt;/h3&gt;

&lt;p&gt;WebGL has pretty good browser support at the moment, and &lt;a href='http://mrdoob.github.com/three.js/'&gt;three.js&lt;/a&gt; is an essential library because of the WebGL boilerplate it handles for you. It has a clean API, built-in functionality, and community support, but documentation is sparse. However, there are so many examples that you’ll inevitably find one which shows how to build what you’re trying to do.&lt;/p&gt;

&lt;p&gt;Many of the examples make use of &lt;a href='https://github.com/mrdoob/stats.js/'&gt;stats.js&lt;/a&gt; and &lt;a href='http://code.google.com/p/dat-gui/'&gt;dat.GUI&lt;/a&gt; for monitoring the frame rate and adjusting settings, which are good tools to include when developing your game. dat.GUI was especially helpful in fine-tuning our latency compensation algorithm and tweaking the game’s appearance, such as light strength and other material properties.&lt;/p&gt;

&lt;p&gt;We bought the air hockey, mallet and puck models from &lt;a href='http://www.turbosquid.com/3d-models/3d-max-air-hockey/430629'&gt;TurboSquid&lt;/a&gt;, and getting them into the browser was easy thanks to three.js’s Blender exporter plugin, which exports Blender scenes as JSON. We honed our Blender skills to separate the models, tweak the materials and reduce the number of polygons to make the resulting file sizes smaller. (One humorous bug was that the puck wasn’t touching one side of the air hockey table — after an hour of debugging the physics engine we found that the 3D puck model was actually offset a few units on the X and Y axes and wasn’t centered on the origin. Oops.)&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/airhockey-blender.jpg' alt='airhockey' /&gt;&lt;/p&gt;

&lt;p&gt;If you’re new to 3D, WebGL and three.js can be daunting since there’s a lot of terminology and unfamiliar concepts. Since none of us are 3D artists it took a lot of time to get lighting and materials just right. We did a lot of experimentation by tweaking the graphics, reloading the game and playing against ourselves. A better approach, which we realized when we watched &lt;a href='http://youtu.be/D8mOtkuN864'&gt;Mr.doob’s presentation on the RO.ME project&lt;/a&gt;, is to separate parts of the presentation into small, stand-alone demos which can be tweaked quickly and easiliy before being included in the final result.&lt;/p&gt;

&lt;h3 id='networking'&gt;Networking&lt;/h3&gt;

&lt;p&gt;We wanted to see if we could make a responsive, low-latency game that challenges players’ reflexes, and air hockey seemed like a good fit. Moving mallets and a puck around requires snappy networking performance, and we knew that the game would be unplayable if the networking was even a little bit slow. Fortunately, WebSockets provided great performance.&lt;/p&gt;

&lt;p&gt;Our approach to networking was relatively unsophisticated but it was good enough to prove our point: “twitch” gaming in HTML5 is totally possible! Our networking code worked like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The client sends the position of the player’s mallet to the server.&lt;/li&gt;

&lt;li&gt;The server computes the velocity of both mallets, based on their previous and current positions, and then advances the game simulator, which detects collisions and computes the new velocity and location of the puck.&lt;/li&gt;

&lt;li&gt;The server sends out the latest puck and mallet locations to the clients, which display it to the players.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Of course, latency complicates this process. If it takes 50ms for a packet to get from the server to the client, then the puck position that the player sees will be 50ms out of date. This makes it harder for the player to hit the puck. Here’s how we solved this problem:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The client measures the latency between the client and the server — For example, 50ms.&lt;/li&gt;

&lt;li&gt;When the client receives the position and velocity of the puck from the server it uses the same physics simulator that the server uses to predict where the puck will be 50ms from now.&lt;/li&gt;

&lt;li&gt;It then displays the puck at this predicted location. Now the player doesn’t have to “lead” the puck in order to hit it reliably.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;There are other modern, well-established techniques for lag compensation that could improve the playability of our game even more, but we didn’t use any of them for our demo. Using only &amp;#8217;90s-era game networking techniques was enough to build a fun, real-time, multiplayer browser game.&lt;/p&gt;

&lt;p&gt;Also, it’s worth noting that the server is authoritative about the state of the game. All real-world multiplayer gaming has to be done this way to prevent cheating.&lt;/p&gt;

&lt;p&gt;&lt;img src='/images/airhockey2.jpg' alt='airhockey' /&gt;&lt;/p&gt;

&lt;h3 id='javascript'&gt;JavaScript&lt;/h3&gt;

&lt;p&gt;We thought that developing an HTML5 frontend with a Node.js backend would simplify development time because we could share JavaScript code between the client and server. This is especially important for real-time games where the same simulation needs to run on both ends. Compared to a previous project in which we had separate codebases for client and server logic, we think we cut development time down by somewhere around 30%.&lt;/p&gt;

&lt;p&gt;We tried using RequireJS to write client-side code, but wrapping all of our code in AMD-style module definitions felt clumsy and alien, and we couldn’t get the whole shared-code thing to work. Later on we discovered &lt;a href='https://github.com/substack/node-browserify'&gt;Browserify&lt;/a&gt;, which was life-changing. Not only did Browserify work great, but it provides wrappers for many standard Node libraries so we could write &lt;code&gt;events = require &amp;#39;events&amp;#39;&lt;/code&gt; and &lt;code&gt;class Game extends events.EventEmitter&lt;/code&gt; and have it work on the client-side. The only thing we couldn’t get to work with Browserify was Backbone.js, so we wrote 50 lines of CoffeeScript to replace the parts we needed from it.&lt;/p&gt;

&lt;p&gt;We chose CoffeeScript over JavaScript because it allowed us to write the same logic in fewer characters, and all of the administrative Node tools, like nodemon and forever, seem to support it. We were worried that CoffeeScript would be hard to debug, but it turned out that the compiled JavaScript was dead easy to navigate. Browserify also makes use of &lt;a href='http://www.html5rocks.com/en/tutorials/developertools/sourcemaps/'&gt;the new source map standard&lt;/a&gt;, which helps a lot with navigation in the Chrome Developer Tools, and we think it won’t be long before someone will make it easy to debug CoffeeScript in the browser directly.&lt;/p&gt;

&lt;h3 id='performance_and_optimization'&gt;Performance and optimization&lt;/h3&gt;

&lt;p&gt;As already mentioned, we run our game server on Node.js. We felt that there was no other sensible option given that Node.js gives us the ability to run the same game code on the client and the server. So far we’ve been pretty pleased with Node’s performance, and in our load tests we found that we can run about 100 concurrent games on a single 512MB Rackspace VM before performance starts to degrade. We spent almost no time optimizing our code so this performance was a rather pleasant surprise.&lt;/p&gt;

&lt;p&gt;Any discussion of HTML5 performance will inevitably include garbage collection, and we were initially concerned that GC pauses might cause noticeable pauses in game play. With Chrome this turned out not to be a problem. When playing Air Hockey on Firefox, unfortunately, there are noticeable blips in smoothness which we think is related to garbage collection. However, we made no effort at all to reduce the amount of garbage we generate, and we think it’s probably possible to get great performance on Firefox by being more careful about how much garbage your code generates.&lt;/p&gt;

&lt;h3 id='lessons_learned'&gt;Lessons learned&lt;/h3&gt;

&lt;p&gt;The biggest thing holding back browser game development is the lack of tools. We see a lot of frameworks, but they either constrain you into making your game a certain way, or they get acquired and are never released. There are some great libraries and components, but it’s still up to you to string them together.&lt;/p&gt;

&lt;p&gt;Flash and Unity have well-established development environments, and iOS and Xbox Live Arcade are platforms which provide end-to-end solutions for building and publishing a game. But the browser is still very, very new, and building an HTML5 game is still analogous to assembly language. In our game there’s no slider we can use to tweak the color of the puck or adjust the brightness of a light — if we wanted any of that we’d have to build it or buy in (literally) to a heavier framework.&lt;/p&gt;

&lt;p&gt;We are excited about the possibilities in terms of bringing near-console-like experiences into the browser with synchronous, multiplayer gaming using HTML5. As fans of StarCraft and Halo ourselves, we’re ready to see those experiences come into the browser, and we hope we can inspire you to want them as well.&lt;/p&gt;

&lt;p&gt;If you would like to get early access to our games and game development tools, please sign up at &lt;a href='http://artillerygames.com/'&gt;http://artillerygames.com&lt;/a&gt;.&lt;/p&gt;

&lt;h3 id='further_reading'&gt;Further reading&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href='http://gafferongames.com/networking-for-game-programmers/what-every-programmer-needs-to-know-about-game-networking/'&gt;What every programmer needs to know about game networking&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='https://developer.valvesoftware.com/wiki/Latency_Compensating_Methods_in_Client/Server_In-game_Protocol_Design_and_Optimization'&gt;Latency Compensating Methods in Client/Server In-game Protocol Design and Optimization&lt;/a&gt;&lt;/li&gt;

&lt;li&gt;&lt;a href='http://www.mine-control.com/zack/timesync/timesync.html'&gt;A Stream-based Time Synchronization Technique For Networked Computer Games&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content>
 </entry>
 

</feed>
