{"id":61,"date":"2023-08-21T10:15:41","date_gmt":"2023-08-21T09:15:41","guid":{"rendered":"https:\/\/dreamshipcreations.com\/?p=61"},"modified":"2025-10-20T06:10:03","modified_gmt":"2025-10-20T05:10:03","slug":"making-a-game-in-javascript-part-6-movement-and-actions","status":"publish","type":"post","link":"https:\/\/dreamshipcreations.com\/index.php\/2023\/08\/21\/making-a-game-in-javascript-part-6-movement-and-actions\/","title":{"rendered":"Making a game in JavaScript Part 6 : Movement and actions"},"content":{"rendered":"\n<p><\/p>\n\n\n\n<p><strong>&#8220;Let&#8217;s make that ninja run!&#8221;<\/strong><\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>The player character is not yet visible on the canvas, but we are going to change that very shortly.<br>We want to set the player idle, and then also the additional player running animation. When we have the player sitting at idle, and able to run in both left and right directions, we will then step up to add the player jump and attack mechanics.<\/p>\n\n\n\n<p>To do this we will need to simultaneously develop the input management, also updating our player.js script to include the appropriate responses for the player.<\/p>\n\n\n\n<p>First let us create the input controller. This is a simple, easily extended object that allows for mapping the keys as you wish, also allowing for the mapping to be later made customisable in-game or via a settings menu.<\/p>\n\n\n\n<p>Open and save an \u2018inputcontroller.js\u2019 in the GameJS\/js\/ folder, and add the following code:<\/p>\n\n\n\n<p>export class InputController<br>{<br>constructor()<br>{<br>this.eKeyState = {<br>eNone : 0,<br>ePressed : 1,<br>eDown : 2,<br>eReleased : 3<br>}<br>}<\/p>\n\n\n\n<p>initialise(canvas)<br>{<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>cycleKeyPress(keyDown)<br>{<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>cycleKeyRelease(keyUp)<br>{<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>getKeyState(keymapping)<br>{<br><br>}<br>}<\/p>\n\n\n\n<p>export default InputController;<\/p>\n\n\n\n<p>The constructor here is setting a \u2018keyState\u2019 variable, which determines whether a key is in a state of pressed (this frame), down (still down from last frame), released (was down last frame, is up this frame), and none (no key state, the key is neither pressed, down, or just now released.)<\/p>\n\n\n\n<p>This is important for determining and storing the state of any key we want to track for user input.<\/p>\n\n\n\n<p>In the initialise function, add the following code:<\/p>\n\n\n\n<p>initialise(canvas)<br>{<br>\/\/ Store the canvas object<br>this.canvas = canvas;<br><br>\/\/ Map a keyboard key to an action name<br>this.mappings = {&#8216;w&#8217;:&#8217;Up&#8217;, &#8216;s&#8217;:&#8217;Down&#8217;, &#8216;a&#8217;:&#8217;Left&#8217;, &#8216;d&#8217;:&#8217;Right&#8217;, &#8216;Space&#8217;:&#8217;Attack&#8217;, &#8216;Ctrl&#8217;:&#8217;Throw&#8217;};<\/p>\n\n\n\n<p>\/\/ Store the keystate for our actions \u2013 currently all keystates will be \u2018none\u2019.<br>this.keys = {<br>&#8216;Up&#8217;: this.eKeyState.eNone, &#8216;Down&#8217;: this.eKeyState.eNone, &#8216;Left&#8217;: this.eKeyState.eNone, &#8216;Right&#8217;:this.eKeyState.eNone, &#8216;Attack&#8217;:this.eKeyState.eNone, &#8216;Throw&#8217;:this.eKeyState.eNone<br>};<\/p>\n\n\n\n<p>\/\/ Add an event listener to the canvas, when a key down event occurs pass the key<br>\/\/ that is pressed to the \u2018cycleKeyPress\u2019 function to update the keystate<br>this.canvas.addEventListener(&#8216;keydown&#8217;, function(k_down) {<br>this.cycleKeyPress(k_down.key);<br>}.bind(this), false );<\/p>\n\n\n\n<p>\/\/ Add an event listener to the canvas, when a key released event occurs pass the key<br>\/\/ that is released to the \u2018cycleKeyRelease\u2019 function to update the key state<br>this.canvas.addEventListener(&#8216;keyup&#8217;, function(k_up) {<br>this.cycleKeyRelease(k_up.key);<br>}.bind(this), false );<br><br>}<\/p>\n\n\n\n<p>Update the cycleKeyPress function to include the following code:<br><br>cycleKeyPress(keyDown)<br>{<br>\/\/ Previously released keys are no longer in a \u2018released\u2019 state and are set to \u2018none\u2019<br>for(var keyState in this.keys)<br>{<br>if(this.keys[keyState] === this.eKeyState.eReleased)<br>{<br>this.keys[keyState] = this.eKeyState.eNone;<br>}<br>}<\/p>\n\n\n\n<p>\/\/ If the key was previously set to \u2018pressed\u2019, update it to \u2018down\u2019<br>\/\/ Else set the key to \u2018pressed\u2019<br>if(this.keys[this.mappings[keyDown]] === this.eKeyState.ePressed)<br>{<br>this.keys[this.mappings[keyDown]] = this.eKeyState.eDown;<br>}<br>else<br>{<br>this.keys[this.mappings[keyDown]] = this.eKeyState.ePressed;<br>}<br>}<\/p>\n\n\n\n<p>Update the cycleKeyRelease function to include the following code:<\/p>\n\n\n\n<p>cycleKeyRelease(keyUp)<br>{<br>\/\/ Previously released keys are no longer in a \u2018released\u2019 state and are set to \u2018none\u2019<br>for(var keyState in this.keys)<br>{<br>if(this.keys[keyState] === this.eKeyState.eReleased)<br>{<br>this.keys[keyState] = this.eKeyState.eNone;<br>}<br>}<\/p>\n\n\n\n<p>\/\/ Set the key state for \u2018keyUp\u2019 to \u2018released\u2019<br>this.keys[this.mappings[keyUp]] = this.eKeyState.eReleased;<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>And update the \u2018getKeyState\u2019 function:<br><br>\/\/ Return Keystate for an action, \u2018Up\u2019 \u2018Down\u2019 \u2018Left\u2019 \u2018Right\u2019 \u2018Attack\u2019 \u2018Throw\u2019<br>\/\/ Keystate = 0 for \u2018None\u2019 1 for \u2018Pressed\u2019 2 for \u2018Down\u2019 and 3 for \u2018Released\u2019<br>getKeyState(keymapping)<br>{<br>if(this.keys[keymapping] === this.eKeyState.eNone)<br>{<br>return 0;<br>}<\/p>\n\n\n\n<p>if(this.keys[keymapping] === this.eKeyState.ePressed)<br>{<br>return 1;<br>}<\/p>\n\n\n\n<p>if(this.keys[keymapping] === this.eKeyState.eDown)<br>{<br>return 2;<br>}<\/p>\n\n\n\n<p>if(this.keys[keymapping] === this.eKeyState.eReleased)<br>{<br>return 3;<br>}<br>}<\/p>\n\n\n\n<p>And that is our input controller! There is nothing more required for the input controller object but we will need to include that in the playable context object. Open \u2018playablecontext.js\u2019 and at the top of the existing script, with the \u2018import\u2019 lines of code, add another import for the input controller:<\/p>\n\n\n\n<p>import { InputController } from &#8216;.\/inputcontroller.js&#8217;;<\/p>\n\n\n\n<p>In the constructor for the PlayableContext object, add the line :<br><br>this.inputController = new InputController();<\/p>\n\n\n\n<p>This can be the last line of the constructor function.<\/p>\n\n\n\n<p>In the \u2018initialise\u2019 function of the PlayableContext, add the following line to initialise the input controller:<br><br>\/\/ Set the input controller<br>this.inputController.initialise(this.canvas);<\/p>\n\n\n\n<p>That is the input controller! It will update the key states independently, as after it is initialised the event listener functions are added to the canvas. These updates to the key states can be checked during the update frames and if the key state is evaluated to be \u2018Pressed\u2019 or \u2018Down\u2019 or \u2018Released\u2019 for a particular game key, we can trigger the required action for the player character.<\/p>\n\n\n\n<p>Next, we want to create the player character code, and we will start with a simplified version of the player character and for now just focus on two actions, \u2018idle\u2019 and \u2018run\u2019. We want to see that this is working correctly before we go and start adding all the additional action triggers and animations.<\/p>\n\n\n\n<p>Open the \u2018player.js\u2019 script and add the following code:<\/p>\n\n\n\n<p>import { AnimationCollection } from &#8216;.\/animationCollection.js&#8217;<br>import { InputController } from &#8216;.\/userinput.js&#8217;<br>import { Sprite } from &#8216;.\/Sprite.js&#8217;;<br><br>export class Player extends AnimationCollection<br>{<br>constructor()<br>{<br>super();<br>this.renderFrame = new Sprite();<br>this.bFacingRight = true;<br>this.playerPositionX = 400;<br>this.playerPositionY = 50;<br>this.xVelocity = 0.0;<br>}<br><br>initialise()<br>{<br>this.renderFrame = this.getAnimationFrame(&#8216;idle&#8217;);<br>this.bFacingRight = true;<br>this.playerPositionX = 400;<br>this.playerPositionY = 50;<br>}<\/p>\n\n\n\n<p>update(inputController)<br>{<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>getRenderFrame()<br>{<br>return this.renderFrame;<br>}<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>export default Player;<\/p>\n\n\n\n<p>This \u2018Player\u2019 class object extends from the previously created \u2018AnimationCollection\u2019. When we \u2018extend\u2019 a class object using this instance as an example, we have created a new class object called \u2018Player\u2019 which is based on the previous object AnimationCollection and has all of the variables and functions of the AnimationCollection. The AnimationCollection is the \u2018super\u2019 or \u2018base\u2019 class, and the Player class can have additional or overriding functions while still using everything from it\u2019s base class.<\/p>\n\n\n\n<p>In the Player constructor, we call the \u2018super()\u2019 function first, which ensures that the AnimationCollection constructor is called. Then we initialise a sprite for the selected render frame from the given animations in the animation collection, we set the player character to be facing to the right (bFacingRight = true) and we set it\u2019s x and y position on the canvas, and velocity.<\/p>\n\n\n\n<p>The \u2018getRenderFrame\u2019 function does exactly that, it returns the current render frame, which is determined by the input and currently playing animation, selecting the current frame in the animation cycle.<\/p>\n\n\n\n<p>We need to add the code for the \u2018update\u2019 function to contain the following lines:<br><br>update(inputController)<br>{<br>this.xVelocity = 0.0;<\/p>\n\n\n\n<p>\/\/ Get input<br>if(inputController.getKeyState(&#8216;Right&#8217;) === 1 || inputController.getKeyState(&#8216;Right&#8217;) === 2)<br>{<br>this.xVelocity = 0.3;<br>}<br>else if(inputController.getKeyState(&#8216;Left&#8217;) === 1 || inputController.getKeyState(&#8216;Left&#8217;) === 2)<br>{<br>this.xVelocity = -0.3;<br>}<br>else<br>{<br>this.xVelocity = 0.0;<br>}<br><br>if(this.xVelocity &gt; 0.2)<br>{<br>this.bFacingRight = true;<br>var run = this.animations[&#8216;run&#8217;].update();<br>this.renderFrame = this.getAnimationFrame(&#8216;run&#8217;);<br>}<br>else if(this.xVelocity &lt; -0.2)<br>{<br>this.bFacingRight = false;<br>var run = this.animations[&#8216;run&#8217;].update();<br>this.renderFrame = this.getAnimationFrame(&#8216;run&#8217;);<br>}<br>else<br>{<br>\/\/ Update player animation<br>var idle = this.animations[&#8216;idle&#8217;].update();<br>this.renderFrame = this.getAnimationFrame(&#8216;idle&#8217;);<br>}<br>}<\/p>\n\n\n\n<p>With the player class containing all of the requirements to have the player\u2019s idle animation update to change direction to face the directional input and \u2018run\u2019 \/ play the run animation, and then return to idle when the user input is not triggering the velocity, we will want to test this is displaying and responding suitably before we start getting to far ahead with the other game mechanics.<\/p>\n\n\n\n<p>Open the PlayableContext code in playablecontext.js, and add the following line to the top of the file with the other imports:<\/p>\n\n\n\n<p>import { Player } from \u2018.\/player.js\u2019<\/p>\n\n\n\n<p>And in the constructor add the following line before\/above the line of code that is initialising the input controller:<\/p>\n\n\n\n<p>this.player = new Player();<\/p>\n\n\n\n<p>In the PlayableContext \u2018initialise()\u2019 function, add these lines after the lines of code for the canvas handle:<\/p>\n\n\n\n<p>\/\/ Set the player animations<br>this.player.initialise();<br>this.setPlayerAnimations();<\/p>\n\n\n\n<p>You will notice above, after we initialise the \u2018this.player\u2019 object within the PlayableContext, that we have placed a call to the function \u2018this.setPlayerAnimations()\u2019 which is referring to \u2018setPlayerAnimations()\u2019 function within this object (the playable context).<\/p>\n\n\n\n<p>This function has not yet been written, so let\u2019s add that now after the constructor here in the playablecontext.js script.<\/p>\n\n\n\n<p>setPlayerAnimations()<br>{<br>\/\/ Set the image source file for each animation frame<br>for(var i = 0; i &lt; 10; i++)<br>{<br>this.player.animations[&#8216;idle&#8217;].animationFrameSrcs[i] = <a href=\"http:\/\/this.files.ninja\/\" target=\"_blank\" rel=\"noreferrer noopener\">this.files.ninja<\/a>_idleFrames[i];<br>this.player.animations[&#8216;run&#8217;].animationFrameSrcs[i] = <a href=\"http:\/\/this.files.ninja\/\" target=\"_blank\" rel=\"noreferrer noopener\">this.files.ninja<\/a>_runFrames[i];<br>this.player.animations[&#8216;jump&#8217;].animationFrameSrcs[i] = <a href=\"http:\/\/this.files.ninja\/\" target=\"_blank\" rel=\"noreferrer noopener\">this.files.ninja<\/a>_jumpFrames[i];<br>this.player.animations[&#8216;dead&#8217;].animationFrameSrcs[i] = <a href=\"http:\/\/this.files.ninja\/\" target=\"_blank\" rel=\"noreferrer noopener\">this.files.ninja<\/a>_deadFrames[i];<br>this.player.animations[&#8216;attack&#8217;].animationFrameSrcs[i] = <a href=\"http:\/\/this.files.ninja\/\" target=\"_blank\" rel=\"noreferrer noopener\">this.files.ninja<\/a>_swordAttackFrames[i];<br>this.player.animations[&#8216;throw&#8217;].animationFrameSrcs[i] = <a href=\"http:\/\/this.files.ninja\/\" target=\"_blank\" rel=\"noreferrer noopener\">this.files.ninja<\/a>_throwAttackFrames[i];<\/p>\n\n\n\n<p>this.player.animations[&#8216;jumpAttack&#8217;].animationFrameSrcs[i] = <a href=\"http:\/\/this.files.ninja\/\" target=\"_blank\" rel=\"noreferrer noopener\">this.files.ninja<\/a>_jumpingSwordAttackFrames[i];<br>this.player.animations[&#8216;jumpThrow&#8217;].animationFrameSrcs[i] = <a href=\"http:\/\/this.files.ninja\/\" target=\"_blank\" rel=\"noreferrer noopener\">this.files.ninja<\/a>_jumpingThrowAttackFrames[i];<br>this.player.animations[&#8216;slide&#8217;].animationFrameSrcs[i] = <a href=\"http:\/\/this.files.ninja\/\" target=\"_blank\" rel=\"noreferrer noopener\">this.files.ninja<\/a>_slideFrames[i];<br>this.player.animations[&#8216;glide&#8217;].animationFrameSrcs[i] = <a href=\"http:\/\/this.files.ninja\/\" target=\"_blank\" rel=\"noreferrer noopener\">this.files.ninja<\/a>_glideFrames[i];<br>this.player.animations[&#8216;climb&#8217;].animationFrameSrcs[i] = <a href=\"http:\/\/this.files.ninja\/\" target=\"_blank\" rel=\"noreferrer noopener\">this.files.ninja<\/a>_climbFrames[i];<br>}<\/p>\n\n\n\n<p>\/\/ Load the sprite image from the previous set source file locations<br>this.player.animations[&#8216;idle&#8217;].loadSpritesFromSrc();<br>this.player.animations[&#8216;run&#8217;].loadSpritesFromSrc();<br>this.player.animations[&#8216;jump&#8217;].loadSpritesFromSrc();<br>this.player.animations[&#8216;dead&#8217;].loadSpritesFromSrc();<br>this.player.animations[&#8216;attack&#8217;].loadSpritesFromSrc();<br>this.player.animations[&#8216;throw&#8217;].loadSpritesFromSrc();<br>this.player.animations[&#8216;jumpAttack&#8217;].loadSpritesFromSrc();<br>this.player.animations[&#8216;jumpThrow&#8217;].loadSpritesFromSrc();<br>this.player.animations[&#8216;slide&#8217;].loadSpritesFromSrc();<br>this.player.animations[&#8216;glide&#8217;].loadSpritesFromSrc();<br>this.player.animations[&#8216;climb&#8217;].loadSpritesFromSrc();<\/p>\n\n\n\n<p>\/\/ The \u2018Run\u2019 animation is slightly wider that the idle animation, and as such changing the width<br>\/\/ skews the height, we need to specifically update the dimensions of all of the frames<br>\/\/ for the run animation<br>for(var i = 0; i &lt; 10; i++)<br>{<br>this.player.animations[&#8216;run&#8217;].animationFrames[i].frameWidth = 93;<br>this.player.animations[&#8216;run&#8217;].animationFrames[i].frameHeight = 112;<br>this.player.animations[&#8216;run&#8217;].animationFrames[i].displayWidth = 93;<br>this.player.animations[&#8216;run&#8217;].animationFrames[i].displayHeight = 112;<br>this.player.animations[&#8216;run&#8217;].animationFrames[i].originalSourceWidth = 363; this.player.animations[&#8216;run&#8217;].animationFrames[i].originalSourceHeight = 458;<br>this.player.animations[&#8216;run&#8217;].animationFrames[i].sourceWidth = 363;<br>this.player.animations[&#8216;run&#8217;].animationFrames[i].sourceHeight = 458;<br>this.player.animations[&#8216;run&#8217;].animationFrames[i].ticksPerFrame = 1;<br>}<\/p>\n\n\n\n<p>}<\/p>\n\n\n\n<p>We now need to update the player object within the PlayableContext. In the \u2018update()\u2019 function, add the following code to call player update:<\/p>\n\n\n\n<p>this.player.update(this.inputController);<\/p>\n\n\n\n<p>And then render the player frame in the render() function of the PlayableContext:<br><br>render()<br>{<br>this.context = this.canvas.getContext(&#8220;2d&#8221;);<br>this.context.clearRect(0,0,1280,680);<br>this.playerFrame = this.player.getRenderFrame();<br><br>if(this.player.bFacingRight === true)<br>{<br>this.context.drawImage(<br>this.playerFrame.img,<br>this.playerFrame.sourceX,<br>this.playerFrame.sourceY,<br>this.playerFrame.sourceWidth,<br>this.playerFrame.sourceHeight,<br>this.playerFrame.positionX,<br>this.playerFrame.positionY,<br>this.playerFrame.displayWidth,<br>this.playerFrame.displayHeight);<br>}<br>else<br>{<br>this.context.save();<br>this.context.scale(-1,1);<br>this.context.drawImage(<br>this.playerFrame.img,<br>this.playerFrame.sourceX,<br>this.playerFrame.sourceY,<br>this.playerFrame.sourceWidth,<br>this.playerFrame.sourceHeight,<br>-this.playerFrame.positionX &#8211; this.playerFrame.displayWidth,<br>this.playerFrame.positionY,<br>this.playerFrame.displayWidth,<br>this.playerFrame.displayHeight<br>);<br><br>this.context.restore();<br>}<br>}<br>}<\/p>\n\n\n\n<p>Now we have the code for the animationCollection, the animations, the animation frames or \u2018sprites\u2019, the file manager, the input controller, and the player. We have the playable context that brings it all together, and the app script which controls what the playable context is doing. We also have the index.html webpage that is running the app script. If we have put it all together right, when re run the python http server and host the index.html, we should be able to:<br><br>* See the player idle animation, it should be running smooth<br>* When pressing and holding \u2018d\u2019 on the keyboard, the player should start running to the right<br>* When pressing and holding \u2018a\u2019 on the keyboard, the player should start running to the left<br>* When the keys are released the player character should return to the idle animation, remaining the same direction it was facing when running.<\/p>\n\n\n\n<p>Please note: There may be some typos in the existing provided code as I am editing the post spacing&#8217;s and wording as I go. I will follow the posts again from the start and ensure the code provided is in line with the coded project I am working from and make a note to update this and provide and note any corrections in time for the next post.<\/p>\n\n\n\n<p>Update: 23\/08\/2023<br>I have gone through the code in my posts and found a couple of parts missing, which I have since gone back over and amended.<br>To save you time re-reading start to finish and locating the changes, and as I have not highlighted or recorded each individual change (and don&#8217;t want to miss highlighting an update that could cause more confusion \ud83d\ude42 ) I have instead zipped the project files for the tutorial going this far into the project.<\/p>\n\n\n\n<p>You can download a copy of the project files here: <br>(Broken Link &#8211; TBC) <a href=\"https:\/\/assets.zyrosite.com\/ALpX9RZyXyH4xG0k\/code-image-files-part-1-6-mP4PXn8gveTLR3Qr.zip\">Making a JavaScript Game Part 1 &#8211; 6 Code + Image Files<\/a><\/p>\n\n\n\n<p>If you would prefer, you can go through the posts and try to match your code to the updated tutorial code. The practice can be useful for those new to coding.<\/p>\n\n\n\n<p>Some importantly useful tips for bug-finding when testing your code:<br><br>+ Ensure that you have at least the python <strong>http server running<\/strong> to host your JavaScript code or it will not run!<br><br>+ If you have the server running and your code is up to date but not displaying a ninja that can idle, or run left and right, then press the <strong>&#8216;F12&#8217; key<\/strong> or go the the browser menu, down to &#8216;More tools&#8217; and open the &#8216;Developer Tools&#8217;.<strong><\/strong><br><strong>In the &#8216;Console&#8217; tab of the Developer Tools<\/strong> you may find any error message that is being provided by the browser, which can help you locate and repair any errors in the script files.<\/p>\n\n\n\n<p>There are a few ways to host the files, I have included one here that is overly simple and excellent for the purpose of code-and-test. It requires Python to be installed, and with it a simple command from the folder directory in the Windows PowerShell or Linux terminal you can start a http server for that folder, and then access the hosted folder as if it is a website by going to the local host address in your browser.<\/p>\n\n\n\n<p>If you don\u2019t already have Python 3 installed, you can download and install it from<\/p>\n\n\n\n<p><a href=\"https:\/\/python.org\/\" target=\"_blank\" rel=\"noreferrer noopener\">https:\/\/python.org\/<\/a> in the Downloads section.<br><br>At the time of writing this Python 3.11.4 is the latest version and should work nicely with the mentioned steps.<\/p>\n\n\n\n<p>In Windows or Linux, there will often be an option to right-click within an open folder in the File explorer and select \u2018Open location in terminal\u2019 or \u2018Open in Terminal\u2019. Alternatively, you can open PowerShell in Windows or the Linux Terminal in Linux and navigate to your directory folder \u2018GameJS\u2019.<\/p>\n\n\n\n<p>With the terminal or PowerShell window open and Python installed, you can start a simple http server with the following command:<\/p>\n\n\n\n<p>python -m http.server<\/p>\n\n\n\n<p>With the http server now running in the PowerShell or terminal window, you can access your site by opening your browser and typing the address:<\/p>\n\n\n\n<p><a href=\"http:\/\/localhost:8000\/\" target=\"_blank\" rel=\"noreferrer noopener\">http:\/\/localhost:8000<\/a><\/p>\n\n\n\n<p>This will open the website up that is hosted on \u2018<a href=\"http:\/\/localhost\/\" target=\"_blank\" rel=\"noreferrer noopener\">localhost<\/a>\u2019 (your PC) on port 8000 (the default for the simple python http server).<\/p>\n\n\n\n<p><\/p>\n\n\n\n<p>=\/<\/p>\n\n\n\n<p><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8220;Let&#8217;s make that ninja run!&#8221; The player character is not yet visible on the canvas, but we are going to change that very shortly.We want to set the player idle, and then also the additional player running animation. When we have the player sitting at idle, and able to run [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[25,22],"tags":[],"class_list":["post-61","post","type-post","status-publish","format-standard","hentry","category-entertainment","category-for-coders"],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/dreamshipcreations.com\/index.php\/wp-json\/wp\/v2\/posts\/61","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/dreamshipcreations.com\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/dreamshipcreations.com\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/dreamshipcreations.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/dreamshipcreations.com\/index.php\/wp-json\/wp\/v2\/comments?post=61"}],"version-history":[{"count":2,"href":"https:\/\/dreamshipcreations.com\/index.php\/wp-json\/wp\/v2\/posts\/61\/revisions"}],"predecessor-version":[{"id":835,"href":"https:\/\/dreamshipcreations.com\/index.php\/wp-json\/wp\/v2\/posts\/61\/revisions\/835"}],"wp:attachment":[{"href":"https:\/\/dreamshipcreations.com\/index.php\/wp-json\/wp\/v2\/media?parent=61"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/dreamshipcreations.com\/index.php\/wp-json\/wp\/v2\/categories?post=61"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/dreamshipcreations.com\/index.php\/wp-json\/wp\/v2\/tags?post=61"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}