{"id":3041,"date":"2014-04-12T18:39:46","date_gmt":"2014-04-13T01:39:46","guid":{"rendered":"http:\/\/www.nathalielawhead.com\/candybox\/?p=3041"},"modified":"2014-12-17T20:45:12","modified_gmt":"2014-12-18T03:45:12","slug":"tutorial-building-a-game-in-edge-animate-offender","status":"publish","type":"post","link":"https:\/\/www.nathalielawhead.com\/candybox\/tutorial-building-a-game-in-edge-animate-offender","title":{"rendered":"Tutorial: Building A Game In Edge Animate (Offender)"},"content":{"rendered":"<p><strong>Introduction:<\/strong><\/p>\n<p>I&#8217;ve decided to build this first <a href=\"http:\/\/tetrageddon.com\" target=\"_blank\">Tetrageddon Games<\/a> &#8220;mini-game&#8221; tutorial, Offender, in <a href=\"http:\/\/html.adobe.com\/edge\/animate\/\" target=\"_blank\">Adobe Edge Animate<\/a> because the program is still very new, and there isn&#8217;t much out there on it in terms of game development.<\/p>\n<p>I think this will make a great &#8220;getting started&#8221; resource for newcomers, as well as demonstrate the capabilities of Edge Animate.<\/p>\n<p>In this tutorial I hope to offer a solid example of building a game with the program.<br \/>\nThis is the first part of a series discussing HTML5 game development.<\/p>\n<p>* <strong>DOWNLOAD<\/strong> the source files here: <a href=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/Offender_HTML.zip\" target=\"_blank\">Offender_HTML.zip<\/a><\/p>\n<p>* Play the finished game here: <a href=\"http:\/\/offender.alienmelon.com\/thegame\/\" target=\"_blank\">Offender HTML<\/a><\/p>\n<p>* Visit the website for it here: <a href=\"http:\/\/offender.alienmelon.com\/\" target=\"_blank\">http:\/\/offender.alienmelon.com\/<\/a><\/p>\n<p>Note, Edge Animate is being used in <em>some<\/em> game projects already. A few interesting links I&#8217;ve stumbled across while working with it are:<\/p>\n<p>* <a href=\"http:\/\/bmanderscheid.com\/tutorials\/2013\/4\/14\/space-invaders-rpg-building-a-game-in-adobe-edge-animate\" target=\"_blank\">Space Invaders RPG. Building a Game in Adobe Edge Animate<\/a><\/p>\n<p>* <a href=\"http:\/\/tv.adobe.com\/watch\/create-like-crazy-with-adobe-edge\/episode-10-controllable-characters-in-an-interactive-environment\/\" target=\"_blank\">Adobe&#8217;s Episode 10: Controllable characters in an interactive environment<\/a><\/p>\n<p>* <a href=\"http:\/\/coherent-labs.com\/create-animated-game-hud-with-adobe-edge-animate-and-coherent-ui\/\" target=\"_blank\">Create animated game HUD with Adobe Edge Animate and Coherent UI (Part 1)<\/a><\/p>\n<p><strong>In terms of HTML5 game development<\/strong>, there are many frameworks out there for making HTML5 games. A list slowly growing <del datetime=\"2014-04-29T22:28:57+00:00\">some of the most popular are<\/del> is:<\/p>\n<p>* <a href=\"http:\/\/www.kiwijs.org\/\" target=\"_blank\">Kiwi.js<\/a><br \/>\nKiwi.js is a fun and friendly Open Source HTML5 Game Engine. Some people call it the WordPress of HTML5 game engines&#8230;<\/p>\n<p>* <a href=\"http:\/\/seenjs.io\/\" target=\"_blank\">seen.js<\/a><br \/>\nLibrary &#8211; Render 3D scenes into SVG or HTML5 Canvas.<\/p>\n<p>* <a href=\"http:\/\/jdan.github.io\/isomer\/\" target=\"_blank\">Isomer<\/a><br \/>\nAn isometric graphics library for HTML5 canvas. Isomer is available for free under the MIT License, but you can also pay for it. <\/p>\n<p>* <a href=\"http:\/\/kineticjs.com\/\" target=\"_blank\">KineticJS<\/a><br \/>\nKineticJS is an HTML5 Canvas JavaScript framework that enables high performance animations, transitions, node nesting, layering, filtering, caching, event handling for desktop and mobile applications, and much more.<\/p>\n<p>* <a href=\"http:\/\/createjs.com\/\" target=\"_blank\">createjs.com\/<\/a><br \/>\nA suite of Javascript libraries &#038; tools for building rich, interactive experiences with HTML5.<\/p>\n<p>* <a href=\"https:\/\/github.com\/photonstorm\/phaser\" target=\"_blank\">https:\/\/github.com\/photonstorm\/phaser<\/a><br \/>\nPhaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.<\/p>\n<p>* <a href=\"http:\/\/html5quintus.com\/\" target=\"_blank\">http:\/\/html5quintus.com\/<\/a><br \/>\nQuintus is an easy-to-learn, fun-to-use JavaScript HTML5 game engine for mobile, desktop and beyond!<\/p>\n<p>* <a href=\"https:\/\/github.com\/GoodBoyDigital\/pixi.js\" target=\"_blank\">https:\/\/github.com\/GoodBoyDigital\/pixi.js<\/a><br \/>\nSuper fast HTML 5 2D rendering engine that uses webGL with canvas fallback<\/p>\n<p>* <a href=\"http:\/\/www.pandajs.net\/\" target=\"_blank\">http:\/\/www.pandajs.net\/<\/a><br \/>\nFree HTML5 game engine for mobile and desktop games<\/p>\n<p>* <a href=\"http:\/\/spelljs.com\/\" target=\"_blank\">http:\/\/spelljs.com\/<\/a><br \/>\nThe SpellJS framework enables you to develop games for the web and mobile platforms. It hides the additional effort associated with the development of cross-platform applications so that you can concentrate on creating games instead of building cross-platform infrastructure. The integrated development enviroment SpellEd assists with the creation of content.<\/p>\n<p>* <a href=\"http:\/\/www.babylonjs.com\/\" target=\"_blank\">http:\/\/www.babylonjs.com\/<\/a><br \/>\nBabylon.js is a 3D engine based on webgl and javascript. It supports many features, and I&#8217;m drooling over it.<\/p>\n<p>* <a href=\"http:\/\/www.blend4web.com\/en\/\" target=\"_blank\">Blend4Web<\/a><br \/>\nBlend4Web is a software framework for authoring and interactive rendering of three-dimensional graphics and audio in browsers, i.e. a three-dimensional engine. The platform is intended for creating visualizations, presentations, online-shops, games and other rich internet applications.<br \/>\nThe Blend4Web framework is integrated tightly with 3D modeling and animation tool Blender (hence the name). The content is rendered by the means of WebGL and other browser technologies, without the use of plugins.<br \/>\nTechnically Blend4Web is a library for web pages, a Blender addon and some tools for debugging and optimization.<\/p>\n<p>* <a href=\"https:\/\/github.com\/rezoner\/CanvasQuery\" target=\"_blank\">Canvas Query<\/a><br \/>\nCanvas for 2d gamedevelopers. Out of box canvas, keyboard, mouse, events.<br \/>\n<a href=\"http:\/\/canvasquery.com\" target=\"_blank\">http:\/\/canvasquery.com<\/a><\/p>\n<p>* <a href=\"http:\/\/www.lwjgl.org\/\" target=\"_blank\">Lightweight Java Game Library 3<\/a><br \/>\nLWJGL is a Java library that enables cross-platform access to popular native APIs useful in the development of graphics (OpenGL), audio (OpenAL) and parallel computing (OpenCL) applications. This access is direct and high-performance, yet also wrapped in a type-safe and user-friendly layer, appropriate for the Java ecosystem.<\/p>\n<p>* <a href=\"https:\/\/www.scirra.com\/construct2\" target=\"_blank\">Construct 2<\/a><br \/>\nThis is the <strong>perfect<\/strong> tool for beginners or non-technical artists. Construct 2 is a powerful ground breaking HTML5 game creator designed specifically for 2D games. It allows anyone to build games \u2014 no coding required! It&#8217;s almost entirely drag-and-drop.<\/p>\n<p>* <a href=\"http:\/\/www.ambiera.com\/copperlicht\/\" target=\"_blank\">CopperLicht<\/a><br \/>\nFree and fast WebGL JavaScript 3D Engine with World Editor. CopperLicht is an open source WebGL library and JavaScript 3D engine for creating games and 3D applications in the webbrowser. It uses the WebGL canvas supported by modern browsers and is able to render hardware accelerated 3d graphics without any plugins.<\/p>\n<p>* <a href=\"http:\/\/www.pixijs.com\/\" target=\"_blank\">pixijs<\/a><br \/>\nPixi.js is a devoted rendering engine. There are a host of other engines covering game, sound and physics etc. and they all work beautifully with Pixi.<\/p>\n<p>* <a href=\"http:\/\/www.cocos2d-x.org\/\" target=\"_blank\">cocos2d<\/a><br \/>\nCross platform open source free 2D game engine for mobile gamedev, that is fast and stable, easy to learn and use.<\/p>\n<p>* <a href=\"http:\/\/www.puzzlescript.net\/\" target=\"_blank\">PuzzleScript<\/a><br \/>\nPuzzleScript is an open-source HTML5 puzzle game engine.<\/p>\n<p><strong>Edge Animate Resources:<\/strong><\/p>\n<p>* <a href=\"http:\/\/www.adobe.com\/devnet-docs\/edgeanimate\/api\/current\/index.html\" target=\"_blank\">Edge Animate Docs<\/a><\/p>\n<p>* <a href=\"http:\/\/www.adobe.com\/devnet-docs\/edgeanimate\/api\/old\/1.0.0\/EdgeAPI.1.0.0.html\" target=\"_blank\">Adobe Edge Animate JavaScript API<\/a><\/p>\n<p>* <a href=\"http:\/\/www.edgehero.com\/articles\/edgehero-js-1-0-released\" target=\"_blank\">Edgehero.js<\/a><\/p>\n<p>*************<\/p>\n<p><strong>Setting up the Game Stage:<\/strong><\/p>\n<p><img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/game.png\" alt=\"\" \/><\/p>\n<p>When first working with Edge scope can be a surprise to beginners &#8212; presents an issue. A great article on the subject is this post (<a href=\"http:\/\/www.dehats.com\/drupal\/node\/111\" target=\"_blank\">HERE<\/a>). To avoid problems, actions are typically added to <code>document.compositionReady<\/code>.<\/p>\n<p>In this case &#8220;<code>global<\/code>&#8221; variables, and sounds, are created in <code>document.compositionReady<\/code>.<\/p>\n<p>Basic keyboard events are in <code>document.keydown<\/code>, and <code>document.keyup<\/code>, which reference <code>document.compositionReady<\/code>&#8216;s &#8220;global&#8221; variables.<br \/>\nThe actual game is in the stage&#8217;s trigger (see label &#8220;<code>game<\/code>&#8220;).<br \/>\nThe game takes place on label &#8220;<code>game<\/code>&#8220;. I thought it most convenient to manage scope by keeping the bulk of the game engine in that trigger.<br \/>\nVariables, states, arrays, etc&#8230; can set\/reset without conflicting with other areas.<\/p>\n<p>Animated\/transitions that will change as the game is played are grouped in symbols.<br \/>\nIt&#8217;s a good idea to plan this carefully, and use symbols (and their timeline) more than sending the &#8220;playhead&#8221; back and forth on the stage&#8217;s timeline (keep things manageable and grouped up). It will be easier to manage when you code.<br \/>\nControl symbols, and use the stage&#8217;s timeline for serious transitions (like changing from the main menu, to the highscores area).<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/playarea01.png\" alt=\"\" \/><\/p>\n<p>In this case we have 3 &#8220;screens&#8221;. The &#8220;play area&#8221;, the &#8220;game over&#8221; screen, and the &#8220;enter your name&#8221; screen (succeeding &#8220;game over&#8221;).<br \/>\nThe above image shows the play area. There are 4 important factors here.<\/p>\n<p>1) The &#8220;Nightmare&#8221; symbol. This is an &#8220;extra&#8221; that shows\/hides as you progress. While you are playing, the bunny is dreaming\/thinking of all the terrible things that will happen to him if he gets abducted. These show in the corner of the screen in little comic book like &#8220;star&#8221; panels. There are two versions of a nightmare, and a random one is selected, and randomly plays. <\/p>\n<p>2) The &#8220;current level&#8221; indicated by how many bunnies are left in bed. This is like a countdown before winning.<br \/>\nWhenever the player reaches a certain score, a bunny is pulled (abducted) out of its bed, until the player reaches the last bunny.<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/img01.png\" alt=\"\" \/><\/p>\n<p><img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/img02.png\" alt=\"\" \/><\/p>\n<p>Progress is indicated in this manner, so I grouped all the bunnies in a symbol (Beds), and the animated bunnies (level 2, and 3) are also symbols where the animation takes place. When the level is to progress, the game will simply play that transition&#8230;<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/img03.png\" alt=\"\" \/><\/p>\n<p>3) Your score. Each bunny you abduct with your ship adds a point. Each bunny that escapes off screen deducts a point.<\/p>\n<p>4) The play area. This is the field. Bunnies created via <code>sym.createChildSymbol<\/code> are placed here (total of 10). The ship, the ships ray, and enemy ships are also added (created dynamically).<\/p>\n<p>The Game Over Screen<br \/>\n<img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/playarea03.png\" alt=\"\" \/><br \/>\nIs a symbol, containing the buttons, and the player&#8217;s score. This shows when the player is killed by an enemy ship. &#8220;Surrender&#8221; will call up the &#8220;enter your name&#8221; screen. &#8220;Overachieve&#8221; is the try again option, and will re-start the game.<\/p>\n<p>Enter Your Name Screen<br \/>\n<img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/playarea02.png\" alt=\"\" \/><br \/>\nThe player will enter their name here. Saving score, and name is done using the HTML5 <code>localStorage<\/code> feature. More notes bellow.<\/p>\n<p>*************<\/p>\n<p><strong>Sound:<\/strong><\/p>\n<p>There are a number of ways to add sound to your project. <em>None<\/em> of them are 100% reliable, due to browser support. See: <a href=\"http:\/\/caniuse.com\/audio\" target=\"_blank\">http:\/\/caniuse.com\/audio<\/a><br \/>\nMy recommendation for Edge Animate is to either use Edge Commons&#8217;s Dirty Little Helpers: <a href=\"http:\/\/www.edgedocks.com\/edgecommons\" target=\"_blank\">http:\/\/www.edgedocks.com\/edgecommons<\/a><br \/>\nHere is the tutorial for setting it up: <a href=\"http:\/\/www.edgedocks.com\/content\/2013\/12\/sound-playback-volume-control-animate-edge-commons\" target=\"_blank\">Sound playback with volume control in Animate with Edge Commons<\/a><\/p>\n<p>Or Buzz!<br \/>\n<a href=\"http:\/\/buzz.jaysalvat.com\/\" target=\"_blank\">http:\/\/buzz.jaysalvat.com\/<\/a><\/p>\n<blockquote><p>Buzz is a small but powerful Javascript library that allows you to easily take advantage of the new HTML5 audio element. It degrades silently on non-modern browsers.<\/p><\/blockquote>\n<p>I will be using Buzz.<\/p>\n<p>Add the script via <em>Library > Scripts + tab<\/em>, and navigate to where you have it.<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/img07.png\" alt=\"\" \/><\/p>\n<p>Then in <code>document.compositionReady<\/code> (to add the <code>compositionReady<\/code> event click on the + next to Stage). The following adds a sound. To play call <code>Aud_GameTrack.play();<\/code><\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>Aud_GameTrack = new buzz.sound(&quot;audio\/mainmenu-loop&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;],\r\n    preload: true,\r\n    autoplay: true,\r\n    loop: true\r\n});\r\n<\/code><\/pre>\n<p><code>Formats<\/code> = Various formats for browsers. Not all browsers support the same sound format, so you need to include the most common ones. See: <a href=\"http:\/\/buzz.jaysalvat.com\/documentation\/sound\/\" target=\"_blank\">http:\/\/buzz.jaysalvat.com\/documentation\/sound\/<\/a><br \/>\nThe best combination is <code>OGG<\/code> + <code>MP3<\/code> formats (according to buzz).<\/p>\n<p>Also, mobile devices will not load\/play sound without user intervention (no autoplay). The sound must be triggered via user input (a button press, for example). iPhone and iPad only play one sound at a time, and you cannot change the volume dynamically.<br \/>\n<a href=\"http:\/\/www.ibm.com\/developerworks\/library\/wa-ioshtml5\/\" target=\"_blank\">See Overcoming iOS HTML5 audio limitations<\/a> And <a href=\"http:\/\/pupunzi.open-lab.com\/2013\/03\/13\/making-html5-audio-actually-work-on-mobile\/\" target=\"_blank\">Making HTML5 audio actually work on mobile<\/a>, for some notes on that.<\/p>\n<p>After you have created your sound (above), in <code>document.compositionReady<\/code>, make sure you call:<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>Aud_GameTrack.load();\r\n<\/code><\/pre>\n<p>Buzz is nice, and has a number of settings.<br \/>\nThe above (<code>Aud_GameTrack.load<\/code>) is a loop, and the main &#8220;soundtrack&#8221; for the game.<br \/>\nI manually made it longer, so it appears to loop. You will notice a &#8220;loop gap&#8221;. It takes a bit more hacking around to get seamless audio looping (Flash does it well, but it&#8217;s trickier in javascript\/html). Here are some notes for those interested in getting that to work:<br \/>\n<a href=\"http:\/\/sound.stackexchange.com\/questions\/8916\/mp3-gapless-looping-help\" target=\"_blank\">Stackexchange &#8211; MP3 gapless looping help?<\/a><br \/>\n<a href=\"http:\/\/forestmist.org\/blog\/html5-audio-loops\/\" target=\"_blank\">HTML5 Audio Loops<\/a><br \/>\nBut this is a simple game, so I&#8217;m keeping the sound aspect simple.<\/p>\n<p>All the sounds in the game are as follows:<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/SOUND\r\n\r\n\/\/I manually made the sound longer so it appears to loop -- nevermind the gap\r\n\/\/it is a bit more hacking around to get seamless audio looping (Flash does it well)\r\n\/\/here are some notes for those interested in getting it to work\r\n\/\/http:\/\/sound.stackexchange.com\/questions\/8916\/mp3-gapless-looping-help\r\n\/\/http:\/\/forestmist.org\/blog\/html5-audio-loops\/\r\n\/\/the main soundrack of the game:\r\nAud_GameTrack = new buzz.sound(&quot;audio\/mainmenu-loop&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;], preload: true, loop: true});\r\n\/\/plays at the end of the game:\r\nAud_GameTrack_2 = new buzz.sound(&quot;audio\/mainmenu-under-loop2&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;], preload: true, loop: true});\r\nAud_ScoresTrack = new buzz.sound(&quot;audio\/scores-loop&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;], preload: true, loop: true});\r\nAud_KeysTrack = new buzz.sound(&quot;audio\/Keys-loop&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;], preload: true, loop: true});\r\n\/\/Menu sounds\r\nAud_MenuPreLoop = new buzz.sound(&quot;audio\/Mainmenu-preloop&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;], preload: true});\r\nAud_MenuLoop = new buzz.sound(&quot;audio\/mainmenu-loop3&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;], preload: true, loop: true});\r\n\r\n\/\/Intro\r\n\/\/Aud_LogoMoron = new buzz.sound(&quot;audio\/morons-blb&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;]});\r\nAud_Intro = new buzz.sound(&quot;audio\/Intro&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;], preload: true});\r\n\r\nAud_Nightmare = new buzz.sound(&quot;audio\/JAPAN-3&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;]});\r\nAud_Explode = new buzz.sound(&quot;audio\/explode&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;],preload: true});\r\nAud_End = new buzz.sound(&quot;audio\/End&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;],preload: true});\r\nAud_Hit1_ = new buzz.sound(&quot;audio\/daaaam-1&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;]});\r\nAud_Hit2_ = new buzz.sound(&quot;audio\/daaaam-2&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;]});\r\nAud_Hit3_ = new buzz.sound(&quot;audio\/daaaam-3&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;]});\r\n\r\nAud_BeamLoop = new buzz.sound(&quot;audio\/beam-loop&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;],\r\n    loop: true\r\n});\r\n\r\nAud_Laser = new buzz.sound(&quot;audio\/LASER&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;]});\r\n\r\n\/\/load them with Edge\r\nAud_GameTrack.load();\r\nAud_GameTrack_2.load();\r\nAud_ScoresTrack.load();\r\nAud_KeysTrack.load();\r\nAud_MenuPreLoop.load();\r\nAud_MenuLoop.load();\r\nAud_Intro.load();\r\nAud_Nightmare.load();\r\nAud_Explode.load();\r\nAud_End.load();\r\nAud_Hit1_.load();\r\nAud_Hit2_.load();\r\nAud_Hit3_.load();\r\n\r\n\/\/stop all currently playing &quot;hits&quot; for menu and anywhere else they trigger on button overs\r\nsym.stopHits = function(){\r\n    Aud_Hit1_.stop();\r\n    Aud_Hit2_.stop();\r\n    Aud_Hit3_.stop();\r\n}\r\n<\/code><\/pre>\n<p>The last one is a function that stops the &#8220;hits&#8221; for the menu. When you mouse over buttons a hit plays. To keep it from piling up, I stop all of them, before playing the button mouseover sound.<\/p>\n<p>*************<\/p>\n<p><strong>Fonts:<\/strong><\/p>\n<p>The original Bitmap font was from: <a href=\"http:\/\/www.04.jp.org\/\" target=\"_blank\">04.jp<\/a><\/p>\n<p>But in this version I am using the Google Font, <a href=\"https:\/\/www.google.com\/fonts\/specimen\/Press+Start+2P\" target=\"_blank\">Press Start 2P<\/a>.<br \/>\n<img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/img08.png\" alt=\"\" \/><\/p>\n<p>To get web fonts working in Edge Animate follow Adobe&#8217;s walkthrough: <a href=\"http:\/\/blogs.adobe.com\/edge\/2012\/01\/27\/web-fonts-and-edge-together-at-last\/\" target=\"_blank\">Web fonts and Edge, together at last.<\/a><\/p>\n<p>*************<\/p>\n<p><strong>All The &#8220;Global&#8221; Variables Of <code>document.compositionReady<\/code><\/strong><\/p>\n<p>Aside from sound, there are a slew of variables in <code>document.compositionReady<\/code>. These are &#8220;global&#8221; variables that I will need to access throughout the game, in all the different places. Like <code>document.keydown<\/code>, or button events. I put them here so that scope will not be an issue.<\/p>\n<p>The first, and most important is <code>sym.SCENE<\/code>. I save the current &#8220;scene&#8221; that the game is on here. For example, if you are viewing the highscore area it is set to &#8220;scores&#8221;, on the main menu it&#8217;s &#8220;menu&#8221;, in the actual game it&#8217;s &#8220;game&#8221;. I do this for the keyboard. If you are playing the game, the keyboard for the &#8220;game&#8221; unlocks by checking against <code>sym.SCENE<\/code> (<code>if sym.SCEME==\"game\"<\/code>). If I where to have custom keyboard events for menu, the keyboard for &#8220;menu&#8221; would unlock. This gives me a platform to build on if I where to make this game keyboard only, or expand the keyboard functionality. More on that in the <em>Keyboard Controls<\/em> section.<\/p>\n<p>The first set of &#8220;global&#8221; variables ranges from numbers like scores, time, <code>enemyAmount<\/code>, to various sprite speeds, to the current level.<br \/>\nBooleans serve as flags, these are for the keyboard (down\/up).<\/p>\n<p>The &#8220;<code>\/\/symbol references<\/code>&#8221; chunk saves symbol names (so they can be more easily referred to through code).<\/p>\n<p>The two arrays are where created symbols (enemies and bunnies) are pushed.<\/p>\n<p>The &#8220;<code>\/\/X Y positions<\/code>&#8221; bit is where I save starting positions for created sprites, as well as where the centerX\/Y of the stage is.<\/p>\n<p>Finally there are &#8220;<code>\/\/Timers - intervals<\/code>&#8220;. I saved the names of all <code>setIntervals<\/code> here to manage the scope for them. They can be stopped better this way.<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/&quot;GLOBAL&quot; VARIABLES\r\n\/\/what label? \r\n\/\/will check against this and if it is &quot;game&quot; then game functionality will unlock\r\n\/\/if it is menu then keyboard for menu will unlock, etc...\r\nsym.SCENE; \r\n\r\nsym.score = 100;    \r\nsym.time = 1;\r\nsym.enemyAmount = 1;\/\/current amount\r\nsym.enemyMax = 3;\/\/maximum amount of enemies alowed at once\r\nsym.timeElapsed = 1;\r\nsym.playerSpeed = 600;\/\/5\r\nsym.playerSpeed_left = 600;\/\/5\r\nsym.playerSpeed_right = 600;\/\/5\r\nsym.bunnySpeed = 5000;\/\/will be random + itself, this is the default minimum value\r\n\/\/sym.bunnyAbAmnt = amount of abducted bunnies, if it's above a certain number then enemies will start appearing\r\n\/\/this keeps the game from generating enemies right away -- gives the player time to adjust\r\nsym.bunnyAbAmnt = 0;\r\n\/\/goals (before leveling up)\r\nsym.lvl1_goal = 300;\r\nsym.lvl2_goal = 530;\r\n\/\/targeted time (how long you have been playing before you can go to next level)\r\nsym.lvl1_time = 300;\r\nsym.lvl2_time = 500;\r\n\/\/above but for winning\r\nsym.win_time = 700;\r\nsym.win_goal = 800;\r\n\r\nsym.bNum = 10;\/\/maximum number of bunnies on stage\r\n\r\n\/\/Booleans - flags\r\nsym.bool_left = false;\r\nsym.bool_right = false;\r\n\r\n\/\/.data to keep it .play() called once\r\n\/\/may only play once if it is true then the transition to next level may play\r\nsym.mc_b1_data = false;\r\nsym.mc_b2_data = false;\r\n\r\n\/\/symbol references\r\nsym.stage = sym.$(&quot;Stage&quot;);\r\nsym.mc_b1 = sym.getSymbol(&quot;Beds&quot;).getSymbol(&quot;IMG_Sprite_Bed02&quot;);\r\nsym.mc_b2 = sym.getSymbol(&quot;Beds&quot;).getSymbol(&quot;IMG_Sprite_Bed03&quot;);\r\nsym.mc_nightmare = sym.getSymbol(&quot;Nightmare&quot;);\r\nsym.mc_transition = sym.getSymbol(&quot;Transition_Blink&quot;);\r\nsym.mc_gameover = sym.getSymbol(&quot;Screen_End&quot;);\r\nsym.mc_score = sym.getSymbol(&quot;Screen_Score&quot;);\r\nsym.mc_ship;\r\nsym.mc_ray;\r\nsym.txt_score = sym.$(&quot;txt_score&quot;);\r\n\r\n\/\/Arrays\r\nsym.arr_bunnies = [];\r\nsym.arr_enemies = [];\r\n\r\n\/\/X Y positions\r\nsym.shipY = 70;\/\/25\r\nsym.enemyY = 88;\r\nsym.rayY = 66;\/\/66\r\nsym.bunnyY = 180;\r\n\/\/centering\r\nsym.centerX = sym.stage.width()\/2;\r\nsym.centerY = sym.stage.height()\/2;\r\n\/\/left\/right bounds\r\nsym.maxX = sym.stage.width();\r\nsym.minX = 10;\/\/minimum placement for ship\r\n\/\/player X (incremented\/decremented via keyboard input, initial value is center)\r\nsym.shipX = sym.centerX;\r\n\r\n\/\/Timers - intervals\r\nsym.timerInt;\r\nsym.timeElapsedInt;\r\nsym.nightmareInterval;\r\nsym.enemyInterval;\r\nsym.shipHitInterval;\r\n<\/code><\/pre>\n<p>*************<\/p>\n<p><strong>Collision detection &#8211; The Bunnies And Enemies<\/strong><\/p>\n<p>Because Edge Animate was never meant for games (according to general sentiment) this is very limited.<br \/>\nThere are a number of discussions out there. For example both <a href=\"http:\/\/stackoverflow.com\/questions\/5930020\/detecting-div-collision\" target=\"_blank\">jquery &#8211; Detecting div collision<\/a>, and <a href=\"http:\/\/stackoverflow.com\/questions\/773717\/please-recommend-a-jquery-plugin-that-handles-collision-detection-for-draggable\" target=\"_blank\">Please recommend a JQuery plugin that handles collision detection for draggable elements<\/a> are good summaries of how to tackle it, and <a href=\"http:\/\/forums.adobe.com\/thread\/1074905\" target=\"_blank\">this thread<\/a> on Adobe Community which has some good tips. Another great 2D Collision Detection tutorial is:<br \/>\n<a href=\"http:\/\/blog.sklambert.com\/html5-canvas-game-2d-collision-detection\/\" target=\"_blank\">HTML5 Canvas Game: 2D Collision Detection<\/a><\/p>\n<p>The best solution out there is JQuery Collision (which I highly recommend)<br \/>\n<a href=\"http:\/\/sourceforge.net\/projects\/jquerycollision\/\" target=\"_blank\">SourceForge: JQuery Collision<\/a><br \/>\nIt is also being used in <a href=\"http:\/\/tv.adobe.com\/watch\/create-like-crazy-with-adobe-edge\/episode-10-controllable-characters-in-an-interactive-environment\/\" target=\"_blank\">Adobe&#8217;s Episode 10: Controllable characters in an interactive environment<\/a> tutorial (which is the most thorough breakdown of hit detection in Edge Animate that I could find).<\/p>\n<p>I&#8217;m using simple object intersection collision detection because this is a small project.<\/p>\n<p>But really, for more elaborate things consider <a href=\"http:\/\/sourceforge.net\/projects\/jquerycollision\/\" target=\"_blank\">JQuery Collision<\/a><\/p>\n<p>Download it here: <a href=\"http:\/\/sourceforge.net\/projects\/jquerycollision\/\" target=\"_blank\">http:\/\/sourceforge.net\/projects\/jquerycollision\/<\/a><\/p>\n<p>And add it via <em>Library > Scripts + tab<\/em>. Navigate to where you have it.<br \/>\n<img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/img06.png\" alt=\"\" \/><\/p>\n<p>Basic collision detection code for this project is as follows:<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>function hitTest(a, b){\r\n    \/\/\r\n    aPos = {x:parseInt(a.css('left')), y:parseInt(a.css('top'))};\r\n    bPos = {x:parseInt(b.css('left')), y:parseInt(b.css('top'))};\r\n    \/\/\r\n    return aPos.x &lt; bPos.x + b.width() &amp;&amp; aPos.x + a.width() &gt; bPos.x &amp;&amp; aPos.y &lt; bPos.y + b.height() &amp;&amp; aPos.y + a.height() &gt; bPos.y\r\n}\r\n\/\/Usage\r\nvar Rectangle = sym.$(&quot;Rectangle&quot;);\r\nvar Rectangle2 = sym.$(&quot;Rectangle2&quot;);\r\nconsole.log(hitTest(Rectangle, Rectangle2));\r\n<\/code><\/pre>\n<p>(Thanks Adobe forms for pointing me in the right direction here!)<\/p>\n<p>Collision detection will take place in two cases.<\/p>\n<p><em>1) When the player presses keyboard &#8220;space&#8221; and the ship&#8217;s beam should pick up bunnies.<\/em><\/p>\n<p>Bunnies are dynamically created with <code>createChildSymbol<\/code>:<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>function makeBunny() {\r\n    for (var i = 0; i&lt;sym.bNum; i++) {\r\n        var mc_bunny = sym.createChildSymbol(&quot;Bunny&quot;, &quot;Stage&quot;).getSymbolElement();\r\n        \/\/push to array for access later and start moving it\r\n        \/\/bunnyM also takes care of placeing them\r\n        \/\/note: bunnies must be stored in array\r\n        \/\/for colision detection, and better access\r\n        sym.arr_bunnies.push(mc_bunny);\r\n        bunnyM(mc_bunny);\/\/movement function\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>After they are created <code>bunnyM<\/code> is called and each is passed as a parameter.<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/Bunnies!\r\nfunction bunnyM(clip) {\r\n    \/\/console.log(clip);\r\n    \/\/speed, and end variables\r\n    var bEnd = sym.stage.width()-clip.width();\r\n    var bSpeed = (Math.ceil(Math.random()*sym.bunnySpeed)+sym.bunnySpeed)-500;\r\n    \/\/place it randomly (x) on the stage\r\n    clip.css({&quot;position&quot;:&quot;absolute&quot;, &quot;top&quot;:sym.bunnyY + &quot;px&quot;, &quot;left&quot;:(Math.ceil(Math.random()*sym.stage.width())-clip.width()) + &quot;px&quot;});\r\n    \/\/call first to cancel queue -- just incase this could become a problem\r\n    clip.stop();\r\n    \/\/\r\n    clip.animate( {left: bEnd}, bSpeed, &quot;linear&quot;, function(){\r\n        sym.score -= 1;\/\/&quot;escapee&quot; penalty\r\n        bunnyM(clip);\r\n    }\r\n    );\r\n}\r\n<\/code><\/pre>\n<p><code>bunnyM<\/code> is responsible for moving them. They are positioned with css. <code>clip.stop<\/code> is called to stop possible previous animation queue, and finally <code>.animate<\/code> is called. When <code>.animate<\/code> is done it calls <code>bunnyM<\/code> again as the complete callback function. See: <a href=\"https:\/\/api.jquery.com\/animate\/\" target=\"_blank\">https:\/\/api.jquery.com\/animate\/<\/a> for more <code>.animate<\/code> options.<\/p>\n<p>Reference to them is stored in an array. This is a good idea when you are dynamically creating symbols because it&#8217;s easier to reference them later. There are other ways of getting symbols (loop through stage), but I prefer this method.<\/p>\n<p>When SPACE is pressed there are two functions associated with it.<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/creating function with sym.\r\n\/\/to change scope so keyboard events can access these\r\nsym.key_onKeyDown = function() {\r\n    sym.mc_ray.show();\r\n    Aud_BeamLoop.play();\r\n    \/\/hit detection\r\n    for (var i = 0; i&lt;sym.arr_bunnies.length; ++i){\r\n          bunnyD(sym.arr_bunnies[i]);\r\n    }\r\n};\r\nsym.key_onKeyUp = function() {\r\n    Aud_BeamLoop.stop();\r\n    sym.mc_ray.hide();\r\n}\r\n<\/code><\/pre>\n<p><code>onKeyDown<\/code> shows the ray, plays the sound, and loops through the bunnies calling <code>bunnyD<\/code> (the collision detection function), and passing each bunny as the function parameter.<\/p>\n<p>AND FINALLY <code>bunnyD<\/code> is where the magic happens.<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>function bunnyD(clip) {\r\n    if(hitTest(sym.mc_ray, clip)){\r\n        sym.score += 1;\r\n        sym.bunnyAbAmnt+=1;\r\n        clip.stop();\/\/stop current animation queue\r\n        clip.animate( {top: 0}, 200, &quot;linear&quot;, function(){\r\n            bunnyM(clip);\r\n        }\r\n        );\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>If the ray hits the clip (array element) increment the score, STOP the current animation (this is good practice because it prevents issues with the <a href=\"https:\/\/api.jquery.com\/animate\/\" target=\"_blank\">animation queue<\/a> because they are animated with <code>.animate<\/code>, and that can get funky), and then <code>.animate<\/code> them to the top of the screen (abduct them). When the bunny reaches the top of the screen the <code>bunnyM<\/code> function is called again (start over).<\/p>\n<p>AND collision detection case #2 is&#8230;<br \/>\n<em>2) When an enemy ship hit the player.<\/em><\/p>\n<p>This one is simpler.<br \/>\nThere are two intervals in the game that manage enemies. <code>enemyInit();<\/code> and <code>sym.timerInt = setInterval(timer, 100);<\/code><\/p>\n<p>Timer interval takes care of incrementing the time (how long player has played), and setting the score. It also increments enemies. If the score is past <code>lvl1_goal<\/code>, and the player has played long enough more enemies show. Up to 4 enemies can be created at a time (<code>sym.enemyMax<\/code>). If the max has been reached they reset back to 1, and start incrementing again. This simulates &#8220;waves of attacks&#8221;.<\/p>\n<p>This is how <code>timer()<\/code> looks:<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/game timer\r\n\/\/initiates enemies\r\nfunction timer(){\r\n    \/\/set score\r\n    sym.txt_score.html(sym.score);\r\n    \/\/increment time\r\n    sym.time+=1;\r\n    \/\/increment enemies, if the score is past lvl1_goal\r\n    if (sym.time&gt;100 &amp;&amp; sym.score&gt;sym.lvl1_goal-100) {\r\n        sym.time = 1;\r\n        if (sym.enemyAmount&lt;sym.enemyMax) {\r\n            sym.enemyAmount++;\r\n        }\r\n        \/\/no more than 4 enemies, reset it\r\n        if (sym.enemyAmount == sym.enemyMax) {\r\n            sym.enemyAmount = 1;\r\n        }\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>Then there is <code>enemyInit()<\/code>. It initiates the enemies (calls to create the enemy). As you play, and as you progress, the game gets more difficult (more enemies get created).<br \/>\n<code>enemyInit<\/code> is an interval that gets called at random intervals. Difficulty is set by shortening the interval. The game gets harder because <code>enemyInit<\/code> is called more often.<\/p>\n<p>Here is how it looks:<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/enemyInit calls to create the enemy\r\n\/\/as you play, and as you progress\r\n\/\/the game gets more difficutl -- more enemies\r\nfunction enemyInit()\r\n{\r\n    clearInterval(sym.enemyInterval);\r\n    \/\/was (Math.random()*20000)+10000;\r\n    var randNum = (Math.random()*9000)+10000;\r\n    \/\/\r\n    if(sym.score&gt;=sym.lvl1_goal-100){\r\n        randNum = (Math.random()*8000)+9000;\r\n    }\r\n    if(sym.score&gt;=sym.lvl2_goal-200){\r\n        randNum = (Math.random()*5000)+7000;\r\n    }\r\n    if(sym.score&gt;=sym.win_goal-400){\r\n        randNum = (Math.random()*1000)+6000;\r\n    }\r\n    if(sym.score&gt;=sym.win_goal-200){\r\n        randNum = (Math.random()*1000)+5000;\r\n    }\r\n    \/\/if sym.bunnyAbAmnt is above the goal\r\n    \/\/then you may start creating enemies\r\n    if(sym.bunnyAbAmnt&gt;10){\r\n        makeEnemyFire();\r\n        attachEnemyShip();\r\n    };\r\n    \/\/\r\n    sym.enemyInterval = setInterval(enemyInit, randNum);\r\n}\r\n<\/code><\/pre>\n<p>Notice <code>var randNum<\/code> is fairly high at the beginning.<br \/>\nIf the score is above the goal for level 1 shorten it, if the score is above the goal for level 2 shorten it, etc&#8230; When you are just about to win the game is hardest (<code>if(sym.score>=sym.win_goal-200)<\/code>).<br \/>\nThe very last condition keep enemies from being created RIGHT AWAY. This will give the player time to adjust to the game. They must abduct at least 10 bunnies before enemies start appearing.<br \/>\nThe final line (<code>sym.enemyInterval = setInterval(enemyInit, randNum);<\/code>) calls the interval after all that is set up&#8230;<\/p>\n<p>The enemies are created with <code>makeEnemyFire();<\/code> and <code>attachEnemyShip();<\/code><br \/>\n<code>makeEnemyFire()<\/code> serves as a warning that an enemy is approaching. The fire does nothing (has no impact on the player). The Fire appears randomly somewhere under the ship. One shot is fired per enemy that approaches.<\/p>\n<p>This is how it looks<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>function makeEnemyFire(){\r\n    Aud_Laser.play();\r\n    \/\/make as much enemy fire as there are enemies, so going by sym.enemyAmount\r\n    for (var i = 1; i&lt;sym.enemyAmount+1; i++)\r\n    {\r\n        var mc_fire = sym.createChildSymbol(&quot;Fire&quot;, &quot;Stage&quot;).getSymbolElement();\r\n        enemyFire(mc_fire); \r\n    }\r\n}\r\n<\/code><\/pre>\n<p>And <code>enemyFire(...)<\/code> is then called, passing the created symbol as a parameter.<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>function enemyFire(clip)\r\n{\r\n    var randSpeed = (Math.random()*20)+10;\r\n    \/\/enemy fire serves as a warning that an enemy is approaching\r\n    \/\/fire does nothing, it passes the ship,\r\n    \/\/and should appear randomly somewhere under the ship, and over the bunnies\r\n    clip.css({&quot;position&quot;:&quot;absolute&quot;, &quot;top&quot;:Math.ceil(Math.random()*40)+90 + &quot;px&quot;, &quot;left&quot;:-clip.width() + &quot;px&quot;});\r\n    \/\/\r\n    clip.animate( {left: (sym.stage.width()+clip.width())}, 1000, &quot;linear&quot;, function(){\r\n        clip.remove();\/\/get rid of it when it's passed\r\n    }\r\n    );\r\n}\r\n<\/code><\/pre>\n<p><code>enemyFire(...)<\/code> animates the fire. The &#8216;<code>clip<\/code>&#8216; is removed once it has animated to the side of the screen.<br \/>\nI am removing the symbol using <code>.remove()<\/code>. You can also use <code>.deleteSymbol()<\/code>. I am not certain what the difference is so I am sticking to <code>.remove();<\/code> see: <a href=\"http:\/\/api.jquery.com\/remove\/\" target=\"_blank\">http:\/\/api.jquery.com\/remove\/<\/a><\/p>\n<p><code>attachEnemyShip();<\/code> is what creates the enemy, and pushes it to the enemy array. Simply put, it looks like this<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>function attachEnemyShip()\r\n{\r\n    for (var i = 0; i&lt;sym.enemyAmount; i++)\r\n    {\r\n        var mc_enemy = sym.createChildSymbol(&quot;Enemy_Ship&quot;, &quot;Stage&quot;).getSymbolElement();\r\n        sym.arr_enemies.push(mc_enemy);\r\n        enemyShip(mc_enemy);\r\n    }\r\n}\r\n<\/code><\/pre>\n<p><code>enemyShip(...)<\/code> positions, and moves the enemy. Enemies move at a random speed. Here&#8217;s the function<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>function enemyShip(clip)\r\n{\r\n    \/\/position ship - somewhere off screen, at same Y\r\n    var enemyStartX = (Math.random()*-500)-200;\r\n    clip.css({&quot;position&quot;:&quot;absolute&quot;, &quot;top&quot;:sym.enemyY + &quot;px&quot;, &quot;left&quot;:enemyStartX + &quot;px&quot;});\r\n    \/\/random speed\r\n    var randNum = (Math.random()*10000)+5000;\r\n    \/\/move it\r\n    clip.animate({\r\n        left: (sym.stage.width()+clip.width())\r\n        }, {\r\n            duration: randNum, \r\n            queue: false,\r\n            easing: &quot;linear&quot;, \r\n            complete: function(){\r\n                clip.remove();\r\n            }\r\n    });\r\n    \/\/start moving it up\/down -- call the starting movement\r\n    \/\/at random -- either the top most or bottom most\r\n    if(randNum&gt;randNum\/2){\r\n        enemyShip_move2(clip);\r\n    }else{\r\n        enemyShip_move4(clip);\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>I&#8217;m doing something different here for enemy movement. Enemies move in an &#8220;8 step&#8221; up\/down pattern (separated into respective functions).<br \/>\nI use <code>.animate<\/code> to call the next function when a certain movement is done. This simulates the ship flying up\/down exactly how I want them (it&#8217;s very specific). They fly up, and stay just above the player giving the player a window to dodge UNDER them, OR move down and stay under the player giving the player a short window to dodge OVER them. Each enemy should randomly start on the lower level, or upper level. <\/p>\n<p>Here are all 8 of the movement functions:<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/enemy ship comes in 8 steps using .anmiate to call the next when a movement is done\r\n\/\/this simulates the ship flying up\/down exactly how I want it\r\n\/\/I'm certain there are better ways of doing this, if so let me know!\r\n\/\/\r\n\/\/the starting function is called at random -- in enemyShip(clip);\r\n\/\/so when there are multiple enemies there is a random flying pattern to doge\r\nvar enemyBounceSpeed = 500; \/\/the speed of up\/down movement -- should last 0.3 seconds\r\nfunction enemyShip_move1(clip){\r\n    clip.animate({\r\n        top: 83\r\n        }, { \r\n            duration: enemyBounceSpeed, \r\n            queue: false, \r\n            easing: &quot;easeInCubic&quot;, \r\n            complete: function(){\r\n                enemyShip_move2(clip);\r\n            }\r\n    });\r\n}\r\nfunction enemyShip_move2(clip){\r\n    clip.animate({\r\n        top: 120\r\n        }, { \r\n            duration: enemyBounceSpeed, \r\n            queue: false, \r\n            easing: &quot;easeOutCubic&quot;, \r\n            complete: function(){\r\n                enemyShip_move3(clip);\r\n            }\r\n    });\r\n}\r\nfunction enemyShip_move3(clip){\r\n    clip.animate({\r\n        top: 60\r\n        }, { \r\n            duration: enemyBounceSpeed, \r\n            queue: false, \r\n            easing: &quot;easeInCubic&quot;, \r\n            complete: function(){\r\n                enemyShip_move4(clip);\r\n            }\r\n    });\r\n}\r\nfunction enemyShip_move4(clip){\r\n    clip.animate({\r\n        top: 25\r\n        }, { \r\n            duration: enemyBounceSpeed, \r\n            queue: false, \r\n            easing: &quot;easeOutCubic&quot;, \r\n            complete: function(){\r\n                enemyShip_move1(clip);\r\n            }\r\n    });\r\n}\r\n<\/code><\/pre>\n<p>notice in the ending condition in <code>enemyShip(...)<\/code><\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>    \/\/start moving it up\/down -- call the starting movement\r\n    \/\/at random -- either the top most or bottom most\r\n    if(randNum&gt;randNum\/2){\r\n        enemyShip_move2(clip);\r\n    }else{\r\n        enemyShip_move4(clip);\r\n    }\r\n<\/code><\/pre>\n<p>This is what calls the random top most or bottom most starting function. I did this because, when there are multiple enemies created, they will sometimes fly in zig-zag (like scissors) and the player has to time his movement carefully to dodge between them. It makes for a fun challenge. The player must pay attention.<br \/>\nI&#8217;m certain there are <strong>many<\/strong> better ways of doing this (managing enemy movement), but this seemed the best\/simplest to me.<\/p>\n<p>AND FINALLY enemy collision detection takes place as a <code>setInterval<\/code>. <code>sym.shipHitInterval = setInterval(enemyHit , 100);<\/code><br \/>\n<code>shipHitInterval<\/code> calls <code>enemyHit<\/code> and this is what checks for ship vs. enemy colision. <code>enemyHit<\/code> looks like this<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\r\n\/\/DEATH\r\n\/\/was the player hit by an enemy ship?\r\nfunction enemyHit(){\r\n    \/\/\r\n    for(var i = 0; i&lt;sym.arr_enemies.length; ++i){\r\n    \/\/\r\n        if(hitTest(sym.mc_ship, sym.arr_enemies[i])){\r\n            \/\/create and place an explosion on the ship coords\r\n            var mc_explode = sym.createChildSymbol(&quot;Explode&quot;, &quot;Stage&quot;).getSymbolElement();\r\n            mc_explode.css({&quot;position&quot;:&quot;absolute&quot;, &quot;top&quot;:sym.mc_ship.position().top + &quot;px&quot;, &quot;left&quot;:sym.mc_ship.position().left+ &quot;px&quot;});\r\n            \/\/\r\n            Aud_Explode.play();\r\n            sym.arr_enemies[i].stop();\r\n            sym.arr_enemies[i].remove();\r\n            \/\/you lose\r\n            sym.SCENE = &quot;lose&quot;;\r\n            stopG();\r\n        }\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>Because all enemies are stored in an array I loop through the contents of this array, and run the <code>hitTest(...)<\/code> on player and enemies.<br \/>\nIf a collision takes place the &#8220;death&#8221; explosion is placed where the player ship is, the explosion sound plays, and the current enemy is stopped and removed. You lose, and the game is stopped. (<code>stopG()<\/code> kills the game).<\/p>\n<p>This is a simple game, so the above method will work, but it is inefficient in that every 100 milliseconds the game must loop through all <em>enemies created<\/em> vs. <em>player<\/em> to check if a collision took place. For something larger performance would suffer&#8230; but it&#8217;s ok for this because it&#8217;s little.<\/p>\n<p>*************<\/p>\n<p><strong>Keyboard Controls, The Player Ship, and The Beam<\/strong><\/p>\n<p>The player ship, and the player beam are probably the simplest symbols here.<br \/>\nThere are two functions that manage their creation, and removal.<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\r\n\/\/Player\r\n\/\/create and place ship and beam\r\nfunction createSprites() {\r\n    sym.mc_ship = sym.createChildSymbol(&quot;Ship&quot;, &quot;Stage&quot;).getSymbolElement();\r\n    sym.mc_ship.css({&quot;position&quot;:&quot;absolute&quot;, &quot;top&quot;:sym.shipY + &quot;px&quot;, &quot;left&quot;:sym.shipX + &quot;px&quot;});\r\n        \/\/\r\n    sym.mc_ray = sym.createChildSymbol(&quot;Ray&quot;, &quot;Stage&quot;).getSymbolElement();\r\n    sym.mc_ray.css({&quot;position&quot;:&quot;absolute&quot;, &quot;top&quot;:sym.rayY + &quot;px&quot;, &quot;left&quot;:sym.shipX + &quot;px&quot;});\r\n    sym.mc_ray.hide();\r\n}\r\n\r\nfunction removeSprites(){\r\n    sym.mc_ship.stop();\r\n    sym.mc_ray.stop();\r\n    sym.mc_ship.remove();\r\n    sym.mc_ray.remove();\r\n}\r\n<\/code><\/pre>\n<p>The first creates it, the second removes it. Like I said, I am removing the symbols using <code>.remove()<\/code>. You can also use <code>.deleteSymbol()<\/code>. See: <a href=\"http:\/\/api.jquery.com\/remove\/\" target=\"_blank\">http:\/\/api.jquery.com\/remove\/<\/a> for more information on .remove.<\/p>\n<p>After this, it becomes a matter of moving the ship left\/right, and triggering the beam when you press SPACE.<br \/>\nWe&#8217;ve already covered the SPACE keyboard event in the above collision detection section:<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/creating function with sym.\r\n\/\/to change scope so keyboard events can access these\r\nsym.key_onKeyDown = function() {\r\n    sym.mc_ray.show();\r\n    Aud_BeamLoop.play();\r\n    \/\/hit detection\r\n    for (var i = 0; i&lt;sym.arr_bunnies.length; ++i){\r\n          bunnyD(sym.arr_bunnies[i]);\r\n    }\r\n};\r\nsym.key_onKeyUp = function() {\r\n    Aud_BeamLoop.stop();\r\n    sym.mc_ray.hide();\r\n}\r\n<\/code><\/pre>\n<p>The rest is taken care of in <code>document.keydown<\/code>, and <code>document.keyup<\/code>.<\/p>\n<p>Taking a look at <code>document.keydown<\/code>, you will see<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/GAME KEYBOARD\r\n\/\/add others according to behavior for desired &quot;SCENE&quot;\r\n\/\/example: if it is main menu then enable main menu keyboard functionality\r\n\/\/if it is game then enable game keyboard functionality\r\n\r\n\/\/GAME\r\nif(sym.SCENE == &quot;game&quot;){\r\n    \/\/32 is SPACE\r\n    if (e.which == 32) {\r\n        \/\/call the function on the stage's &quot;game trigger&quot;\r\n        sym.getComposition().getStage().key_onKeyDown();\r\n    }\r\n    \/\/37 is LEFT\r\n    if (e.which == 37){\r\n        \/\/keeps it from &quot;crawling&quot; if key is pressed while ship is close to left of screen\r\n        sym.playerSpeed_left = (sym.mc_ship.position().left);\r\n        sym.bool_left = true;\r\n    }\r\n    \/\/39 is RIGHT\r\n    if (e.which == 39){\r\n        \/\/keeps it from &quot;crawling&quot; if key is pressed while ship is close to right of screen\r\n        sym.playerSpeed_right = (sym.stage.width()-(sym.mc_ship.position().left));\r\n        sym.bool_right = true;\r\n    }\r\n    \/\/player movement\r\n    \/\/is an interval - target left\/right location are the sides of the screen\r\n    \/\/if the keyboard key is released .anmiate is stopped\/canceled (see keyup)\r\n    \/\/there are a number of ways to animate with css\/js http:\/\/www.dehats.com\/drupal\/node\/120\r\n    \/\/has some good examples. I've chosen .animate here, and because the target are the edges\r\n    \/\/of the screen it will continue to move there untill you release the key\r\n    \/\/it will also not go off the screen...\r\n    if(sym.bool_left){\r\n        sym.mc_ship.animate( {left: sym.minX}, {duration: sym.playerSpeed_left, easing: &quot;linear&quot;} );\r\n        sym.mc_ray.animate( {left: sym.minX}, {duration: sym.playerSpeed_left, easing: &quot;linear&quot;} );\r\n    }\r\n    if(sym.bool_right){\r\n        sym.mc_ship.animate( {left: sym.maxX}, {duration: sym.playerSpeed_right, easing: &quot;linear&quot;} );\r\n        sym.mc_ray.animate( {left: sym.maxX}, {duration: sym.playerSpeed_right, easing: &quot;linear&quot;} );\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>The two variables that are set:<br \/>\n<code>sym.playerSpeed_left = (sym.mc_ship.position().left);<br \/>\nsym.playerSpeed_right = (sym.stage.width()-(sym.mc_ship.position().left));<\/code><br \/>\nWill make the ship keep a steady speed (duration) even when close to the sides of the screen. The ship moves using <code>.animate<\/code> (see the last two <code>if<\/code> conditions). If I don&#8217;t do this, then, when the ship is closest to its target left\/right, it will crawl there. This is not good for a game, so I make sure to always update the speed according to ship position.<\/p>\n<p>The last two conditions are what take care of moving (if the key is pressed &#8212; <code>sym.bool_left<\/code> and <code>sym.bool_right<\/code>). The <code>.animate<\/code> target is always the sides of the screen. This way I don&#8217;t have to write a collision detection to stop the ship, it will just never go further than that.<br \/>\nBoth the ship and the ray are moved to the same location.<\/p>\n<p>Stopping the ship and ray takes place in <code>document.keyup<\/code>. This is how it looks<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/GAME\r\nif(sym.SCENE == &quot;game&quot;){\r\n    \/\/32 is SPACE\r\n    if (e.which == 32) {\r\n        sym.getComposition().getStage().key_onKeyUp();\r\n    }\r\n    \/\/37 is LEFT\r\n    if (e.which == 37){\r\n        sym.bool_left = false;\r\n    }\r\n    \/\/39 is RIGHT\r\n    if (e.which == 39){\r\n        sym.bool_right = false;\r\n    }\r\n    \/\/stop movement and cancel anything queue -- prevents animation queue buildup\r\n    if(!sym.bool_left &amp;&amp; !sym.bool_right){\r\n        sym.mc_ship.animate( {left: sym.mc_ship.position().left}, {duration: sym.playerSpeed, easing: &quot;linear&quot;} );\r\n        sym.mc_ship.finish();\r\n        sym.mc_ray.finish();\r\n        \/\/force placement of ray back to ship's x...\r\n        sym.mc_ray.css({&quot;position&quot;:&quot;absolute&quot;, &quot;top&quot;:sym.rayY + &quot;px&quot;, &quot;left&quot;:sym.mc_ship.position().left + &quot;px&quot;});\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>Condition 3 and 4 (<code>if (e.which == 37)<\/code> and <code>if (e.which == 39)<\/code>) set the booleans for <code>if<\/code> left\/right is down to <code>false<\/code>.<br \/>\nThe last bit &#8220;stops&#8221; the ship if these are false. It is stopped by setting the target <code>.animate<\/code> to the ships current\/last position. I do this to avoid issues with the animation queue (which can present issues when working with jquery <code>.animate<\/code> see: <a href=\"http:\/\/stackoverflow.com\/questions\/1058158\/can-somebody-explain-jquery-queue-to-me\" target=\"_blank\">StackOverflow &#8211; Can somebody explain jQuery queue to me?<\/a> for explanation) <code>.finish<\/code> is called to clear the queue and jump to the end value (which would be: <code>sym.mc_ship.animate( {left: sym.mc_ship.position().left}, {duration: sym.playerSpeed, easing: \"linear\"} );<\/code> ).<br \/>\nThe very last bit places the ray right under the ship.<\/p>\n<p>I&#8217;m certain there are many better ways of doing this, but this is how I chose to do it.<\/p>\n<p>*************<\/p>\n<p><strong>HIGHSCORES &#8211; LEADERBOARDS<\/strong><\/p>\n<p>I won&#8217;t implement an elaborate version here. For those interested here are some good resources for making your own:<\/p>\n<p>Using Playtomic API: <a href=\"http:\/\/gmc.yoyogames.com\/index.php?showtopic=538699\" target=\"_blank\">http:\/\/gmc.yoyogames.com\/index.php?showtopic=538699<\/a><br \/>\nAdd online highscores to your HTML5 games: <a href=\"http:\/\/gmc.yoyogames.com\/index.php?showtopic=525654\" target=\"_blank\">http:\/\/gmc.yoyogames.com\/index.php?showtopic=525654<\/a><\/p>\n<p>For simplicity&#8217;s sake, I will be using <code>localStorage<\/code>:<br \/>\n<a href=\"http:\/\/coding.smashingmagazine.com\/2010\/10\/11\/local-storage-and-how-to-use-it\/\" target=\"_blank\">Local Storage And How To Use It On Websites<\/a><br \/>\n<a href=\"http:\/\/hacks.mozilla.org\/2009\/06\/localstorage\/\" target=\"_blank\">Saving data with localStorage<\/a><\/p>\n<p>Highscores, and player name, will be stored locally. This will also give people a prototype of using <code>localStorage<\/code> with Edge Animate.<\/p>\n<p>What I came up with is to use <code>bootstrapCallback<\/code> in the html file, do a check if the user&#8217;s browser supports <code>localStorage<\/code>, and create a <code>setScore<\/code> and <code>getScore<\/code> function assigned to stage ( <code>AdobeEdge.getComposition(compId).getStage()<\/code> ).<br \/>\nHere (underneath <code>< ! -- Adobe Edge Runtime End -- ><\/code> ):<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>&lt;script type=&quot;text\/javascript&quot;&gt;\r\n    \/\/handle localStorage &quot;highscores&quot; here...\r\n    var comp;\r\n    \/\/callback\r\n    AdobeEdge.bootstrapCallback(function(compId) {\r\n        comp = AdobeEdge.getComposition(compId).getStage();\r\n        \/\/check if local storage is supported (browser)\r\n        if(typeof(Storage)!==&quot;undefined&quot;){\r\n            console.log(&quot;localStorage is supported.&quot;);\r\n            \/\/if it's supported create this functions on\/to stage\r\n            \/\/usage: sym.getComposition().getStage().setScore(&quot;50&quot;);\r\n            \/\/SCORE:\r\n            comp.setScore = function(plyr_score){\r\n                localStorage.setItem(&quot;score&quot;, plyr_score);\r\n                console.log(&quot;setScore called. plyr_score: &quot; + plyr_score);\r\n            }\r\n            comp.getScore = function(){\r\n                return localStorage.getItem(&quot;score&quot;);\r\n                console.log(&quot;getScore called.&quot;);\r\n            }\r\n            \/\/NAME:\r\n            comp.setName = function(plyr_name){\r\n                localStorage.setItem(&quot;name&quot;, plyr_name);\r\n                console.log(&quot;setName called. plyr_name: &quot; + plyr_name);\r\n            }\r\n            comp.getName = function(){\r\n                return localStorage.getItem(&quot;name&quot;);\r\n                console.log(&quot;getName called.&quot;);\r\n            }\r\n        }else{\r\n            \/\/ browser is too old -- or no web storage support\r\n            window.alert(&quot;Your browser does not support web storage. Score will not be saved.&quot;);\r\n        }\r\n    });\r\n&lt;\/script&gt;\r\n<\/code><\/pre>\n<p>Simple! Read up on web storage here: <a href=\"http:\/\/dev.w3.org\/html5\/webstorage\/\" target=\"_blank\">http:\/\/dev.w3.org\/html5\/webstorage\/<\/a><br \/>\nHere: <a href=\"http:\/\/www.w3schools.com\/html\/html5_webstorage.asp\" target=\"_blank\">http:\/\/www.w3schools.com\/html\/html5_webstorage.asp<\/a><br \/>\nAnd: <a href=\"http:\/\/html5laboratory.com\/local-storage.php\" target=\"_blank\">Using localStorage<\/a><br \/>\nAnd, again, here: <a href=\"http:\/\/hacks.mozilla.org\/2009\/06\/localstorage\/\" target=\"_blank\">http:\/\/hacks.mozilla.org\/2009\/06\/localstorage\/<\/a><\/p>\n<p>In this instance I save only the most recent <em>name<\/em> and <em>score<\/em> (just one), but you could easily built on it and save more.<\/p>\n<p>For an example of how this works in the game refer to the &#8220;name submission window&#8221; (Symbol: <code>Screen_Score<\/code>):<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/playarea02.png\" alt=\"\" \/><\/p>\n<p>The text field is called &#8220;<code>txt_name<\/code>&#8220;.<\/p>\n<p>The code that sets it up is as follows<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/ prepare input field\r\nvar namefield = sym.$(&quot;txt_name&quot;)\r\nnamefield.html(&quot;Name, plz: &quot;);\r\ninputName = $('&lt;input \/&gt;').attr({'type':'text', 'value':'x', 'id':'plyr_name'});\/\/id must be unique\r\ninputName.appendTo(namefield);\r\n<\/code><\/pre>\n<p>Basically this creates and appends an input text field, with id &#8220;<code>plyr_name<\/code>&#8220;, to <code>txt_name<\/code>.<\/p>\n<p>The end result will look like this<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/nametxt.png\" alt=\"\" \/><\/p>\n<p>The button (<code>Btn_OK<\/code>) is where all the action happens.<br \/>\nIt has a click event, which looks like<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/get the value and send to localStorage!\r\nvar _score = sym.getComposition().getStage().score;\r\nvar _name = plyr_name.value;\r\n\/\/\r\nsym.getComposition().getStage().setScore(_score);\r\nsym.getComposition().getStage().setName(_name);\r\n\/\/go to the &quot;scores&quot; scene\r\nsym.getComposition().getStage().gotoScores();\r\n<\/code><\/pre>\n<p>The first two variables get the values to send to <code>localStorage<\/code>. <code>_score<\/code> gets the player&#8217;s score from stage, and <code>_name<\/code> gets what the user just input into the text field (the assigned id &#8216;<code>plyr_name<\/code>&#8216;).<br \/>\nAfter that we call the two javascript functions created earlier in our <code>AdobeEdge.bootstrapCallback<\/code>.<br \/>\nBecause we assigned them to &#8216;<code>comp<\/code>&#8216; (the stage) we can easily call them. We send the variables <code>_score<\/code>, and <code>_name<\/code> to their respective javascript functions. Done! Now the player name and score is saved!<br \/>\nThe last one calls a function which just sends the timeline to go to the score screen.<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/done submitting scores, and playing, go to the scores scene\r\n\/\/leaves the game -- called in Screen_Score\r\nsym.gotoScores = function(){\r\n    sym.SCENE = &quot;scores&quot;;\r\n    sym.stop(&quot;scores&quot;);\r\n}\r\n<\/code><\/pre>\n<p>The very same thing happens a final time when the player wins.<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/nametxt02.png\" alt=\"\" \/><\/p>\n<p>Showing the scores is just as simple. There is a label, and trigger (with code) on the main timeline<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/scores.png\" alt=\"\" \/><\/p>\n<p>It will look like this, live<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/scores02.png\" alt=\"\" \/><\/p>\n<p>The code for it is as follows<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>sym.SCENE = &quot;scores&quot;;\r\nsym.stop();\r\n\r\n\/\/sound\r\nAud_ScoresTrack.play();\r\n\r\n\/\/get and set record holder (player + score + funny little comment)\r\nvar scr_plyrName = sym.getComposition().getStage().getName();\r\nvar scr_plyrScore = sym.getComposition().getStage().getScore();\r\n\r\n\/\/the funny comment\r\nvar arr_scoreMsg = [&quot;Such an excellent role model!&quot;, &quot;It was a magnificent harvest!&quot;, &quot;The harvest was great!&quot;, &quot;It was a sight to see!&quot;, &quot;Such excellence will not go unnoticed!&quot;];\r\nvar rand_scoreNum = Math.ceil(Math.random()*arr_scoreMsg.length)-1;\r\nvar rand_msg = arr_scoreMsg[rand_scoreNum];\r\n\/\/if it returns null then set it to one\r\nif(arr_scoreMsg[rand_scoreNum] == undefined){\r\n    rand_msg = arr_scoreMsg[0];\r\n}\r\n\/\/create the message\r\nvar msg_score = &quot;The latest record holder is, &quot; + scr_plyrName + &quot;, who abducted, &quot; + scr_plyrScore + &quot; rabbits. &quot; + rand_msg;\r\n\/\/if player hasn't played yet, and there is nothing to show in getName or getScore...\r\nif(scr_plyrScore == undefined){\r\n    msg_score = &quot;Nothing here, move along.&quot;\r\n}\r\n\/\/set the message\r\nsym.$(&quot;txt_highscore&quot;).html(msg_score);\r\n<\/code><\/pre>\n<p>The variables <code>scr_plyrName<\/code> and <code>scr_plyrScore<\/code> make a call to our two <code>AdobeEdge.bootstrapCallback<\/code> javascript functions that return the saved name, and score.<\/p>\n<p>The bit bellow that creates a random &#8220;funny comment&#8221; &#8212; chosen at random from an array and set as variable <code>rand_msg<\/code>.<\/p>\n<p>Bellow that the message is created, stringing <code>scr_plyrName<\/code>, <code>scr_plyrScore<\/code>, and <code>rand_msg<\/code> together. The variable <code>msg_score<\/code> is set to that.<br \/>\nThen the text field is set to <code>msg_score<\/code>: <code>sym.$(\"txt_highscore\").html(msg_score);<\/code><\/p>\n<p>Simple!<\/p>\n<p>*************<\/p>\n<p><strong>TIMERS<\/strong><\/p>\n<p>There are 5 &#8220;timers&#8221; in the game. These are <code>setIntervals<\/code>, and run at varying intervals.<br \/>\nAs I&#8217;ve already described, in <code>document.compositionReady<\/code>:<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/Timers - intervals\r\nsym.timerInt;\r\nsym.timeElapsedInt;\r\nsym.nightmareInterval;\r\nsym.enemyInterval;\r\nsym.shipHitInterval;\r\n<\/code><\/pre>\n<p>These are set in <code>resumeG()<\/code> in the &#8220;game&#8221; trigger:<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>    enemyInit();\r\n    nightmareInit();  \r\n    sym.timerInt = setInterval(timer, 100);\r\n    sym.timeElapsedInt = setInterval(elapsed, 100);\r\n    sym.shipHitInterval = setInterval(enemyHit , 100);\r\n<\/code><\/pre>\n<p>We already covered <code>timer()<\/code>, <code>enemyHit()<\/code>, and <code>enemyInit()<\/code> above in the <em>Collision Detection<\/em> section, but here is a rundown of what they all are.<\/p>\n<p><code>enemyInit();<\/code> &#8212; Initiates the enemies, and sets the difficulty (the closer to winning you are the more enemies are created).<\/p>\n<p><code>nightmareInit();<\/code> &#8212; Plays (hides\/shows) the bunny&#8217;s nightmare. While you are playing a little comic book like star panel shows on the side depicting what the bunny is dreaming (all those dreadful things that will happen to him!).<br \/>\nIt looks like this:<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/Bunny nightmare pannel\r\n\/\/bad dreams ocasionally show up acompanied with a sound\r\nfunction nightmareInit() {\r\n    clearInterval(sym.nightmareInterval);\r\n    var randNum = (Math.random()*10000)+10000;\r\n    sym.mc_nightmare.play();\r\n    Aud_Nightmare.play();\r\n    \/\/start again\r\n    sym.nightmareInterval = setInterval(nightmareInit, randNum);\r\n}\r\n<\/code><\/pre>\n<p>It shows at random by clearing the last interval, and calling itself again at a random interval.<\/p>\n<p><code>timer();<\/code> &#8212; <code>sym.timerInt = setInterval(timer, 100);<\/code> &#8212; This updates the score textbox with the current score, and increments the time between enemy increments. If time hits 100 then the <code>enemyAmount<\/code> is incremented. There cannot be more than a certain amount of enemies (<code>enemyMax<\/code>), so the enemies, and counter are regularly reset when it reaches the maximum amount of enemies. This simulates &#8220;waves of attacks&#8221;.<br \/>\nAgain, <code>timer();<\/code> looks like this:<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/game timer\r\n\/\/initiates enemies\r\nfunction timer(){\r\n    \/\/set score\r\n    sym.txt_score.html(sym.score);\r\n    \/\/increment time\r\n    sym.time+=1;\r\n    \/\/increment enemies, if the score is past lvl1_goal\r\n    if (sym.time&gt;100 &amp;&amp; sym.score&gt;sym.lvl1_goal-100) {\r\n        sym.time = 1;\r\n        if (sym.enemyAmount&lt;sym.enemyMax) {\r\n            sym.enemyAmount++;\r\n        }\r\n        \/\/no more than 4 enemies, reset it\r\n        if (sym.enemyAmount == sym.enemyMax) {\r\n            sym.enemyAmount = 1;\r\n        }\r\n    }\r\n}\r\n<\/code><\/pre>\n<p><code>elapsed();<\/code> &#8212; <code>sym.timeElapsedInt = setInterval(elapsed, 100);<\/code> &#8212; This is the leveling system. It is also what triggers the &#8220;win&#8221;.<br \/>\nIf your <code>timeElapsed<\/code> is above the <code>win_time<\/code> (to keep people from winning too fast), and the score is above the <code>win_goal<\/code>, the game is beat! It stops the game, clears everything, and plays the win animation.<br \/>\nHere is how it looks:<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/leveling system\r\nfunction elapsed() {\r\n    sym.timeElapsed += 1;\r\n    \/\/win\r\n    if (sym.timeElapsed&gt;sym.win_time &amp;&amp; sym.score&gt;sym.win_goal) {\r\n        console.log(&quot;You win.&quot;);\r\n        sym.SCENE = &quot;win&quot;;\r\n        \/\/play();\r\n        stopG();\r\n        sym.$(&quot;Screen_End&quot;).hide();\/\/hide gameover\r\n        sym.play();\r\n    }\r\n    \/\/.data to keep it .play() called once\r\n    if ((sym.timeElapsed&gt;sym.lvl2_time &amp;&amp; sym.score&gt;sym.lvl2_goal) &amp;&amp; sym.mc_b2_data != false) {\r\n        randHit();\r\n        sym.mc_transition.play(&quot;transition&quot;);\/\/blink\r\n        sym.mc_b2.play();\r\n        sym.mc_b2_data = false;\r\n    }\r\n    if ((sym.timeElapsed&gt;sym.lvl1_time &amp;&amp; sym.score&gt;sym.lvl1_goal) &amp;&amp; sym.mc_b1_data != false) {\r\n        randHit();\r\n        sym.mc_transition.play(&quot;transition&quot;);\/\/blink\r\n        sym.mc_b1.play();\r\n        sym.mc_b1_data = false;\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>The other two conditions are what set &#8220;next level&#8221;. If you met your goal then the screen blinks, and the bunny gets pulled out of its bed. A random hit sound (<code>randHit();<\/code>) also plays with this event. Next level.<\/p>\n<p><code>enemyHit();<\/code> &#8212; <code>sym.shipHitInterval = setInterval(enemyHit , 100);<\/code> &#8212; has already been covered in the <em>Collision Detection<\/em> section above. This is what continuously checks if the ship has been hit by an enemy.<\/p>\n<p>*************<\/p>\n<p><strong>Starting &#038; Stopping The Game<\/strong><\/p>\n<p>Starting and stopping the game takes place in two functions (on the &#8220;<code>game<\/code>&#8221; timeline trigger). Starting is responsible for setting or re-setting the game, and starting it up again.<br \/>\nIt looks like this:<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/resumeG functions both as init() and resuming\r\n\/\/if the player loses, the game is cleared in stopG(),\r\n\/\/and this would be called to start a fresh one\r\n\/\/so this is setting all values to their default state\r\n\/\/as well as creating all new sprites\r\nfunction resumeG() {\r\n    sym.SCENE = &quot;game&quot;; \/\/set to game so game keyboard input will work\r\n    sym.score = 1;    \r\n    sym.mc_b1.stop(0);\r\n    sym.mc_b2.stop(0);\r\n    sym.mc_b1_data = true;\r\n    sym.mc_b2_data = true;\r\n    sym.bunnyAbAmnt = 0;\r\n    \/\/clear\/reset arrays\r\n    \/\/there are a number of ways to do this, for example: \r\n    \/\/http:\/\/stackoverflow.com\/questions\/1232040\/how-to-empty-an-array-in-javascript\r\n    \/\/but keeping it simple...\r\n    sym.arr_bunnies = [];\r\n    sym.arr_enemies = [];\r\n    \/\/start the music\r\n    Aud_GameTrack.play().fadeIn();\r\n    sym.$(&quot;Screen_End&quot;).hide();\/\/hide mc_gameover\r\n    sym.$(&quot;Screen_Score&quot;).hide();\/\/hide the &quot;your name here&quot; screen\r\n    createSprites();\r\n    makeBunny();\r\n    enemyInit();\r\n    nightmareInit();  \r\n    sym.timerInt = setInterval(timer, 100);\r\n    sym.timeElapsedInt = setInterval(elapsed, 100);\r\n    sym.shipHitInterval = setInterval(enemyHit , 100);\r\n    \/\/\r\n    \/\/removeEnemyShip();\r\n    \/\/reset vars\r\n    sym.time = 1;\r\n    sym.enemyAmount = 1;\r\n    sym.timeElapsed = 1;\r\n    \/\/set these values AFTER sprites have been created\r\n    sym.maxX = sym.stage.width()-sym.mc_ship.width();\r\n    sym.minX = 0;\r\n}\r\n\r\n\/\/Start game\r\nresumeG();\r\n<\/code><\/pre>\n<p><code>sym.SCENE<\/code> is set to &#8220;<code>game<\/code>&#8221; again. Reset score, and all necessary symbols (like putting the bunnies back in their bed).<br \/>\nThe arrays are also cleared out (reset).<br \/>\nThe game soundtrack is started again, and the two screens (<code>Screen_End<\/code>, and <code>Screen_Score<\/code>) are both hidden. Incase they where open.<br \/>\nAfter arrays are cleared, sprites are created again.<br \/>\nAll intervals\/&#8221;timers&#8221; (as just described above) are also started.<br \/>\nThen reset the last variables (<code>time<\/code>, <code>enemyAmount<\/code>, and <code>timeElapsed<\/code>).<br \/>\nThe last two <code>maxX<\/code>, and <code>minX<\/code> set the desired bounds for ship movement.<\/p>\n<p><code>stopG()<\/code> does the opposite. It serves as the &#8220;game over&#8221; function. It works with <code>Screen_End<\/code>:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/gameover.png\" alt=\"\" \/><\/p>\n<p>This is how the function looks:<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/stops the game\r\n\/\/this clears the current game\r\n\/\/to start it again call resumeG();\r\nfunction stopG() {\r\n    SoundMixer_stopAll();\r\n    \/\/set player score message for if this is gameover\r\n    sym.mc_gameover.$(&quot;txt_plyr_score&quot;).html(&quot;You score &quot;+sym.score+&quot;!&quot;);\r\n    \/\/\r\n    randHit();\r\n    Aud_Explode.play();\r\n    \/\/show gameover\r\n    sym.$(&quot;Screen_End&quot;).show();\r\n    \/\/\r\n    removeEnemyShip();\r\n    removeSprites();\r\n    removeBunny();\r\n    clearInterval(sym.timerInt);\r\n    clearInterval(sym.nightmareInterval);\r\n    clearInterval(sym.enemyInterval);\r\n    clearInterval(sym.timeElapsedInt);\r\n    clearInterval(sym.shipHitInterval);\r\n}\r\n<\/code><\/pre>\n<p>The first 8 lines manage the game over event, as well as show the game over screen (<code>Screen_End<\/code>). In cases where I don&#8217;t want a game over, I call this same function, but just hide <code>Screen_End<\/code> (<code>sym.$(\"Screen_End\").hide()<\/code>). You&#8217;ll have noticed this in <code>elapsed();<\/code>, above.<br \/>\nThe final section removes all created sprites, and clears all intervals.<\/p>\n<p>The remove functions look like this:<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>function removeEnemyShip()\r\n{\r\n    \/\/remove all enemies\r\n    for (var i = 0; i&lt;sym.arr_enemies.length; ++i){\r\n    \/\/You can remove in two ways .remove() or .deleteSymbol()\r\n    \/\/I am not certain what the difference is so I am using .remove()\r\n    \/\/see: http:\/\/api.jquery.com\/remove\/\r\n    \/\/always .stop(); if you are removing a symbol with .animate()\r\n        sym.arr_enemies[i].stop();\r\n        sym.arr_enemies[i].remove();\r\n        \/\/sym.getSymbol(sym.arr_enemies[i]).deleteSymbol();\r\n    }\r\n}\r\n\r\nfunction removeSprites(){\r\n    sym.mc_ship.stop();\r\n    sym.mc_ray.stop();\r\n    sym.mc_ship.remove();\r\n    sym.mc_ray.remove();\r\n}\r\n\r\nfunction removeBunny() {\r\n    \/\/delete bunnies\r\n    \/\/You can remove in two ways .remove() or .deleteSymbol()\r\n    \/\/I am not certain what the difference is so I am using .remove()\r\n    \/\/see: http:\/\/api.jquery.com\/remove\/\r\n    \/\/always .stop(); to cancel the .animate();\r\n    for (var i = 0; i&lt;sym.arr_bunnies.length; ++i){\r\n        sym.arr_bunnies[i].stop();\r\n        sym.arr_bunnies[i].remove();\r\n        \/\/sym.getSymbol(sym.arr_bunnies[i]).deleteSymbol();\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>*************<\/p>\n<p><strong>Going The Extra Mile For Mobile<\/strong><\/p>\n<p>It would be simple, from this point on, to do a mobile check. If the player is on a mobile device, then enable touchscreen controls.<br \/>\nThere are a number of ways to do mobile check. The simplest, and not always most reliable is: <code>if(\/Android|webOS|iPhone|iPad|iPod|BlackBerry\/i.test(navigator.userAgent)){returns true or false};<\/code><br \/>\nThe best would be:<br \/>\n<a href=\"http:\/\/detectmobilebrowsers.com\/\" target=\"_blank\">Detect Mobile Browsers | Open source mobile phone detection<\/a><br \/>\n<a href=\"https:\/\/github.com\/sebarmeli\/JS-Redirection-Mobile-Site\" target=\"_blank\">JS Mobile Redirection<\/a> (Javascript mobile redirection library)<br \/>\nOr refer to this thread: <a href=\"http:\/\/stackoverflow.com\/questions\/11381673\/javascript-solution-to-detect-mobile-browser\" target=\"_blank\">http:\/\/stackoverflow.com\/questions\/11381673\/javascript-solution-to-detect-mobile-browser<\/a><\/p>\n<p>I&#8217;m not going to do this here. I&#8217;m going to be lazy because it&#8217;s Saturday! In the menu I run the simple check, and display a little <code>window.alert<\/code> telling them that the game is not yet compatible with touchscreen.<\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>sym.isMobile = \/Android&#124;webOS&#124;iPhone&#124;iPad&#124;iPod&#124;BlackBerry\/i.test(navigator.userAgent);\r\n\/\/\r\nif (sym.isMobile) { \r\n    \/\/sym.stop();\r\n    window.alert(&quot;Sorry mobile, but this game is not yet compatible for touchscreen devices.&quot;);\r\n}else{\r\n    \/\/you may pass\r\n}\r\n<\/code><\/pre>\n<p>I <a href=\"https:\/\/itunes.apple.com\/us\/app\/offender\/id618430404?ls=1&#038;mt=8\" target=\"_blank\">have it as an App in the App Store<\/a>. Incase you&#8217;re wondering. :)<\/p>\n<p>*************<\/p>\n<p><strong>ALL THE CODE:<\/strong><\/p>\n<p>That&#8217;s it! And, in conclusion, the entire game engine, as comfortably tucked away in <code>Trigger @ 22000 ms<\/code> is as follows:<\/p>\n<p><img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/triggerGame.png\" alt=\"\" \/><\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>sym.stop();\r\n\r\n\/* Score usage:\r\nsym.getComposition().getStage().setScore(&quot;50&quot;);\r\nconsole.log(&quot;SCORE: &quot;+comp.getScore()); \r\n*\/\r\n\r\n\/\/Collision Detection\r\n\/\/simple object intersection hit test because this is a small project\r\n\/\/consider using JQuery Collision http:\/\/sourceforge.net\/projects\/jquerycollision\/\r\n\/\/for more elaborate things -- thanks to Adobe forums for pointing me in the right direction\r\nfunction hitTest(a, b){\r\n    \/\/\r\n    aPos = {x:parseInt(a.css('left')), y:parseInt(a.css('top'))};\r\n    bPos = {x:parseInt(b.css('left')), y:parseInt(b.css('top'))};\r\n    \/\/\r\n    return aPos.x &lt; bPos.x + b.width() &amp;&amp; aPos.x + a.width() &gt; bPos.x &amp;&amp; aPos.y &lt; bPos.y + b.height() &amp;&amp; aPos.y + a.height() &gt; bPos.y\r\n}\r\n\r\n\/\/Player\r\n\/\/create and place ship and beam\r\nfunction createSprites() {\r\n    sym.mc_ship = sym.createChildSymbol(&quot;Ship&quot;, &quot;Stage&quot;).getSymbolElement();\r\n    sym.mc_ship.css({&quot;position&quot;:&quot;absolute&quot;, &quot;top&quot;:sym.shipY + &quot;px&quot;, &quot;left&quot;:sym.shipX + &quot;px&quot;});\r\n        \/\/\r\n    sym.mc_ray = sym.createChildSymbol(&quot;Ray&quot;, &quot;Stage&quot;).getSymbolElement();\r\n    sym.mc_ray.css({&quot;position&quot;:&quot;absolute&quot;, &quot;top&quot;:sym.rayY + &quot;px&quot;, &quot;left&quot;:sym.shipX + &quot;px&quot;});\r\n    sym.mc_ray.hide();\r\n}\r\n\r\nfunction removeSprites(){\r\n    sym.mc_ship.stop();\r\n    sym.mc_ray.stop();\r\n    sym.mc_ship.remove();\r\n    sym.mc_ray.remove();\r\n}\r\n\r\n\/\/Sound\r\n\/\/random &quot;hits&quot; for when bunnies get abducted or player dies\r\nvar randHitArr = [Aud_Hit1_, Aud_Hit2_, Aud_Hit3_];\r\nfunction randHit() {\r\n    var randHit = randHitArr[Math.floor(Math.random()*randHitArr.length)];\r\n    if(randHit == undefined){\r\n        randHit = randHitArr[0];\r\n    }\r\n    randHit.play();\r\n}\r\n\r\n\/\/Bunnies!\r\nfunction bunnyM(clip) {\r\n    \/\/console.log(clip);\r\n    \/\/speed, and end variables\r\n    var bEnd = sym.stage.width()-clip.width();\r\n    var bSpeed = (Math.ceil(Math.random()*sym.bunnySpeed)+sym.bunnySpeed)-500;\r\n    \/\/place it randomly (x) on the stage\r\n    clip.css({&quot;position&quot;:&quot;absolute&quot;, &quot;top&quot;:sym.bunnyY + &quot;px&quot;, &quot;left&quot;:(Math.ceil(Math.random()*sym.stage.width())-clip.width()) + &quot;px&quot;});\r\n    \/\/call first to cancel queue -- just incase this could become a problem\r\n    clip.stop();\r\n    \/\/\r\n    clip.animate( {left: bEnd}, bSpeed, &quot;linear&quot;, function(){\r\n        sym.score -= 1;\/\/&quot;escapee&quot; penalty\r\n        bunnyM(clip);\r\n    }\r\n    );\r\n}\r\n\r\nfunction makeBunny() {\r\n    for (var i = 0; i&lt;sym.bNum; i++) {\r\n        var mc_bunny = sym.createChildSymbol(&quot;Bunny&quot;, &quot;Stage&quot;).getSymbolElement();\r\n        \/\/push to array for access later and start moving it\r\n        \/\/bunnyM also takes care of placeing them\r\n        \/\/note: bunnies must be stored in array\r\n        \/\/for colision detection, and better access\r\n        sym.arr_bunnies.push(mc_bunny);\r\n        bunnyM(mc_bunny);\r\n    }\r\n}\r\n\r\nfunction removeBunny() {\r\n    \/\/delete bunnies\r\n    \/\/You can remove in two ways .remove() or .deleteSymbol()\r\n    \/\/I am not certain what the difference is so I am using .remove()\r\n    \/\/see: http:\/\/api.jquery.com\/remove\/\r\n    \/\/always .stop(); to cancel the .animate();\r\n    for (var i = 0; i&lt;sym.arr_bunnies.length; ++i){\r\n        sym.arr_bunnies[i].stop();\r\n        sym.arr_bunnies[i].remove();\r\n        \/\/sym.getSymbol(sym.arr_bunnies[i]).deleteSymbol();\r\n    }\r\n}\r\n\r\nfunction bunnyD(clip) {\r\n    if(hitTest(sym.mc_ray, clip)){\r\n        sym.score += 1;\r\n        sym.bunnyAbAmnt+=1;\r\n        clip.stop();\/\/stop current animation queue\r\n        clip.animate( {top: 0}, 200, &quot;linear&quot;, function(){\r\n            bunnyM(clip);\r\n        }\r\n        );\r\n    }\r\n}\r\n\r\n\/\/creating function with sym.\r\n\/\/to change scope so keyboard events can access these\r\nsym.key_onKeyDown = function() {\r\n    sym.mc_ray.show();\r\n    Aud_BeamLoop.play();\r\n    \/\/hit detection\r\n    for (var i = 0; i&lt;sym.arr_bunnies.length; ++i){\r\n          bunnyD(sym.arr_bunnies[i]);\r\n    }\r\n};\r\nsym.key_onKeyUp = function() {\r\n    Aud_BeamLoop.stop();\r\n    sym.mc_ray.hide();\r\n}\r\n\r\n\/\/Enemy Ship\r\n\/\/And Enemy Laser\r\n\r\nfunction enemyFire(clip)\r\n{\r\n    var randSpeed = (Math.random()*20)+10;\r\n    \/\/enemy fire serves as a warning that an enemy is approaching\r\n    \/\/fire does nothing, it passes the ship,\r\n    \/\/and should appear randomly somewhere under the ship, and over the bunnies\r\n    clip.css({&quot;position&quot;:&quot;absolute&quot;, &quot;top&quot;:Math.ceil(Math.random()*40)+90 + &quot;px&quot;, &quot;left&quot;:-clip.width() + &quot;px&quot;});\r\n    \/\/\r\n    clip.animate( {left: (sym.stage.width()+clip.width())}, 1000, &quot;linear&quot;, function(){\r\n        clip.remove();\/\/get rid of it when it's passed\r\n    }\r\n    );\r\n}\r\n\r\n\r\nfunction makeEnemyFire(){\r\n    Aud_Laser.play();\r\n    \/\/make as much enemy fire as there are enemies, so going by sym.enemyAmount\r\n    for (var i = 1; i&lt;sym.enemyAmount+1; i++)\r\n    {\r\n        var mc_fire = sym.createChildSymbol(&quot;Fire&quot;, &quot;Stage&quot;).getSymbolElement();\r\n        enemyFire(mc_fire); \r\n    }\r\n}\r\n\r\n\/\/enemy ship comes in 8 steps using .anmiate to call the next when a movement is done\r\n\/\/this simulates the ship flying up\/down exactly how I want it\r\n\/\/I'm certain there are better ways of doing this, if so let me know!\r\n\/\/\r\n\/\/the starting function is called at random -- in enemyShip(clip);\r\n\/\/so when there are multiple enemies there is a random flying pattern to doge\r\nvar enemyBounceSpeed = 500; \/\/the speed of up\/down movement -- should last 0.3 seconds\r\nfunction enemyShip_move1(clip){\r\n    clip.animate({\r\n        top: 83\r\n        }, { \r\n            duration: enemyBounceSpeed, \r\n            queue: false, \r\n            easing: &quot;easeInCubic&quot;, \r\n            complete: function(){\r\n                enemyShip_move2(clip);\r\n            }\r\n    });\r\n}\r\nfunction enemyShip_move2(clip){\r\n    clip.animate({\r\n        top: 120\r\n        }, { \r\n            duration: enemyBounceSpeed, \r\n            queue: false, \r\n            easing: &quot;easeOutCubic&quot;, \r\n            complete: function(){\r\n                enemyShip_move3(clip);\r\n            }\r\n    });\r\n}\r\nfunction enemyShip_move3(clip){\r\n    clip.animate({\r\n        top: 60\r\n        }, { \r\n            duration: enemyBounceSpeed, \r\n            queue: false, \r\n            easing: &quot;easeInCubic&quot;, \r\n            complete: function(){\r\n                enemyShip_move4(clip);\r\n            }\r\n    });\r\n}\r\nfunction enemyShip_move4(clip){\r\n    clip.animate({\r\n        top: 25\r\n        }, { \r\n            duration: enemyBounceSpeed, \r\n            queue: false, \r\n            easing: &quot;easeOutCubic&quot;, \r\n            complete: function(){\r\n                enemyShip_move1(clip);\r\n            }\r\n    });\r\n}\r\n\r\nfunction enemyShip(clip)\r\n{\r\n    \/\/position ship - somewhere off screen, at same Y\r\n    var enemyStartX = (Math.random()*-500)-200;\r\n    clip.css({&quot;position&quot;:&quot;absolute&quot;, &quot;top&quot;:sym.enemyY + &quot;px&quot;, &quot;left&quot;:enemyStartX + &quot;px&quot;});\r\n    \/\/random speed\r\n    var randNum = (Math.random()*10000)+5000;\r\n    \/\/move it\r\n    clip.animate({\r\n        left: (sym.stage.width()+clip.width())\r\n        }, {\r\n            duration: randNum, \r\n            queue: false,\r\n            easing: &quot;linear&quot;, \r\n            complete: function(){\r\n                clip.remove();\r\n            }\r\n    });\r\n    \/\/start moving it up\/down -- call the starting movement\r\n    \/\/at random -- either the top most or bottom most\r\n    if(randNum&gt;randNum\/2){\r\n        enemyShip_move2(clip);\r\n    }else{\r\n        enemyShip_move4(clip);\r\n    }\r\n}\r\n\r\n\/\/DEATH\r\n\/\/was the player hit by an enemy ship?\r\nfunction enemyHit(){\r\n    \/\/\r\n    for(var i = 0; i&lt;sym.arr_enemies.length; ++i){\r\n    \/\/\r\n        if(hitTest(sym.mc_ship, sym.arr_enemies[i])){\r\n            \/\/create and place an explosion on the ship coords\r\n            var mc_explode = sym.createChildSymbol(&quot;Explode&quot;, &quot;Stage&quot;).getSymbolElement();\r\n            mc_explode.css({&quot;position&quot;:&quot;absolute&quot;, &quot;top&quot;:sym.mc_ship.position().top + &quot;px&quot;, &quot;left&quot;:sym.mc_ship.position().left+ &quot;px&quot;});\r\n            \/\/\r\n            Aud_Explode.play();\r\n            sym.arr_enemies[i].stop();\r\n            sym.arr_enemies[i].remove();\r\n            \/\/you lose\r\n            sym.SCENE = &quot;lose&quot;;\r\n            stopG();\r\n        }\r\n    }\r\n}\r\n\r\n\r\nfunction attachEnemyShip()\r\n{\r\n    for (var i = 0; i&lt;sym.enemyAmount; i++)\r\n    {\r\n        var mc_enemy = sym.createChildSymbol(&quot;Enemy_Ship&quot;, &quot;Stage&quot;).getSymbolElement();\r\n        sym.arr_enemies.push(mc_enemy);\r\n        enemyShip(mc_enemy);\r\n    }\r\n}\r\n\r\n\r\nfunction removeEnemyShip()\r\n{\r\n    \/\/remove all enemies\r\n    for (var i = 0; i&lt;sym.arr_enemies.length; ++i){\r\n    \/\/You can remove in two ways .remove() or .deleteSymbol()\r\n    \/\/I am not certain what the difference is so I am using .remove()\r\n    \/\/see: http:\/\/api.jquery.com\/remove\/\r\n    \/\/always .stop(); if you are removing a symbol with .animate()\r\n        sym.arr_enemies[i].stop();\r\n        sym.arr_enemies[i].remove();\r\n        \/\/sym.getSymbol(sym.arr_enemies[i]).deleteSymbol();\r\n    }\r\n}\r\n\r\n\/\/enemyInit calls to create the enemy\r\n\/\/as you play, and as you progress\r\n\/\/the game gets more difficutl -- more enemies\r\nfunction enemyInit()\r\n{\r\n    clearInterval(sym.enemyInterval);\r\n    \/\/was (Math.random()*20000)+10000;\r\n    var randNum = (Math.random()*9000)+10000;\r\n    \/\/\r\n    if(sym.score&gt;=sym.lvl1_goal-100){\r\n        randNum = (Math.random()*8000)+9000;\r\n    }\r\n    if(sym.score&gt;=sym.lvl2_goal-200){\r\n        randNum = (Math.random()*5000)+7000;\r\n    }\r\n    if(sym.score&gt;=sym.win_goal-400){\r\n        randNum = (Math.random()*1000)+6000;\r\n    }\r\n    if(sym.score&gt;=sym.win_goal-200){\r\n        randNum = (Math.random()*1000)+5000;\r\n    }\r\n    \/\/if sym.bunnyAbAmnt is above the goal\r\n    \/\/then you may start creating enemies\r\n    if(sym.bunnyAbAmnt&gt;10){\r\n        makeEnemyFire();\r\n        attachEnemyShip();\r\n    };\r\n    \/\/\r\n    sym.enemyInterval = setInterval(enemyInit, randNum);\r\n}\r\n\r\n\/\/Bunny nightmare pannel\r\n\/\/bad dreams ocasionally show up acompanied with a sound\r\nfunction nightmareInit() {\r\n    clearInterval(sym.nightmareInterval);\r\n    var randNum = (Math.random()*10000)+10000;\r\n    sym.mc_nightmare.play();\r\n    Aud_Nightmare.play();\r\n    \/\/start again\r\n    sym.nightmareInterval = setInterval(nightmareInit, randNum);\r\n}\r\n\r\n\/\/game timer\r\n\/\/initiates enemies\r\nfunction timer(){\r\n    \/\/set score\r\n    sym.txt_score.html(sym.score);\r\n    \/\/increment time\r\n    sym.time+=1;\r\n    \/\/increment enemies, if the score is past lvl1_goal\r\n    if (sym.time&gt;100 &amp;&amp; sym.score&gt;sym.lvl1_goal-100) {\r\n        sym.time = 1;\r\n        if (sym.enemyAmount&lt;sym.enemyMax) {\r\n            sym.enemyAmount++;\r\n        }\r\n        \/\/no more than 4 enemies, reset it\r\n        if (sym.enemyAmount == sym.enemyMax) {\r\n            sym.enemyAmount = 1;\r\n        }\r\n    }\r\n}\r\n\r\n\/\/leveling system\r\nfunction elapsed() {\r\n    sym.timeElapsed += 1;\r\n    \/\/win\r\n    if (sym.timeElapsed&gt;sym.win_time &amp;&amp; sym.score&gt;sym.win_goal) {\r\n        console.log(&quot;You win.&quot;);\r\n        sym.SCENE = &quot;win&quot;;\r\n        \/\/play();\r\n        stopG();\r\n        sym.$(&quot;Screen_End&quot;).hide();\/\/hide gameover\r\n        sym.play();\r\n    }\r\n    \/\/.data to keep it .play() called once\r\n    if ((sym.timeElapsed&gt;sym.lvl2_time &amp;&amp; sym.score&gt;sym.lvl2_goal) &amp;&amp; sym.mc_b2_data != false) {\r\n        randHit();\r\n        sym.mc_transition.play(&quot;transition&quot;);\/\/blink\r\n        sym.mc_b2.play();\r\n        sym.mc_b2_data = false;\r\n    }\r\n    if ((sym.timeElapsed&gt;sym.lvl1_time &amp;&amp; sym.score&gt;sym.lvl1_goal) &amp;&amp; sym.mc_b1_data != false) {\r\n        randHit();\r\n        sym.mc_transition.play(&quot;transition&quot;);\/\/blink\r\n        sym.mc_b1.play();\r\n        sym.mc_b1_data = false;\r\n    }\r\n}\r\n\r\n\/\/stop all sounds :)\r\n\/\/better yet would be to use a groupd\r\n\/\/and buzz.all() to do this: http:\/\/buzz.jaysalvat.com\/documentation\/group\/\r\nfunction SoundMixer_stopAll(){\r\n    Aud_GameTrack.stop();\r\n    Aud_Hit1_.stop();\r\n    Aud_Hit2_.stop();\r\n    Aud_Hit3_.stop();\r\n    Aud_BeamLoop.stop();\r\n    Aud_Laser.stop();\r\n    Aud_Nightmare.stop();\r\n}\r\n\r\n\/\/&quot;submit&quot; your score window\r\n\/\/hide the current gameover window\r\n\/\/and open the submission one\r\n\/\/to call from screen: sym.getComposition().getStage().scorecall();\r\nsym.scorecall = function() {\r\n    sym.$(&quot;Screen_End&quot;).hide();\/\/hide mc_gameover\r\n    sym.$(&quot;Screen_Score&quot;).show();\r\n}\r\n\/\/same as above but the &quot;overachieve&quot; option\r\n\/\/to call from screen: sym.getComposition().getStage().overachieve();\r\nsym.overachieve = function(){\r\n    resumeG();\r\n}\r\n\/\/done submitting scores, and playing, go to the scores scene\r\n\/\/leaves the game -- called in Screen_Score\r\nsym.gotoScores = function(){\r\n    sym.SCENE = &quot;scores&quot;;\r\n    sym.stop(&quot;scores&quot;);\r\n}\r\n\r\n\/\/stops the game\r\n\/\/this clears the current game\r\n\/\/to start it again call resumeG();\r\nfunction stopG() {\r\n    SoundMixer_stopAll();\r\n    \/\/set player score message for if this is gameover\r\n    sym.mc_gameover.$(&quot;txt_plyr_score&quot;).html(&quot;You score &quot;+sym.score+&quot;!&quot;);\r\n    \/\/\r\n    randHit();\r\n    Aud_Explode.play();\r\n    \/\/show gameover\r\n    sym.$(&quot;Screen_End&quot;).show();\r\n    \/\/\r\n    removeEnemyShip();\r\n    removeSprites();\r\n    removeBunny();\r\n    clearInterval(sym.timerInt);\r\n    clearInterval(sym.nightmareInterval);\r\n    clearInterval(sym.enemyInterval);\r\n    clearInterval(sym.timeElapsedInt);\r\n    clearInterval(sym.shipHitInterval);\r\n}\r\n\r\n\/\/resumeG functions both as init() and resuming\r\n\/\/if the player loses, the game is cleared in stopG(),\r\n\/\/and this would be called to start a fresh one\r\n\/\/so this is setting all values to their default state\r\n\/\/as well as creating all new sprites\r\nfunction resumeG() {\r\n    sym.SCENE = &quot;game&quot;; \/\/set to game so game keyboard input will work\r\n    sym.score = 1;    \r\n    sym.mc_b1.stop(0);\r\n    sym.mc_b2.stop(0);\r\n    sym.mc_b1_data = true;\r\n    sym.mc_b2_data = true;\r\n    sym.bunnyAbAmnt = 0;\r\n    \/\/clear\/reset arrays\r\n    \/\/there are a number of ways to do this, for example: \r\n    \/\/http:\/\/stackoverflow.com\/questions\/1232040\/how-to-empty-an-array-in-javascript\r\n    \/\/but keeping it simple...\r\n    sym.arr_bunnies = [];\r\n    sym.arr_enemies = [];\r\n    \/\/start the music\r\n    Aud_GameTrack.play().fadeIn();\r\n    sym.$(&quot;Screen_End&quot;).hide();\/\/hide mc_gameover\r\n    sym.$(&quot;Screen_Score&quot;).hide();\/\/hide the &quot;your name here&quot; screen\r\n    createSprites();\r\n    makeBunny();\r\n    enemyInit();\r\n    nightmareInit();  \r\n    sym.timerInt = setInterval(timer, 100);\r\n    sym.timeElapsedInt = setInterval(elapsed, 100);\r\n    sym.shipHitInterval = setInterval(enemyHit , 100);\r\n    \/\/\r\n    \/\/removeEnemyShip();\r\n    \/\/reset vars\r\n    sym.time = 1;\r\n    sym.enemyAmount = 1;\r\n    sym.timeElapsed = 1;\r\n    \/\/set these values AFTER sprites have been created\r\n    sym.maxX = sym.stage.width()-sym.mc_ship.width();\r\n    sym.minX = 0;\r\n}\r\n\r\n\/\/Start game\r\nresumeG();\r\n<\/code><\/pre>\n<p><code>document.compositionReady<\/code><br \/>\n<img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/triggerGlobal.png\" alt=\"\" \/><\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/&quot;GLOBAL&quot; VARIABLES\r\n\/\/what label? \r\n\/\/will check against this and if it is &quot;game&quot; then game functionality will unlock\r\n\/\/if it is menu then keyboard for menu will unlock, etc...\r\nsym.SCENE; \r\n\r\nsym.score = 100;    \r\nsym.time = 1;\r\nsym.enemyAmount = 1;\/\/current amount\r\nsym.enemyMax = 3;\/\/maximum amount of enemies alowed at once\r\nsym.timeElapsed = 1;\r\nsym.playerSpeed = 600;\/\/5\r\nsym.playerSpeed_left = 600;\/\/5\r\nsym.playerSpeed_right = 600;\/\/5\r\nsym.bunnySpeed = 5000;\/\/will be random + itself, this is the default minimum value\r\n\/\/sym.bunnyAbAmnt = amount of abducted bunnies, if it's above a certain number then enemies will start appearing\r\n\/\/this keeps the game from generating enemies right away -- gives the player time to adjust\r\nsym.bunnyAbAmnt = 0;\r\n\/\/goals (before leveling up)\r\nsym.lvl1_goal = 300;\r\nsym.lvl2_goal = 530;\r\n\/\/targeted time (how long you have been playing before you can go to next level)\r\nsym.lvl1_time = 300;\r\nsym.lvl2_time = 500;\r\n\/\/above but for winning\r\nsym.win_time = 700;\r\nsym.win_goal = 800;\r\n\r\nsym.bNum = 10;\/\/maximum number of bunnies on stage\r\n\r\n\/\/Booleans - flags\r\nsym.bool_left = false;\r\nsym.bool_right = false;\r\n\r\n\/\/.data to keep it .play() called once\r\n\/\/may only play once if it is true then the transition to next level may play\r\nsym.mc_b1_data = false;\r\nsym.mc_b2_data = false;\r\n\r\n\/\/symbol refferences\r\nsym.stage = sym.$(&quot;Stage&quot;);\r\nsym.mc_b1 = sym.getSymbol(&quot;Beds&quot;).getSymbol(&quot;IMG_Sprite_Bed02&quot;);\r\nsym.mc_b2 = sym.getSymbol(&quot;Beds&quot;).getSymbol(&quot;IMG_Sprite_Bed03&quot;);\r\nsym.mc_nightmare = sym.getSymbol(&quot;Nightmare&quot;);\r\nsym.mc_transition = sym.getSymbol(&quot;Transition_Blink&quot;);\r\nsym.mc_gameover = sym.getSymbol(&quot;Screen_End&quot;);\r\nsym.mc_score = sym.getSymbol(&quot;Screen_Score&quot;);\r\nsym.mc_ship;\r\nsym.mc_ray;\r\nsym.txt_score = sym.$(&quot;txt_score&quot;);\r\n\r\n\/\/Arrays\r\nsym.arr_bunnies = [];\r\nsym.arr_enemies = [];\r\n\r\n\/\/X Y positions\r\nsym.shipY = 70;\/\/25\r\nsym.enemyY = 88;\r\nsym.rayY = 66;\/\/66\r\nsym.bunnyY = 180;\r\n\/\/centering\r\nsym.centerX = sym.stage.width()\/2;\r\nsym.centerY = sym.stage.height()\/2;\r\n\/\/left\/right bounds\r\nsym.maxX = sym.stage.width();\r\nsym.minX = 10;\/\/minimum placement for ship\r\n\/\/player X (incremented\/decremented via keyboard input, initial value is center)\r\nsym.shipX = sym.centerX;\r\n\r\n\/\/Timers - intervals\r\nsym.timerInt;\r\nsym.timeElapsedInt;\r\nsym.nightmareInterval;\r\nsym.enemyInterval;\r\nsym.shipHitInterval;\r\n\r\n\/\/SOUND\r\n\r\n\/\/I manually made the sound longer so it appears to loop -- nevermind the gap\r\n\/\/it is a bit more hacking around to get seamless audio looping (Flash does it well)\r\n\/\/here are some notes for those interested in getting it to work\r\n\/\/http:\/\/sound.stackexchange.com\/questions\/8916\/mp3-gapless-looping-help\r\n\/\/http:\/\/forestmist.org\/blog\/html5-audio-loops\/\r\n\/\/the main soundrack of the game:\r\nAud_GameTrack = new buzz.sound(&quot;audio\/mainmenu-loop&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;], preload: true, loop: true});\r\n\/\/plays at the end of the game:\r\nAud_GameTrack_2 = new buzz.sound(&quot;audio\/mainmenu-under-loop2&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;], preload: true, loop: true});\r\nAud_ScoresTrack = new buzz.sound(&quot;audio\/scores-loop&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;], preload: true, loop: true});\r\nAud_KeysTrack = new buzz.sound(&quot;audio\/Keys-loop&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;], preload: true, loop: true});\r\n\/\/Menu sounds\r\nAud_MenuPreLoop = new buzz.sound(&quot;audio\/Mainmenu-preloop&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;], preload: true});\r\nAud_MenuLoop = new buzz.sound(&quot;audio\/mainmenu-loop3&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;], preload: true, loop: true});\r\n\r\n\/\/Intro\r\n\/\/Aud_LogoMoron = new buzz.sound(&quot;audio\/morons-blb&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;]});\r\nAud_Intro = new buzz.sound(&quot;audio\/Intro&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;], preload: true});\r\n\r\nAud_Nightmare = new buzz.sound(&quot;audio\/JAPAN-3&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;]});\r\nAud_Explode = new buzz.sound(&quot;audio\/explode&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;],preload: true});\r\nAud_End = new buzz.sound(&quot;audio\/End&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;],preload: true});\r\nAud_Hit1_ = new buzz.sound(&quot;audio\/daaaam-1&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;]});\r\nAud_Hit2_ = new buzz.sound(&quot;audio\/daaaam-2&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;]});\r\nAud_Hit3_ = new buzz.sound(&quot;audio\/daaaam-3&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;]});\r\n\r\nAud_BeamLoop = new buzz.sound(&quot;audio\/beam-loop&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;],\r\n    loop: true\r\n});\r\n\r\nAud_Laser = new buzz.sound(&quot;audio\/LASER&quot;, {formats: [&quot;wav&quot;, &quot;ogg&quot;, &quot;mp3&quot;]});\r\n\r\n\/\/load them with Edge\r\nAud_GameTrack.load();\r\nAud_GameTrack_2.load();\r\nAud_ScoresTrack.load();\r\nAud_KeysTrack.load();\r\nAud_MenuPreLoop.load();\r\nAud_MenuLoop.load();\r\nAud_Intro.load();\r\nAud_Nightmare.load();\r\nAud_Explode.load();\r\nAud_End.load();\r\nAud_Hit1_.load();\r\nAud_Hit2_.load();\r\nAud_Hit3_.load();\r\n\r\n\/\/stop all currently playing &quot;hits&quot; for menu and anywhere else they trigger on button overs\r\nsym.stopHits = function(){\r\n    Aud_Hit1_.stop();\r\n    Aud_Hit2_.stop();\r\n    Aud_Hit3_.stop();\r\n}\r\n<\/code><\/pre>\n<p><code>document.keydown<\/code><br \/>\n<img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/triggerKeyDown.png\" alt=\"\" \/><\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/GAME KEYBOARD\r\n\/\/add others acording to behavior for desired &quot;SCENE&quot;\r\n\/\/example: if it is main menu then enable main menu keyboard functionality\r\n\/\/if it is game then enable game keyboard functionality\r\n\r\n\/\/GAME\r\nif(sym.SCENE == &quot;game&quot;){\r\n    \/\/32 is SPACE\r\n    if (e.which == 32) {\r\n        \/\/call the function on the stage's &quot;game trigger&quot;\r\n        sym.getComposition().getStage().key_onKeyDown();\r\n        \/\/sym.mc_ray.show();\r\n        \/\/Aud_BeamLoop.play();\r\n    }\r\n    \/\/37 is LEFT\r\n    if (e.which == 37){\r\n        \/\/keeps it from &quot;crawling&quot; if key is pressed while ship is close to left of screen\r\n        sym.playerSpeed_left = (sym.mc_ship.position().left);\r\n        sym.bool_left = true;\r\n    }\r\n    \/\/39 is RIGHT\r\n    if (e.which == 39){\r\n        \/\/keeps it from &quot;crawling&quot; if key is pressed while ship is close to right of screen\r\n        sym.playerSpeed_right = (sym.stage.width()-(sym.mc_ship.position().left));\r\n        sym.bool_right = true;\r\n    }\r\n    \/\/player movement\r\n    \/\/is an interval - target left\/right location are the sides of the screen\r\n    \/\/if the keyboard key is released .anmiate is stopped\/canceled (see keyup)\r\n    \/\/there are a number of ways to animate with css\/js http:\/\/www.dehats.com\/drupal\/node\/120\r\n    \/\/has some good examples. I've chosen .animate here, and because the target are the edges\r\n    \/\/of the screen it will continue to move there untill you release the key\r\n    \/\/it will also not go off the screen...\r\n    if(sym.bool_left){\r\n        sym.mc_ship.animate( {left: sym.minX}, {duration: sym.playerSpeed_left, easing: &quot;linear&quot;} );\r\n        sym.mc_ray.animate( {left: sym.minX}, {duration: sym.playerSpeed_left, easing: &quot;linear&quot;} );\r\n    }\r\n    if(sym.bool_right){\r\n        sym.mc_ship.animate( {left: sym.maxX}, {duration: sym.playerSpeed_right, easing: &quot;linear&quot;} );\r\n        sym.mc_ray.animate( {left: sym.maxX}, {duration: sym.playerSpeed_right, easing: &quot;linear&quot;} );\r\n    }\r\n}\r\n\r\n\/\/DEBUG\r\nif(e.which==27){\r\n\/\/\r\n}\r\n<\/code><\/pre>\n<p>document.keyup<br \/>\n<img decoding=\"async\" src=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/images\/triggerKeyUp.png\" alt=\"\" \/><\/p>\n<pre style=\"font-family: Andale Mono, Lucida Console, Monaco, fixed, monospace; color: #000000; background-color: #eee;font-size: 12px;border: 1px dashed #999999;line-height: 14px;padding: 5px; overflow: auto; width: 100%\"><code>\/\/GAME KEYBOARD\r\n\/\/add others acording to behavior for desired &quot;SCENE&quot;\r\n\/\/example: if it is main menu then enable main menu keyboard functionality\r\n\/\/if it is game then enable game keyboard functionality\r\n\r\n\/\/GAME\r\nif(sym.SCENE == &quot;game&quot;){\r\n    \/\/32 is SPACE\r\n    if (e.which == 32) {\r\n        \/\/sym.mc_ray.hide();\r\n        \/\/Aud_BeamLoop.stop();\r\n        sym.getComposition().getStage().key_onKeyUp();\r\n    }\r\n    \/\/37 is LEFT\r\n    if (e.which == 37){\r\n        sym.bool_left = false;\r\n    }\r\n    \/\/39 is RIGHT\r\n    if (e.which == 39){\r\n        sym.bool_right = false;\r\n    }\r\n    \/\/stop movement and cancel anything queue -- prevents animation queue buildup\r\n    if(!sym.bool_left &amp;&amp; !sym.bool_right){\r\n        sym.mc_ship.animate( {left: sym.mc_ship.position().left}, {duration: sym.playerSpeed, easing: &quot;linear&quot;} );\r\n        sym.mc_ship.finish();\r\n        sym.mc_ray.finish();\r\n        \/\/force placement of ray back to ship's x...\r\n        sym.mc_ray.css({&quot;position&quot;:&quot;absolute&quot;, &quot;top&quot;:sym.rayY + &quot;px&quot;, &quot;left&quot;:sym.mc_ship.position().left + &quot;px&quot;});\r\n    }\r\n}\r\n<\/code><\/pre>\n<p>*************<\/p>\n<p><strong>CONCLUSION<\/strong><\/p>\n<p>I hope this will be helpful to some, or that it will have provided some useful insight for creating a game in Edge Animate. In the next tutorial I&#8217;m going to cover <a href=\"http:\/\/www.nathalielawhead.com\/candybox\/tutorial-building-a-game-with-flash-html5-canvas-createjs-haxatron-2000\" target=\"_self\">creating HTML5 content in Flash<\/a>.<\/p>\n<p>Download all sourcefiles here, and take a look:<br \/>\n<a href=\"http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/\" target=\"_blank\">http:\/\/nathalielawhead.com\/sourcefiles\/Offender_HTML5_Tutorial\/<\/a><\/p>\n<p>You can play the end result here:<br \/>\n<a href=\"http:\/\/offender.alienmelon.com\/thegame\/\" target=\"_blank\">http:\/\/offender.alienmelon.com\/thegame\/<\/a><\/p>\n<p>Visit the NEXT tutorial: <a href=\"http:\/\/www.nathalielawhead.com\/candybox\/tutorial-building-a-game-with-flash-html5-canvas-createjs-haxatron-2000\" target=\"_self\">Building A Game With Flash HTML5 Canvas &#038; CreateJS (Haxatron 2000)<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Introduction: I&#8217;ve decided to build this first Tetrageddon Games &#8220;mini-game&#8221; tutorial, Offender, in Adobe Edge Animate because the program is still very new, and there isn&#8217;t much out there on it in terms of game development. I think this will make a great &#8220;getting started&#8221; resource for newcomers, as well as demonstrate the capabilities of Edge Animate. In this tutorial I hope to offer a solid example of building a game with the program. This is the first part of a series discussing HTML5 game development. * DOWNLOAD the source files here: Offender_HTML.zip * Play the finished game here: Offender&#46;&#46;&#46;<\/p>\n","protected":false},"author":1,"featured_media":4522,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"","fifu_image_alt":"","footnotes":"","_links_to":"","_links_to_target":""},"categories":[30,12],"tags":[],"class_list":["post-3041","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-games","category-resources"],"_links":{"self":[{"href":"https:\/\/www.nathalielawhead.com\/candybox\/wp-json\/wp\/v2\/posts\/3041","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.nathalielawhead.com\/candybox\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.nathalielawhead.com\/candybox\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.nathalielawhead.com\/candybox\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.nathalielawhead.com\/candybox\/wp-json\/wp\/v2\/comments?post=3041"}],"version-history":[{"count":56,"href":"https:\/\/www.nathalielawhead.com\/candybox\/wp-json\/wp\/v2\/posts\/3041\/revisions"}],"predecessor-version":[{"id":3271,"href":"https:\/\/www.nathalielawhead.com\/candybox\/wp-json\/wp\/v2\/posts\/3041\/revisions\/3271"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.nathalielawhead.com\/candybox\/wp-json\/wp\/v2\/media\/4522"}],"wp:attachment":[{"href":"https:\/\/www.nathalielawhead.com\/candybox\/wp-json\/wp\/v2\/media?parent=3041"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.nathalielawhead.com\/candybox\/wp-json\/wp\/v2\/categories?post=3041"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.nathalielawhead.com\/candybox\/wp-json\/wp\/v2\/tags?post=3041"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}