Appstore Blogs Appstore DeveloperBlog /blogs/appstore/feed/entries/atom 2018-01-16T21:18:15+00:00 Apache Roller /blogs/appstore/post/fbc64579-e411-455d-ad10-3b09a507ae76/how-to-create-a-great-tv-login-experience-with-cordova-part-2 How to Create a Great TV Login Experience with Cordova (Part 2) Emily Esposito Fulkerson 2018-01-16T21:01:01+00:00 2018-01-16T21:01:01+00:00 <p><img alt="011618_TVlogin_image3.PNG" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/FireTV/011618_TVlogin_image3._CB489333492_.png?t=true" style="display:block; margin-left:auto; margin-right:auto" /><br /> In my <a href="https://developer.amazon.com/blogs/appstore/post/a75a9783-53b8-46df-9433-85ad9a7664a7/how-to-create-a-great-tv-login-experience" target="_blank">recent blog post</a>, I demonstrated what we have found to be a good login experience for customers using an Amazon Fire TV and remote control. In this second part, we’ll create a Cordova app which utilizes Login with Amazon via a third-party open source plugin.</p> <p><img alt="011618_TVlogin_image3.PNG" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/FireTV/011618_TVlogin_image3._CB489333492_.png?t=true" style="display:block; margin-left:auto; margin-right:auto" /><br /> The way people&nbsp;log&nbsp;in, register&nbsp;an app, and purchase&nbsp;content could be the difference between their becoming&nbsp;customers or not. In my <a href="https://developer.amazon.com/blogs/appstore/post/a75a9783-53b8-46df-9433-85ad9a7664a7/how-to-create-a-great-tv-login-experience" target="_blank">recent blog post</a>, I demonstrated what we have found to be a good login experience for customers using an Amazon Fire TV and remote control. In this second part, we’ll create a Cordova app which utilizes Login with Amazon via a third-party open source plugin.</p> <h1>Prerequisites</h1> <p>There are a couple of&nbsp;steps we need to follow before we can start:</p> <ul> <li>Install the latest version of Cordova, <a href="https://cordova.apache.org/" target="_blank">here</a>.&nbsp;</li> <li>Download the Android (not Cordova) <a href="https://developer.amazon.com/public/resources/development-tools/sdk" target="_blank">Apps &amp; Games SDK pack</a> which contains the latest version of the Login with Amazon SDK. Unzip this somewhere for later.</li> <li>Install the latest <a href="http://developer.android.com/sdk/index.html" target="_blank">Android SDK</a><br /> &nbsp;</li> </ul> <h1>7 steps to create an app with Cordova</h1> <p><br /> <strong>1. Go to your working/projects folder and create the Cordova project:</strong></p> <p><em># cordova create lwasample com.amazon.lwasample LWASample</em></p> <p>This creates a folder called ‘lwasample,' generates a project with the app name ‘LWASample,’ and package name ‘com.amazon.lwasample.’<br /> &nbsp;</p> <p><strong>2.&nbsp;Add the Cordova platform Android for Fire TV Support</strong></p> <p><em># cd lwasample</em></p> <p><em># cordova platform add android</em><br /> &nbsp;</p> <p><strong>3. Clone or download this <a href="https://github.com/edu-com/cordova-plugin-amazon-login" target="_blank">third-party Login with Amazon Cordova plugin</a> and add to the Cordova project</strong></p> <p><em># cordova plugin add &lt;path_to_plugin&gt;</em><br /> &nbsp;</p> <p><strong>4.&nbsp;Copy the required libraries to your project</strong></p> <p><em># cp &lt;path_to_sdk_download&gt;/<strong>login-with-amazon-sdk.jar</strong> platforms/android/libs/</em></p> <p>Android support libraries found in the Android SDK:</p> <p><em># cp &lt;path_to_android_sdk&gt;/extras/android/support/v4/<strong>android-support-v4.jar /</strong>platforms/android/libs/</em><br /> &nbsp;</p> <p><strong>5. Generate the release and debug keys for signing the app</strong></p> <p><em># keytool -genkey -v -keystore my-key.keystore -alias release -keyalg RSA -keysize 2048 -validity 10000</em></p> <p><em># keytool -genkey -v -keystore my-key.keystore -alias debug -keyalg RSA -keysize 2048 -validity 10000</em></p> <p>We now need to get some information from the keystore by using the following command:</p> <p><em># keytool -list -v -alias debug -keystore my-key.keystore</em></p> <p>From this command make the note of the MD5 and SHA256 signatures:</p> <p><img alt="011618_TVlogin_image1.PNG" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/FireTV/011618_TVlogin_image1._CB489333496_.png?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p><br /> <strong>6. Create the security profiles</strong></p> <p>Click <a href="https://developer.amazon.com/lwa/sp/overview.html" target="_blank">here</a> and create a security profile for debug and release using the MD5 and SHA256 signatures obtained in step 5.&nbsp;<br /> &nbsp;</p> <p><img alt="011618_TVlogin_image2.PNG" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/FireTV/011618_TVlogin_image2._CB489333498_.png?t=true" style="display:block; height:309px; margin-left:auto; margin-right:auto; width:700px" /></p> <p><strong>7. Paste the API keys into app config which should be created in config\project.json</strong></p> <p>For example, your config\project.json should look like this:</p> <pre> <code>{ &quot;debug&quot;: { &quot;AMAZON_API_KEY&quot; : &quot;eyJhbG......5csT==&quot; }, &quot;release&quot;: { &quot;AMAZON_API_KEY&quot; : &quot;df4Fsv......yc1A==&quot; } }</code></pre> <p>Now the Login with Amazon plugin is set up and ready to go! The API can be used within your TV web app by using the following methods:<br /> &nbsp;</p> <p><strong>Authorize</strong></p> <p><em>window.AmazonLogin.authorize(Object options, Function success, Function failure)</em></p> <p>The success function will return a json object:</p> <pre> <code>{ accessToken: &quot;...&quot;, user: { name: &quot;Full Name&quot;, email: &quot;email@example.com&quot;, user_id: &quot;123456789&quot;, postal_code: 'EC1A4JU' } }</code></pre> <p>A failure will return an error string.<br /> &nbsp;</p> <p><strong>signOut</strong></p> <p><em>window.AmazonLogin.signOut(Function success, Function failure)</em><br /> &nbsp;</p> <h1>More resources</h1> <p>To help you get started, a sample web app using Login with Amazon can be found <a href="https://s3-us-west-2.amazonaws.com/phamptonamazon/blogs/cordovalwa.zip" target="_blank">here</a>.&nbsp;</p> <p>And, click here to read <a href="https://developer.amazon.com/blogs/appstore/post/a75a9783-53b8-46df-9433-85ad9a7664a7/how-to-create-a-great-tv-login-experience" target="_blank">my first blog post</a> on how to create a good TV app registration and login experience with Login with Amazon and Amazon In-App Purchasing.&nbsp;</p> <p>&nbsp;</p> /blogs/appstore/post/43b97c01-4dfd-4e27-90dd-f70f8dd55c59/webinar-catalog-integration-on-amazon-fire-tv Webinar: Catalog Integration on Amazon Fire TV Emily Esposito Fulkerson 2018-01-10T22:20:21+00:00 2018-01-10T22:20:21+00:00 <p><img alt="" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/default/blong._CB490578608_.jpg" style="display:block; height:628px; margin-left:auto; margin-right:auto; width:1200px" /></p> <p>In this webinar, you will learn about the specific steps required to include your content in universal browse and search results across content providers.</p> <ul> </ul> <p><img alt="" /><a href="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/default/blong._CB490578608_.jpg"><img alt="" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/default/blong._CB490578608_.jpg" style="display:block; height:628px; margin-left:auto; margin-right:auto; width:1200px" /></a></p> <p>Catalog integration allows users to seamlessly view, browse, and search for their&nbsp;content alongside content from Amazon and other streaming media providers within Amazon Fire TV. Regardless of where in the Fire TV user interface (UI) users find your content, they can play it directly without needing to open your app first. Catalog integration can drive new users to download and use your app, help&nbsp;retain existing users, and make&nbsp;your content eligible for promotion through Featured Content on the Fire TV.<br /> &nbsp;<br /> In this webinar, you will learn about the specific steps required&nbsp;to include your content in universal browse and search results across content providers.&nbsp;You will also learn more about:</p> <ul> <li>The benefits of integrating your catalog with Fire TV</li> <li>Components of catalog integration</li> <li>Content and user experience guidelines</li> </ul> <p>We are offering two sessions of this webinar on Thursday, January 25, 2018: 7:00 a.m. PST and 1:00 p.m. PST. Sign up today to reserve your spot!</p> <p>&nbsp;</p> <p><a href="https://goto.webcasts.com/starthere.jsp?ei=1176960&amp;tp_key=1451843b44" target="_blank"><img alt="" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/default/7AM_Webinar_Button._CB528958595_.png" style="display:block; height:50px; margin-left:auto; margin-right:auto; width:200px" /></a><a href="https://goto.webcasts.com/starthere.jsp?ei=1177130&amp;tp_key=d737e0d04d" target="_blank"><img alt="" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/default/1PM_Webinar_Button._CB528958592_.png" style="display:block; height:50px; margin-left:auto; margin-right:auto; width:200px" /></a></p> /blogs/appstore/post/c8621010-1e59-491b-b358-a86e609433f4/gamemaker-basics-screen-shake GameMaker Basics: Screen Shake Emily Esposito Fulkerson 2018-01-10T18:07:08+00:00 2018-01-10T18:07:32+00:00 <p><img alt="0109_ScreenShake_image4.gif" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/0109_ScreenShake_image4._CB490508961_.gif?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p>We are going to talk about everyone’s favorite indie effect: screen shake! A classic that is sure to beef up your impacts, explosions, sudden realizations, gunshots, and more. Setting up screen shake is a pretty simple process, but as you will see, there are a lot of nuances.</p> <p><img alt="0109_ScreenShake_image4.gif" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/0109_ScreenShake_image4._CB490508961_.gif?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p>Howdy folks! Today, we are going to talk about everyone’s favorite indie effect: screen shake! A classic that is sure to beef up your impacts, explosions, sudden realizations, gunshots, and more. Setting up screen shake is a pretty simple process, but as you will see, there are a lot of nuances you can tweak to dramatically impact the feeling of it. This blog assumes you are somewhat familiar with views in GameMaker. If you aren’t familiar with views, check out <a href="https://developer.amazon.com/blogs/appstore/post/cd476239-5866-46f7-a881-de584e10fe86/gamemaker-basics-views" target="_blank">this previous blog post on views</a>!</p> <h1>Set up&nbsp;</h1> <p>Before we can start shaking the camera around, it is a good idea to initialize some variables that will help us control screen shake, and fine tune it. The best way to handle this is to do so from a game controller type object. A game controller object is a persistent object that manages many parts of your game. Things like score, the camera, changing levels, controlling menus, and lots of other things can be controlled from your game controller object. If your project does not have a game controller, now would be a good time to add one! Then, let's initialize some variables.</p> <p><strong>Game controller create event</strong></p> <pre> <code>shake = false; shakeDur = 5; shakeForce = 1;</code></pre> <p>These three variables will let us easily manage the ferocity of our screen shake, and its duration. The first variable is used to turn the screen shake effect on and off. The second, <strong>shakeDur</strong>, is the duration the effect lasts. Finally, <strong>shakeForce</strong>, is how dramatic the shake effect is. Now we need to put these to use.</p> <p><strong>Game controller step event</strong></p> <pre> <code>if(shake){ shakeDur --; view_xview += choose(-shakeForce,shakeForce); view_yview += choose(-shakeForce,shakeForce); if(shakeDur &lt;= 0){ shake = false; shakeDur = 5; } }else{ view_xview = approach(view_xview,0,0.3); view_yview = approach(view_yview,0,0.3); }</code></pre> <p>Alright, real quick before I explain this, I want to point out this <strong>approach</strong> script at the bottom. If you don’t have the <strong>approach </strong>script (which is featured heavily in my previous blog entries) here it is. Create a new script, name it approach, and throw this code in there.</p> <p><strong>Approach script</strong></p> <pre> <code>/// approach(start, end, shift); if(argument0 &lt; argument1){ return min(argument0 + argument2, argument1); }else{ return max(argument0 - argument2, argument1); }</code></pre> <p>Quick shout out to Matt Thorson (Towerfall, Celeste) for this handy script that I have been using for years. This script takes a value, and shifts it towards another value by a set amount each frame. In the instance above, we are using it to reset our camera position back to zero, which is the default camera position. Now, back to the screen shake.</p> <p>This is a pretty simple bit of code. First, we check to see if shake is true, and if it is, start counting down our <strong>shakeDur</strong> variable. Once <strong>shakeDur</strong> reaches zero, <strong>shake</strong> is set to false, and <strong>shakeDur</strong> is reset to its maximum value of five. While <strong>shakeDur</strong> counts down, we move the <strong>view</strong> around by adding <strong>shakeForce</strong> to it randomly. If you are unfamiliar with <strong>choose,</strong> it is pretty self explanatory. It simply chooses one of the arguments provided. In this case, it is choosing either <strong>shakeForce </strong>or <strong>negative shakeForce</strong>, so either one or negative one. This means our camera is moving around one pixel up, down, left, or right randomly every frame for five frames. Once <strong>shakeDur</strong> reaches zero and <strong>shake</strong> is no longer true, the <strong>view </strong>is reset back to zero by using the <strong>approach </strong>script.</p> <p>That's basically it! Or, at least, it's basically the basics of screen shake. If you run the game and you have set a button press or some action to set shake to true, you should get a fairly small screen shake. Here is an example from a little game I have been working on lately.</p> <p><img alt="0109_ScreenShake_image4.gif" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/0109_ScreenShake_image4._CB490508961_.gif?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p style="text-align:center">Can Kicker Xtreme (working title)</p> <h1>Tweaking the variables</h1> <p>Now you have the basics in place. If you haven’t already, take some time to mess with the <strong>shakeDur</strong> and <strong>shakeForce</strong> variables we created. See what happens if you increase/decrease those variables in the create event of your game controller object. Here are a couple of examples.</p> <p><img alt="0109_ScreenShake_image1.gif" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/0109_ScreenShake_image1._CB490508970_.gif?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p><img alt="0109_ScreenShake_image3.gif" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/0109_ScreenShake_image3._CB490508967_.gif?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p>In the first animation, we have a <strong>shakeDur </strong>of 60 and a <strong>shakeForce </strong>of one. In the second animation, a <strong>shakeDur</strong> of five and a <strong>shakeForce </strong>of three.</p> <p>You can also get a lot of mileage out of messing with the <strong>view_angle</strong> when shaking the screen. The setup for this is exactly like <strong>view_xview </strong>and <strong>view_yview</strong> above. It's fairly subtle in the animation below, but you can see how it adds just a little bit extra oomph to the shake.</p> <p><img alt="0109_ScreenShake_image2.gif" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/0109_ScreenShake_image2._CB490508965_.gif?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <h1>Final advice on screen shake</h1> <p>That about wraps it up for screen shake. This&nbsp;just barely scratching the surface of how this can be applied and tweaked, but it should set you on the right track.</p> <p>I’d also like to offer some general advice for using screen shake.</p> <p>I see a lot of folks using it for… well… everything in their games all the time. With screen shake, often less is more. Use it to accentuate certain actions to give them more weight and impact. Don’t use it for every single gunshot. Use it for that big powerful gun that you have limited ammo for!</p> <p>Thank you for taking the time to read over this, and I’ll catch you next time. As always, you can reach me on <a href="https://www.twitter.com/ratcasket" target="_blank">Twitter</a> or visit my <a href="http://www.ratcasket.com/" target="_blank">website</a> for more gamedev stuff.</p> <p>&nbsp;</p> <p style="text-align:center"><a href="https://www.twitter.com/ratcasket"><img alt="NathanRBio.jpg" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/default/NathanRBio._CB513300692_.jpg?t=true" /></a></p> <p style="text-align:center"><em>Nathan Ranney is the founder of punk house game dev shop, <a href="http://www.ratcasket.com" target="_blank">RatCasket</a>. He’s best known for the creation and development of Kerfuffle, an online indie fighting game.</em></p> /blogs/appstore/post/55ff2f01-7ed1-4572-a6fa-7151157b6471/how-to-port-your-unity-game-from-google-play-to-amazon-appstore How to Port Your Unity&reg; Game from Google Play to the Amazon Appstore Emily Esposito Fulkerson 2018-01-03T17:18:30+00:00 2018-01-03T18:22:54+00:00 <p><img alt="unity_to_amazon.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/Unity/unity_to_amazon._CB490687033_.png?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p>In this blog post, I'll cover the&nbsp;seven&nbsp;basic steps for bringing your Unity&reg; app to the Amazon Appstore, quickly and easily.</p> <p><img alt="unity_to_amazon.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/Unity/unity_to_amazon._CB490687033_.png?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p>I love the smell of fresh ports in the morning. Unfortunately for me—but lucky for you—developing for Amazon Appstore is not really &quot;porting.&quot; It’s pretty much the same as your Android build for Google Play.</p> <p>In this blog post, I'll cover the&nbsp;seven&nbsp;basic steps for bringing your Unity app to the Amazon Appstore, quickly and easily.</p> <p>First, let's establish some assumptions about your game.</p> <p><strong>Development assumptions:</strong></p> <p>We are assuming in this post that you have developed a Unity&reg; game that:</p> <ul> <li>Works on Android devices.</li> <li>Does not include game mechanics that rely on Google Play services.</li> <li>Uses the Unity&reg; Purchasing API, or it doesn’t use In-App Purchasing at all.</li> </ul> <h1>1. Develop your Android app or game</h1> <p>Amazon Fire TV and Fire tablets run&nbsp;Fire OS, Amazon’s version of Android. Current Amazon devices are running Fire OS 5 based on Android L, with some future devices being released with Fire OS 6 based on Android N. If your game runs on Android L or N, it will run on Fire OS. Know which OS you want to target based on the devices you want to support. The Amazon Appstore developer console supports multiple APKs based on device configuration.</p> <p>For more information about targeting Fire OS 6 specifically, check out this blog about <a href="https://developer.amazon.com/public/solutions/devices/fire-tv/docs/fire-tv-fire-os-6" target="_blank">developing for devices running Fire OS 6</a>.</p> <h1>2. Address Google Play services</h1> <p>Amazon devices do not support Google Play services. If your game utilizes Google Play services, you should check if it is available at runtime and fallback gracefully.</p> <p><em>Note:</em> You can still upload a game with Google Play services if you only want to target non-Amazon devices.&nbsp;</p> <h1>3. Remove features that require hardware not available on targeted devices</h1> <p>Amazon’s current first-party devices lack GPS and cellular data, and Amazon Fire TV devices do not support touch screens. Make sure your game doesn’t require support for these features. Learn about Amazon device specs for <a href="https://developer.amazon.com/docs/fire-tablets/ft-specs-custom.html" target="_blank">Fire tablets</a> and Amazon <a href="https://developer.amazon.com/public/solutions/devices/fire-tv/docs/device-and-platform-specifications" target="_blank">Fire TV</a>.</p> <p>For more information, visit the <a href="https://developer.amazon.com/public/support/submitting-your-app/tech-docs/targeting-amazon-devices-with-your-android-manifest#targeting-amazon-devices-with-your-android-manifest" target="_blank">targeting Amazon devices with your Android manifest</a> technical documentation.&nbsp;</p> <h1>4. Flip the store switch of the Unity&reg; Purchasing API in your project</h1> <p>You can do this&nbsp;using the editor. Just set the target store using <strong>Unity&reg; IAP’s Window &gt; Unity IAP &gt; Android &gt; Target Amazon</strong> menu item. This is used to toggle between Google, Amazon, and other Android stores, too.</p> <p>Alternatively, you can call the API and do it in code with this snippet:</p> <p><em>UnityPurchasingEditor.TargetAndroidStore(AndroidStore.AmazonAppStore)</em></p> <h1>5. Create your Amazon build</h1> <p>Just click the&nbsp;button&nbsp;to build your game as if you were building any Android build.</p> <p><img alt="010518_UnityPorting_1.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/Unity/010518_UnityPorting_1._CB491320401_.png?t=true" style="display:block; height:678px; margin-left:auto; margin-right:auto; width:728px" /></p> <h1>6. Set up your IAP and DRM support in the Amazon developer console</h1> <p>If you don’t have any - great, skip to the next paragraph. Otherwise, you can follow this guide to <a href="https://developer.amazon.com/public/apis/earn/in-app-purchasing/docs-v2/submitting-iap-items" target="_blank">create and submit IAP items</a>. For simplicity, you can use the same SKU names as the ones on Google Play, but you don’t have to.&nbsp;Just make sure you change them in your code, too.</p> <h1>7. Test your game, then submit it to the store</h1> <p>You can upload your&nbsp;game to the store and test it with a feature we call Live App Testing on the Amazon developer console. This&nbsp;will help you with testing the In-App Purchasing if you had it. It will also help you see your submission on the Amazon Appstore right before you make it live and have a limited number of beta testers to test it. Follow <a href="https://developer.amazon.com/docs/app-submission/live-app-testing-getting-started.html" target="_blank">this guide</a> to get started with Live App Testing.</p> <p>After you are ready and everything looks great in Live App Testing, you can promote the submission to live.</p> <p><strong>A note about games developed with older versions of&nbsp;Unity&reg;</strong></p> <p style="margin-left:0in; margin-right:0in">If you have a game app developed with an older version of Unity&reg; (such as Unity&reg; 4.5 or 4.6, when <code>UnityPlayerNativeActivity</code> was the default activity), your game might have a one to two second blank white screen before the game loads for the very first time in the memory. The issue is due to Android N’s cold start while the app loads to memory (and waits for all the work to be completed). This issue happens for all Nougat devices and is not specific to Fire OS 6.</p> <p style="margin-left:0in; margin-right:0in">To fix the issue, upgrade to the latest version of Unity&reg;. If upgrading is not an option, you can try updating your Android Manifest file b changing <code>UnityPlayerNativeActivity</code> to <code>UnityPlayerActivity</code>, available since Unity&reg; 5.0b12. For more information, see <a href="https://docs.unity3d.com/Manual/android-manifest.html" target="_blank">Android Manifest</a> in the Unity&reg; documentation.</p> /blogs/appstore/post/3bb65890-7230-431f-836e-35455ae996bf/easy-input-replay-system-in-gamemaker-studio-2 Easy Input Replay System in GameMaker Studio 2 Emily Esposito Fulkerson 2017-12-28T23:48:37+00:00 2017-12-28T23:48:37+00:00 <p><img alt="1228_Replay_image5.gif" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/1228_Replay_image5._CB491391630_.gif?t=true" style="display:block; margin-left:auto; margin-right:auto" /><br /> In this post I will go over the basics of setting up a replay system and leave you with ideas on how to integrate it in your game and expand it.&nbsp;</p> <p><img alt="1228_Replay_image5.gif" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/1228_Replay_image5._CB491391630_.gif?t=true" style="display:block; margin-left:auto; margin-right:auto" /><br /> GameMaker is an engine that works with frames instead of delta time and thanks to this advantage, we can trivially record the player inputs and match them with a frame number. We can then simulate replaying the input and create a replay system. There are many uses for this kind of system,&nbsp;such as creating cutscenes, automating tests for your game to run on a loop, acting as tutorials, ghost replaying, etc.</p> <p>In this post I will go over the basics of setting up this system and leave you with ideas on how to integrate it in your game and expand it. Let’s begin!</p> <p><img alt="1228_Replay_image7.gif" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/1228_Replay_image7._CB491391640_.gif?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p style="text-align:center"><em>Example of the system being used for tutorials in HackyZach.</em></p> <h1>Setup</h1> <p>Here’s <a href="https://drive.google.com/file/d/1vKxBk9ZAnkm7xGnvuNR3EaRIt7STHI3G/view" target="_blank">a link to the assets</a> I used for the demo, if you want to follow along. The finished demo is also available for download at the end of the article.</p> <p>We need a scene to test the input controller, so let’s make a little one. We need to create three objects: <strong>oPlayer</strong>, <strong>oPot</strong>, and <strong>oWall</strong>.</p> <p><img alt="1228_Replay_image8.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/1228_Replay_image8._CB491391642_.png?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p>The wall and the pot objects will be empty as they are used for collision and for drawing. Set the sprites to anything you want, or use the assets provided. As for the player, we need to create the four directional animations. Last, we add the tileset sprite, and create a tileset object using it.</p> <p><img alt="1228_Replay_image3.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/1228_Replay_image3._CB491391629_.png?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p>As for the player object, we will create a simple top-down controller for it. In the <strong>Create Event</strong>, let’s declare some variables:</p> <pre> <code>/// Create Event _kLeft = false; _kRight = false; _kUp = false; _kDown = false; _kAction = false; image_speed = 0.5;</code></pre> <p>We will use these variables to store the input and set the animation speed to half. Next, in the <strong>Begin Step</strong> event we will listen to the input. In a full game, it is a better idea to get the input from an input manager, not the player object itself, but that’s outside of the scope of this article, so we will go with this solution.</p> <pre> <code>// Begin Step Event _kLeft = keyboard_check(vk_left); _kRight = keyboard_check(vk_right); _kUp = keyboard_check(vk_up); _kDown = keyboard_check(vk_down); _kAction = keyboard_check_pressed(vk_space);</code></pre> <p>Last, in the <strong>Step Event</strong> we are going to move the character, set the correct sprite, check for collision with walls, and place a Pot when we hit the spacebar (action key). This is what it looks like:</p> <pre> <code>// Step Event var moveSpeed = 4; // Movement in all directions. Accepts multiple inputs. // NOTE: Moves faster on diagonals, but that's an easy fix. if (_kLeft &amp;&amp; !place_meeting(x - moveSpeed, y, oWall)) { x -= moveSpeed; sprite_index = sPlayerLeft; image_speed = 0.5; } if (_kRight &amp;&amp; !place_meeting(x + moveSpeed, y, oWall)) { x += moveSpeed; sprite_index = sPlayerRight; image_speed = 0.5; } if (_kUp &amp;&amp; !place_meeting(x, y - moveSpeed, oWall)) { y -= moveSpeed; sprite_index = sPlayerUp; image_speed = 0.5; } if (_kDown &amp;&amp; !place_meeting(x, y + moveSpeed, oWall)) { y += moveSpeed; sprite_index = sPlayerDown; image_speed = 0.5; } // Go back to the idle position in the animation and stop it when there are no inputs if (!_kLeft &amp;&amp; !_kRight &amp;&amp; !_kDown &amp;&amp; !_kUp) { image_index = 1; image_speed = 0; } // Place a pot when the action key is pressed if (_kAction) instance_create_layer(x, y, &quot;Pots&quot;, oPot);</code></pre> <p>With that out of the way, we can create a little play area to test our code. This is the one I came up with:</p> <div> &nbsp; </div> <p><img alt="1228_Replay_image6.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/1228_Replay_image6._CB491391646_.png?t=true" style="display:block; height:410px; margin-left:auto; margin-right:auto; width:728px" /></p> <div> &nbsp; </div> <p>And just place wall objects where needed.</p> <div> &nbsp; </div> <p><img alt="1228_Replay_Image1.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/1228_Replay_Image1._CB491391664_.png?t=true" style="display:block; height:441px; margin-left:auto; margin-right:auto; width:728px" /></p> <div> &nbsp; </div> <p>Nice! If we run the game now, we should be able to have a character moving around, playing the correct animations, and colliding with walls. Also, if you press the spacebar, you will drop a pot under the character.</p> <div> &nbsp; </div> <p><img alt="1228_Replay_image2.gif" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/1228_Replay_image2._CB491391666_.gif?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <h1>Input recorder&nbsp;</h1> <p>Create a new object called <strong>oInputRecorder</strong> and turn on the <strong>Persistent</strong> flag. Next, we will make sure there’s only one copy of this object ever, so at the beginning of the <strong>Create Event</strong> we will call this script&nbsp;<strong>MakeUnique</strong>.</p> <pre> <code>// MakeUnique Script if (instance_number(object_index) &gt; 1) instance_destroy();</code></pre> <p>It’s a pretty simple script that ensures there’s only one copy of the object it’s called on. It works like the singleton pattern, but it’s not quite the same, so I named it differently. Here what the Create Event looks like, and I will explain what each of the variables do below.</p> <pre> <code>// Create Event // Only one copy of this should be running MakeUnique(); // Keys Enum enum eKey { LeftPressed = 0, RightPressed, UpPressed, DownPressed, ActionPressed, LeftReleased, RightReleased, UpReleased, DownReleased, NUM_KEYS } // Variables _fileName = &quot;Recording_&quot; + string(room_get_name(room)) + &quot;.txt&quot;; // Check if currently recording or playing _isRecording = false; _isPlaying = false; // Variables to keep track of the frames _frame = 0; _index = 0; // Arrays to store the keys to record, and the recorded values and frames _input = array_create(eKey.NUM_KEYS, false); _inputSequence = [0, 0]; // Hotkeys to start/stop recording and playback _kRecord = 0; _kPlay = 0; </code></pre> <p>OK, there’s a lot to digest here, but nothing is too complicated. First, we call the <strong>MakeUnique </strong>script as we discussed before. Next, we declare an enumerator with each of the key events we want to record. Note it is not keys, but key events, such as pressed and released. For this example we will keep track of the four directional arrows (both on pressed and released) and the spacebar for the action, but we only need this one on pressed. The last element in the enumerator will be useful later for loops as it automatically holds the number of key events in the enum.</p> <p>We then choose a <strong>_filename</strong> where we will store our recording. I made the name include the room name so it is unique per room, but you can pick anything here. This text file will be saved by default in your AppData folder. Later we have two of boolean variables (<strong>_isPlaying</strong> and <strong>_isRecording</strong>) that will check if we are currently recording input, or playing back our recorded input. The <strong>_frame</strong> variable will store the frame at which the key events happen and the <strong>_index</strong> is the position in the array where it is stored. These don’t match because it is possible to have multiple inputs in the same frame. The <strong>_input</strong> array stores the state of each key. We are using an array to make the next section easier to code and make adding new key events straightforward. The other array is <strong>_inputSequence</strong>, which is a 2D array that pairs a key event with the frame when it happened. Last, we have <strong>_kRecord</strong> and <strong>_kPlay</strong>, which are used to check the state of the hotkeys to activate recording and playback.</p> <p>Phew! That was a lot. Next, we need to check our inputs in the <strong>Begin Step</strong> event. As I mentioned before, in an actual game it is advisable to get the input from your input manager, but we will get it directly to keep it simple. We will store all the inputs we intend to record (the ones in the enumerator) inside of the <strong>_input</strong> array, and the rest in their respective variables. This is what it looks like:</p> <pre> <code>// Begin Step Event // Keys we want to record _input[eKey.LeftPressed] = keyboard_check_pressed(vk_left); _input[eKey.RightPressed] = keyboard_check_pressed(vk_right); _input[eKey.UpPressed] = keyboard_check_pressed(vk_up); _input[eKey.DownPressed] = keyboard_check_pressed(vk_down); _input[eKey.ActionPressed] = keyboard_check_pressed(vk_space); _input[eKey.LeftReleased] = keyboard_check_released(vk_left); _input[eKey.RightReleased] = keyboard_check_released(vk_right); _input[eKey.UpReleased] = keyboard_check_released(vk_up); _input[eKey.DownReleased] = keyboard_check_released(vk_down); // Keys we don't want to record _kRecord = keyboard_check_pressed(ord(&quot;Q&quot;)); _kPlay = keyboard_check_pressed(ord(&quot;P&quot;));</code></pre> <p>We are finally here, the meat of the article! Most of the code related to the input recording system lies within the <strong>Step Event</strong>, so I will break it up into four parts to explain each bit individually, but it all goes in the same script. If you are confused, make sure to reference the demo.</p> <h2>Part one</h2> <p>First, we need to check if the record hotkey was pressed and that we are not currently playing a recording. Then, we check if the <strong>_isRecording</strong> flag is on, which means that we are trying to stop the recording. Hence, we will write what we have recorded so far into a file. We then flip the value of the <strong>_isRecording</strong> variable.</p> <pre> <code>// Step Event Part 1 // Turn recording on if not currently on playback if (_kRecord &amp;&amp; !_isPlaying) { // Save the recording if (_isRecording) WriteInputRecording(_fileName); _isRecording = !_isRecording; }</code></pre> <p><strong>WriteInputRecording </strong>is a script that writes what we have stored in <strong>_inputSequence</strong> to a file. The script is quite simple: first, we open the file with the name provided to the script. We then iterate through every element in the sequence and write the frame number next to the key event. We then write a new line and keep going. Once the loop is over, we set the <strong>_inputSequence</strong> to zero to delete the data structure and clean up after ourselves. Last, we close the text file. Note I am taking advantage of how GameMaker works where we can access variables in the scope where the script is called. If you wish to call this script from another object, pass the <strong>_inputSequence</strong> as an argument.</p> <pre> <code>// WriteInputRecording Script var file = file_text_open_write(argument0); for (var i = 0; i &lt; array_height_2d(_inputSequence); ++i) { file_text_write_real(file, _inputSequence[i, 0]); file_text_write_real(file, _inputSequence[i, 1]); file_text_writeln(file); } _inputSequence = 0; file_text_close(file);</code></pre> <p>For part two, we will check if we are currently recording. If we are, we will go through every key event checking if it’s been triggered. When we find a match, we store the frame and the event number, advancing the index. We only advance the frame after this loop, which allows us to store multiple inputs per frame. One thing to note is that for values we want to check if they are down (such as the directional arrows) we are only storing the frame where they are first down, and when we release them. We could store each frame they are down, but this way we are making the save file a lot smaller.</p> <pre> <code>// Step Event Part 2 // Fill out array while the game is recording if (_isRecording) { // Iterate through each key and store the input and frame. Accepts multiple inputs at once. for (var i = 0; i &lt; eKey.NUM_KEYS; ++i) { if (_input[i]) { _inputSequence[_index, 0] = _frame; _inputSequence[_index, 1] = i; ++_index; } } ++_frame; }</code></pre> <p>If we play the game now, we can press Q and record some movement and pot placing. Once we are done, we press Q again to stop recording and store the information in the file which should look something like this:</p> <p><img alt="1228_Replay_image4.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/1228_Replay_image4._CB491391631_.png?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p>If you got everything working until this point, we can start working on the playback functionality. The third part of the <strong>Step</strong> <strong>Event</strong> involves checking the playback hotkey (if not already recording), and if the flag is on, then we read the file and store all the information in our <strong>_inputSequence</strong> array. This is so we only have to open and read the file once since opening files is an expensive operation.</p> <pre> <code>// Step Event Part 3 // If the play hotkey is pressed and we are not recording, start playing if (_kPlay &amp;&amp; !_isRecording) { _isPlaying = !_isPlaying; // Load up all the recording sequence from the file into memory if (_isPlaying) ReadInputRecording(_fileName); }</code></pre> <p>As you can see, we have another script here to read the file. These are the contents of that script:</p> <pre> <code>// ReadInputRecording var file = file_text_open_read(argument0); var i = 0; while (!file_text_eof(file)) { _inputSequence[i, 0] = file_text_read_real(file); _inputSequence[i, 1] = file_text_read_real(file); file_text_readln(file); ++i; } file_text_close(file);</code></pre> <p>It’s the complementary script to the WriteInputRecording one, where instead we open the file and store all the values in the file into our array. We then close the file and prepare to execute the key events.</p> <p>In the fourth and last <strong>Step Event</strong> section, we will simply check if the <strong>_isPlaying</strong> flag is active, and calling a script to execute the key events if it is.</p> <pre> <code>// Step Event Part 4 // Runs every frame to play the sequence when needed if (_isPlaying) PlayInputRecording();</code></pre> <p>Nothing much to see here, so let’s get into the <strong>PlayInputRecording</strong> script.</p> <pre> <code>// PlayInputRecording Script var player = instance_find(oPlayer, 0); if (player != noone) { player._kAction = false; while (_index &lt; array_height_2d(_inputSequence) &amp;&amp; _inputSequence[_index, 0] == _frame) { switch (_inputSequence[_index, 1]) { case eKey.LeftPressed: player._kLeft = true; break; case eKey.RightPressed: player._kRight = true; break; case eKey.UpPressed: player._kUp = true; break; case eKey.DownPressed: player._kDown = true; break; case eKey.ActionPressed: player._kAction = true; break; case eKey.LeftReleased: player._kLeft = false; break; case eKey.RightReleased: player._kRight = false; break; case eKey.UpReleased: player._kUp = false; break; case eKey.DownReleased: player._kDown = false; break; } ++_index; } ++_frame; }</code></pre> <p>We first get the object we want to hijack the input from (in this case the player) and we get the instance. If you are using an input manager, you should get that object instead. We then set all the key events that are triggered on pressed only (such as our action) and set them to false. We then iterate through the <strong>_inputSequence</strong> array and set the variables inside our player to the appropriate values, keeping track of our index and current frame. As you may have guessed, we also need to make a slight modification to our player <strong>Begin Step </strong>event, to prevent it from updating the values of its variables. We surround the input check section like this:</p> <pre> <code>// Player Modified Begin Step var recorder = instance_find(oInputRecorder, 0); if (recorder != noone &amp;&amp; !recorder._isPlaying) { _kLeft = keyboard_check(vk_left); _kRight = keyboard_check(vk_right); _kUp = keyboard_check(vk_up); _kDown = keyboard_check(vk_down); _kAction = keyboard_check_pressed(vk_space); }</code></pre> <p>And that should be it! All we need to do now to test our system is:</p> <ol> <li> <p>Press Q to start recording.</p> </li> <li> <p>Perform a series of movements and pot placing.</p> </li> <li> <p>Press Q again to stop recording.</p> </li> <li> <p>Press F5 to restart the level to its initial state.</p> </li> <li> <p>Press P to start the playback.</p> </li> </ol> <p>You should see the player object perform the exact same moves recorded previously. To make debugging easier, I added some <strong>Draw GUI</strong> code that displays when I’m recording or playing back the sequence.</p> <pre> <code>// Draw GUI Event var color = c_white; draw_text_color(5, 5, &quot;Press Q to start/stop recording&quot;, color, color, color, color, 1.0); draw_text_color(5, 25, &quot;Press P to start/stop playing&quot;, color, color, color, color, 1.0); draw_text_color(5, 45, &quot;Press F5 to restart the room&quot;, color, color, color, color, 1.0); var text = &quot;&quot;; if (_isRecording) { color = c_red; text = &quot;Recording&quot;; } if (_isPlaying) { color = c_yellow; text = &quot;Playing&quot;; } draw_text_color(5, 65, text, color, color, color, color, 1.0);</code></pre> <p>Here is our final scene.</p> <p><img alt="1228_Replay_image5.gif" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/1228_Replay_image5._CB491391630_.gif?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <h1>Expanding the system</h1> <p>The system is very basic as it is now, but it’s easy to add more to it. First, if you want to add more inputs to record, you will need to add them to the enum in the <strong>Create Event</strong>, update its value in the <strong>Begin Step</strong> either by getting the value from the input manager, or by calling the correct input function from GameMaker. Last, set the value to the appropriate value in the <strong>PlayInputRecording</strong> script. Remember that variables that only trigger once (On Pressed) should be set to false before the while loop.</p> <p>Another way to expand the system would be to add mouse events, which would probably include the mouse coordinates at the time of the mouse press event. This system also works for controller inputs with no modifications, by calling the right functions.</p> <h1>Demo</h1> <p>Download the Demo and project files <a href="https://drive.google.com/open?id=1WJF2Mi3D6jMLuSCciiXVto0W4A8KyKcV" target="_blank">here</a>.</p> <h1>Conclusion</h1> <p>I hope you enjoyed this article! This simple system can save you a lot of time when creating complex cutscenes, or it can create a nice ghost replay effect to your games, similar to those found in Super Meat Boy for example. If you have any questions, you can contact me on <a href="http://twitter.com/AleHitti" target="_blank">Twitter</a>. Until next time!</p> <p>&nbsp;</p> <p style="text-align:center"><img alt="AlejandroBio.jpg" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/default/AlejandroBio._CB512098171_.jpg?t=true" style="height:145px; width:583px" /></p> <p style="text-align:center"><em>Alejandro Hitti is a videogame Programmer and Designer from Venezuela. Although his background is in C++ and working using custom-made game engines, his two commercial games, INK and HackyZack, were made using GameMaker Studio 1.4. With the release of GameMaker Studio 2, that became his engine of choice. The novelty of GMS2, paired with his knowledge of the previous version, ignited his interest to create tutorials that focus on this new engine.</em></p> /blogs/appstore/post/a75a9783-53b8-46df-9433-85ad9a7664a7/how-to-create-a-great-tv-login-experience How to Create a Great TV Login Experience (Part 1) Emily Esposito Fulkerson 2017-12-21T17:21:06+00:00 2018-01-16T21:18:15+00:00 <p><img alt="1214_TVlogin_1.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/FireTV/1214_TVlogin_1._CB490893504_.png?t=true" style="display:block; height:409px; margin-left:auto; margin-right:auto; width:728px" /><br /> In this two-part blog post, I’d first like to explain how to create a good TV app registration and login experience with Login with Amazon and Amazon In-App Purchasing. In the second part, we’ll use a third-party Cordova plugin to create an app utilizing Login with Amazon.</p> <p><img alt="1214_TVlogin_1.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/FireTV/1214_TVlogin_1._CB490893504_.png?t=true" style="display:block; height:409px; margin-left:auto; margin-right:auto; width:728px" /><br /> The way customers have&nbsp;to log in, register an app, and purchase content could be the difference between their becoming customers&nbsp;or not.</p> <p>Did you know the average number of keypresses for a regular username and password using a remote control &quot;D pad&quot;&nbsp;is between 200 and 300 in total?&nbsp;This can lead to massive churn when customers become&nbsp;frustrated with the whole experience. However, there are other, better ways of registering and in particular, using Login with Amazon can reduce the number of clicks from over 200 to just two.</p> <p>In this two-part blog post, I’d first like to explain how to create a good TV app registration and login experience with Login with Amazon and Amazon In-App Purchasing. In the <a href="https://developer.amazon.com/blogs/appstore/post/fbc64579-e411-455d-ad10-3b09a507ae76/how-to-create-a-great-tv-login-experience-with-cordova-part-2" target="_blank">second part</a>, we’ll use a third-party Cordova plugin to create an app utilizing Login with Amazon.</p> <h1>TV login and registration best practices&nbsp;</h1> <p>Using a sample &quot;Lorem Ipsum&quot;&nbsp;app, which could be any typical video on demand or live TV app, I’m going to demonstrate a flow that works well for our customers on Amazon Fire TV.</p> <p>Upon opening the app, customers would be presented with two options, either Login with Amazon or log&nbsp;in using their existing &quot;Lorem Ipsum&quot;&nbsp;account:<br /> &nbsp;</p> <p><img alt="1214_TVlogin_1.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/FireTV/1214_TVlogin_1._CB490893504_.png?t=true" style="display:block; height:409px; margin-left:auto; margin-right:auto; width:728px" /></p> <p>If customers select&nbsp;Login with Amazon, they are asked if the developer can be provided with their name, email address, and postcode (if they have already agreed to this on another device, this will not be shown and they will be logged in automatically):<br /> &nbsp;</p> <p><img alt="1214_TVlogin_2.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/FireTV/1214_TVlogin_2._CB490893506_.png?t=true" style="display:block; height:409px; margin-left:auto; margin-right:auto; width:728px" /></p> <p>Once customers have agreed to provide the information, they are able to enter the app and the developer &quot;Lorem Ipsum&quot;&nbsp;can now send a welcome email including a &quot;set password&quot; link if the account is new. This step is not mandatory, but a lot of developers like to do this, especially if the app is cross-platform and the customer will likely be logging in on other devices:<br /> &nbsp;</p> <p><img alt="1214_TVlogin_3.PNG" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/FireTV/1214_TVlogin_3._CB490893533_.png?t=true" style="display:block; margin-left:auto; margin-right:auto" /><br /> <br /> If there is premium content and they are not already a subscriber, customers can now subscribe using In-App Purchasing:<br /> &nbsp;</p> <p><img alt="1214_TVlogin_4.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/FireTV/1214_TVlogin_4._CB490893535_.png?t=true" style="display:block; height:409px; margin-left:auto; margin-right:auto; width:728px" /></p> <p><br /> Selecting the &quot;Subscribe now&quot;&nbsp;button brings up the detail page for the subscription. The price, icon, and description are set by the developer:<br /> &nbsp;</p> <p><img alt="1214_TVlogin_5.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/FireTV/1214_TVlogin_5._CB490893534_.png?t=true" style="display:block; height:409px; margin-left:auto; margin-right:auto; width:728px" /></p> <p>When the customer selects &quot;Subscribe,&quot;&nbsp;Amazon checks that payment can be made. If payment is successful, then customers will receive a message thanking them&nbsp;and explaining how the subscription will automatically continue:<br /> &nbsp;</p> <p><img alt="1214_TVlogin_6.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/FireTV/1214_TVlogin_6._CB490893473_.png?t=true" style="display:block; height:409px; margin-left:auto; margin-right:auto; width:728px" /><br /> <br /> Customers will also receive an email from Amazon confirming their subscription:</p> <p><img alt="1214_TVlogin_7.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/FireTV/1214_TVlogin_7._CB490893475_.png?t=true" style="display:block; height:652px; margin-left:auto; margin-right:auto; width:728px" />Now the customers are fully-fledged subscribers to your app and they can go ahead and start watching your great content. No laptop or phone was required, no fiddly TV password entry, just a simple customer journey with just a few clicks.</p> <p>To find out more about Login with Amazon, please visit the <a href="https://login.amazon.com/" target="_blank">Login with Amazon Developer Center</a>.</p> <p>In the <a href="https://developer.amazon.com/blogs/appstore/post/fbc64579-e411-455d-ad10-3b09a507ae76/how-to-create-a-great-tv-login-experience-with-cordova-part-2" target="_blank">next part of this blog</a>, we’ll create a Cordova app and demonstrate how to incorporate Login with Amazon using a third-party open source plugin.</p> /blogs/appstore/post/a07ab562-0609-4519-a2ba-9b15d69ea62b/introduction-to-game-math-raw-and-cooked Introduction to Game Math: Bouncing a Ball Emily Esposito Fulkerson 2017-12-19T19:08:19+00:00 2017-12-19T19:15:48+00:00 <p><img alt="1219_GameMath_Hero.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMath/1219_GameMath_Hero._CB490819335_.png?t=true" style="display:block; margin-left:auto; margin-right:auto" /><br /> I talk to loads of developers just itching to try their hand at games, and the question of math comes up a lot. To&nbsp;begin our quest for math literacy in pursuit of superior game creation, let's bounce a ball!</p> <p><img alt="1219_GameMath_Hero.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMath/1219_GameMath_Hero._CB490819335_.png?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p>Ask any non-programmer what it takes to write computer code and the tentative response might be something like, “You have to be good at math?”</p> <p>As developers, of course we know this isn't true, but it's a common misconception that works in our favor. In a survey conducted for <a href="http://www.changetheequation.org/" target="_blank">Change the Equation</a>, 30 percent of Americans say they'd rather clean the bathroom than solve a math problem. As long as that's true, our reputation as lovable math geniuses is safe.</p> <p>I talk to loads of developers just itching to try their hand at games, and the question of math comes up a lot. The bad news is that game development usually does involve math (at least more than some other kinds of programming). The good news is that game math isn't actually that hard (Mostly. Some of it is very, very hard).&nbsp;The rise of frameworks like Unity has had an overall calming effect on math anxiety among first-time game programmers, but the truth is that understanding the math at the heart of these frameworks makes for better games.</p> <h1>A bouncing ball</h1> <p>So where do we begin our quest for math literacy in pursuit of superior game creation? Let's bounce a ball! It's a good example because just moving something around the screen can be instructive, but it's also a problem of surprising depth. There are lots of interesting ratholes and tangents for us to explore as we tackle this simple exercise.</p> <p>Let's start with the basics. We have a circle on the screen. We want it to move in straight lines at a constant speed. We want the screen edges to act as “walls,” reflecting the circle's motion.</p> <p><img alt="1219_GameMath_1.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMath/1219_GameMath_1._CB492654902_.png?t=true" style="display:block; height:416px; margin-left:auto; margin-right:auto; width:728px" /></p> <p>To make all this happen, there are a few things we need to keep track of. The circle (our low-tech ball) has a position and a velocity. The screen has a width and height. We'll ignore complications like friction, elasticity, and ball diameter for now (but reserve the right to add them later, if we feel ambitious).</p> <p><img alt="1219_GameMath_2.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMath/1219_GameMath_2._CB492654896_.png?t=true" style="display:block; height:437px; margin-left:auto; margin-right:auto; width:728px" /></p> <p>For simplicity, we treat the lower-left corner of the screen as the origin (0, 0) of our coordinate system, with x increasing to the right and y increasing as we move toward the top of the screen. This is the arrangement commonly used in mathematics—and has been adopted by many popular game development frameworks—so it feels natural.</p> <p>Now we can represent the ball's position by the coordinate pair (x, y). Similarly, we represent the ball's velocity by a pair of deltas, v<sub>x</sub> and v<sub>y</sub>, that get added to x and y (respectively) every time we update the screen. Technically, the deltas v<sub>x</sub> and v<sub>y</sub> describe a vector, but we often write them as a point—such as (v<sub>x</sub>,v<sub>y</sub>)—because points and vectors are so intimately connected, and are frequently manipulated together.</p> <p>Vectors are quantities with direction and magnitude. We draw them as arrows in order to convey both of these characteristics simultaneously, since an arrow (obviously) has a direction, and its length can indicate magnitude. We label them using bold or a little arrow hat, as in the diagram above.</p> <p><img alt="1219_GameMath_3.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMath/1219_GameMath_3._CB492654898_.png?t=true" style="display:block; height:112px; margin-left:auto; margin-right:auto; width:728px" /></p> <p>Vectors have no inherent location, but they can be used to modify the location of objects that do, like our ball. We can add and subtract vectors to produce new vectors, and combine them with points to move those points around. They're also useful for figuring out angles and distances, and are critical to 96.57 percent of computer game graphics (approximately). Bare vectors are sometimes shown starting at the origin.</p> <p><img alt="1219_GameMath_4.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMath/1219_GameMath_4._CB492654861_.png?t=true" style="display:block; height:449px; margin-left:auto; margin-right:auto; width:728px" /></p> <p>As you can see above, adding vectors together amounts to arranging them head-to-tail. Adding one to a point moves the point in the vector's direction by a distance equal to the vector's length. You can also multiply a vector by a scalar, which, as the name implies, is just a scaling factor. To multiply <strong>v</strong> by the scalar 6/5, multiply each component by the scalar value to yield (6/5 v<sub>x</sub>, 6/5 v<sub>y</sub>). Subtracting a vector is the same as flipping its direction with a scalar of -1, then adding.</p> <h1>Moving with vectors&nbsp;</h1> <p>Armed with nothing more than points and vectors, we can start to think about how our ball will actually bounce around a screen. Given an initial position (x, y) and velocity (v<sub>x</sub>, v<sub>y</sub>), we can always figure out where it will end up after the next update.</p> <p><img alt="1219_GameMath_5.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMath/1219_GameMath_5._CB492654863_.png?t=true" style="display:block; margin-left:auto; margin-right:auto" /><br /> Of course, the new position may be off the screen, which is where the bounce comes in. If y<sub>new</sub> is out of bounds, for example, we reposition the ball by a distance equal to the amount it overshot the boundary, but in the opposite direction. That is, if the new position would be n vertical pixels off the screen, we substract 2n from the new y component to move the ball back onscreen by the same amount. We also flip the sign of the vertical velocity so the ball will move in the opposite vertical direction from now on, away from the wall it just “hit.”</p> <p><img alt="1219_GameMath_6.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMath/1219_GameMath_6._CB492654876_.png?t=true" style="display:block; height:491px; margin-left:auto; margin-right:auto; width:728px" /></p> <p>The next time the ball needs updating, we again add its current position and velocity—now (v<sub>x</sub>,−v<sub>y</sub>), since the last bounce changed its vertical direction of motion. This time perhaps xnew will be out of bounds, passing m pixels beyond the edge of the screen. We compensate in the same way we did for the vertical component: we adjust the horizontal position by −2m and flip the sign of the horizontal velocity.</p> <p><img alt="1219_GameMath_7_V2.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/default/1219_GameMath_7_V2._CB492657987_.png?t=true" style="display:block; height:280px; margin-left:auto; margin-right:auto; width:728px" /></p> <p>Because all of the boundaries in this simplified scenario are perfectly horizontal or perfectly vertical, these straightforward bounce calculations are pretty easy to implement in code. For example:</p> <pre> <code>// Basic bouncing ball public class Ball { private int x, y; private int vx, vy; public Ball( int x, int y, int vx, int vy ) { this.x = x; this.y = y; this.vx = vx; this.vy = vy; } // Called every frame with the current screen width and height. public void move( int width, int height ) { // Add the velocity to position. x += vx; y += vy; // Bounce off vertical walls, if necessary. if( 0 &gt; x || x &gt;= width ) { // Flip the horizontal velocity. vx = -vx; // If x is negative (the ball is off the screen to the left), // then simply flipping its sign is enough to move it to where // we want it to be. Otherwise (the ball is off the screen to // the right), we need to take the excess x - width and subtract // it from the screen width, yielding x = width - (x - width) = // width - x + width = 2*width - x. Either way, we negate x. In // the first case, we’re done; in the second, we just need to // add 2*width. x = -x; if( 0 &gt; x ) // if now negative, must be 2nd case x += width &lt;&lt; 1; } // Bounce off horizontal walls, if necessary. if( 0 &gt; y || y &gt;= height ) { // Follow the same logic as above. vy = -vy; y = -y; if( 0 &gt; y ) y += height &lt;&lt; 1; } } } </code></pre> <p>Note that in most cases, we probably won't see the actual bounce itself. This is because the ball will appear to have jumped from its starting position to its final “bounced” position between frames. (We'll see it actually touch the wall only if adding its velocity and position places it in direct contact with the boundary.) It turns out this isn't a problem, though, because our brain can “fill in” the missing action. It combines the old and new locations, plus what it knows of the ball's previous speed and trajectory, to infer that a bounce happened—even though we didn't actually witness it.</p> <p>There's a wrinkle here that we haven't addressed, though. What happens when the ball's velocity is so great that it hits multiple walls during a single update? This isn't as pathological as it sounds—just picture a fast ball headed into a corner, or one constrained by some on-screen container.</p> <p><img alt="1219_GameMath_8.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMath/1219_GameMath_8._CB492654873_.png?t=true" style="display:block; height:272px; margin-left:auto; margin-right:auto; width:728px" /></p> <p>We have to adjust our code a little bit to account for all bounces that may apply; we have to process the ball's position until the result is a valid screen location (see highlighted loop, below). Again, the bounces themselves won't necessarily be visible, since the ball simply moves from its starting position to its ending position.</p> <pre> <code>public void move( int width, int height ) { // Add the velocity to position. x += vx; y += vy; while( 0 &gt; x || x &gt;= width || y &gt; 0 || y &gt;= height ) { // Same vertical bounce code as before. if( 0 &gt; x || x &gt;= width ) { vx = -vx; x = -x; if( 0 &gt; x ) x += width &lt;&lt; 1; } // Similarly for the horizontal bounce code. if( 0 &gt; y || y &gt;= height ) { vy = -vy; y = -y; if( 0 &gt; y ) y += height &lt;&lt; 1; } } } </code></pre> <h1>We're just getting started</h1> <p>Now that we have a basic understanding of what a vector is (direction and magnitude), how we represent one (as a point whose x and y coordinates each measure a delta along the corresponding axis), and why they're useful in games (they can model velocity and movement), we can explore common ways to manipulate them to achieve interesting effects. We've already seen how we can use vectors to reflect motion—at least, as long as the reflective surface is straight up and down or perfectly level—but what if we want to bounce our ball on a surface that's slanted? What if we don't necessarily want to move in a straight line? What if we want our velocity to change over time?</p> <p>It turns out that vectors can help in all of these situations, which is good, because they are all common occurrences in a typical game. Over the course of the next few installments in this series, we'll cover these and many more useful applications of our new best friend, the vector. That's just the beginning, though.</p> <p>Join us for future posts on other mathematical tidbits indispensable to game developers, like interpolation, bit manipulation, randomization, path finding, 3D, and much more.</p> <p>Stay tuned!</p> <p>-peter (<a href="http://www.twitter.com/peterdotgames" target="_blank">@peterdotgames</a>)</p> /blogs/appstore/post/6452ac09-31c3-4b28-a5fb-8348b70ae254/amazon-developer-blog-summary-december-18-2017 Amazon Developer Blog Summary: December 18, 2017 Serena McIntire 2017-12-18T23:55:10+00:00 2017-12-18T23:55:10+00:00 <p style="text-align:center"><img alt="lifestyle-laptop-WIR-3.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/LifestyleImages/lifestyle-laptop-WIR-3._CB505371676_.png?t=true" /></p> <p>Too busy to keep up with us at the Amazon Appstore? We've been busy too, from <a href="https://developer.amazon.com/blogs/appstore/post/6dbf19dd-6130-4e06-85ae-e51980d41353/gamemaker-basics-object-orchestration">setting up object orchestration in GameMaker with&nbsp;Nathan Ranney</a> to <a href="https://developer.amazon.com/blogs/appstore/post/2ef7b757-557e-4464-b4e8-a6cf67ccb598/managing-app-permissions-with-fire-tv-gen-3">managing app permissions with Fire TV Gen 3</a>. Read more to see what you missed!</p> <p style="text-align:center"><img alt="lifestyle-laptop-WIR-3.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/LifestyleImages/lifestyle-laptop-WIR-3._CB505371676_.png?t=true" /></p> <p>Too busy to keep up with us at the Amazon Appstore? We've been busy too, from <a href="https://developer.amazon.com/blogs/appstore/post/6dbf19dd-6130-4e06-85ae-e51980d41353/gamemaker-basics-object-orchestration">setting up object orchestration in GameMaker with&nbsp;Nathan Ranney</a> to <a href="https://developer.amazon.com/blogs/appstore/post/2ef7b757-557e-4464-b4e8-a6cf67ccb598/managing-app-permissions-with-fire-tv-gen-3">managing app permissions with Fire TV Gen 3</a>. Read more to see what you missed!</p> <blockquote> <h2><a href="https://developer.amazon.com/blogs/appstore/post/6dbf19dd-6130-4e06-85ae-e51980d41353/gamemaker-basics-object-orchestration">GameMaker Basics: Object Orchestration</a></h2> <p>Object orchestration is the act of controlling objects from inside&nbsp;another object. This is very useful for something like a “controller” object, which manages many things in your game. <a href="https://developer.amazon.com/blogs/appstore/post/6dbf19dd-6130-4e06-85ae-e51980d41353/gamemaker-basics-object-orchestration">In this tutorial,</a> guest blogger Nathan Ranney will walk you through the process of creating objects and setting up controls for them all from a controller object.</p> <h2><a href="https://developer.amazon.com/blogs/appstore/post/2ef7b757-557e-4464-b4e8-a6cf67ccb598/managing-app-permissions-with-fire-tv-gen-3">Managing App Permissions with Fire TV Gen 3</a></h2> <p>Starting with Android 6 (API 23), users can grant or revoke certain permissions to apps while they are running, instead of when they first install the app. This helps streamline the app install process for the user because they can install an app without setting permissions they don't want included. <a href="https://developer.amazon.com/blogs/appstore/post/2ef7b757-557e-4464-b4e8-a6cf67ccb598/managing-app-permissions-with-fire-tv-gen-3">See how to access the new Amazon Fire TV permission settings in this post.</a></p> <h2><a href="https://developer.amazon.com/blogs/appstore/post/220b89c2-2a27-4868-a020-318b17d10fe4/dev-chat-with-waipu-tv-user-centered-multi-screen-design">Dev Chat with waipu.tv: How to Develop a User-Centric TV Experience</a></h2> <p>In&nbsp;<a href="https://www.youtube.com/user/AmazonAppDistro/playlists" target="_blank">Dev Chat – Short Answers to Big Questions</a>,&nbsp;our series of short videos created by Amazon Appstore, developers of successful apps and games answer your questions in less than 90 seconds. waipu.tv launched its&nbsp;services in September 2016 and so far, it has&nbsp;generated more than 50,000 subscribers. How did German company&nbsp;EXARING AG, developers of waipu.tv, develop this user-centric TV experience? <a href="https://developer.amazon.com/blogs/appstore/post/220b89c2-2a27-4868-a020-318b17d10fe4/dev-chat-with-waipu-tv-user-centered-multi-screen-design">Find out in this edition of Dev Chat.&nbsp;</a></p> </blockquote> <p>Too busy to keep up with our blog? Don't worry, we've got you covered. Sign up to have our weekly summary sent directly to your inbox every week.</p> <p style="text-align:center"><a href="http://m.amazonappservices.com/blog-subscription?cmp=US_2017-00_ACH-Blog-Subscription&amp;ch=blg&amp;chlast=blg&amp;pub=blg&amp;publast=blg&amp;type=org&amp;typelast=org" target="_blank"><img alt="Blog_Subscribe_Button.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/default/Blog_Subscribe_Button._CB529593605_.png?t=true" /></a></p> /blogs/appstore/post/2ef7b757-557e-4464-b4e8-a6cf67ccb598/managing-app-permissions-with-fire-tv-gen-3 Managing App Permissions with Fire TV Gen 3 Emily Esposito Fulkerson 2017-12-15T17:28:40+00:00 2017-12-15T21:00:43+00:00 <p><img alt="1215_AppPermission_Hero2.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/FireTV/1215_AppPermission_Hero2._CB491147321_.png?t=true" style="display:block; margin-left:auto; margin-right:auto" /><br /> Starting with Android 6 (API 23), users can grant or revoke certain permissions to apps while they are running, instead of when they first install the app. This helps streamline the app install process for the user because he can install an app without setting permissions he doesn't want included.&nbsp;</p> <p><img alt="1215_AppPermission_Hero2.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/FireTV/1215_AppPermission_Hero2._CB491147321_.png?t=true" style="display:block; margin-left:auto; margin-right:auto" /><br /> Starting with Android 6 (API 23), users can grant or revoke certain permissions to apps while they are running, instead of when they first install the app. This approach helps streamline the app install process for the user as the user does not have to set permissions he doesn't want, but can still be able to install the app.</p> <p>It also enables the user to decide which permissions to grant or revoke at run time. For example, an app may ask for camera access and device location, and the user can choose to deny camera access, but allow device location at run time.</p> <p>To support this Android feature, Fire TV Gen 3 has a new permission setting section which is relevant for apps that target Android 6.0 (API 23) and above to compile.</p> <p>This new permission setting is found under Settings-&gt;Applications-&gt;Managed Applications-&gt; (Selected app for which user needs to change the permission) -&gt;Permissions.<br /> &nbsp;</p> <p><img alt="1215_AppPermissions_1.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/FireTV/1215_AppPermissions_1._CB490944601_.png?t=true" style="display:block; height:492px; margin-left:auto; margin-right:auto; width:725px" /></p> <p>This setting is relevant for only the dangerous permissions declared in the manifest file of an app. The dangerous permissions are the permissions which explicitly ask for user-specific information, for example, access to location or storage. The normal permissions in the manifest would continue to be automatically granted to the user.</p> <p>The developer must handle the scenarios where the user grants or revokes the permission at run time so that the app continues to run with limited capabilities. It is also a best practice to remove irrelevant dangerous permissions from your manifest file so that they do not show up under the Permissions section. For example, an app requesting access to contacts on Fire TV is irrelevant and might end up confusing the user since he does not have contacts maintained on Fire TV and hence can’t perform any action.</p> <p>You can refer to Android’s best practices for managing runtime permissions for more details, <a href="https://developer.android.com/training/permissions/requesting.html" target="_blank">here</a>.</p> /blogs/appstore/post/6dbf19dd-6130-4e06-85ae-e51980d41353/gamemaker-basics-object-orchestration GameMaker Basics: Object Orchestration Emily Esposito Fulkerson 2017-12-12T17:30:58+00:00 2017-12-12T17:30:58+00:00 <p><img alt="121217_Orchestration_image4.gif" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/121217_Orchestration_image4._CB492441054_.gif?t=true" style="display:block; margin-left:auto; margin-right:auto" /><br /> I want to talk about something cool&nbsp;that I’m calling “orchestration.&quot;&nbsp;Object orchestration is the act of controlling objects from inside of another object. This is very useful for something like a “controller” object, which manages many things in your game.</p> <p><img alt="121217_Orchestration_image4.gif" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/121217_Orchestration_image4._CB492441054_.gif?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p>Today, I want to talk about something cool&nbsp;that I’m calling “orchestration.&quot;&nbsp;Object orchestration is the act of controlling objects from inside&nbsp;another object. This is very useful for something like a “controller” object, which manages many things in your game. Let's say you wanted to spawn a bunch of enemies to attack your player. You could manage the enemy behavior from inside each enemy object, or you could set the behavior of all enemies at once via the controller object. This is helpful&nbsp;when you need to address multiple objects at once, and inform those objects of the current state of the game.</p> <p>In the example below, we will create a bunch of objects and control them all from a controller object.</p> <h1>Basic setup</h1> <p>The first thing we need to do is create a couple of objects. I’ve created three sprites; a circle, a square, and a triangle, and I have named them accordingly. If you are following along with this example, it doesn’t necessarily matter what your sprites look like as long as they are all different.</p> <p>Now create an object for each sprite. You do not need to add any events to the objects.</p> <p><img alt="121217_Orchestration_Image1.png" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/121217_Orchestration_Image1._CB492441027_.png?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p>Create a new room, name it whatever you want, and make it whatever size you want (I’m using 512x512).&nbsp;</p> <h1>Controller object setup</h1> <p>Now we are going to create our <strong>Controller Object</strong>. This will be the overseer of our game, and will be used to address the objects we will be creating. When creating your controller object, choose a name that is short. You will often reference this object, and it is easier to type a shorter name. For this example, I am using <strong>oGame</strong> as the name of this object. Add the <strong>Create Event</strong> and let's initialize some variables.</p> <p><strong>oGame Create Event</strong></p> <pre> <code>left = false; right = false; up = false; down = false; spawn = false; rotate = false; circle = -1; square = -1; triangle = -1; triList = ds_list_create();</code></pre> <p>The first set of booleans are going to be used as shortcuts for keyboard inputs. Since a button press is either pressed or not, storing that input in a boolean will save you a lot of trouble in the long run. The second set of variables will be used to store the ID of the objects we are going to create and control. These are set to a negative value when initialized to ensure that no asset, or object ID is stored. All asset indexes and object IDs have to be positive numbers. The last variable is used to store the index of a list we are creating. We will be adding object IDs to this list, and using the list of IDs to control those objects.</p> <p>Add the <strong>Step Event</strong> to the <strong>oGame</strong> object and add the following code.</p> <p><strong>oGame Step Event</strong></p> <pre> <code>//keyboard inputs left = keyboard_check(vk_left); right = keyboard_check(vk_right); up = keyboard_check(vk_up); down = keyboard_check(vk_down); spawn = keyboard_check_pressed(vk_space); rotate = keyboard_check(vk_rshift); </code></pre> <p>Here we have assigned keyboard inputs to variables. By doing this we can simply call the variable name when we need to check for keyboard input. Now let’s spawn some objects. Add this under the code we just typed up.</p> <p><strong>oGame Step Event</strong></p> <pre> <code>//spawn some objects if(spawn){ circle = instance_create(room_width * 0.5, room_height * 0.5, oCircle); square = instance_create(room_width * 0.5 - 32, room_height * 0.5, oSquare); for(i = 0; i &lt; 3; i ++){ triangle = instance_create(room_width * 0.5 + 32, room_height * 0.5 - 32 + (i * 32), oTriangle); ds_list_add(triList,triangle); } }</code></pre> <p>This code will check to see if we pressed our <strong>spawn</strong> button, which is set to the spacebar, and will create some objects for us to noodle around with. It also stores the ID of these objects in the circle, square, and triangle variables. For the <strong>oTriangle</strong> objects, this code will create three of them, and add their IDs to the <strong>ds_list</strong> we’ve created. If you are unfamiliar with for loops, click <a href="http://docs.yoyogames.com/source/dadiospice/002_reference/001_gml%20language%20overview/401_11_for.html" target="_blank">here</a> to read some documentation. Essentially a for loop runs x number of times, running the code inside of it as many times as it loops.</p> <p>In this case it runs for three loops, creates an <strong>oTriangle </strong>object, and adds it to the <strong>triList</strong> with each loop. When adding data (in this case an object ID) to a list, the data is added sequentially. The first piece of data is stored in position zero (the start) of the list, and each subsequent piece of data is stored to the end of the list in position one, two, three, etc. This isn’t super important for this example, but it is good to know.&nbsp;</p> <p>Add your <strong>oGame</strong> object to the room if you haven’t already, and run the game. Push the spacebar and, if everything was set up correctly, some objects should spawn in the center of the room! Now that we have some objects, we can work on controlling them.</p> <p><img alt="121217_Orchestration_image3.gif" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/121217_Orchestration_image3._CB492441052_.gif?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p style="text-align:center"><em>Wait for it… BAM! Objects!</em></p> <h1>Object orchestration&nbsp;</h1> <p>There are two main ways to address objects from inside of other objects. First, we can address the object directly by using the ID of the object. Since the ID of our newly created objects are stored in a variable (square, circle, triangle) this is very easy. Add this chunk of code to the end of your <strong>oGame Step Event</strong>.</p> <p><strong>oGame Step Event</strong></p> <pre> <code>//address object directly if(instance_exists(square)){ if(left){ square.x -= 2; }else if(right){ square.x += 2; } } </code></pre> <p>Here's a quick tip. Whenever you are trying to address an object, check to see if it exists first. If not, GameMaker will freak out and crash on you. Here we are able to use the left/right keyboard inputs to move the <strong>oSquare</strong> object left and right. This is done by calling the ID of the object, and then whatever variable inside the object we want to control. In this case the x coordinate. If the <strong>oSquare</strong> object ID was not stored in the <strong>square</strong> variable, and we instead used <strong>oSquare </strong>(oSquare.x), we would be addressing every single <strong>oSquare</strong> object in the game! Considering we only have one this isn’t a big deal, but just be aware of that!</p> <p>That being said, let’s see how we CAN address every instance of an object! The easiest way to do this is to use the <strong>with</strong> construction. If our last method of control is like telling an object what to do, then using <strong>with</strong> is like controlling the object from the inside. Add this code to the end of your <strong>oGame Step Event</strong>.</p> <p><strong>oGame Step Event</strong></p> <pre> <code>//address objects using with with(oCircle){ if(other.up){ y -= 2; }else if(other.down){ y += 2; } } </code></pre> <p>This time we are telling the <strong>oCircle </strong>object what to do. By using <strong>with(oCircle) </strong>we are addressing every single instance of the <strong>oCricle</strong> object in the game at the time. For us, this is only a single object. The important part about using <strong>with</strong> is that if you need to refer back to the object that is calling the function, you must use <strong>other</strong>. So when we say <strong>other.up</strong> and <strong>other.down</strong> we are referring back to the <strong>oGame</strong> object variables <strong>up</strong> and <strong>down</strong>. If you were to just use up and down without other, the game would crash since your <strong>oCircle</strong> object doesn’t have an up and down variable. <strong>With</strong> can be used to address single instances of an object as well. You can do this by using the ID of a particular object instance just like we did when we moved the square around.</p> <p>Finally, let’s look at how to control a bunch of different instances of an object, but not necessarily every instance of an object. Above we created three <strong>oTriangle </strong>objects and added them to the <strong>triList</strong>. Now we can loop through the list of objects, and address them all individually at the same time! Or in this case, address two of the three triangles at the same time. Add some more code to the end of your <strong>oGame Step Event.</strong></p> <p><strong>oGame Step Event</strong></p> <pre> <code>//address objects in a list for(i = 0; i &lt; ds_list_size(triList) - 1; i ++){ tri = triList[|i]; with(tri){ if(other.rotate){ image_angle += 2; } } }</code></pre> <p>Just like when we created our <strong>oTriangle</strong> objects, we are using a for loop. This time the loop is used to loop through the list of object IDs we have stored in the <strong>triList</strong>. We assign an object ID from the list to the <strong>tri </strong>variable, and using <strong>with</strong> we address those objects.</p> <p><img alt="121217_Orchestration_image4.gif" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/GameMakerStudio2/121217_Orchestration_image4._CB492441054_.gif?t=true" style="display:block; margin-left:auto; margin-right:auto" /></p> <p style="text-align:center"><em>Conducting the world's worst sounding orchestra.</em></p> <h1>Resources&nbsp;</h1> <p>That about wraps it up for the basics of object orchestration. This is a very powerful concept and can be used in many different ways. Having a master control object is vital to a successful, and efficient game! Check out the links below for more information on some of the concepts we discussed above.</p> <ul> <li><a href="https://docs.yoyogames.com/source/dadiospice/002_reference/001_gml%20language%20overview/401_18_with.html" target="_blank">GameMaker: With Constructor</a></li> <li><a href="https://docs.yoyogames.com/source/dadiospice/002_reference/data%20structures/ds%20lists/index.html" target="_blank">GameMaker: ds_lists</a></li> <li><a href="https://docs.yoyogames.com/source/dadiospice/002_reference/001_gml%20language%20overview/401_11_for.html" target="_blank">GameMaker: For Loops</a></li> <li>Download the example project file <a href="https://drive.google.com/file/d/1lN7Vwice1mSKpheZQoYeJ-d5mRtE0MPQ/view?usp=drive_web" target="_blank">here</a>&nbsp;</li> </ul> <p>As always, you can reach me on <a href="https://www.twitter.com/ratcasket" target="_blank">Twitter</a> or visit my <a href="http://www.ratcasket.com" target="_blank">website</a> for more gamedev stuff. Until next time!</p> <div> &nbsp; </div> <p style="text-align:center"><a href="https://www.twitter.com/ratcasket"><img alt="NathanRBio.jpg" src="https://m.media-amazon.com/images/G/01/DeveloperBlogs/AppstoreBlogs/default/NathanRBio._CB513300692_.jpg?t=true" /></a></p> <p style="text-align:center"><em>Nathan Ranney is the founder of punk house game dev shop, <a href="http://www.ratcasket.com" target="_blank">RatCasket</a>. He’s best known for the creation and development of Kerfuffle, an online indie fighting game.</em></p>