How to detemine which sprite called the pointerdown handler?

I’m working on a level select screen in Phaser 3.

phaser3_level_select
I’ve created a grid of level icons each with a number and add an handler to each icon, see code below.
However, in the pointerdown handler as input I only see a pointer, x,y coordinates and an Object:StopPropagation (whatever that is), the parameters do not include the sprite, is that correct?

My question is: In the pointerdown event handler, how can I retrieve the sprite that called the handler so that I can use its getData() method?

create: function ()
{
	// add all level select icons
	var index = 0;
	for (var y=0; y < LEVEL_SELECT_Y; y++) {
		for (var x=0; x < LEVEL_SELECT_X; x++) {
		
			// next position
			var xpos = 96 + x * 96;
			var ypos = 128 + y * 96;
			
			// add panel icon and add number
			var icon1 = this.add.image(xpos, ypos, "sprites", "select1");
			var txt = this.add.bitmapText(xpos, ypos-6, "fontwhite", ""+(index+1), 40);
			txt.setOrigin(0.5).setCenterAlign();
			
			// store level index in data of sprite, to use in the pointerdown handler
			icon1.setData("index", index);

			// add input handler
			icon1.setInteractive();
			icon1.on('pointerdown', this.onLevelIconDown.bind(this));

			// next level index
			index++;
		};
	};
},

onLevelIconDown: function(pointer, x, y, PropagationObj) {
	debugger;
	// ?? how to determine which sprite called onLevelIconDown ??
},
1 Like

In my code, I would normally write the handler in-line so that I would have icon1 in scope through a closure. However, that is a good question on how to use a separate handler method and refer back to the source game object since all of the targets in the pointer event are DOM-generated and only refer to the canvas itself (in non-game development JS, that is how you would get a reference to the event target).

I would also be interested in a good strategy for handling this.

1 Like

Looking at the Destroy Sprite On Down Event example, it seems that in Phaser3 you can only set a global handler for ALL gameobjects in the scene, not for individual game objects.

The only downside is that ALL interactive objects will call this handler. If you also have other interactive images (like a back-button etc) they will also trigger the gameobjectdown-handler when clicked. So unless there is a way to set the handler for each sprite, I think I’ll change my code to something like this:

create: function ()
{
	// add all level select icons
	var index = 0;
	for (var y=0; y < LEVEL_SELECT_Y; y++) {
		for (var x=0; x < LEVEL_SELECT_X; x++) {
		
			// next position
			var xpos = 96 + x * 96;
			var ypos = 128 + y * 96;
			
			// add panel icon and add number
			var icon1 = this.add.image(xpos, ypos, "sprites", "select1");
			var txt = this.add.bitmapText(xpos, ypos-6, "fontwhite", ""+(index+1), 40);
			txt.setOrigin(0.5).setCenterAlign();
			
			// store level index in data of sprite, to use in the pointerdown handler
			icon1.setData("levelindex", index);

			// add input handler
			icon1.setInteractive();

			// next level index
			index++;
		};
	};

	// set down handler for all interactive objects in scene
	this.input.on('gameobjectdown', this.onGameObjectDown, this);
},

onGameObjectDown: function(ptr, img) {
	// get level index from sprite
	var levelindex = img.getData("index");
	
	// make sure level icon was clicked, in that case levelindex is defined
	if (typeof levelindex !== "undefined" ) {
		// etc.
	};
},

There is a way to avoid the global event listener if you want to, by the way. Your old code already used bind to set the handler’s context. bind can receive additional arguments, which will be passed to the function. So, if you instead use this.onLevelIconDown.bind(this, icon1), the handler will receive the icon as the first argument, followed by the pointer and the coordinates.

As a side note, the fourth argument (the one with the stopPropagation function) is the event object itself. You can call that function to stop the event from propagating to lower game objects or scenes.

3 Likes

@Telinc1 nice, thanks for pointing it out :sunglasses: So the code from the first post with these changes, this works

// add input handler
icon1.setInteractive();
icon1.on('pointerdown', this.onLevelIconDown.bind(this, icon1));

// and

onLevelIconDown: function(img, pointer, x, y, PropagationObj) {
    var idx = img.getData("index");

@Telinc1 Oh crap! I should have thought of that :stuck_out_tongue: I had just used that earlier that day at work haha! Good thinking there!