Phaser game - get last frame of a sprite - javascript

I don't want to play animation,I want to chage sprite's frames by clicking right and left buttons.
var sprite = game.add.sprite(200, 100, 'mySprite');
sprite.frame = 3;
Now, if a right button is pressed I want this sprite goes to next frame
sprite.frame += 1;
If left button is pressed, sprites goes to the previous frame.
sprite.frame -= 1;
If left is pressed and current frame is 0 the sprite does not change it's frame, it stops on frame 0. I want the sprite goes from 0 to the last frame when I click left button.
For example, in Actionscript 3, I can do this:
sprite.gotoAndStop(sprite.totalFrames);
Is there "totalFrames" in Phaser/JS?

I did not find any answer, I have created a custom variable 'totalFrames' for all objects. The first frame is 0, then 1 and so on...
if (rightClick)
{
objects.frame += 1;
}
else if (leftClick)
{
if (objects.frame > 0)
{
objects.frame -= 1;
}
else
{
objects.frame = objects.totalFrames;
}
}

A bit late, buy you could try Phaser.GameObjects.Sprite.anims.getTotalFrames()

Related

Paper.js scale transform continues outside the onFrame event

I'm running into a bit of an odd issue with Paper.js - I'm using the library to scale the "petals" of a randomly generated flower while audio plays.
The issue crops up if the flower is "growing" and the user navigates to a different tab in the browser. Even though it appears that the onFrame event is not firing when the window is out of view, whichever petal is currently scaling at the time will continue to scale indefinitely.
I even tried using a special js library to determine if the window is in view and still wasn't able to get the petals to stop scaling.
You can view a demo here, as I was not even able to replicate this in a Paper sketch: https://demos2.paperbeatsscissors.com/
Also including my onFrame code here in case the problem is obvious to someone:
view.onFrame = function(event) {
// See if something is playing
if (playing > -1) {
// Get the active flower
var activeFlower = garden[playing],
activeData = activeFlower.data;
// Active layer and petal
var activeLayer = getEl(activeFlower, activeData.lIndex),
activePetal = getEl(activeLayer, activeData.pIndex);
// Variables
var time = activeData.audio.seek(),
scaleAmount = (1 / (activeData.timing / event.delta.toFixed(3))) * 2;
// Petal progression
if (!activeData.completed) {
if (activePetal.scaling.x < 1 && activePetal.scaling.y < 1) {
activePetal.pivot = {x: 0, y: activePetal.height / 2};
activePetal.scaling.x = activePetal.scaling.x + scaleAmount;
activePetal.scaling.y = activePetal.scaling.y + scaleAmount;
} else {
if (activeData.pIndex < (activeLayer.children.length - 1)) {
// If the petal is scaled, jump to a new petal
activeData.pIndex += 1;
} else {
if (activeData.lIndex > 0) {
// When all petals are bloomed, jump to a new layer
activeData.pIndex = 0;
activeData.lIndex -= 1;
} else {
// Set the flower as completed
activeData.completed = true;
}
}
}
}
activeFlower.rotate(.125, activeData.center);
// Reset the playing variable if the audio clip is complete and the flower has completed
if (!activeData.audio.playing() && time === 0 && activeData.completed) {
playing = -1;
}
}
}
Really stumped on this one so any help is greatly appreciated!
I think that your problem is coming from the fact that you base your scaling calculation on event.delta which represents the time elapsed since the last event fired.
The thing is that, if I'm not mistaken, under the hood, Paper.js onFrame event relies on requestAnimationFrame which does not fire when the tab if inactive.
So when you switch tab, wait for a while and get back to your tab event.delta value is big and your scaling value too, hence the size of your petals. This basic sketch showcase this behavior.
So in my opinion, you should simply check event.delta value and limit it if it's too high.

Phaser, make a button click event continuous

I'm using Phaser.js to create a map (tileSprite) and have some sprites on it, because not all the sprites can get in, I'm using the camera to pan right and left.
I want the user to either click a keyboard key (left or right) or a directional button sprite to continuously pan the camera until the user releases the control.
I've implemented keyboard panning similar to this example, I hold down a key and the camera moves/pans (10 pixels to each side on an event) and stops on key release.
However, when I've tried to implement the same thing using the 2 sprite buttons, each button fired only 1 event and panned the camera only 10 pixels per click. I need to to keep firing until I let go of the key.
var panRightButton = game.add.button(800, 5, 'right_pan_btn', onClickAction, this);
panRightButton.onInputOver.add(onButtonOver, this);
panRightButton.onInputOut.add(onButtonOut, this);
panRightButton.onInputDown.add(panScreenRight, this);
function panScreenRight() {
game.camera.x += 10;
}
I've tried using a boolean flag (isPanning) that would turn to true if i'm clicking a button and false on release. and have a while loop on game.camera.x += 10;, but it just slowed and stopped the script.
function onClickAction() {
isPanning = true;
}
function onButtonOut() {
isPanning = false;
}
function onButtonUp() {
isPanning = false;
}
function panScreenLeft() {
if (isPanning) {
game.camera.x -= 10;
}
}
The proper way to do it is on the update method, but not within a loop. Using a flag to know if the button is being pressed is ok, but just let Phaser to update the camera position, like in the example that you have linked:
function update() {
//...
if (isPanningLeft) {
game.camera.x -= 10;
} else if (isPanningRight) {
game.camera.x += 10;
}
//...
}
You don't need a loop because the update method is executed within a loop (and it is expected to be executed once by frame)

Image Slide Calculation (position,index,which..)

Goal
Create a responsive slide for low ram devices.(immagine a set of many images at high resolution.. mobile device would crash).i want to show only one image and preload N images.
Scenario
Let's say i have 77 images (nI=77,variable).
Obiovsly i want to load the first image, but also want to preload 2 images per side (nP=2,variable).
That is a total of 5 boxes ( center, 2left, 2right ).nB=nP*2+1.
On init i want to disply the boxes/images as follows(the number is the image index)
[75][76][0][1][2]
0, the first image is atm the only visible image.
Now comes the tricky part.
If i press < (next) the static visualizzation is:
[76][0][1][2][3]
but every box moves! so if we start with a default position set:
[75][76][0][1][2]//image index
[ 0][ 1][2][3][4]//box index
[-2][-1][0][1][2]//box position
<
[76][0][1][2][ 3]//image index
[ 1][2][3][4][ 0]//box index
[-2][-1][0][1][2]//box position
Pressing left loads the the following image into the first box, moves the first box into the last position, every other box moves (one offsetwidth) to the left.
>
[74][75][76][0][1]//image index
[4][ 0][ 1][2][3]//box index
[-2][-1][0][1][2]//box position
Pressing right loads the the preceding image into the last box, moves the last box into the first position, every other box moves (one offsetwidth) to the right.
Some relevant js
var I=ARRAYOFIMAGES,
nI=images.length,
nP=2,
nB=nP*2+1,
nC=0,
slideWidth=slide.offsetWidth; // CURRENT IMAGE INDEX 200px variable
function defaultPos(a,b){//[-400, -200, 0, 200, 400]
for(a=[],b=0;b<nB;b++){
a[b]=(b-nP)*slideWidth
}
return a
}
function currentInd(a,b){//[75, 76, 0, 1, 2]
for(b=[],a=0;a<nB;a++){
b[a]=(a+nC-nP+nI)%nI
}
return b
}
function next(e){
nC=++nC%nI;
d=1; // direction
calculate()
}
function prev(e){
nC=(--nC+nI)%nI;
d=0;
calculate()
}
function calculate(){
//for(BOXES){
// if(ISIMAGE2CHANGE){box[l].style.backgroundImage='url('+I[IMAGEINDEX]+')')}
// box[l].style.webkitTransform='translate3d('+POSITION+'px'+',0,0)';
//}
}
Partially working DEMO
First Demo
http://jsfiddle.net/VfYR4/
New Demo (shorter but not loading proper image)
http://jsfiddle.net/7Nedw/1/
Note: adjust the delay to -webkit-transition:-webkit-transform 1000ms ease 1000ms; to see what is going on.
Problem
The math is wrong. if the index is 0 and i move backwards the positions and indexes are messed up.
the function returns the wrong index to load,position and in which box to load.
Give your HTML markup like this
<img src="" data-src="images/1.jpg" alt="img0"/>
<img src="" data-src="images/2.jpg" alt="img1"/>
<img src="" data-src="images/3.jpg" alt="img2"/>
<img src="" data-src="images/4.jpg" alt="img3"/>
And use this method, when you will press your left or right button:
function preLoadImages() {
var $image = $(".my-image");
var $imageUnloaded = $(".my-image[src='']");
for(var i=current;i<current+4;i++) { //(current+1) is image index shown to user
var j = (i+$image.length)%$image.length;
console.log("Image to be loaded : "+j);
var $this = $($image[j]);
if($this.attr('src') == '') {
$this.attr('src',$this.data('src'));
}
}
}
You can change the logic slightly if you want to change the number of preload images on each side.

EaselJS SpriteSheet isn't responding to gotoAndPlay

I'm developing a Fez-based HTML5 Canvas game using EaselJS and I've found a problem, that I can't solve myself, while trying to implement SpriteSheets to the hero.
The problem is that I've defined three animations to my hero ("stand", "jump" and "run") and when I try to change from one animation to another using hero.gotoAndPlay("run") or hero.gotoAndStop("stand") the animations don't change, change but show the first frame only or change to the wrong animation.
Can someone help me? What I'm doing wrong and how can I fix it? Thanks.
Here's the relevant JavaScript code I'm using to create the hero Sprite:
var data = {
images: ["http://i.imgur.com/M0GmFnz.png"],
frames: {width:34, height:46},
animations: {
stand:0,
run:[0,12,true,0.25],
jump:13
}
};
var spriteSheet = new createjs.SpriteSheet(data);
var hero = new createjs.Sprite(spriteSheet, "stand");
hero.offset = 4 + 1; // "+1" is important, change the first number only.
hero.regX = hero.offset + 2;
hero.regY = hero.offset;
hero.width = 34 - (hero.offset*2) - 12;
hero.height = 46 - (hero.offset*2);
hero.x = 0;
hero.y = 0;
hero.jumping = true;
stage.addChild(hero);
And the code I'm using to change the animation:
if(!left && !right){ // User isn't pressing left arrow or right arrow
hero.gotoAndStop("stand");
}else{
hero.gotoAndPlay("run");
}
JSFiddle
Official Site
If you are calling gotoAndStop or gotoAndPlay in a tick (or similar) then it will constantly reset to the first frame. You have to ensure you only call these functions one time when the animation changes.
A good way to set this up is to store the current animation, store it, and only change it up if the animation changes. Something like:
var animation;
if(!left && !right){ // User isn't pressing left arrow or right arrow
animation = "stand";
}else{
animation = "run";
}
if (currentAnimation != animation) {
hero.gotoAndStop(animation);
}
This is just an example, but should give you an idea. You should only call these methods one time to kick off an animation.

make a div return to it's original position when animating to top( like jumping effect )

this is my code :
var pane = $('#Container'),
box = $('#PLayer'),
w = pane.width() - box.width(),
d = {},
x = 3;
function newv(v, a, b) {
var n = parseInt(v, 10) - (d[a] ? x : 0) + (d[b] ? x : 0);
return n < 0 ? 0 : n > w ? w : n;
}
$(window).keydown(function (e) { d[e.which] = true; });
$(window).keyup(function (e) { d[e.which] = false; });
setInterval(function () {
box.css({
left: function (i, v) { return newv(v, 37, 39); },
top: function (i, v) { return newv(v, 38, 40); }
});
}, 20);
<div id="Container" class="Container">
<div id="PLayer" class="player" ></div>
</div>
by this code i managed to make the div animate by using the arrow key but how can i make that jumping effect ? like the one used here
Here's a link to a fork of your fiddle:
http://jsfiddle.net/dJut2/
I made two changes:
Jquery wanted top to have an initial value while using the 2-argument callback inside .css(...), so I set it to 50% in CSS: .player{ ... top: 50%; }
I added "gravity" using another ternary check inside the input response/collision function. It checks against whether 38/the up-key is passed as an input case and adds 2 to the top: ... + (a==38 ? 2 : 0)
By the way, verbose variable names or comments could really make your code easier to read. Also, ternary operators aren't as efficient or readable as some if statements. Lastly, you should break your input response and collision functionality into specific cases so you can edit them each specifically later without having to refactor.
Lastly, if you want to simulate a 'jump', you'll need to have some kind of timed input case. This can be accomplished automatically with an acceleration variable (set it to a number, subtract it from the top every frame, and decrement it every frame flooring at 0 when on the ground; the gravity I added can be removed in this case) or some kind of specific animation (subtract 4 every frame for 20 frames).
If you want to do something similar to that platformer game you linked (which is awesome), why not just check out the source code for it? http://taffatech.com/Platformer.js
if(Player.isUpKey == true)
{
if(!Player.jumping){
Player.jumping = true;
Player.velY = -Player.speed*2;
}
}
If you look there you see he's not actually using CSS animations, but recalculating the player's position every frame. If the player hit's the up key, their y velocity is increased, and then every frame this is called to move the player
//gravity would be a numeric variable, this makes the player constantly move
//back downwards when they leave the ground
Player.velY += gravity;
//adjusting the player's position according to new
//calculated x and y velocity
Player.x += Player.velX;
Player.y += Player.velY;
This is similar to how most game engines work, recalculating the scenario and forces each frame so they can constantly react to what's going on. Instead of animations, a physics engine is doing the math and moving things accordingly on screen.

Categories