{"id":23,"date":"2019-12-18T15:19:51","date_gmt":"2019-12-18T15:19:51","guid":{"rendered":"http:\/\/127.0.0.1\/blog\/?p=23"},"modified":"2019-12-18T17:38:28","modified_gmt":"2019-12-18T17:38:28","slug":"ai-in-steel-circus-part-1","status":"publish","type":"post","link":"https:\/\/philippseifried.com\/blog\/2019\/12\/ai-in-steel-circus-part-1\/","title":{"rendered":"AI in &#8220;Steel Circus&#8221;, Part 1: Overview"},"content":{"rendered":"\n<h2 class=\"wp-block-heading\">The Game<\/h2>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio wp-caption-text\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Steel Circus AI: Humans Playing With Bots\" width=\"788\" height=\"443\" src=\"https:\/\/www.youtube.com\/embed\/vyddRgPZ0zQ?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><figcaption>Gameplay from a 3 vs. 3 Steel Circus match with one bot on each team.<\/figcaption><\/figure>\n\n\n\n<p><a href=\"https:\/\/playsteelcircus.com\/\">Steel Circus<\/a> is a futuristic ball sport with MOBA or &#8220;Hero Shooter&#8221; elements. Each champion has two unique skills, such as placing defensive walls or stunning enemies. There&#8217;s no automatic passing &#8211; passing the ball requires precise aiming. Players also need to manage their stamina, which is used for sprinting, tackling opponents or making quick dodge maneuvers when you have the ball.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Background and Scope<\/h2>\n\n\n\n<figure class=\"wp-block-image size-large\"><img loading=\"lazy\" decoding=\"async\" width=\"1024\" height=\"450\" src=\"http:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/steam-1024x450.png\" alt=\"\" class=\"wp-image-44\" srcset=\"https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/steam-1024x450.png 1024w, https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/steam-300x132.png 300w, https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/steam-768x337.png 768w, https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/steam-788x346.png 788w, https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/steam.png 1284w\" sizes=\"auto, (max-width: 1024px) 100vw, 1024px\" \/><\/figure>\n\n\n\n<p>We originally designed the bots as backfill for human players leaving in the middle of a game. When Steel Circus launched, we were fortunate to receive a main header feature on Steam, which brought in droves of new players for the week that it was active. However, many of these players decided to quit the game during their first match, which ruined the game for everyone else. While we had anticipated this could be a problem, the scale of it surprised us.<\/p>\n\n\n\n<!--more-->\n\n\n\n<p>We worked on various ends to mitigate the issue (such as matchmaking), but in the end, we felt that adding bots to the game as soon as possible was our best bet for improving first time players\u2019 experience and budgeted three weeks during an already hectic launch month to implement them. In the end, it took about 90 hours from start to initial release to write the AI.<\/p>\n\n\n\n<p>This meant I had very little time to backtrack or experiment and had to rely on techniques I knew would work well enough.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">General Advice<\/h2>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio wp-caption-text\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Steel Circus AI: Bots vs. Bots\" width=\"788\" height=\"443\" src=\"https:\/\/www.youtube.com\/embed\/yto-w6amSl4?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><figcaption>A 3 vs. 3 match with all characters (including the player character) controlled by AI.<\/figcaption><\/figure>\n\n\n\n<p>I hope if you find yourself in a similar situation, these posts will offer some help. I think one of the main takeaways is that you often don\u2019t need fancy ingredients (such as behaviour trees) to get decent AI on a budget. The state machine that powers Steel Circus\u2019 AI is really basic. Most of the more complex behaviours arise from evaluating influence maps, which are really the heart of our AI and have been around forever.<\/p>\n\n\n\n<p>My main advice, if you\u2019re not specialized in writing AI, is to start with a basic sensorium, a set of low level helper functions that you can easily test and that will become the building blocks for higher level abstractions. I spent about the first quarter of the time on just that &#8211; utility functions for predicting where the ball would travel, which player would be in the best position to intercept it, where to shoot to score a goal or make a pass, threat evaluation, and so on.<\/p>\n\n\n\n<p>These helper functions didn\u2019t have any decision making logic by themselves, but their output was easy to visualize, and I could play an actual match against other people on the team while recording the debug output on my screen, and then go back and verify that my functions were doing what they were supposed to do. Higher level AI tends to be much more difficult to debug (or at least needs an order of magnitude more time on debug visualization code), so it helps a lot to make sure your foundations are solid. For me, it also helps a lot to not have to deal with implementing low level code when you\u2019re trying to focus on higher level behaviour. Not all of the helpers I wrote ended up being used by the AI, but I think getting them out of the way saved me lots of time and headaches.<\/p>\n\n\n\n<p>Another piece of advice is that, particularly if you\u2019re on a shoestring budget, screen recording software and printing AI state to an on-screen console are your friends. After the low level sensorium, the first thing I built was logic to make a pass or shoot goals. I set it up so that I could have this logic take over my character\u2019s aim while playtesting with the rest of the team (favourite moment: a colleague who didn\u2019t know the AI had taken over and shouted \u201cNice pass!\u201d), and it would output every piece of internal state I could think of to a little window in a screen corner (I could have output to Unity\u2019s console, but our console logs are full of other data, and the Unity console actually updates with a lower frequency than the main render loop!). Screen recording ensured that if I caught an edge case, I could go back and look at the AI\u2019s state during that situation and the preceding simulation ticks, which is often much more meaningful than breakpoints or long lists of logs.<\/p>\n\n\n\n<h2 class=\"wp-block-heading\">Basic Concepts \/ High Level Overview<\/h2>\n\n\n\n<p>We\u2019ve already touched on the helper functions \/ basic sensorium upon which the higher level AI is built. The bots in Steel Circus create the same sort of input that other players do (i.e. they set &#8220;joystick&#8221; directions and &#8220;button&#8221; states). Building on the helpers, it was easy to write a simple AI stub that would pass and shoot goals, by just controlling my aim and throw button whenever I held the ball. The logical next step was to deal with positioning while holding the ball.<\/p>\n\n\n\n<p>Steel Circus is a team sport, so positioning is one of the main skills that differentiates good players from bad ones. If you have the ball, you want to generally move towards the enemy goal, or positions where you can get a clear shot at it, while, among other things: avoiding bumpers, really avoiding enemies, not standing too close to other team mates, keeping clear pass lines to team mates, not standing too close to the edges of the field. The qualifiers here (\u201cnot too close\u201d, \u201creally avoid\u201d) are important. Steel Circus is less about complex path finding and more about traversing the field by moving from one position to a nearby one that\u2019s a bit more advantageous. Influence maps are great at that.<\/p>\n\n\n\n<style id=\"wp_carousel_dynamic_css62\">#sp-wp-carousel-free-id-62 .wpcp-swiper-dots {margin: 40px 0px 0px 0px;}.wpcp-wrapper-62 .swiper-wrapper .swiper-slide-kenburn, .wpcp-wrapper-62 .swiper-wrapper, .wpcp-wrapper-62 .wpcpro-row{align-items: center;}#sp-wp-carousel-free-id-62 .wpcp-single-item {box-shadow: 0px 0px 0px 0px #dddddd;transition: all .3s;margin: 0px;}#sp-wp-carousel-free-id-62.swiper-flip .wpcp-single-item{margin: 0!important;}#sp-wp-carousel-free-id-62 .wpcp-single-item:hover {box-shadow: 0px 0px 0px 0px #dddddd;}#sp-wp-carousel-free-id-62.sp-wpcp-62 .wpcp-single-item {border: 1px solid #dddddd;}#sp-wp-carousel-free-id-62.sp-wpcp-62 .swiper-button-prev,#sp-wp-carousel-free-id-62.sp-wpcp-62 .swiper-button-next,#sp-wp-carousel-free-id-62.sp-wpcp-62 .swiper-button-prev:hover,#sp-wp-carousel-free-id-62.sp-wpcp-62 .swiper-button-next:hover {background: none;border: none;font-size: 30px;}#sp-wp-carousel-free-id-62.sp-wpcp-62 .swiper-button-prev i,#sp-wp-carousel-free-id-62.sp-wpcp-62 .swiper-button-next i {color: #aaa;}#sp-wp-carousel-free-id-62.sp-wpcp-62 .swiper-button-prev i:hover,#sp-wp-carousel-free-id-62.sp-wpcp-62 .swiper-button-next i:hover {color: #52b3d9;}#sp-wp-carousel-free-id-62.sp-wpcp-62 .wpcp-swiper-dots .swiper-pagination-bullet {background-color: #cccccc;}#sp-wp-carousel-free-id-62.sp-wpcp-62 .wpcp-swiper-dots .swiper-pagination-bullet.swiper-pagination-bullet-active {background-color: #52b3d9;} #sp-wp-carousel-free-id-62.sp-wpcp-62.wpcp-image-carousel .wpcp-single-item:hover img, #sp-wp-carousel-free-id-62.sp-wpcp-62.wpcp-post-carousel .wpcp-single-item:hover img, #sp-wp-carousel-free-id-62.sp-wpcp-62.wpcp-product-carousel .wpcp-single-item:hover img{-webkit-transform: scale(1.2);-moz-transform: scale(1.2);transform: scale(1.2);}#sp-wp-carousel-free-id-62 .wpcpro-row>[class*=\"wpcpro-col-\"] { padding: 0 10px; padding-bottom: 20px;} #sp-wp-carousel-free-id-62 .swiper-slide .single-item-fade:not(:last-child) { margin-right: 20px;}@media (min-width: 480px) { .wpcpro-row .wpcpro-col-sm-1 { flex: 0 0 100%; max-width: 100%; } .wpcpro-row .wpcpro-col-sm-2 { flex: 0 0 50%; max-width: 50%; } .wpcpro-row .wpcpro-col-sm-2-5 { flex: 0 0 75%; max-width: 75%; } .wpcpro-row .wpcpro-col-sm-3 { flex: 0 0 33.333%; max-width: 33.333%; } .wpcpro-row .wpcpro-col-sm-4 { flex: 0 0 25%; max-width: 25%; } .wpcpro-row .wpcpro-col-sm-5 { flex: 0 0 20%; max-width: 20%; } .wpcpro-row .wpcpro-col-sm-6 { flex: 0 0 16.66666666666667%; max-width: 16.66666666666667%; } .wpcpro-row .wpcpro-col-sm-7 { flex: 0 0 14.28571428%; max-width: 14.28571428%; } .wpcpro-row .wpcpro-col-sm-8 { flex: 0 0 12.5%; max-width: 12.5%; } } @media (max-width: 480px) { .wpcpro-row .wpcpro-col-xs-1 { flex: 0 0 100%; max-width: 100%; } .wpcpro-row .wpcpro-col-xs-2 { flex: 0 0 50%; max-width: 50%; } .wpcpro-row .wpcpro-col-xs-3 { flex: 0 0 33.222%; max-width: 33.222%; } .wpcpro-row .wpcpro-col-xs-4 { flex: 0 0 25%; max-width: 25%; } .wpcpro-row .wpcpro-col-xs-5 { flex: 0 0 20%; max-width: 20%; } .wpcpro-row .wpcpro-col-xs-6 { flex: 0 0 16.6667%; max-width: 16.6667%; } .wpcpro-row .wpcpro-col-xs-7 { flex: 0 0 14.28571428%; max-width: 14.28571428%; } .wpcpro-row .wpcpro-col-xs-8 { flex: 0 0 12.5%; max-width: 12.5%; } } @media (min-width: 736px) { .wpcpro-row .wpcpro-col-md-1 { flex: 0 0 100%; max-width: 100%; } .wpcpro-row .wpcpro-col-md-2 { flex: 0 0 50%; max-width: 50%; } .wpcpro-row .wpcpro-col-md-2-5 { flex: 0 0 75%; max-width: 75%; } .wpcpro-row .wpcpro-col-md-3 { flex: 0 0 33.333%; max-width: 33.333%; } .wpcpro-row .wpcpro-col-md-4 { flex: 0 0 25%; max-width: 25%; } .wpcpro-row .wpcpro-col-md-5 { flex: 0 0 20%; max-width: 20%; } .wpcpro-row .wpcpro-col-md-6 { flex: 0 0 16.66666666666667%; max-width: 16.66666666666667%; } .wpcpro-row .wpcpro-col-md-7 { flex: 0 0 14.28571428%; max-width: 14.28571428%; } .wpcpro-row .wpcpro-col-md-8 { flex: 0 0 12.5%; max-width: 12.5%; } } @media (min-width: 980px) { .wpcpro-row .wpcpro-col-lg-1 { flex: 0 0 100%; max-width: 100%; } .wpcpro-row .wpcpro-col-lg-2 { flex: 0 0 50%; max-width: 50%; } .wpcpro-row .wpcpro-col-lg-3 { flex: 0 0 33.222%; max-width: 33.222%; } .wpcpro-row .wpcpro-col-lg-4 { flex: 0 0 25%; max-width: 25%; } .wpcpro-row .wpcpro-col-lg-5 { flex: 0 0 20%; max-width: 20%; } .wpcpro-row .wpcpro-col-lg-6 { flex: 0 0 16.6667%; max-width: 16.6667%; } .wpcpro-row .wpcpro-col-lg-7 { flex: 0 0 14.28571428%; max-width: 14.28571428%; } .wpcpro-row .wpcpro-col-lg-8 { flex: 0 0 12.5%; max-width: 12.5%; } } @media (min-width: 1200px) { .wpcpro-row .wpcpro-col-xl-1 { flex: 0 0 100%; max-width: 100%; } .wpcpro-row .wpcpro-col-xl-2 { flex: 0 0 50%; max-width: 50%; } .wpcpro-row .wpcpro-col-xl-3 { flex: 0 0 33.22222222%; max-width: 33.22222222%; } .wpcpro-row .wpcpro-col-xl-4 { flex: 0 0 25%; max-width: 25%; } .wpcpro-row .wpcpro-col-xl-5 { flex: 0 0 20%; max-width: 20%; } .wpcpro-row .wpcpro-col-xl-6 { flex: 0 0 16.66667%; max-width: 16.66667%; } .wpcpro-row .wpcpro-col-xl-7 { flex: 0 0 14.28571428%; max-width: 14.28571428%; } .wpcpro-row .wpcpro-col-xl-8 { flex: 0 0 12.5%; max-width: 12.5%; } }<\/style><div class=\"wpcp-carousel-wrapper wpcp-wrapper-62\">\n\t<div id=\"wpcp-preloader-62\" class=\"wpcp-carousel-preloader\"><img decoding=\"async\" src=\"https:\/\/philippseifried.com\/blog\/wp-content\/plugins\/wp-carousel-free\/public\/css\/spinner.svg\" alt=\"Preloader Image\" \/><\/div>\t<div class=\"wpcp-carousel-content-wrapper\">\n\t<div id=\"sp-wp-carousel-free-id-62\" class=\"wpcp-carousel-section sp-wpcp-62  nav-vertical-center wpcp-image-carousel wpcp-preloader wpcp-standard\" data-swiper='{ &quot;accessibility&quot;:true, &quot;spaceBetween&quot;:20, &quot;arrows&quot;:true, &quot;freeMode&quot;: false, &quot;autoplay&quot;:false, &quot;effect&quot;: &quot;slide&quot;, &quot;centerMode&quot;: false, &quot;autoplaySpeed&quot;:3000, &quot;dots&quot;:true, &quot;infinite&quot;:false, &quot;speed&quot;:600, &quot;pauseOnHover&quot;:true,\n\t\t\t&quot;slidesToShow&quot;:{&quot;lg_desktop&quot;:1, &quot;desktop&quot;: 1, &quot;laptop&quot;: 1, &quot;tablet&quot;: 1, &quot;mobile&quot;: 1}, &quot;responsive&quot;:{&quot;desktop&quot;:1200, &quot;laptop&quot;: 980, &quot;tablet&quot;: 736, &quot;mobile&quot;: 480}, &quot;rtl&quot;:false, &quot;lazyLoad&quot;: &quot;false&quot;, &quot;swipe&quot;: true, &quot;draggable&quot;: true, &quot;swipeToSlide&quot;:true }' dir=\"ltr\">\n\t\t<div class=\"swiper-wrapper\">\n\t\t<div class=\"swiper-slide\">\n\t<div class=\"wpcp-single-item\">\n\t\t\t<a class=\"wcp-light-box\" data-buttons='[\"close\"]' data-wpc_url='https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/simplified_influence_maps_0.png' href=\"https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/simplified_influence_maps_0.png\" data-fancybox=\"wpcp_view\">\n\t\t<figure>\n\t\t\t<img loading=\"lazy\" decoding=\"async\" class=\"skip-lazy\" src=\"https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/simplified_influence_maps_0.png\" alt=\"simplified_influence_maps_0\" width=\"1478\" height=\"852\">\t\t<\/figure>\n\t<\/a>\n\t\t<\/div>\n<\/div>\n\t<div class=\"swiper-slide\">\n\t<div class=\"wpcp-single-item\">\n\t\t\t<a class=\"wcp-light-box\" data-buttons='[\"close\"]' data-wpc_url='https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/simplified_influence_maps_1.png' href=\"https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/simplified_influence_maps_1.png\" data-fancybox=\"wpcp_view\">\n\t\t<figure>\n\t\t\t<img loading=\"lazy\" decoding=\"async\" class=\"skip-lazy\" src=\"https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/simplified_influence_maps_1.png\" alt=\"simplified_influence_maps_1\" width=\"1478\" height=\"852\">\t\t<\/figure>\n\t<\/a>\n\t\t<\/div>\n<\/div>\n\t<div class=\"swiper-slide\">\n\t<div class=\"wpcp-single-item\">\n\t\t\t<a class=\"wcp-light-box\" data-buttons='[\"close\"]' data-wpc_url='https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/simplified_influence_maps_2.png' href=\"https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/simplified_influence_maps_2.png\" data-fancybox=\"wpcp_view\">\n\t\t<figure>\n\t\t\t<img loading=\"lazy\" decoding=\"async\" class=\"skip-lazy\" src=\"https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/simplified_influence_maps_2.png\" alt=\"simplified_influence_maps_2\" width=\"1478\" height=\"852\">\t\t<\/figure>\n\t<\/a>\n\t\t<\/div>\n<\/div>\n\t<div class=\"swiper-slide\">\n\t<div class=\"wpcp-single-item\">\n\t\t\t<a class=\"wcp-light-box\" data-buttons='[\"close\"]' data-wpc_url='https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/simplified_influence_maps_3.png' href=\"https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/simplified_influence_maps_3.png\" data-fancybox=\"wpcp_view\">\n\t\t<figure>\n\t\t\t<img loading=\"lazy\" decoding=\"async\" class=\"skip-lazy\" src=\"https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/simplified_influence_maps_3.png\" alt=\"simplified_influence_maps_3\" width=\"1478\" height=\"852\">\t\t<\/figure>\n\t<\/a>\n\t\t<\/div>\n<\/div>\n\t<div class=\"swiper-slide\">\n\t<div class=\"wpcp-single-item\">\n\t\t\t<a class=\"wcp-light-box\" data-buttons='[\"close\"]' data-wpc_url='https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/simplified_influence_maps_4.png' href=\"https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/simplified_influence_maps_4.png\" data-fancybox=\"wpcp_view\">\n\t\t<figure>\n\t\t\t<img loading=\"lazy\" decoding=\"async\" class=\"skip-lazy\" src=\"https:\/\/philippseifried.com\/blog\/wp-content\/uploads\/2019\/12\/simplified_influence_maps_4.png\" alt=\"simplified_influence_maps_4\" width=\"1478\" height=\"852\">\t\t<\/figure>\n\t<\/a>\n\t\t<\/div>\n<\/div>\n\t\t\t<\/div>\n\t\t\t\t\t<div class=\"wpcp-swiper-dots swiper-pagination\"><\/div>\n\t\t\t\t<!-- If we need navigation buttons -->\n\t\t\t\t\t<div class=\"wpcp-prev-button swiper-button-prev\"><i class=\"fa fa-angle-left\"><\/i><\/div>\n\t\t\t<div class=\"wpcp-next-button swiper-button-next\"><i class=\"fa fa-angle-right\"><\/i><\/div>\n\t\t\t<\/div>\n\t<\/div>\n<\/div>\n\n\n\n\n<p class=\"wp-caption-text\">Assembling an influence map from various gradients: Resulting scores after each step are shown on the bottom. Higher-score regions are brighter. Note that this is a grossly simplified version of the gradients we use in the game.<\/p>\n\n\n\n<p>Influence maps are like heat maps &#8211; you define gradients for bad or good locations, hotter or colder, if you will. You can then sample pseudo-random nearby points and evaluate their \u201cscore\u201d to figure out where to move next. I\u2019ll go into more details on how an influence map for a particular state was set up in the next post, for now I\u2019ll just say that it made positioning for ball ownership a breeze: all I had to do was guesstimate gradients for various factors (enemy proximity, goal proximity and so on), then have a debug AI that would print evaluations of my current position to my onscreen console, watch the score as I moved along the field, and tweak the gradients. It was then trivial to write movement code that sampled pseudo-random points around my character and determined its next target position. I\u2019d let the movement code take over my character and watch how it\u2019d perform in different situations, until it could deal well with enemies in its way.<\/p>\n\n\n\n<figure class=\"wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio wp-caption-text\"><div class=\"wp-block-embed__wrapper\">\n<iframe loading=\"lazy\" title=\"Steel Circus AI: Influence Maps\" width=\"788\" height=\"443\" src=\"https:\/\/www.youtube.com\/embed\/jXqOEm_KcD0?feature=oembed\" frameborder=\"0\" allow=\"accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture\" allowfullscreen><\/iframe>\n<\/div><figcaption>A half-speed visualization of the influence maps for various states the player can be in. The video only shows the influence maps for the player character (the one with the green arrow over his head). Scores are shown relative to the score of the player&#8217;s current position.<\/figcaption><\/figure>\n\n\n\n<p>To a large degree, states other than ball ownership also rely on influence maps for positioning. If a team mate has the ball, many of the same rules apply, with slightly different weights. Beyond that and the basic state machine (with the main states being ball ownership, team mate ball ownership, enemy ball ownership and free ball movement), the major missing pieces are a central AI cache to speed up common queries and a simplified collision system to further boost performance. I\u2019ll go over the details in the next posts.<\/p>\n\n\n\n<p><a href=\"http:\/\/philippseifried.com\/blog\/2019\/12\/ai-in-steel-circus-part-1\/\">Part 1: Overview<\/a><br><a href=\"http:\/\/philippseifried.com\/blog\/2019\/12\/ai-in-steel-circus-part-2\/\">Part 2: The FSM and Ball Ownership<\/a><br><a href=\"http:\/\/philippseifried.com\/blog\/2019\/12\/ai-in-steel-circus-part-3\/\">Part 3: Other States<\/a><br><a href=\"http:\/\/philippseifried.com\/blog\/2019\/12\/ai-in-steel-circus-part-4\/\">Part 4: Optimization and Future Work<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>The Game Steel Circus is a futuristic ball sport with MOBA or &#8220;Hero Shooter&#8221; elements. Each champion has two unique skills, such as placing defensive walls or stunning enemies. There&#8217;s no automatic passing &#8211; passing the ball requires precise aiming. Players also need to manage their stamina, which is used for sprinting, tackling opponents or [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[3,4],"class_list":["post-23","post","type-post","status-publish","format-standard","hentry","category-uncategorized","tag-ai","tag-steel-circus"],"_links":{"self":[{"href":"https:\/\/philippseifried.com\/blog\/wp-json\/wp\/v2\/posts\/23","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/philippseifried.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/philippseifried.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/philippseifried.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/philippseifried.com\/blog\/wp-json\/wp\/v2\/comments?post=23"}],"version-history":[{"count":12,"href":"https:\/\/philippseifried.com\/blog\/wp-json\/wp\/v2\/posts\/23\/revisions"}],"predecessor-version":[{"id":82,"href":"https:\/\/philippseifried.com\/blog\/wp-json\/wp\/v2\/posts\/23\/revisions\/82"}],"wp:attachment":[{"href":"https:\/\/philippseifried.com\/blog\/wp-json\/wp\/v2\/media?parent=23"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/philippseifried.com\/blog\/wp-json\/wp\/v2\/categories?post=23"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/philippseifried.com\/blog\/wp-json\/wp\/v2\/tags?post=23"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}