{"id":164,"date":"2011-12-18T14:27:23","date_gmt":"2011-12-18T22:27:23","guid":{"rendered":"https:\/\/invader.trystorymachine.com\/?p=164"},"modified":"2014-07-26T18:16:33","modified_gmt":"2014-07-27T01:16:33","slug":"locomotion-smoke-and-mirrors","status":"publish","type":"post","link":"https:\/\/invader.trystorymachine.com\/?p=164","title":{"rendered":"Locomotion Smoke and Mirrors"},"content":{"rendered":"<p>If we&#8217;ve done our jobs right, Wind-up Knight is a fairly simple game. \u00a0There are only four inputs, and only two are ever needed simultaneously. \u00a0Sir Sprint, our heroic spring-loaded knight, runs forward automatically, removing the need for a classic directional pad or analog stick. \u00a0The challenge is derived from careful level design rather than a complex interface, and though the game is not easy, it&#8217;s straightforward.<\/p>\n<p>Achieving a control scheme that is simple to understand and simple to operate, even for a straightforward game like Wind-up Knight, is actually a pretty complicated problem. \u00a0The term I use for this kind of code is <strong>player handling<\/strong>, referring both to the steering of the player&#8217;s avatar, and to the manipulation of the player himself. \u00a0You see, games that control well often do it by lying to the player, by fudging the simulation, by breaking the rules.<\/p>\n<p>Good player handling code is often smoke and mirrors; the player presses buttons and sees a reasonable result, but in between those two operations a whole lot of code is working to ensure that the result is the <em>best<\/em> of many potential results. \u00a0For example, my friend <a href=\"http:\/\/greggman.com\/\">Greggman<\/a> discovered that <a href=\"http:\/\/games.greggman.com\/game\/programming_m_c__kids\/\">Mario 3&#8217;s jumping rules change depending on whether or not a level has slopes in it.<\/a>\u00a0 Halo&#8217;s targeting reticle famously slows as it passes over an enemy to make it easier to target with an analog stick without using an auto-aim system. When Spider-Man swings, he certainly does not orient about the spot where his web connects to a building (at least, he didn&#8217;t in the <a href=\"http:\/\/www.youtube.com\/watch?v=orbWj7zh9lE\">swinging system I wrote<\/a>).<\/p>\n<p>Good player handling code doesn&#8217;t just translate the player&#8217;s inputs into action, it tries to discern the player&#8217;s <em>intent<\/em>. \u00a0Once the intended action has been identified, if the rules of the game allow it, good player handling code makes the action happen&#8211;<em>even if it means breaking the rules of the simulation a little. \u00a0<\/em>The goal of good handling code isn&#8217;t to maintain a &#8220;correct&#8221; simulation, it&#8217;s to provide a fun game. \u00a0It sucks to miss a jump by three centimeters. \u00a0It sucks to take the full force of a hit from a blow that visually missed. \u00a0It sucks to swing into a brick wall at 80 miles per hour instead of continuing down the street. \u00a0To the extent that the code can understand the player&#8217;s intent, it should act on that intent rather than on the raw input. \u00a0<em>Do what I mean, not what I say.<\/em><\/p>\n<p>Wind-up Knight appears to be a pretty simple game, but we actually pull a few tricks under the hood to make the game control the way you expect it to (rather than the way it would if left to a pure physics simulation).<\/p>\n<h2>Jumping<\/h2>\n<p>Sir Sprint does a lot of jumping, mostly from off of solid surfaces. \u00a0But he can also jump right after running off a ledge&#8211;for a very short amount of time, we&#8217;ll allow a press to the jump button to result in a regular jump, even though there&#8217;s nothing under his feet. \u00a0This is particularly helpful to players on phones that occasionally slow down; they shouldn&#8217;t have to die because the frame rate fluctuates right at the point of a jump.<\/p>\n<p><a href=\"https:\/\/invader.trystorymachine.com\/wp-content\/uploads\/2011\/12\/Screen-Shot-2011-12-18-at-2.15.52-PM.png\"><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-168 alignnone\" title=\"Screen Shot 2011-12-18 at 2.15.52 PM\" src=\"https:\/\/invader.trystorymachine.com\/wp-content\/uploads\/2011\/12\/Screen-Shot-2011-12-18-at-2.15.52-PM.png\" alt=\"\" width=\"628\" height=\"319\" srcset=\"https:\/\/invader.trystorymachine.com\/wp-content\/uploads\/2011\/12\/Screen-Shot-2011-12-18-at-2.15.52-PM.png 698w, https:\/\/invader.trystorymachine.com\/wp-content\/uploads\/2011\/12\/Screen-Shot-2011-12-18-at-2.15.52-PM-300x152.png 300w\" sizes=\"auto, (max-width: 628px) 100vw, 628px\" \/><\/a><\/p>\n<p>&nbsp;<\/p>\n<p>We also allow wall jumping to occur while Sprint is in mid-air. \u00a0If you jump at a wall and hit jump again before he lands on the surface, Sprint will automatically flip, snap to the wall, and jump off it again. \u00a0This makes the wall jump feel a little more sticky, and it means you have a larger margin of error when timing a wall jump; even if you press the button slightly too early he&#8217;ll probably still make it.<\/p>\n<h2>Rolling<\/h2>\n<p><a href=\"https:\/\/invader.trystorymachine.com\/wp-content\/uploads\/2011\/12\/Screen-Shot-2011-12-18-at-2.15.15-PM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"size-full wp-image-169 alignright\" title=\"Roll Box\" src=\"https:\/\/invader.trystorymachine.com\/wp-content\/uploads\/2011\/12\/Screen-Shot-2011-12-18-at-2.15.15-PM.png\" alt=\"\" width=\"342\" height=\"249\" srcset=\"https:\/\/invader.trystorymachine.com\/wp-content\/uploads\/2011\/12\/Screen-Shot-2011-12-18-at-2.15.15-PM.png 342w, https:\/\/invader.trystorymachine.com\/wp-content\/uploads\/2011\/12\/Screen-Shot-2011-12-18-at-2.15.15-PM-300x218.png 300w\" sizes=\"auto, (max-width: 342px) 100vw, 342px\" \/><\/a><\/p>\n<p>If you are rolling under a low ceiling and release the roll button, the knight will continue to roll until he reaches an area where he can stand. \u00a0In that case, if you hit attack or shield while rolling, the move will be queued up and executed automatically as soon as the knight stands up. \u00a0This lets you make moves immediately after exiting the roll state even if you press the button slightly too early.<\/p>\n<p>The low-hanging ceilings, by the way, often extend invisibly on either side so that you don&#8217;t automatically stand up into some spikes.<\/p>\n<h2>Collision Detection<\/h2>\n<p>We have a fairly complicated &#8220;hit type&#8221; system to allow the rejection of legitimate collisions based on arbitrary game rules. \u00a0For example, if an enemy hits the player as the player is in the middle of swinging his sword, we ignore the hit to the player and instead reverse it to kill the enemy. \u00a0There are no double K.O.s in Wind-up Knight; when it happens, the player always wins.<\/p>\n<p>We also ignore hits from falling things to Sir Sprint&#8217;s body region if his shield is up. \u00a0If the shield is up, all falling things are considered impotent. \u00a0This way, if Sprint runs into an object that has just fallen in front of him (missing his shield but not his torso), he won&#8217;t die.<\/p>\n<h2>Camera<\/h2>\n<p>The camera in Wind-up Knight is the second most complicated system in the game (the first being Sir Sprint&#8217;s locomotion code). \u00a0It watches where Sprint is going and tries to prepare itself ahead of time for dramatic changes in motion so that it never snaps or cuts jarringly.<\/p>\n<p>The most interesting case is the way that the camera watches for upcoming walls. \u00a0If Sprint hits a wall he turns and runs back the way he came, which requires the camera to do a fairly dramatic sweep in the opposite direction. \u00a0To smooth that transition out, the camera searches for walls ahead of Sir Sprint and then moves to align itself to them. \u00a0However, not all walls will cause Sprint to change direction; low obstacles, for example, are probably going to get jumped over.<\/p>\n<p><a href=\"https:\/\/invader.trystorymachine.com\/wp-content\/uploads\/2011\/12\/Screen-Shot-2011-12-18-at-2.13.53-PM.png\"><img loading=\"lazy\" decoding=\"async\" class=\"alignright  wp-image-170\" title=\"Wall Rays 2\" src=\"https:\/\/invader.trystorymachine.com\/wp-content\/uploads\/2011\/12\/Screen-Shot-2011-12-18-at-2.13.53-PM.png\" alt=\"\" width=\"380\" height=\"304\" srcset=\"https:\/\/invader.trystorymachine.com\/wp-content\/uploads\/2011\/12\/Screen-Shot-2011-12-18-at-2.13.53-PM.png 422w, https:\/\/invader.trystorymachine.com\/wp-content\/uploads\/2011\/12\/Screen-Shot-2011-12-18-at-2.13.53-PM-300x240.png 300w\" sizes=\"auto, (max-width: 380px) 100vw, 380px\" \/><\/a>It took me quite a while to find a heuristic that could reliably detect upcoming walls but reject lower platforms. \u00a0In the end I went with a system that shoots three rays out from Sir Sprint&#8217;s position, and only accepts an upcoming wall if all three intersect the same plane. \u00a0You might not even notice that the camera speeds up and slows down in order to deal with dramatic orientation changes, but without that code the game would feel a lot less smooth.<\/p>\n<p>Sometimes heuristics are not enough to get the correct effect, and you have to fudge it even further. \u00a0We place secret camera &#8220;hint&#8221; objects in pits and shafts that Sprint is meant to slide down so that the camera can move to ensure the upcoming floor is always visible even before Sprint begins to fall down the shaft.<\/p>\n<p>Though helping the player complete an action that they intended to complete is almost always the right thing to do, it is possible to go overboard with this kind of system. \u00a0Games like Prince of Persia (the <a href=\"http:\/\/www.metacritic.com\/game\/playstation-3\/prince-of-persia\/trailers\/1103682\">next-gen cel-shaded version<\/a>, not the wonderful original) go so far in assisting the player that it&#8217;s almost impossible to actually fail. \u00a0If the assistance is so obvious that the player notices it, the game feels suddenly like a false challenge, as if it is on rails. \u00a0For Wind-up Knight, we chose a few areas to smooth out to ensure the best play experience, but the rest we left up to the physics simulation and the player&#8217;s actual prowess.<\/p>\n<p>It may be smoke and mirrors, but good player handling systems are almost always focused on translating player intent, rather than player action, into game play. \u00a0Hopefully the work we put into this area on Wind-up Knight makes it a better game, even if most players never know it&#8217;s there.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>If we&#8217;ve done our jobs right, Wind-up Knight is a fairly simple game. \u00a0There are only four inputs, and only two are ever needed simultaneously. \u00a0Sir Sprint, our heroic spring-loaded knight, runs forward automatically, removing the need for a classic &hellip; <a href=\"https:\/\/invader.trystorymachine.com\/?p=164\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[5,11,8],"tags":[],"class_list":["post-164","post","type-post","status-publish","format-standard","hentry","category-game-design","category-game-engineering","category-wind-up-knight"],"_links":{"self":[{"href":"https:\/\/invader.trystorymachine.com\/index.php?rest_route=\/wp\/v2\/posts\/164","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/invader.trystorymachine.com\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/invader.trystorymachine.com\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/invader.trystorymachine.com\/index.php?rest_route=\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/invader.trystorymachine.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=164"}],"version-history":[{"count":8,"href":"https:\/\/invader.trystorymachine.com\/index.php?rest_route=\/wp\/v2\/posts\/164\/revisions"}],"predecessor-version":[{"id":176,"href":"https:\/\/invader.trystorymachine.com\/index.php?rest_route=\/wp\/v2\/posts\/164\/revisions\/176"}],"wp:attachment":[{"href":"https:\/\/invader.trystorymachine.com\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=164"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/invader.trystorymachine.com\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=164"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/invader.trystorymachine.com\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=164"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}