is there a way to bind a click handler to an individual isolated Sprite
sprite.getChildren().forEach(
s => s.setInteractive({ cursor: 'url(./src/games/gewgly/assets/images/pointer.png), pointer' })
);
I used this method to tie isolated sprites, but it hasn't worked yet, is there a better way
A Sprite in Phaser 3 cannot have children, so the sprite.getChildren part of your code worries me a bit. Only Groups have a getChildren method.
At its most simple:
const player = this.add.sprite(x, y, texture);
player.setInteractive();
player.on('pointerdown', () => {
console.log('You clicked the player sprite');
});
// Or, if you have a Group full of Sprites:
const sprites = yourGroup.getChildren();
sprites.forEach((child) => {
child.setInteractive();
child.on('pointerdown', () => {
console.log('You clicked a Group sprite');
});
});
Related
Right now i am working on a way to update the state of an element based on IF the mouse is down as well as if the mouse is over the element. This means that once the mouse is down, every time it hovers over one of the elements , the state changes.The tracking is inaccurate, it does not capture every single action. How do i better the process?
The code for my present implmentation is:
document.onmousedown = () => {
document.onmousemove = (e) => {
if (e.buttons === 1) {
let svg = e.target as HTMLElement;
if (svg.id.startsWith('svg')) {
let SVG_ID = svg.id;
let HoverPropsID = svg.id.replace('svg', 'props');
if (document.getElementById(HoverPropsID).classList.contains('no-node')) {
toRemove.forEach(element => document.getElementById(SVG_ID).classList.remove(element));
document.getElementById(SVG_ID).classList.add(`svg-${node}`);
document.getElementById(HoverPropsID).classList.remove('no-node');
document.getElementById(HoverPropsID).classList.add(node);
multiNodeGraphUpdate(node, Number(HoverPropsID.substring(HoverPropsID.lastIndexOf('-') + 1)), 10, false)
}
nodeHoverAnimation(HoverPropsID);
}
}
}
I understand that the information i have provided might be a big ambiguous, so i am linking two website, one is the inspiration website: https://clementmihailescu.github.io/Pathfinding-Visualizer/
and the other one is the WiP webiste (my one):https://aarnavv.github.io/Vagus/
The game I'm creating doesn't require any physics, however you are able to interact when hovering over/clicking on the sprite by using sprite.setInteractive({cursor: "pointer"});, sprite.on('pointermove', function(activePointer) {...}); and similar. However I noticed two issues with that:
The sprite has some area which are transparent. The interactive functions will still trigger when clicking on those transparent areas, which is unideal.
When playing a sprite animation, the interactive area doesn't seem to entirely (at all?) change, thus if the sprite ends on a frame bigger than the previous, there end up being small areas I can't interact with.
One option I thought of was to create a polygon over my sprite, which covers the area I want to be interactive. However before I do that, I simply wanted to ask if there are simpler ways to fix these issues.
Was trying to find an answer for this myself just now..
Think Make Pixel Perfect is what you're looking for.
this.add.sprite(x, y, key).setInteractive(this.input.makePixelPerfect());
https://newdocs.phaser.io/docs/3.54.0/focus/Phaser.Input.InputPlugin-makePixelPerfect
This might not be the best solution, but I would solve this problem like this. (If I don't want to use physics, and if it doesn't impact the performance too much)
I would check in the event-handler, if at the mouse-position the pixel is transparent or so, this is more exact and less work, than using bounding-boxes.
You would have to do some minor calculations, but it should work well.
btw.: if the origin is not 0, you would would have to compensate in the calculations for this. (in this example, the origin offset is implemented)
Here is a demo, for the click event:
let Scene = {
preload ()
{
this.load.spritesheet('brawler', 'https://labs.phaser.io/assets/animations/brawler48x48.png', { frameWidth: 48, frameHeight: 48 });
},
create ()
{
// Animation set
this.anims.create({
key: 'walk',
frames: this.anims.generateFrameNumbers('brawler', { frames: [ 0, 1, 2, 3 ] }),
frameRate: 8,
repeat: -1
});
// create sprite
const cody = this.add.sprite(200, 100).setOrigin(0);
cody.play('walk');
cody.setInteractive();
// just info text
this.mytext = this.add.text(10, 10, 'Click the Sprite, or close to it ...', { fontFamily: 'Arial' });
// event to watch
cody.on('pointerdown', function (pointer) {
// calculate x,y position of the sprite to check
let x = (pointer.x - cody.x) / (cody.displayWidth / cody.width)
let y = (pointer.y - cody.y) / (cody.displayHeight / cody.height);
// just checking if the properties are set
if(cody.anims && cody.anims.currentFrame){
let currentFrame = cody.anims.currentFrame;
let pixelColor = this.textures.getPixel(x, y, currentFrame.textureKey, currentFrame.textureFrame);
// alpha > 0 a visible pixel of the sprite, is clicked
if(pixelColor.a > 0) {
this.mytext.text = 'Hit';
} else {
this.mytext.text = 'No Hit';
}
// just reset the textmessage
setTimeout(_ => this.mytext.text = 'Click the Sprite, or close to it ...' , 1000);
}
}, this);
}
};
const config = {
type: Phaser.AUTO,
width: 400,
height: 200,
scene: Scene
};
const game = new Phaser.Game(config);
<script src="https://cdn.jsdelivr.net/npm/phaser#3.55.2/dist/phaser.js"></script>
I've got two sets of range sliders on a video file that need some fine-tuning.
Clicking and dragging the slider will adjust the settings. But clicking without dragging will not change the settings, it will only move the slider.
I need the slider to adjust the settings when any point is clicked within the range. In the words, if the range is currently set to the far right and I click the far left, I'd like it to change settings.
I tested it and noticed that the line with the comment doesn't seem to activate the function handleRangeUpdate.
const ranges = player.querySelectorAll(".player__slider");
let isDragging = false;
function handleRangeUpdate() {
if (!isDragging) return;
console.log(`${this.name}: ${this.value}`);
video[this.name] = this.value;
}
ranges.forEach(range => range.addEventListener("mousemove", handleRangeUpdate));
ranges.forEach(range =>
range.addEventListener("mousedown", () => {
isDragging = true;
handleRangeUpdate; // This doesn't seem to function
})
);
ranges.forEach(range =>
range.addEventListener("mouseup", () => (isDragging = false))
);
You can find all my code on: My Github Repo
I am new to Famo.us, can anybody explain me what does rootmodifers do in famo.us, here is its example
function SlideshowView () {
Views.apply(this, arguments);
this.rootModifier = new StateModifier({
size:this.options.size
});
this.mainNode = this.add(this.rootModifier);
_createLightBox.call(this);
_createSlides.call(this);
}
this.rootMidifier just allows you to have a way to control the entire slideShow's position, opacity, origin, or alignment later in the applications. More importantly this.rootModifier is added to the render node like this this.mainNode = this.add(this.rootModifier); This code places the modifier at the top of the render tree for the slideshow branch and exposes access to the modifier for later use in the all. For example later in the app you could have a function that changes the opacity.
SlideShow.prototype.hide = function() {
this.rootModifier.setOpacity(0, {duration: 3000});
}
I have a scrollview with a number of images.
events are working such that the scrollview can be dragged around.
i want to be able to click on a single image to get a detail view so used a:
surface.on 'click', => #parent.navTo('detail')
however, this has the effect that if i click an image when scrolling the above event will also fire.
i guess this is the whole reason mobile browsers have that 300ms delay - to tell if you're clicking or dragging. does Famous have other events to listen for?
In inputs/FastClick.js i only see 'touchstart' 'touchmove' and 'touchend'
do we have to track if a drag motion happened, in our own code, or does the famous engine assist with this?
FWIW i'm using a GenericSync to pipe the events around, and to make the view also work on the desktop.
constructor: (#parentView, #data) ->
SCROLLDIR = 1 # 0 horiz, 1 vertical
super({
direction: SCROLLDIR
paginated: true
pageStopSpeed: 5
})
#addContent()
#mouseSync = new famous.inputs.MouseSync({direction: SCROLLDIR})
#mouseSync.pipe(this)
addContent: () ->
comics = Comics.find()
surfaces = []
#sequenceFrom(surfaces)
for item in comics.fetch()
div = document.createElement('div')
comp = UI.renderWithData(Template.comicCover, item)
UI.insert(comp, div)
surface = new famous.core.Surface({
content: div
size: [undefined, 400]
properties:
backgroundColor: "#eff"
})
surfaces.push(surface)
surface.pipe(this)
surface.on 'click', => #parentView.navTo('comicPages')
# surface.pipe(#mouseSync)
return #surface
I have encountered a similar issue. To get around it, I simply track when the scrollview is scrolling and then ensure not scrolling on click.
Here is the code that I would add.. Hope it helps!
# In constructor
this.sync.on 'update', () => #scrolling = true
this.sync.on 'end', () => #scrolling = false
# In addContent
surface.on 'click', () =>
if !#scrolling
#parentView.navTo('comicPages')