BrunoHautenfaust Posted August 25, 2015 Share Posted August 25, 2015 After 5 hours I still can't get a decent animation. My eyes and head already hurt. And there I thought this was supposed to be a breeze. function preload () { game.load.spritesheet('idle', 'resources/standing/krn_standing.png', 138, 359); game.load.spritesheet('running', 'resources/running/krn_running.png', 321, 357); }function create () { player = game.add.sprite(game.world.width / 2, 0, 'idle'); player.animations.add('idle'); player.animations.add('running');}function update() { if (controls.right.isDown) { player.body.velocity.x = 150; player.animations.play('running', 10, true); } else { player.body.velocity.x = 0; player.animations.play('idle', 10, true); } }}player.add.sprite loads a spritesheet and uses it only. Regardless of the fact that I add other spritesheets and animations. Only the idle sequence is being played.I've tried cramming 'idle' and 'running' in one png file and defining with an array from which frame to which to do what. The result - the entire sheet played and disappeared. Even though it was set to loop. Can't reproduce that as I don't remember how I did it. Link to comment Share on other sites More sharing options...
CodeToWin Posted August 25, 2015 Share Posted August 25, 2015 you never specify the frames to use in your animations. You should have something like player.animations.add('player_idle', [8,9,10,11,12], 4, true); Link to comment Share on other sites More sharing options...
BrunoHautenfaust Posted August 25, 2015 Author Share Posted August 25, 2015 I'm not specifying the frames because the whole spritesheet contains all the needed frames. I have one spritesheet for 'idle' and another one for 'running'. And what I'm trying to do is: if (moving right) { player.animations.play('running', 10, true); } else { player.animations.play('idle', 10, true); } Basically, the object sees only this spritesheet: player = game.add.sprite(game.world.width / 2, 0, 'idle');And even if I tell the object to move and change the animation(loaded from another spritesheet), it won't do that. Link to comment Share on other sites More sharing options...
CodeToWin Posted August 25, 2015 Share Posted August 25, 2015 Ah, thanks. That wasn't clear to me. try adding a stop command before you start the new animation. Link to comment Share on other sites More sharing options...
Tom Atom Posted August 25, 2015 Share Posted August 25, 2015 Hi, you have to change texture from idle to running and back. It is also good to track if character is running or not, because loadTexture can do some allocations and you are currently triggering animation on every update. It is OK, as triggering the same animation that is currently running is ignored, but you are also changing texture... update() { // shortcut var keyboard: Phaser.Keyboard = this.game.input.keyboard; if (keyboard.isDown(Phaser.Keyboard.RIGHT)) { if (!this.running) { this.player.loadTexture("running") this.player.animations.play('running', 10, true); this.running = true; } this.player.body.velocity.x = 15; } else { if (this.running) { this.player.loadTexture("idle") this.player.animations.play('idle', 10, true); this.running = false; } this.player.body.velocity.x = 0; } } Link to comment Share on other sites More sharing options...
BrunoHautenfaust Posted August 25, 2015 Author Share Posted August 25, 2015 Ah, thanks. That wasn't clear to me. try adding a stop command before you start the new animation. I already did. It freezes the animation altogether.Right now I'm trying(again...) to use one spritesheet: game.load.spritesheet('sheet', 'resources/sheet.png'); << So far, so goodvar idle = player.animations.add('idle', [0,1,2,3], 10, true); << Something's wrong here. I think it's because there's no connection to 'sheet'. And I don't know how it should be established.player.animations.play('idle', 10, true); << Most likely here, tooAnd I get Cannot read property 'index' of undefined I read the documentation about Animations: packed with arguments which nobody seems to use. And I've been looking at source codes, googling, youtubing and swearing this whole beautifully wasted day. EDIT: TomAtom, what is 'this' in this case?(No pun intended). The update method? Also, isn't loadTexture() kinda heavy on resources? EDIT 2:OK. Getting a bit closer(or not). I switched to Phaser.CANVAS. Because WebGL is giving me a hard time.Here's what I got:- game.load.spritesheet('sheet', 'resources/sheet_old.png', 321, 360);- player = game.add.sprite(game.world.width / 2, 0, 'sheet');function update() { controls = game.input.keyboard.createCursorKeys(); game.physics.arcade.collide(player, platforms); // controls: if (controls.left.isDown) { // left player.body.velocity.x = -150; } else if (controls.right.isDown) { player.body.velocity.x = 150; player.animations.play('sheet', 19, [8,9,10,11,12,13,14,15]); } else { player.body.velocity.x = 0; player.animations.play('sheet', [0,1,2,3], true); } if (controls.up.isDown) { player.body.velocity.y = -350; } }As I have both idle and running sequence on one spritesheet, no matter what I do, it keeps playing all the frames. EDIT 3: I tried with the 'dude' sprite from the tutorials and it worked. Guess the spritesheet size is crucial for all this crap to work. But wait... no. It works now. Oh, COME ON!!!! A whole day wasted and NOW it works!? Somehow. It appears that adding more arguments to the game.animations.play(<desired animation>), other than just the desired animation,can break things tremendously. I am too tired to be confused... Link to comment Share on other sites More sharing options...
Tom Atom Posted August 25, 2015 Share Posted August 25, 2015 TomAtom, what is 'this' in this case?(No pun intended). The update method? Also, isn't loadTexture() kinda heavy on resources? 1) code I pasted in my answer was written in Typescript. But the idea should be clear - changing texture to needed one and doing so only if necessary ... 2) loadTexture is way how to switch texture if you have animations in different spritesheets. Although it says "load" it may not do any loading from disk or so as Phaser looks into cache if texture is already there. Anyway, there is some overhead and it is always better to create spritesheets with all needed frames or even better to use atlases as you can get rid of empty spaces (altases are much better packed than spritesheets). BrunoHautenfaust and jdnichollsc 2 Link to comment Share on other sites More sharing options...
jdnichollsc Posted August 26, 2015 Share Posted August 26, 2015 Use a atlas or a big spritesheet with all frames and you don't need change the texture my friend To improve your code, you can changeplayer.animations.play('sheet', 19, [8,9,10,11,12,13,14,15]);for thisplayer.animations.play('sheet', 19, Phaser.ArrayUtils.numberArray(8, 15));Regards, Nicholls BrunoHautenfaust 1 Link to comment Share on other sites More sharing options...
BrunoHautenfaust Posted August 26, 2015 Author Share Posted August 26, 2015 1) code I pasted in my answer was written in Typescript. But the idea should be clear - changing texture to needed one and doing so only if necessary ... 2) loadTexture is way how to switch texture if you have animations in different spritesheets. Although it says "load" it may not do any loading from disk or so as Phaser looks into cache if texture is already there. Anyway, there is some overhead and it is always better to create spritesheets with all needed frames or even better to use atlases as you can get rid of empty spaces (altases are much better packed than spritesheets). I tried loadTexture. It really does switch spritesheets. Neat! But maybe the best option as you all recommend is trying this atlas thing. Use a atlas or a big spritesheet with all frames and you don't need change the texture my friend To improve your code, you can changeplayer.animations.play('sheet', 19, [8,9,10,11,12,13,14,15]);for thisplayer.animations.play('sheet', 19, Phaser.ArrayUtils.numberArray(8, 15));Regards, NichollsThanks, Nicholls! I was wondering how to set an interval for the frames. Currently I'm trying out the atlas. It's not as complicated as I thought.I used this to export a JSON file with ShoeBox. Now I have a main.png and main.JSON. OK. Yet, I can't get it to work. I only get the first frame.game.load.atlas('main', 'main.png', 'main.json'); // Atlas preloadedplayer = game.add.sprite(game.world.width / 2, game.world.height / 2, 'main');player.animations.add('idle', Phaser.Animation.generateFrameNames('Krn', 0, 7, '', 3), 30, true); // The filenames are Krn_000 up to Krn_007. I even tried with "Krn_" as the first parameter in generateFrameNames().player.animations.play('idle'); // Doesn't work. I'm getting Uncaught TypeError: Cannot read property 'index' of undefined (phaser.js:68763)I took a peek at phaser.js. As far as I understood, for some reason it can't iterate over the frames. But why? Link to comment Share on other sites More sharing options...
Skeptron Posted August 26, 2015 Share Posted August 26, 2015 Could you show us your JSON atlas? Did you remove the images extensions in it? (Like "Krn_000" instead of "Krn_000.png") BrunoHautenfaust 1 Link to comment Share on other sites More sharing options...
BrunoHautenfaust Posted August 26, 2015 Author Share Posted August 26, 2015 I see. I should've removed the file extensions. And I did. Then I added that underscore. And it worked. But the animation is jiggly. Moving back and forth by a few pixels. Probably due to the x, y coordinates from 'frame' and/or 'spritesource'. They differ. Could it be from the texture padding? I hope there's an elegant fix for that? Because I'd sure hate to manually edit the spritesheet and test whether it works.I'm quite positive that most of the sprite problems I'm having are due to the fact that I'm using separate files for each frame. Which I pack in a spritesheet. But the final spritesheet is not quite as it should be. So far the sprites are 8 in total. Ordered in 2 rows and 4 columns. And some empty space in the bottom and right.Here's the edited JSON file:{"frames": [ { "filename": "Krn_000", "frame": {"x":0, "y":358, "w":133, "h":356}, "spriteSourceSize": {"x":331,"y":222,"w":800,"h":640}, "sourceSize": {"w":800,"h":640} }, { "filename": "Krn_001", "frame": {"x":0, "y":0, "w":138, "h":357}, "spriteSourceSize": {"x":326,"y":221,"w":800,"h":640}, "sourceSize": {"w":800,"h":640} }, { "filename": "Krn_002", "frame": {"x":134, "y":358, "w":133, "h":358}, "spriteSourceSize": {"x":331,"y":220,"w":800,"h":640}, "sourceSize": {"w":800,"h":640} }, { "filename": "Krn_003", "frame": {"x":268, "y":0, "w":132, "h":359}, "spriteSourceSize": {"x":332,"y":219,"w":800,"h":640}, "sourceSize": {"w":800,"h":640} }, { "filename": "Krn_004", "frame": {"x":268, "y":360, "w":128, "h":359}, "spriteSourceSize": {"x":336,"y":219,"w":800,"h":640}, "sourceSize": {"w":800,"h":640} }, { "filename": "Krn_005", "frame": {"x":401, "y":0, "w":122, "h":358}, "spriteSourceSize": {"x":342,"y":220,"w":800,"h":640}, "sourceSize": {"w":800,"h":640} }, { "filename": "Krn_006", "frame": {"x":397, "y":360, "w":122, "h":357}, "spriteSourceSize": {"x":342,"y":221,"w":800,"h":640}, "sourceSize": {"w":800,"h":640} }, { "filename": "Krn_007", "frame": {"x":139, "y":0, "w":128, "h":356}, "spriteSourceSize": {"x":336,"y":222,"w":800,"h":640}, "sourceSize": {"w":800,"h":640} }],"meta": { "image": "main.png", "size": {"w": 1024, "h": 1024}, "scale": "1"}} Link to comment Share on other sites More sharing options...
Skeptron Posted August 26, 2015 Share Posted August 26, 2015 Using separate images and turning them into a spritesheet is the correct way to do it. I've had spritesheets made from more than 40 images and they work really well. I'm surprised though : how come your sprite be squared (1024x1024) with 2 rows and 4 columns? You must be wasting a lot of memory for useless transparent space (I guess). How did you pack it? Did you use TexturePacker? There's a free version which really does a great job. And Damn I can't remember the exact structure of the JSON (don't have my code now), but what's the difference between frame and spriteSourceSize? Why those 2 fields? BrunoHautenfaust 1 Link to comment Share on other sites More sharing options...
BrunoHautenfaust Posted August 26, 2015 Author Share Posted August 26, 2015 I'm using shoebox. There were a lot of online spritesheet generators. I tried a few including leshylabs. But I was having problems properly animating while using game.load.spritesheet. I must've thought it was due to the spritesheet packer or something. Can't remember. Anyway, you're right. There's a lot of wasted empty space. But I plan on adding more frames. As this point I just want to get the idle animation going correctly. Here's what I've found out: We have a sprite and empty space around, like so:Sprite"frame": {"x":0, "y":358, "w":133, "h":356}, -> X and Y are the starting coordinates for each frame in the spritesheet, w and h are width and height of the frame."spriteSourceSize": {"x":331,"y":222,"w":800,"h":640}, -> X and Y are the starting coordinates for the sprite. W and H is the whole size of the file. The rest is empty space."sourceSize": {"w":800,"h":640} -> original size of each sprite imported in the sheet. I think I should crop them. Shoebox has such option. Or another way to look at it:"spriteSourceSize": {"x":331,"y":222, <sourceSize>}, I don't think I'm supposed to edit those manually. Feels like a waste of time. EDIT: Now I saw that the option for spritesheet export + JSON in Shoebox messes with the order of the files. Because of their names. So I should either change them manually or give that texture packer a go....TexturePacker's not bad.And what's the difference between JSONArray and JSONHash?EDIT2: For some reason exporting Phaser JSONArray file lead to Cannot read property 'index' of undefined.But using JSONHash worked. The spritesheet is smaller in size. Correctly arranged. And the animation is right. So far so good! However, I do need to point out that I had to edit the sprite.body size. Initially, the body size is quite big. But player.body.setSize(w, h, x, y); did the trick. And wouldn't you know it - importing more frames and assigning them different animations works flawlessly!This atlas thing is amazing! Only one question - is there a program that quickly removes sprite extensions in the JSON file? If not I suppose I could write one. Link to comment Share on other sites More sharing options...
Skeptron Posted August 26, 2015 Share Posted August 26, 2015 I'm pretty sure TexturePacker offers such an option. Anyways GG! =D Link to comment Share on other sites More sharing options...
Tom Atom Posted August 26, 2015 Share Posted August 26, 2015 I did small propagation to my texture atlas tool in this forum post: http://www.html5gamedevs.com/topic/3606-what-spritesheet-toolkit-does-everyone-use/page-2 The tool is free and offers additional benefits like adding custom properties, naming sprites, ... BrunoHautenfaust 1 Link to comment Share on other sites More sharing options...
BrunoHautenfaust Posted August 26, 2015 Author Share Posted August 26, 2015 Thanks, Tom! --- By the way, earlier I said that exporting Phaser JSONArray through TexturePacker gave me an error when trying to use it. It might have forgotten to save the file when I removed the file extensions in the JSON.As for what's the difference between JSONArray and JSONHash, I found out the following:Which of the two Phaser exporters you choose does not really matter. They contain the identical data with some different layout. It's just the loading instruction that is different. For now use Phaser (JSONHash).I'm just putting this here if anyone else wonders. EDIT: I found where the trimming sprite names option is in TexturePacker: Trim sprite names. Just needed to expand the Data settings. Link to comment Share on other sites More sharing options...
Recommended Posts