{"id":5242,"date":"2015-05-02T15:16:54","date_gmt":"2015-05-02T22:16:54","guid":{"rendered":"http:\/\/g-liu.com\/blog\/?p=5242"},"modified":"2018-01-16T12:01:41","modified_gmt":"2018-01-16T19:01:41","slug":"animating-a-2d-sprite-with-css-animation","status":"publish","type":"post","link":"https:\/\/g-liu.com\/blog\/2015\/05\/animating-a-2d-sprite-with-css-animation\/","title":{"rendered":"Animating a 2D sprite with CSS animation"},"content":{"rendered":"<p>With new features in CSS 3 such as animation and three-dimensional transforms, you can do some <a href=\"http:\/\/codepen.io\/TimPietrusky\/pen\/eHGfj\" class=\"broken_link\" rel=\"nofollow\">pretty amazing things<\/a>. With multiple animations on one element, it&#8217;s possible to take a sprite sheet and animate it frame by frame. This tutorial assumes basic knowledge of CSS3. Knowing CSS3 animations is a plus.<\/p>\n<p><!--more--><\/p>\n<p><s>At the time of this tutorial, only Chrome, Safari, and possibly Internet Explorer are supported. This is due to <a href=\"http:\/\/stackoverflow.com\/questions\/9653685\/is-background-position-x-background-position-y-a-standard-w3c-css-property\" target=\"_BLANK\" class=\"broken_link\" rel=\"nofollow\">inconsistent support of <code>background-position-x<\/code> and <code>background-position-y<\/code> among different rendering engines<\/a>. If you find that your animations do not work, try using one of these browsers.<\/s> Update 16 Jan 2018: Almost all the major browsers now support <code>background-position-x\/y<\/code> consistently, meaning that this tutorial should work in Chrome, Firefox, Safari, IE, Microsoft Edge, and Opera. You may check <a href=\"https:\/\/caniuse.com\/#search=background-position\" target=\"_BLANK\">https:\/\/caniuse.com\/#search=background-position<\/a> for the latest cross-browser compatibility.<\/p>\n<h1>What&#8217;s a sprite sheet?<\/h1>\n<p>A sprite sheet is a single image that consists of a bunch of smaller images. The easiest way to explain it is to look at a picture of one:<\/p>\n<figure style=\"width: 2048px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/www.fabiobiondi.com\/blog\/wp-content\/uploads\/2012\/08\/runningGrant.png\" alt=\"Sprite sheet &quot;Running Grant&quot;\" width=\"2048\" height=\"2048\" \/><figcaption class=\"wp-caption-text\">Source: http:\/\/smwiki2014.wikidot.com\/wiki:android-game-development<\/figcaption><\/figure>\n<p>Reading from left to right, top to bottom, notice how our figure changes position ever so slightly. In fact, if we cut this large image up into its constituent images and rapidly flash&nbsp;them in sequence, we will get the illusion of movement.<\/p>\n<h1>Primer: one-dimensional sprite sheet animation<\/h1>\n<p>Before delving into two dimensions, let&#8217;s take a look at how we can animate just the top row of the sprite sheet above.<\/p>\n<p>First we must know how to show one part of the image. The easiest way to achieve this is with a <code>div<\/code> of set width and height, and a background image. There are other ways of achieving this, but we will stick with this method.<\/p>\n<pre class=\"brush: xml; title: ; notranslate\" title=\"\">\r\n\r\n&lt;div id=&quot;sprite&quot;&gt;&lt;\/div&gt;\r\n\r\n<\/pre>\n<pre class=\"brush: css; title: ; notranslate\" title=\"\">\r\n#sprite {\r\n    height: 294px;\r\n    width: 165px;\r\n    background-image: url(http:\/\/www.fabiobiondi.com\/blog\/wp-content\/uploads\/2012\/08\/runningGrant.png);\r\n    background-position: 0 0;\r\n}\r\n<\/pre>\n<p>Setting the width and height on the div effectively crops the background image. The specific numbers are derived from the dimensions of each frame of the sprite sheet. The important property here is <code>background-position<\/code>, which we will use to shift the background image inside the <code>div<\/code>. Right now it is set to <code>0 0<\/code>, which shows the background image starting at the top-left corner of the image.<\/p>\n<h2>Defining the animation<\/h2>\n<p>What we want to do then, is rapidly change the value of <code>background-position<\/code> in our animation. First, let&#8217;s define that animation. Add this to the bottom of your CSS.<\/p>\n<pre class=\"brush: css; title: ; notranslate\" title=\"\">\r\n@keyframes run-x {\r\n    from {\r\n        background-position-x: 0;\r\n    }\r\n    to {\r\n        background-position-x: -1980px;\r\n    }\r\n}\r\n<\/pre>\n<p>In the code above, we start at <code>0<\/code> for our <code>background-x-position<\/code>. By the end of the animation, the background will have shifted to <code>-1980px<\/code>. How did we arrive at this number? Let&#8217;s temporarily ignore the negative sign. Examining the image of running Grant, we see that each &#8220;frame&#8221; is 165 pixels wide. The sprite sheet is 12 frames across. By simple math, we figure out that the last frame is positioned at 12 \u00d7 165px = 1980px.<\/p>\n<p>Now you may wonder why there is a negative sign. Background position is a strange beast; it is not specified in terms of the image itself, but rather the element that has the background image. Do not worry too much about whether to use a negative sign, as this tutorial will give you the exact numbers to use.<\/p>\n<h2>Apply the animation<\/h2>\n<p>Right now nothing on your screen will move. That&#8217;s because we haven&#8217;t referred to the animation yet. Now we&#8217;ll modify the CSS for <code>#sprite<\/code>. The changes are highlighted.<\/p>\n<pre class=\"brush: css; highlight: [6,7,8,9]; title: ; notranslate\" title=\"\">\r\n#sprite {\r\n    width: 300px;\r\n    width: 165px;\r\n    background-image: url(http:\/\/www.fabiobiondi.com\/blog\/wp-content\/uploads\/2012\/08\/runningGrant.png);\r\n    background-position: 0 0;\r\n    animation-name: run-x;\r\n    animation-duration: 0.4s;\r\n    animation-iteration-count: infinite;\r\n    animation-timing-function: steps(12);\r\n}\r\n<\/pre>\n<p><strong>Note:<\/strong> when using Chrome or Safari, prefix all <code>animation-*<\/code> properties with <code>-webkit-<\/code>. For example, <code>animation-name<\/code> becomes <code>-webkit-animation-name<\/code>.<\/p>\n<p>The four lines of code we added define the animation that is applied to the element and some properties of the animation.<\/p>\n<ul>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/animation-name\" target=\"_BLANK\"><code>animation-name<\/code><\/a> is name of the animation is what we just defined: &#8220;run-x&#8221;.<\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/animation-duration\" target=\"_BLANK\"><code>animation-duration<\/code><\/a> says that this animation lasts for 0.4 seconds<\/li>\n<li><a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/animation-iteration-count\" target=\"_BLANK\"><code>animation-iteration-count<\/code><\/a> sets the animation to loop <em>ad infinitum<\/em><\/li>\n<li>The <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/CSS\/animation-timing-function\" target=\"_BLANK\"><code>animation-timing-function<\/code><\/a>, <code>steps(12)<\/code> tells us to break up the animation into twelve discrete stages. Try removing this line of code. You&#8217;ll notice a sort of filmstrip effect, where it feels like someone is pulling the sprite sheet at a rapid speed. This is because the animation is hitting every value between 0 and -1980 pixels. The <a href=\"http:\/\/designmodo.com\/steps-css-animations\/\" target=\"_BLANK\"><code>steps<\/code><\/a> function makes it so that the background is at <code>0<\/code> for some time, then <code>-165px<\/code>, then <code>-330px<\/code>, and so on. Rather than a continuous progression of values, <code>steps()<\/code> makes the CSS properties take on discrete values per unit of time. And this is really what sprite animation is all about: taking a frame and displaying it for a short time, showing the next frame and displaying that frame for a short time, and so on.<\/li>\n<\/ul>\n<h1>Intermediate step: another animation<\/h1>\n<p>If we want the animation to run in two dimensions, then we have to change the y-position of the background along with the x-position. The concept is the same as before; only this time we will use <code>background-position-y<\/code> instead of <code>background-position-x<\/code>. At the bottom of your CSS, add a new keyframe definition.<\/p>\n<pre class=\"brush: css; title: ; notranslate\" title=\"\">\r\n@keyframes run-y {\r\n    from {\r\n        background-position-y: 0;\r\n    }\r\n    to {\r\n        background-position-y: -1764px;\r\n    }\r\n}\r\n<\/pre>\n<p>Each frame&#8217;s height is about 294 pixels, and the sheet is 6 frames tall. 294 \\times 6 = 1764px. Note that we don&#8217;t have to touch <code>background-position-x<\/code>. We already have an animation definition for manipulating this property.<\/p>\n<p>We will not apply this animation immediately. Instead, we&#8217;ll combine it with the <code>run-x<\/code> animation we defined above to produce the 2D animation.<\/p>\n<h1>Putting it all together<\/h1>\n<p>One of the beautiful things about CSS3 animations is that it can accept multiple animations per element. We have already applied the animation in the x-direction. Now, we just add on the y-direction animation.<\/p>\n<pre class=\"brush: css; highlight: [6,7,8,9]; title: ; notranslate\" title=\"\">\r\n#sprite {\r\n    width: 300px;\r\n    width: 165px;\r\n    background-image: url(http:\/\/www.fabiobiondi.com\/blog\/wp-content\/uploads\/2012\/08\/runningGrant.png);\r\n    background-position: 0 0;\r\n    animation-name: run-x, run-y;\r\n    animation-duration: 0.4s, 2.4s;\r\n    animation-iteration-count: infinite;\r\n    animation-timing-function: steps(12), steps(6);\r\n}\r\n<\/pre>\n<p>And there you have it! Here&#8217;s an explanation of the changes made in order to produce the effect:<\/p>\n<ul>\n<li>I added <code>run-y<\/code> to <code>animation-name<\/code> to apply another animation at the same time as the existing <code>run-x<\/code> animation.<\/li>\n<li>Skipping to the timing function, <code>run-y<\/code> is presented in six discrete steps, as the sprite sheet is 6 frames tall. This will become important in determining the duration of <code>run-y<\/code><\/li>\n<li><code>run-x<\/code> runs in 0.4 seconds, and <code>run-y<\/code> runs in 2.4 seconds. How did we arrive at these numbers? The idea is that we want to run the first row completely, then immediately jump to the next row and run its length, and so on. It takes 0.4 seconds to run an entire row of the sprite sheet. Think of the <code>run-y<\/code> animation as &#8220;selecting&#8221; a row. We want to select a row for 0.4 seconds, then select the next row for 0.4 seconds, and so on. There are six rows altogether in the sprite sheet, so <code>run-y<\/code> should take 0.4 \u00d7 6 = 2.4 seconds to run.<\/li>\n<li>Both animations run on loop, so <code>animation-iteration-count<\/code> is not changed.<\/li>\n<\/ul>\n<h1>A short word about shorthand<\/h1>\n<p>Instead of writing<\/p>\n<pre class=\"brush: css; title: ; notranslate\" title=\"\">\r\nanimation-name: run-x, run-y;\r\nanimation-duration: 0.4s, 2.4s;\r\nanimation-iteration-count: infinite;\r\nanimation-timing-function: steps(12), steps(6);\r\n<\/pre>\n<p>we can write<\/p>\n<pre class=\"brush: css; title: ; notranslate\" title=\"\">\r\nanimation: run-x 0.4s infinite steps(12),\r\n    run-y 2.4s infinite steps(6);\r\n<\/pre>\n<p>This is called <a href=\"https:\/\/css-tricks.com\/almanac\/properties\/a\/animation\/\" target=\"_BLANK\">shorthand<\/a>, where multiple CSS properties are compressed into one. The animations themselves are separated by commas, while animation properties are separated by spaces.<\/p>\n<h1>The whole thing<\/h1>\n<p>You can see a complete demonstration, along with source code, at <a href=\"http:\/\/codepen.io\/g-liu\/pen\/XbrMzr?editors=110\" target=\"_BLANK\" class=\"broken_link\" rel=\"nofollow\">http:\/\/codepen.io\/g-liu\/pen\/XbrMzr?editors=110<\/a>. At the time of this post, the demo only works on Chrome and Safari, due to lack of support for <code>background-position-x<\/code> and <code>background-position-y<\/code>.<\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content --><!-- AddThis Related Posts generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>With new features in CSS 3 such as animation and three-dimensional transforms, you can do some pretty amazing things. With multiple animations on one element, it&#8217;s possible to take a sprite sheet and animate it frame by frame. This tutorial assumes basic knowledge of CSS3. Knowing CSS3 animations is a plus.<!-- AddThis Advanced Settings generic via filter on wp_trim_excerpt --><!-- AddThis Share Buttons generic via filter on wp_trim_excerpt --><!-- AddThis Related Posts generic via filter on wp_trim_excerpt --><\/p>\n","protected":false},"author":2,"featured_media":5293,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"jetpack_post_was_ever_published":false,"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"footnotes":"","jetpack_publicize_message":"Animating a 2D sprite with CSS #animation http:\/\/wp.me\/p2Zt3y-1my #css3","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[830],"tags":[],"jetpack_publicize_connections":[],"aioseo_notices":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"https:\/\/g-liu.com\/blog\/wp-content\/uploads\/2015\/05\/muybridge.jpg","jetpack_shortlink":"https:\/\/wp.me\/p2Zt3y-1my","_links":{"self":[{"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/posts\/5242"}],"collection":[{"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/comments?post=5242"}],"version-history":[{"count":25,"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/posts\/5242\/revisions"}],"predecessor-version":[{"id":5929,"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/posts\/5242\/revisions\/5929"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/media\/5293"}],"wp:attachment":[{"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/media?parent=5242"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/categories?post=5242"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/g-liu.com\/blog\/wp-json\/wp\/v2\/tags?post=5242"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}