{"id":20,"date":"2014-09-04T00:20:00","date_gmt":"2014-09-04T04:20:00","guid":{"rendered":"http:\/\/naplandgames.com\/blog\/2014\/09\/04\/asynchronous-animations\/"},"modified":"2018-12-18T09:12:46","modified_gmt":"2018-12-18T14:12:46","slug":"asynchronous-animations","status":"publish","type":"post","link":"https:\/\/naplandgames.com\/blog\/2014\/09\/04\/asynchronous-animations\/","title":{"rendered":"Asynchronous Animations"},"content":{"rendered":"<div style=\"clear: both; text-align: center;\"><\/div>\n<div style=\"margin-left: 1em; margin-right: 1em;\">\n<div style=\"text-align: center;\"><a href=\"http:\/\/www.thegamecreators.com\/pages\/newsletters\/newsletter_issue_139.html\">Check out the full AGK Newsletter here<\/a><\/div>\n<div style=\"text-align: center;\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/images-blogger-opensocial.googleusercontent.com\/gadgets\/proxy?url=http%3A%2F%2Fwww.thegamecreators.com%2Fimages%2Fnewsletter%2Fissue136%2Fagk_mastery.jpg&amp;container=blogger&amp;gadget=a&amp;rewriteMime=image%2F*\" width=\"400\" height=\"68\" border=\"0\" \/><\/div>\n<p>The more animation and movement you have in your games, the more flashy and appealing they can be to players. In this tutorial I&#8217;ll be showing you how to build animations that run in their own self-contained functions.<\/p>\n<div style=\"clear: both; text-align: center;\"><\/div>\n<p><a href=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2014\/09\/1080x1920_ss03-1.png\" rel=\"lightbox[20]\"><img loading=\"lazy\" decoding=\"async\" class=\"alignright size-medium wp-image-106\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2014\/09\/1080x1920_ss03-1-169x300.png\" alt=\"1080x1920_ss03\" width=\"169\" height=\"300\" srcset=\"https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2014\/09\/1080x1920_ss03-1-169x300.png 169w, https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2014\/09\/1080x1920_ss03-1-768x1365.png 768w, https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2014\/09\/1080x1920_ss03-1-576x1024.png 576w, https:\/\/naplandgames.com\/blog\/wp-content\/uploads\/2014\/09\/1080x1920_ss03-1.png 1080w\" sizes=\"(max-width: 169px) 100vw, 169px\" \/><\/a>This allows them to be interrupted at any time, allows for simultaneous user input and anything else you wish to occur in your game loop without having to wait for the animation script to finish. In our most recent game, Sudoku In Space, we make extensive use of this for background animations, main menu animations, and particle animations when you make a completion move. Since we use a timer in Sudoku In Space, it is important to not prevent the user from interacting with the game while an animation is happening for a row, column, or block completion.<\/p>\n<p>To keep things simple this tutorial will only show the background animations for the larger stars that wink in and out. If you&#8217;re interested in seeing how I did the particle animations just let me know and I&#8217;ll do it in a future continuation of this article.<\/p>\n<p>First, we&#8217;ll need a user defined type and a variable of that type. In Sudoku In Space I actually made this variable global so that all of our screens could have the background animation, however, it is not necessary if you are using the animation in only one area of your game since the function to handle the animation has a feedback loop. A feedback loop is when a function accepts input of a specific variable and then outputs to that same variable.<\/p>\n<p>The following setup will make a star appear in a random location on the screen, color it one of three different colors at random, and make it grow and then shrink.<\/p>\n<p>Our type:<\/p>\n<pre style=\"background-attachment: initial; background-clip: initial; background-color: #eeecf6; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 1px solid #cccccc; color: #493617; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; line-height: 17.280000686645508px; padding-left: 16px;\">type star_type\u00a0\r\n\u00a0 \u00a0 max_W# as float\r\n\u00a0 \u00a0 dir as integer\r\n\u00a0 \u00a0 spriteID as integer\r\n\u00a0 \u00a0 abs_max_W# as float\r\n\u00a0 \u00a0 abs_min_W# as float\r\n\u00a0 \u00a0 time as integer\r\nendtype<\/pre>\n<ul>\n<li><i>max_W#<\/i> will contain a random size that we want the star to grow to.<\/li>\n<li><i>dir<\/i> is the direction of the sprite&#8217;s growth.<\/li>\n<li><i>spriteID<\/i> is the sprite ID of the star.<\/li>\n<li><i>abs_max_W<\/i># is the maximum width the star should ever grow to so that the sprite&#8217;s image doesn&#8217;t become fuzzy or larger than we want it to appear.<\/li>\n<li><i>abs_min_W<\/i># is the minimum width the star should ever shrink to and serves as a starting and stopping point for the shrink\/grow animation.<\/li>\n<li><i>time<\/i> will allow us to control when the star reappears.<\/li>\n<\/ul>\n<div style=\"margin-left: 1em; margin-right: 1em;\"><\/div>\n<p>Now let&#8217;s look at the self-contained feedback loop function:<\/p>\n<pre style=\"background-attachment: initial; background-clip: initial; background-color: #eeecf6; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 1px solid #cccccc; color: #493617; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; line-height: 17.280000686645508px; padding-left: 16px;\"><span style=\"line-height: 1.5;\">function HandleStar(star as star_type , fFT# , tT#)<\/span>\u00a0 \u00a0 \/\/ fFT# is frame time as obtained from GetFrameTime()\r\n \/\/ in the main loop\r\n\u00a0 \u00a0 \/\/ tT# is the total time we want the growing or shrinking to take\r\n\u00a0\r\n\u00a0 \u00a0 \/\/the depth of the sprite\r\n\u00a0 \u00a0 depth = 2000\u00a0\r\n\u00a0\r\n\u00a0 \u00a0 \/\/ If the direction is 0 then this is the first time we're\u00a0\r\n\u00a0 \u00a0 \/\/ running the function so we need to set direction to 1 (grow).\r\n\u00a0 \u00a0 if star.dir = 0\r\n\u00a0 \u00a0 \u00a0 \u00a0 star.dir = 1\r\n\u00a0 \u00a0 endif\r\n\u00a0\r\n\u00a0 \u00a0 \/\/Instantiate the sprite if it doesn't already exist.\r\n\u00a0 \u00a0 if GetSpriteExists(star.spriteID) = 0\r\n\u00a0 \u00a0 \u00a0 \u00a0 img = LoadImage(\u201cstar.png\u201d)\r\n\u00a0 \u00a0 \u00a0 \u00a0 star.spriteID = CreateSprite(img)\u00a0\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ We'll allow the star to grow up to 5%\r\n        \/\/ of the screen width.\r\n\u00a0 \u00a0 \u00a0 \u00a0 star.abs_max_W# = 5.0\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ The star image was designed for an 800px wide screen\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ We want to prevent it from being smaller\r\n        \/\/ than 10px at 800px resolution\r\n\u00a0 \u00a0 \u00a0 \u00a0 star.abs_min_W# = 100.0 * 10.0 \/ 800.0\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ Initialize the size at the minimum size\r\n        \/\/ so that it will grow\r\n\u00a0 \u00a0 \u00a0 \u00a0 SetSpriteSize(star.spriteID , star.abs_min_W# , -1)\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ Initialize the max_W# variable to a negative so that\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ we can set it to a random value\r\n\u00a0 \u00a0 \u00a0 \u00a0 star.max_W# = -1.0\r\n\u00a0 \u00a0 endif\r\n\u00a0\r\n\u00a0\r\n\u00a0 \u00a0 \/\/ Initialize the animation variables \u2013 this happens every time the\u00a0\r\n\u00a0 \u00a0 \/\/ star is shrunk to its minimum size as well\r\n    \/\/ as the first run of the function\r\n\u00a0 \u00a0 \/\/\r\n\u00a0 \u00a0 \/\/ If the max_W# variable is negative then we need to\r\n\u00a0 \u00a0 \/\/ determine a random size we'll allow the star to grow to\r\n\u00a0 \u00a0 \/\/ as well set it's initial position, color, and angle\r\n\u00a0\r\n\u00a0 \u00a0 if star.max_W# &lt; 0.001\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ Determine a random value for the max width to grow to.\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ Here I multiply the maximum and minimum by 100 so that I can\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ make use of the random() function which only works on integers\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ and then divide by 100. This way the star can have a max width\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ with fractional percentages.\r\n\u00a0 \u00a0 \u00a0 \u00a0 r_low = floor(100.0 * (star.abs_max_W# - 0.4 * star.abs_max_W#))\r\n\u00a0 \u00a0 \u00a0 \u00a0 r_high = floor(100.0 * (star.abs_max_W#))\r\n\u00a0 \u00a0 \u00a0 \u00a0 star.max_W# = random(r_low , r_high) \/ 100.0\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ Similar is done to find the initial position\r\n\u00a0 \u00a0 \u00a0 \u00a0 r_x_low = 100\r\n\u00a0 \u00a0 \u00a0 \u00a0 r_x_high = floor(100.0 * (100.0 - star.max_W#))\r\n\u00a0 \u00a0 \u00a0 \u00a0 x# = random(r_x_low , r_x_high) \/ 100.0\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 r_y_low = 100\r\n\u00a0 \u00a0 \u00a0 \u00a0 maxY# = 100.0 \u2013 GetSpriteHeight(star.spriteID)\r\n\u00a0 \u00a0 \u00a0 \u00a0 r_y_high = floor(100.0 * maxY#)\r\n\u00a0 \u00a0 \u00a0 \u00a0\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 y# = random(r_y_low , r_y_high) \/ 100.0\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ Now we can position the star\r\n\u00a0 \u00a0 \u00a0 \u00a0 SetSpritePosition(star.spriteID , x# , y#)\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ Give it a random angle for more randomness\r\n\u00a0 \u00a0 \u00a0 \u00a0 r_angle = random(1,360)\r\n\u00a0 \u00a0 \u00a0 \u00a0 SetSpriteAngle(star.spriteID , r_angle)\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ Set the time at which we initialized the star and make it visible.\r\n\u00a0 \u00a0 \u00a0 \u00a0 star.time = GetMilliseconds()\r\n\u00a0 \u00a0 \u00a0 \u00a0 SetSpriteVisible(star.spriteID , 1)\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ Set random color\r\n\u00a0 \u00a0 \u00a0 \u00a0 r_color_num = random(1,4)\r\n\u00a0 \u00a0 \u00a0 \u00a0 if r_color_num = 1\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 color$ = \"200,255,255\" \/\/blue-ish\r\n\u00a0 \u00a0 \u00a0 \u00a0 elseif r_color_num = 2\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 color$ = \"255,255,200\" \/\/purple-ish\r\n\u00a0 \u00a0 \u00a0 \u00a0 else\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 color$ = \u201c255,255,255\u201d \/\/white\r\n\u00a0 \u00a0 \u00a0 \u00a0 endif\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ This is a home brewed function I use that makes it a\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ Little easier to set sprite colors \u2013\r\n        \/\/ included after this function\r\n\u00a0 \u00a0 \u00a0 \u00a0 _SetSpriteColor(star.spriteID , color$)\r\n\u00a0 \u00a0 endif\r\n\u00a0\r\n\u00a0\r\n\u00a0\r\n\u00a0 \u00a0 \/\/ Now we can actually animate the growth and shrinking of the star.\r\n\u00a0\r\n\u00a0 \u00a0 \/\/ Determine the distance between the random width we grow to\r\n\u00a0 \u00a0 \/\/ and the minimum allowable width.\r\n\u00a0 \u00a0 dist# = star.max_W# - star.abs_min_W#\r\n\u00a0\r\n\u00a0 \u00a0 \/\/ Get the current widht of the star so we can see if it should still\u00a0\r\n\u00a0 \u00a0 \/\/ grow or shrink\r\n\u00a0 \u00a0 current_W# = GetSpriteWidth(star.spriteID)\r\n\u00a0\r\n\u00a0 \u00a0 \/\/ Initialize this to a negative so that we can skip the sizing of\u00a0\r\n\u00a0 \u00a0 \/\/ the star when we're pausing between appearances.\r\n\u00a0 \u00a0 new_W# = -1.0\r\n\u00a0\r\n\u00a0 \u00a0 \/\/ If the direction is 1 then we are growing the star\r\n\u00a0 \u00a0 if star.dir = 1\u00a0\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ If the current width is less than the maximum\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ width we want the star to grow to then grow it!\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ Otherwise stop growing and negate the direction\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ So that it will start shrinking.\r\n\u00a0 \u00a0 \u00a0 \u00a0 if current_W# &lt; star.max_W#\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ Here we use a linear equation based on frame time (fFT#)\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ to increase the size of the sprite over time tT#\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 new_W# = current_W# + dist# * fFT# \/ tT#\r\n\u00a0 \u00a0 \u00a0 \u00a0 else\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ We're done growing, so negate the direction\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 new_W# = star.max_W#\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 star.dir = star.dir * -1\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 endif\r\n\u00a0\r\n\u00a0\r\n\u00a0 \u00a0 elseif star.dir = -1 \u00a0\/\/Otherwise we're shrinking the star\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ If the current width of the star is still greater\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ than the allowable minimum width then grow it.\r\n\u00a0 \u00a0 \u00a0 \u00a0 \/\/ Otherwise stop.\r\n\u00a0 \u00a0 \u00a0 \u00a0 if current_W# &gt; star.abs_min_W#\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ Use the same linear equation for growth based on frame time,\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ but negate the distance variable\r\n            \/\/ so we're making the width smaller.\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 new_W# = current_W# - dist# * fFT# \/ tT#\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 else\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ We're done growing so set the new width to the minimum width\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ Doing this helps if a large number of frames were skipped.\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 new_W# = star.abs_min_W#\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ Hide the star for now because we're going to wait to make\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ it reappear\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 SetSpriteVisible(star.spriteID , 0)\r\n\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ Now when it is time, set max_W# to a negative to\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ reinitialize the star's animation (random max w, color, position)\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ The calculation here is tT# in seconds which needed to be\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ converted to milliseconds \u2013 so basically we're adding 3 seconds\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \/\/ before the star will restart the animation.\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 if GetMilliseconds() &gt; star.time + 3000.0 * tT#\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 star.max_W# = -1.0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 star.dir = star.dir * -1\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0\u00a0\r\n\u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 endif\r\n\u00a0 \u00a0 \u00a0 \u00a0 endif\r\n\u00a0 \u00a0 endif\r\n\u00a0\r\n\u00a0 \u00a0 \/\/ Only grow and reposition the star if new_W# if positive.\r\n\u00a0 \u00a0 \/\/ This allows us to skip over the sizing when the star is waiting\u00a0\r\n\u00a0 \u00a0 \/\/ to be reinitialized\r\n\u00a0 \u00a0 if new_W# &gt; 0.0\r\n\u00a0 \u00a0 \u00a0 \u00a0 x# = GetSpriteXByOffset(star.spriteID)\r\n\u00a0 \u00a0 \u00a0 \u00a0 y# = GetSpriteYByOffset(star.spriteID)\r\n\u00a0 \u00a0 \u00a0 \u00a0 SetSpriteSize(star.spriteID , new_W# , -1)\r\n\u00a0 \u00a0 \u00a0 \u00a0 SetSpritePositionByOffset(star.spriteID , x# , y#)\r\n\u00a0 \u00a0 endif\r\nendfunction star<\/pre>\n<p>This is used to color sprites with only a comma separated string for the R, G, and B values.<\/p>\n<pre style=\"background-attachment: initial; background-clip: initial; background-color: #eeecf6; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 1px solid #cccccc; color: #493617; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; line-height: 17.280000686645508px; padding-left: 16px;\">function _SetSpriteColor(iID , sColor$)\u00a0\r\n     if GetSpriteExists(iID) = 1\r\n          r = val(GetStringToken(sColor$ , \",\" , 1))\r\n          g = val(GetStringToken(sColor$ , \",\" , 2))\r\n          b = val(GetStringToken(sColor$ , \",\" , 3))\r\n          SetSpriteColor(iID , r , g , b , 255)\r\n     endif\r\nendfunction<\/pre>\n<p>Now all that needs to be done is run this function in a loop like so:<\/p>\n<pre style=\"background-attachment: initial; background-clip: initial; background-color: #eeecf6; background-image: initial; background-origin: initial; background-position: initial; background-repeat: initial; background-size: initial; border: 1px solid #cccccc; color: #493617; font-family: Verdana, Arial, Helvetica, sans-serif; font-size: 12px; line-height: 17.280000686645508px; padding-left: 16px;\"><span style=\"line-height: 1.5;\">myStar as star_type<\/span>shrink_grow_time# = 0.50\r\n\u00a0\r\ndo\r\n\u00a0 \u00a0 ft# = GetFrameTime()\r\n\u00a0 \u00a0 myStar = HandleStar(myStar , ft# , shrink_grow_time#)\r\n\u00a0 \u00a0 Sync()\r\nloop<\/pre>\n<p>Hopefully you can also see how this can be extended for more complex animations where there are various states for the animation. One example you can see is in Sudoku In Space on the home screen. Our game character, Allen the Alien, flies onto the screen, appears to hover with some up and down tweening, and continues to do so until the player presses the play button, at which time he flies away. I also built that animation so it can be interrupted and the player does not need to wait for Allen to be in the center of the screen before they can tap a button. Tapping a button will simply allow Allen to keep moving across the screen until he&#8217;s gone.<\/p>\n<p>In Sudoku In Space we take advantage of this method for many of the animations so that user input is not hampered. Please take a look at the game to see these animations in action. The most complex of them are the particle animations for when you complete a puzzle. If you&#8217;d like to see an example of that in a future tutorial, just let me know (n&#97;&#x70;&#x6c;a&#110;&#x64;&#x67;a&#109;&#x65;&#x73;&#64;&#103;&#x6d;&#x61;i&#108;&#x2e;&#x63;o&#109;)! Sudoku In Space is free on Google Play and the App Store.<\/p>\n<div style=\"text-align: center;\"><a href=\"https:\/\/play.google.com\/store\/apps\/details?id=com.naplandgames.sudokuinspace\"><img decoding=\"async\" src=\"https:\/\/images-blogger-opensocial.googleusercontent.com\/gadgets\/proxy?url=http%3A%2F%2Fdeveloper.android.com%2Fimages%2Fbrand%2Fen_generic_rgb_wo_45.png&amp;container=blogger&amp;gadget=a&amp;rewriteMime=image%2F*\" border=\"0\" \/><\/a> <a href=\"https:\/\/itunes.apple.com\/us\/app\/sudoku-in-space\/id902000374?mt=8&amp;uo=4\"><img decoding=\"async\" src=\"https:\/\/images-blogger-opensocial.googleusercontent.com\/gadgets\/proxy?url=http%3A%2F%2Flinkmaker.itunes.apple.com%2FhtmlResources%2Fassets%2Fen_us%2F%2Fimages%2Fweb%2Flinkmaker%2Fbadge_appstore-lrg.png&amp;container=blogger&amp;gadget=a&amp;rewriteMime=image%2F*\" border=\"0\" \/><\/a><\/div>\n<\/div>\n<div style=\"color: black; font-size: 14px; line-height: 21.600000381469727px; margin-left: 1em; margin-right: 1em;\"><\/div>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_20\" class=\"pvc_stats all  \" data-element-id=\"20\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n","protected":false},"excerpt":{"rendered":"<p>Check out the full AGK Newsletter here The more animation and movement you have in your games, the more flashy and appealing they can be to players. In this tutorial I&#8217;ll be showing you how to build animations that run in their own self-contained functions. This allows them to be interrupted at any time, allows for simultaneous user input and anything else you wish to occur in your game loop without having to wait for the animation script to finish. In our most recent game, Sudoku In Space, we make extensive use of this for background animations, main menu animations,&#8230;<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/naplandgames.com\/blog\/2014\/09\/04\/asynchronous-animations\/\">Continue reading<span class=\"screen-reader-text\">Asynchronous Animations<\/span><\/a><\/div>\n<div class=\"pvc_clear\"><\/div>\n<p id=\"pvc_stats_20\" class=\"pvc_stats all  \" data-element-id=\"20\" style=\"\"><i class=\"pvc-stats-icon medium\" aria-hidden=\"true\"><svg aria-hidden=\"true\" focusable=\"false\" data-prefix=\"far\" data-icon=\"chart-bar\" role=\"img\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" viewBox=\"0 0 512 512\" class=\"svg-inline--fa fa-chart-bar fa-w-16 fa-2x\"><path fill=\"currentColor\" d=\"M396.8 352h22.4c6.4 0 12.8-6.4 12.8-12.8V108.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v230.4c0 6.4 6.4 12.8 12.8 12.8zm-192 0h22.4c6.4 0 12.8-6.4 12.8-12.8V140.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v198.4c0 6.4 6.4 12.8 12.8 12.8zm96 0h22.4c6.4 0 12.8-6.4 12.8-12.8V204.8c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v134.4c0 6.4 6.4 12.8 12.8 12.8zM496 400H48V80c0-8.84-7.16-16-16-16H16C7.16 64 0 71.16 0 80v336c0 17.67 14.33 32 32 32h464c8.84 0 16-7.16 16-16v-16c0-8.84-7.16-16-16-16zm-387.2-48h22.4c6.4 0 12.8-6.4 12.8-12.8v-70.4c0-6.4-6.4-12.8-12.8-12.8h-22.4c-6.4 0-12.8 6.4-12.8 12.8v70.4c0 6.4 6.4 12.8 12.8 12.8z\" class=\"\"><\/path><\/svg><\/i> <img loading=\"lazy\" decoding=\"async\" width=\"16\" height=\"16\" alt=\"Loading\" src=\"https:\/\/naplandgames.com\/blog\/wp-content\/plugins\/page-views-count\/ajax-loader-2x.gif\" border=0 \/><\/p>\n<div class=\"pvc_clear\"><\/div>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3],"tags":[],"a3_pvc":{"activated":true,"total_views":860,"today_views":0},"_links":{"self":[{"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/posts\/20"}],"collection":[{"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/comments?post=20"}],"version-history":[{"count":4,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/posts\/20\/revisions"}],"predecessor-version":[{"id":108,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/posts\/20\/revisions\/108"}],"wp:attachment":[{"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/media?parent=20"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/categories?post=20"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/naplandgames.com\/blog\/wp-json\/wp\/v2\/tags?post=20"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}