I'm learning the phaser-framework to create a game, and want to make a start menu using a set of sprites I've created myself that have animations attached. Ideally, as you use 'wasd' or up and down on the keyboard, you would be able to scroll down the menu and the appropriate animation (https://imgur.com/a/TVqJRh9 for a sample)
Essentially I want to move through 5 sprites that start at one frame and are queued to animate as I scroll up and down the menu.
I've tried several things so far. My main idea was to hold all of the sprites in an array, and every time there is an appropriate key press add to an index variable so it knows which one to animate.
create() {
this.anims.create({
key: 'startanim',
frames: [
{key: 'start1'},
{key: 'start2'},
{key: 'start3'},
{key: 'start4'},
{key: 'start5'},
{key: 'start6'},
{key: 'start7'},
{key: 'start8'},
{key: 'start9'},
],
frameRate: 24,
repeat: 0,
})
this.startButton = this.add.sprite(500, 100, 'start1')
this.startButton2 = this.add.sprite(500, 200, 'start1')
this.startButton3 = this.add.sprite(500, 300, 'start1')
this.startButton4 = this.add.sprite(500, 400, 'start1')
this.startButton5 = this.add.sprite(500, 500, 'start1')
gameState.menuList = [this.startButton, this.startButton2, this.startButton3, this.startButton4, this.startButton5];
gameState.menuIndex = 0;
this.input.keyboard.on('keydown_S', () => {
gameState.menuList[gameState.menuIndex].play('startanim')
gameState.menuIndex++;
})
}
update() {
}
}
This is the closest I've gotten but if I try to add an event listener for it to go up the list it won't repeat a second time. If I put the listener in the update function it does them all at the same time . I'm honestly just looking for a push in the right direction as nothing in google seems to be helpful and I can't find anything directly related here.
I'd say you're on the right track, using array for the menu items. If I understand correctly you want to use the keyboard to go through the menu items, and each time the current selected menu item should play the animation continuously.
I think you need to make 2 changes, First make the animation repeat infinitely, and second stop the animation when selecting the next menu item. So something like this:
this.anims.create({
key: 'startanim',
frames: [
{key: 'start1'},
{key: 'start2'},
{key: 'start3'},
{key: 'start4'},
{key: 'start5'},
{key: 'start6'},
{key: 'start7'},
{key: 'start8'},
{key: 'start9'},
],
frameRate: 24,
repeat: -1 // <- once playing; infinitely repeat
})
and in the keyboard handler:
this.input.keyboard.on('keydown_S', () => {
// stop animation on current menu item (stop at first frame)
gameState.menuList[gameState.menuIndex].stopOnFrame(0);
// go to next menu item
gameState.menuIndex++;
// when past last menu item, warp to first
if (gameState.menuIndex > gameState.menuList.length-1) gameState.menuIndex = 0;
// play animation on new menu item
gameState.menuList[gameState.menuIndex].play('startanim');
})
Btw instead of .stopOnFrame(0) you could also just do .stop() and then setFrame(0) or something, to stop the animation immediately.
Related
I have a grid on this page. The last column is off screen to the right. I want to read the header cell text.
I saw this snippet at
https://pptr.dev/#?product=Puppeteer&version=v5.1.0&show=api-class-mouse
So I ran the code below in cucumber/puppeteer. There were no errors but nothing happened in the browser. So how do I scroll to the right using this feature or any other way.
I can't use querySelector... to get the header because the selectors don't exist until the column is visible. Please advise.
async function scrollRight() {
await this.page.mouse.wheel({ deltaX: 2500 })
}
Your scrollRight() function should have a part where the mouse hovers over the right column. In the linked example there is a page.mouse.move(x,y) which should be applied in your case as well.
To get the X Y coordinates of your column you can use elementHandle.boundingBox puppeteer function. With a simple formula you can position the cursor exactly to the center of the column.
E.g.:
async function scrollRight() {
const elem = await page.$('.last-column');
const boundingBox = await elem.boundingBox();
await page.mouse.move(
boundingBox.x + boundingBox.width / 2, // x
boundingBox.y + boundingBox.height / 2 // y
);
await page.mouse.wheel({ deltaX: 2500 });
}
To check visibility of the column you can use page.waitForSelector's visible: true option, which waits for the element to be visible, i.e. to not have display: none or visibility: hidden CSS properties. It defaults to false, so if it caused problems in your use case that it was not visible it may help.
await page.waitForSelector('.last-column', {
visible: true,
});
I am using multiatlas and json file for my sprites in Phaser 3. How can I set an offset (like setOrigin) for specific frames?
There are some properties in the json which I suppose may help, but I don't understand their meaning. What's the difference between sourceSize and spriteSourceSize? I have also seen anchor property, but I suspect it's an old Phaser version...
The best alternative would be if it was possible to set the frame offset in the animation definition itself, and not in the json definition of frames. But is it possible?
EDIT: nevermind, I misunderstood the question. It's about animation frames and setOrigin, and wether the setOrigin can be different for different frames. AFIAK all animation sprites get the same origin, so the same "anchor", but I'm not 100% sure about this.
v--old answer--v
Wait, are you storing the animation-sequence in the sprite json file? If so, I'd like to know how you do that, because AFAIK you have to create the animation sequences programmatically in JavaScript, I usually do that in the preloader:
// preloader scene
create: function ()
{
// create animations
this.anims.create({
key: 'anim_run',
frames: [
{ key: 'sprites', frame: 'guyrun1' },
{ key: 'sprites', frame: 'guyrun2' },
{ key: 'sprites', frame: 'guyrun3' },
{ key: 'sprites', frame: 'guyrun2' }
],
frameRate: 15,
repeat: -1
});
//..etc.
},
And you can start the animation with a startFrame parameter to offset the animation, i.e. start at a frame other than the first frame, like so
// start animation with random offset
var r = Phaser.Math.RND.between(0, 3);
mainguy.play('anim_run', null, r); // key, ignoreIfPlaying = null, startFrame = r
Basically the problem is that after you rotate the camera, the points that are given as arguments in the callback for dragging are not what I expected. I'm guessing I have to Rotate the given points also but I just couldn't.
Can Someone explain what is going on, is this some kind of bug or what should I do in order the sprite to follow the mouse cursor?
Easiest way to explain the problem is to reproduce it:
1) Go to Phaser Example Runner
2) Copy- Paste this code:
var config = {
type: Phaser.WEBGL,
parent: 'phaser-example',
scene: {
preload: preload,
create: create
}
};
var game = new Phaser.Game(config);
function preload ()
{
this.load.image('eye', 'assets/pics/lance-overdose-loader-eye.png');
}
function create ()
{
var image = this.add.sprite(200, 300, 'eye').setInteractive();
this.cameras.main.setRotation(Math.PI);
image.on('pointerover', function () {
this.setTint(0x00ff00);
});
image.on('pointerout', function () {
this.clearTint();
});
this.input.setDraggable(image);
this.input.on('dragstart', function (pointer, gameObject) {
gameObject.setTint(0xff0000);
});
this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
console.log(`x: ${dragX}, y: ${dragY}`);
gameObject.x = dragX;
gameObject.y = dragY;
});
this.input.on('dragend', function (pointer, gameObject) {
gameObject.clearTint();
});
}
3) Open the console, drag around the Eye and look at what coordinates are given.
4) If you remove line 24 (the rotation of the camera) Everything works as expected.
(The example is taken from Phaser 3 Official examples and a bit changed for the bug)
According to Phaser's API Documentation on the setRotation() method, the rotation given in radians applies to everything rendered by the camera. Unfortunately, your pointer isn't rendered by the camera so it doesn't get the same rotated coordinates. Not sure if this is a bug with the library or just a poorly documented exception, but I believe there is a workaround.
Create 2 variables to hold an initial position and a final position:
var image = this.add.sprite(200, 300, 'eye').setInteractive();
var initial = [];
var final = [];
Populate the initial position in your .on('dragstart') method:
this.input.on('dragstart', function (pointer, gameObject) {
initial = [
gameObject.x,
gameObject.y,
pointer.x,
pointer.y
];
gameObject.setTint(0xff0000);
});
Then, populate the final variable in your .on('drag') method:
this.input.on('drag', function (pointer, gameObject, dragX, dragY) {
final = [
gameObject.x, // not necessary but keeping for variable shape consistency
gameObject.y, // not necessary but keeping for variable shape consistency
pointer.x,
pointer.y
];
gameObject.x = initial[0] + (initial[2] - final[2]);
gameObject.y = initial[1] + (initial[3] - final[3]);
});
All we're doing here is keeping track of the change in pointer position and mimicking that change in our gameObject.
Every next search query starts with previous page height and index count.
What can I do to update the index count in cellRenderer and the height of the page on a new search query?
Next code help to avoid errors, but doesn't solve the problem:
cellRenderer = ({index, key, parent, style}) => {
const image = this.props.images.items[index];
if (!image) {
console.log('!image (empty image with index: ', index, 'style', style);
return;
}
Code: pastebin.com/FB7kzDb4
tl;dr You can fix your demo by doing the following:
// Clear any JIT measurements
cellMeasurerCache.clearAll();
// Reset the position cache
cellPositioner.reset({
columnCount: this.columnCount,
columnWidth: this.columnWidth,
spacer: this.spacer,
});
// Let Masonry know it needs to relayout
this.masonry.clearCellPositions();
Here is an example of me doing the same on the RV demo page. You can see it running here by clicking the "Reset List" button.
I am trying to zoom and pan a text which is draggable already. All the examples are on images or shapes and it seems I cannot adapt it to a text object. My questions are:
Do I have to use the anchors or is any simpler way zoom a text with Kineticjs?
I found an example regarding zooming a shape and the code crashes here:
var layer = new Kinetic.Layer({
drawFunc : drawTriangle //drawTriangle is a function defined already
});
Can we call a function while we are creating a layer?
I usually create a layer and then add the outcome of the function in it.
Any idea would be great, thanks.
I thought of many ways you could do this but this is the one I ended up implementing: jsfiddle
Basically, you have an anchor (which doesn't always have to be there, you can hide and show it if you would like. Let me know if you need help with that) and if you drag the anchor down it increases the fontSize, and if you drag the anchor up it decreases the fontSize.
I followed the exact same anchor tutorial but instead I added a dragBoundFunc to limit dragging to the Y-axis:
var anchor = new Kinetic.Circle({
x: x,
y: y,
stroke: '#666',
fill: '#ddd',
strokeWidth: 2,
radius: 8,
name: name,
draggable: true,
dragOnTop: false,
dragBoundFunc: function (pos) {
return {
x: this.getAbsolutePosition().x,
y: pos.y
};
}
});
And then I updated the updateAnchor() function to only detect the single anchor I added to the group named sizeAnchor:
var mY = 0;
function update(activeAnchor, event) {
var group = activeAnchor.getParent();
var sizeAnchor = group.get('.sizeAnchor')[0];
var text = group.get('.text')[0];
if (event.pageY < mY) {
text.setFontSize(text.getFontSize()-1);
} else {
text.setFontSize(text.getFontSize()+1);
}
sizeAnchor.setPosition(-10, 0);
mY = event.pageY;
}
Basically mY is used compared to the e.PageY to see if the mouse is moving up or down. Once we can determine the mouse direction, then we can decide if we should increase or decrease the fontSize!
Alternatively, you can use the mousewheel to do the exact same thing! I didn't implement it myself but it's definitely doable. Something like:
Mousewheel down and the fontSize decreases
Mousewheel up and the fontSize increases
Hopefully this emulates "Zooming" a text for you. And I guess being able to drag the text acts as "panning" right?
UPDATE (based on comment below)
This is how you would limit dragging to the Y-Axis using dragBoundFunc:
var textGroup = new Kinetic.Group({
x: 100,
y: 100,
draggable: true,
dragBoundFunc: function (pos) {
return {
x: this.getAbsolutePosition().x,
y: pos.y
};
}
});
See the updated jsfiddle (same jsfiddle as above)