I am trying to port a word game from Pixi.js version 6.5.9 to 7.2.3:
In the game I use a custom class Tile.js
to represent the yellow draggable letter tiles:
'use strict';
function Tile(letter, value) {
PIXI.Container.call(this); // Uncaught TypeError: Class constructor _Container cannot be invoked without 'new'
this.col = NaN;
this.row = NaN;
this.letter = letter;
this.value = value;
// is this tile being dragged?
this.drag = false;
this.graph = new PIXI.Graphics();
this.addChild(this.graph);
this.letterText = new PIXI.Text('', {fontFamily: 'Arial', fontSize: 40, fill: 0x000000});
this.letterText.anchor.set(0.5);
this.addChild(this.letterText);
this.indexText = new PIXI.Text('', {fontFamily: 'Arial', fontSize: 20, fill: 0x000000});
this.indexText.anchor.set(1);
this.addChild(this.indexText);
this.setLetter(letter);
this.setValue(value);
}
The class extends the PIXI.Container
class by using this code:
Tile.prototype = Object.create(PIXI.Container.prototype);
Tile.prototype.constructor = Tile;
And then to implement dragging I have added the methods:
Tile.prototype.setIteractive = function(onDragStart, onDragMove, onDragEnd) {
this.eventMode = 'static'; // previously: this.interactive = true;
this.buttonMode = true;
// it is important to set hitArea, otherwise pointerdown will be called on wrong tiles
this.hitArea = new PIXI.Rectangle(0, 0, Tile.WIDTH, Tile.HEIGHT);
this.on('pointerdown', onDragStart)
.on('pointermove', onDragMove)
.on('pointerup', onDragEnd);
};
Tile.prototype.startDragging = function() {
this.drag = true;
this.scale.x = 1.4;
this.scale.y = 1.4;
this.alpha = 0.9;
};
Tile.prototype.stopDragging = function() {
this.drag = false;
this.scale.x = 1;
this.scale.y = 1;
this.alpha = 1;
};
After upgrading from Pixi.js version 6.5.9 to 7.2.3 I get the following error in the Edge browser console:
Uncaught TypeError: Class constructor _Container cannot be invoked without 'new'
Has my way of extending the Container
class been deprecated?
I have searched at the Github trying to understand, how to extend classes in the PixiJS v7 properly... I have tried to understand how Container
extends DisplayObject
, but it is very different syntax (maybe because it is typescript?)...
UPDATE:
I have tried the suggestion by @domis86 and have rewritten my custom Tile.js
class to have a PIXI.Container member:
function Tile(letter, value) {
var _col = NaN;
var _row = NaN;
var _letter = letter;
var _value = value;
// is this tile being dragged?
var _drag = false;
var _cont = new PIXI.Container();
_cont.eventMode = 'static';
_cont.buttonMode = true;
// the following line does not work, is undefined
_cont.tile = this;
var _graph = new PIXI.Graphics();
_cont.addChild(_graph);
var _letterText = new PIXI.Text('', {fontFamily: 'Arial', fontSize: 40, fill: 0x000000});
_letterText.anchor.set(0.5);
_cont.addChild(_letterText);
var _indexText = new PIXI.Text('', {fontFamily: 'Arial', fontSize: 20, fill: 0x000000});
_indexText.anchor.set(1);
_cont.addChild(_indexText);
setLetter(letter);
setValue(value);
function getContainer() {
return _cont;
}
function setIteractive(onDragStart, onDragMove, onDragEnd) {
_cont.eventMode = 'static';
_cont.buttonMode = true;
setDrawSides(true, true, true, true);
// it is important to set hitArea, otherwise pointerdown will be called on wrong tiles
_cont.hitArea = new PIXI.Rectangle(0, 0, WIDTH, HEIGHT);
_cont.on('pointerdown', onDragStart)
.on('pointermove', onDragMove)
.on('pointerup', onDragEnd);
}
function startDragging() {
_drag = true;
_cont.scale.x = 1.4;
_cont.scale.y = 1.4;
_cont.alpha = 0.9;
redraw();
}
function stopDragging() {
_drag = false;
_cont.scale.x = 1;
_cont.scale.y = 1;
_cont.alpha = 1;
redraw();
}
...more methods here...
// return the public methods
return {
getContainer: getContainer,
setIteractive: setIteractive,
startDragging: startDragging,
stopDragging: stopDragging,
...
redraw: redraw
};
}
The problem is, when a Tile
instance is being dragged, then the pointerdown
and other events are now called on the _cont
and not on the Tile
instance itself - and then I do not know how to access the additional properties (like _letter
, _value
, _col
, _row
) of the letter tile:
function onDragStart(ev) {
this.data = ev.data;
var pos = this.data.getLocalPosition(this.parent);
this.x = pos.x - this.width / 2;
this.y = pos.y - this.height / 2;
// put the tile on top
app.stage.removeChild(this);
app.stage.addChild(this);
// the following line gives error because PIXI.Container does not have the method
this.startDragging();
// here I only have access to the _cont through "this"
// but how to access the _letter, _value of the tile?
}
I have tried adding a .tile
property to the _cont
by:
_cont.tile = this;
but it gives me undefined
when I try to access this.tile
in onDragStart
UPDATE 2:
The PixiJS Elementals tutorial mentions that there is a way to pass a custom object (which would be the Tile
instance in my case) to mouse events:
The basic anatomy of adding an event listener to an imput is: yourObject.on("stringOfWhatYouWantToKnow", functionToBeCalled, contextForTheFunction)
but how to add it to my code, since this
seems to be undefined and how to read it in the onStartDrag()
etc.?
I prepared jsfiddle :
https://jsfiddle.net/k1qr5m8g/
( is modified example from user bigtimebuddy from question "what's suggested way of implementing dragging in v7?" - https://github.com/pixijs/pixijs/discussions/8813#discussioncomment-4038065 )
Please run it and observe the browser console. You should see something like this after clicking on rectangle (sprite):
called Tile.getMyValue() - value: 123
dumping "this":
Object { iAmTile: true }
The PixiJS Elementals tutorial mentions that there is a way to pass a custom object (which would be the Tile instance in my case) to mouse events:
Notice this code fragment:
// Here we are passing the "that" (aka: original "this" of Tile object instance) as third argument.
// It will cause "this" inside getMyValue function to point to the Tile instance.
sprite.on('pointerdown', getMyValue, that);
Btw 1: I would recommend to convert your code to ES6 class - so as is done in https://www.pixijselementals.com/#getting-interactive
Btw 2: in your code do you create instances of Tile objects using "new" keyword? See at end of jsfiddle:
var tileInstance = new Tile('A', 123, app);
tileInstance.initializeInteractiveListeners();