Bonjour,
Je réalise en ce moment même un mini jeux 2D avec phaser 3
Mon problème est lorsque je veux supprimer un élément enfant d’un groupe précédemment crée dans la fonction UPDATE. Et plus particulièrement quand je veux supprimer une boule d’énergie envoyé par le sorcier lorsque celle ci est à plus de 200px du sorcier. Pour cela je fais shoot.destroy();
dans this.shootMage.children.iterate(function (shoot) { ... }
pour supprimer ma boule d’énergie mais sans succès
Voici une image du jeu en cours de développement :
Mais le problème : j’obtiens l’erreur suivante dans la console de mon navigateur : Uncaught TypeError: Cannot read property ‘x’ of undefined
Voici une partie de mon code pour vous éclairer (Scene de mon jeu uniquement):
class PlayScene extends Phaser.Scene {
constructor() {
super({
key: "PlayScene"
});
}
init () {
this.game.log('PlayScene.js', 'green');
}
// --------------------------------------------------------------------------------
// ------------------------------ PRELOAD --------------------------------------
// --------------------------------------------------------------------------------
preload () {
}
// --------------------------------------------------------------------------------
// ------------------------------ CREATE ---------------------------------------
// --------------------------------------------------------------------------------
create () {
// ------------------ Variables --------------------------------------------
this.gameOver = false;
// Largeur et hautaur de la camera (fenetre)
this.widthCamera = this.cameras.main.width;
this.heightCamera = this.cameras.main.height;
// Donne la position droite de la camera
this.positionRightCamera = this.cameras.main.worldView.x+this.cameras.main.width;
// Valeur du déplacement de
this.velocityX = 200;
this.velocityY = 650;
this.velocityXMage = 100;
this.shootMageVelocity = 1.7;
this.shieldActive = false;
this.shootActive = false;
this.frequenceShield = 3000;
this.frequenceHeart = 3000;
this.frequenceShoot = 3000;
this.frequenceCoin= 1000;
this.frequencePersoMage= 1;
this.distanceShootMage = 200;
this.timeBetweenShoot = 1000;
this.timeShield = 5000;
this.timeShoot = 5000;
this.nbCoin = 3;
this.nbLifes = 3;
this.scoreCoin = 10;
this.scorePotion = 100;
this.scoreChest = 150;
this.moneyCoin = 5;
this.moneyChest = 50;
// ------------------ Décors --------------------------------------------
// Ciel
this.background = this.add.image(this.widthCamera/2, this.heightCamera/2, 'sky').setScale(1.2).setOrigin(0.5, 0.5);
// Lune
this.moon = this.add.image(this.widthCamera/2+40, 150, 'moon').setOrigin(0.5, 0.5);
// ------------------ Les groupes --------------------------------------------
this.coins = this.physics.add.group();
this.potions = this.physics.add.group();
this.platforms = this.physics.add.staticGroup();
this.shootMage = this.physics.add.group();
// ------------------ Les pièces --------------------------------------------
// Créer un nombre max de pieces pour la partie
for (var i = 0; i < this.nbCoin; i++) {
this.coins.create(Phaser.Math.Between(this.positionRightCamera, this.positionRightCamera+this.frequenceCoin), this.heightCamera-150, 'coin');
}
// Pour tous les enfants de coins => met un rebond lors de leur chute
this.coins.children.iterate(function (coin) {
// Attribue une valeur de rebond
coin.setBounceY(Phaser.Math.FloatBetween(0.4, 0.8));
});
// ------------------ Le personnage FAZER --------------------------------------------
// Crée le sprite possédant un corps de physique dynamique par défault
this.player = this.physics.add.sprite(100, 450, 'fazer');
// Effet de rebond
this.player.setBounce(0.2);
// ------------------ Les ennemis --------------------------------------------
// MAGE
this.persoMage = this.physics.add.sprite(Phaser.Math.Between(this.positionRightCamera, this.positionRightCamera+this.frequencePersoMage), 450, 'mage');
this.persoMage.setBounce(0.2);
this.shootMageSprite = this.add.sprite(this.persoMage.x, this.persoMage.y, 'boule-energie').setOrigin(0, 0);
this.shootMage.add(this.shootMageSprite);
this.time.delayedCall(this.timeBetweenShoot, timeBetweenShoot, [], this);
// ------------------ Les potions --------------------------------------------
// potionShield
this.potionShield = this.potions.create(Phaser.Math.Between(this.positionRightCamera, this.positionRightCamera+this.frequenceShield), this.heightCamera-200, 'potion-shield').setOrigin(0.5, 1);
// Shield
this.shield = this.add.image(this.player.x, 700, 'shield').setOrigin(0.5, -0.5);
// potionHeart
// potionShoot
// ------------------ Les platformes au sol--------------------------------------------
this.platform1 = this.platforms.create(0, this.heightCamera-100, 'ground').setOrigin(0, 0).refreshBody();
this.platform2 = this.platforms.create(1000, this.heightCamera-100, 'ground').setOrigin(0, 0).refreshBody();
// ------------------ Les animations pour les différents personnages -------------------------------------------
// Mage
this.anims.create({
key: 'run-mage',
frames: this.anims.generateFrameNumbers('mage', { start: 3, end: 8 }),
frameRate: 10,
repeat: -1
});
this.anims.create({
key: 'dead-mage',
frames: this.anims.generateFrameNumbers('mage', { start: 0, end: 2 }),
frameRate: 10,
repeat: 0
});
// Fazer
this.anims.create({
key: 'idle',
frames: this.anims.generateFrameNumbers('fazer', { start: 0, end: 4 }),
frameRate: 10,
repeat: -1
});
this.anims.create({
key: 'run',
frames: this.anims.generateFrameNumbers('fazer', { start: 5, end: 9 }),
frameRate: 10,
repeat: -1
});
this.anims.create({
key: 'dead',
frames: this.anims.generateFrameNumbers('fazer', { start: 10, end: 13 }),
frameRate: 5,
repeat: 0
});
// Boule d'énergie
this.anims.create({
key: 'shoot',
frames: this.anims.generateFrameNumbers('boule-energie', { start: 0, end: 3 }),
frameRate: 10,
repeat: -1
});
// ------------------ Les collisions --------------------------------------------
// Collision entre le joeur et les platformes
this.physics.add.collider(this.player, this.platforms);
// Collision entre les ennemis et les platformes
this.physics.add.collider(this.persoMage, this.platforms);
// Collision entre els étoiles et les platformes
this.physics.add.collider(this.coins, this.platforms);
// Collision entre les potions et les platformes
this.physics.add.collider(this.potions, this.platforms);
this.physics.add.collider(this.platforms, this.shootMage);
// Collision entre le joueur et les bombes -
this.collisionPlayer = this.physics.add.collider(this.player, this.persoMage, damagePlayer, null, this);
this.collisionPlayerShoot = this.physics.add.collider(this.player, this.shootMage, damagePlayer, null, this);
// ------------------ Passage sur élément --------------------------------------------
// Si le joueur passe sur une étoile - on lance la fonction collectCoin
this.physics.add.overlap(this.player, this.coins, collectCoin, null, this);
// Si le joueur passe sur la potion de bouclier - on lance la fonction activeShield
this.physics.add.overlap(this.player, this.potionShield, activeShield, null, this);
// ------------------ Les vies --------------------------------------------
// Vies initiales
this.lifes = this.nbLifes;
// Affichage des coeurs
this.tab = [];
for (var i = 0; i < this.lifes; i++) {
this.tab.push(this.add.image(14 + 40*i, 16, 'heart').setOrigin(0, 0));
this.tab[i].setScrollFactor(0);
}
// ------------------ Le score --------------------------------------------
// Score initial
this.score = 0;
// Affiche le score dans le coin supérieur gauche
this.scoreText = this.add.text(this.widthCamera/2, 16, 'Score: 0', { fontSize: '32px', fill: '#fff' }).setOrigin(0.5, 0);
// ------------------ La caméra --------------------------------------------
this.cameras.main.setBounds(0, 0, 5000, 100);
this.cameras.main.startFollow(this.player, true, 0.08, 0.08, 0.1, 0.1);
// ------------------ Element ataché à la caméra --------------------------------------------
this.scoreText.setScrollFactor(0);
this.background.setScrollFactor(0);
this.moon.setScrollFactor(0);
// ------------------ Les événements --------------------------------------------
// Gère les touches de clavier
this.cursors = this.input.keyboard.createCursorKeys();
// Si appui sur la touche ECHAP on revient à l'accueil du jeu
this.input.keyboard.on('keyup-ESC', function() {
this.scene.start('MenuScene');
}, this);
// ------------------ FONCTION qui envoie une boule denergie a partir dun certains temps --------------------------------------------
function timeBetweenShoot() {
this.shootMage.create(this.persoMage.x, this.persoMage.y, 'boule-energie').setOrigin(0, 0);
// this.shootMageSprite = this.add.sprite(this.persoMage.x, this.persoMage.y, 'boule-energie').setOrigin(0, 0);
// this.shootMage.add(this.shootMageSprite);
this.time.delayedCall(this.timeBetweenShoot, timeBetweenShoot, [], this);
}
// ------------------ FONCTION qui gère la récupération d'une pièce + augmentation du score --------------------------------------------
function collectCoin (player, coin)
{
// ------------------ Gére le coin récupéré --------------------------------------------
// On détruit la piece récupéré
coin.destroy();
// On en créer une autre
this.coin = this.coins.create(Phaser.Math.Between(this.positionRightCamera, this.positionRightCamera+this.frequenceCoin), this.heightCamera-150, 'coin');
this.coin.setBounce(1);
// ------------------ Augmentation du score --------------------------------------------
// Ajout de points au score
this.score += this.scoreCoin;
// Met à jour le texte
this.scoreText.setText('Score: ' + this.score);
}
// ------------------ FONCTION qui gère la récupération de la potion de bouclier + augmentation du score + bouclier --------------------------------------------
function activeShield(player, potionShield) {
// ------------------ Gére la potion bouclier récupérée --------------------------------------------
// On détruit la potion récuperée
potionShield.destroy();
// ------------------ Augmentation du score --------------------------------------------
// Ajout de points au score
this.score += this.scorePotion;
// Met à jour le texte
this.scoreText.setText('Score: ' + this.score);
// ------------------ Bouclier --------------------------------------------
// Bouclier activé => plus de dégat causé par les ennemis
this.shieldActive = true;
// Après un certains temps le bouclier se désactive
this.durationShield = this.time.delayedCall(this.timeShield, removeShield, [], this);
}
// ------------------ FONCTION suppression du bouclier --------------------------------------------
function removeShield() {
// On cache le bouclier en dehors de la fenêtre
this.shield.setPosition(this.player.x, 700).setOrigin(0.5, 0.5);
// On désactive le bouclier - désormais vulnérable
this.shieldActive = false;
// Place une nouvelle potion de bouclier plus loin
this.potionShield = this.potions.create(Phaser.Math.Between(this.positionRightCamera, this.positionRightCamera+this.frequenceShield), this.heightCamera-200, 'potion-shield').setOrigin(0.5, 1);
this.physics.add.overlap(this.player, this.potionShield, activeShield, null, this);
}
// ------------------ FONCTION des vies du personnage --------------------------------------------
function damagePlayer (player, ennemi)
{
var that = this;
// On enlève la collision entre les 2 personnages
this.collisionPlayer.active = false;
this.collisionPlayerShoot.active = false;
// On enlève une vie si le bouclier n'est pas activé
if (this.lifes>=1 && !this.shieldActive) {
// -1 vie
this.lifes--;
// On déplace chaque coeur vers la gauche pour simuler le faite d'avoir perdu une vie car les coeurs seront caché pas la fenêtre
for (var i = 0; i < this.tab.length; i++) {
this.tab[i].x -= 40;
// Animation sur les coeurs
this.tweens.add({
targets: this.tab[i],
duration: 300,
ease: "Elastic",
easeParams: [1, 1],
scaleX: 1.1,
scaleY: 1.1,
}, this);
}
}
// Si le bouclier est activé lors de la collision entre l'ennemi et le joueur
if(this.shieldActive) {
// On lance une animation sur le bouclier
this.tweens.add({
targets: this.shield,
duration: 300,
ease: "Elastic",
easeParams: [1, 1],
scaleX: 1.1,
scaleY: 1.1,
onComplete: function(src, target) {
that.shield.setScale(1);
}
}, this);
}
// Si le joueur n'a plus de vie
if (this.lifes<=0) {
// Animation de mort
this.player.anims.play('dead', true);
// Le jeu est fini
this.gameOver = true;
// Il ne peut plus bouger
this.player.setVelocity(0);
// On va à lécran de scores après un certains délai
setTimeout(function() { that.scene.start('MenuScene')}, 1500);
}
// // Si il n'y a pas de Game
if (!this.gameOver) {
// Animation d'opacity sur Fazer
this.tweens.add({
targets: player,
duration: 300,
ease: "Elastic",
easeParams: [1, 1],
repeat: 3,
alpha: {
getStart: () => 0,
getEnd: () => 1
},
onComplete: function(src, target) {
that.collisionPlayer.active = true;
that.collisionPlayerShoot.active = true;
}
}, this);
} else {
// Animation d'opacity sur Fazer
this.tweens.add({
targets: player,
duration: 300,
ease: "Elastic",
easeParams: [1, 1],
repeat: 3,
alpha: {
getStart: () => 0,
getEnd: () => 1
}
}, this);
}
}
// ------------------ FONCTION lors d'un tir sur un ennemi --------------------------------------------
function damageEnnemis (shoot, ennemi)
{
ennemi.setX((this.positionRightCamera, this.positionRightCamera+this.frequencePersoMage), 450);
console.log('ok');
}
}
// --------------------------------------------------------------------------------
// ------------------------------ UPDATE ---------------------------------------
// --------------------------------------------------------------------------------
update () {
// ------------------ Variables --------------------------------------------
this.positionRightCamera = this.cameras.main.worldView.x+this.cameras.main.width;
// Si le bouclier est activé, on le place au centre du personnage
if (this.shieldActive) {
this.shield.setPosition(this.player.x, this.player.y).setOrigin(0.5, 0.5);
}
// ------------------ Re-spawn des ennemis --------------------------------------------
// Pour Mage
if (this.persoMage.x+this.persoMage.width <= this.cameras.main.worldView.x) {
this.persoMage.setPosition(Phaser.Math.Between(this.positionRightCamera, this.positionRightCamera+this.frequencePersoMage), this.heightCamera-150);
}
// Il y a un bug lors de l'apparition de nouvelle étoile donc rectification de leur position en y
if (this.persoMage.y < 0 || this.persoMage.y > this.cameras.main.worldView.height) {
this.persoMage.y = this.heightCamera/2;
this.persoMage.setBounce(0);
}
// ------------------ Re-spawn des objets --------------------------------------------
// Pour chaque pieces
this.coins.children.iterate(function (coin) {
// Si pièce non ramassé
if (coin.x+coin.width <= this.cameras.main.worldView.x) {
var aleat = Phaser.Math.Between(this.positionRightCamera, this.positionRightCamera+this.frequenceCoin);
coin.setPosition(aleat, this.heightCamera-150);
}
// Il y a un bug lors de l'apparition de nouvelle étoile donc rectification de leur position en y
if (coin.y < 0 || coin.y > this.cameras.main.worldView.height) {
coin.y = this.heightCamera/2;
coin.setBounceY(0);
}
}, this);
// Pour les potions de bouclier
if (this.potionShield.x+this.potionShield.width <= this.cameras.main.worldView.x && this.activeShield) {
this.potionShield.destroy();
this.potionShield = this.potions.create(Phaser.Math.Between(this.positionRightCamera, this.positionRightCamera+this.frequenceShield), this.heightCamera-200, 'potion-shield').setOrigin(0.5, 1);
}
// Il y a un bug lors de l'apparition de nouvelle étoile donc rectification de leur position en y
if (this.potionShield.y < 0 || this.potionShield.y > this.cameras.main.worldView.height) {
this.potionShield.y = this.heightCamera/2;
this.potionShield.setBounce(0);
}
// ------------------ Boule d'énergie --------------------------------------------
// this.shootMage.x -= this.shootMageVelocity;
// this.shootMage.anims.play('shoot', true);
// console.log(this.shootMage.x, this.shootMage.y);
var that = this;
this.shootMage.children.iterate(function (shoot) {
shoot.x -= that.shootMageVelocity;
shoot.anims.play('shoot', true);
shoot.flipX = true;
if (shoot.y > that.cameras.main.worldView.height) {
shoot.y = that.heightCamera/2;
}
var distance = that.persoMage.x - shoot.x
if ( shoot.x+shoot.width <= that.cameras.main.worldView.x || distance >= that.distanceShootMage) {
shoot.destroy();
// that.shootMage.remove(shoot[0]);
// that.shootMage.remove(shoot);
// that.shootMage.destroy(shoot);
// that.tweens.add({
// targets: shoot,
// duration: 300,
// ease: "Elastic",
// easeParams: [1, 1],
// repeat: 3,
// alpha: {
// getStart: () => 0,
// getEnd: () => 1
// },
// onComplete: function(src, target) {
// console.log(src);
// console.log(target);
// },
// });
}
});
// ------------------ Déplacement des ennemis --------------------------------------------
this.persoMage.setVelocityX(-this.velocityXMage);
this.persoMage.anims.play('run-mage', true);
// ------------------ Déplacement du personnage Fazer --------------------------------------------
if ( !this.gameOver ) {
// Si flèche de gauche enfoncée
if (this.cursors.left.isDown && this.player.x-this.player.width/2 >= this.cameras.main.worldView.x)
{
// Le joueur se déplace vers la gauche
this.player.setVelocityX(-this.velocityX);
// Joue l'animation de gauche
this.player.anims.play('run', true);
// Direction du personnage (regarde à gauche)
this.player.flipX = true;
}
// Si flèche de droite enfoncée
else if (this.cursors.right.isDown)
{
// Le joueur se déplace vers la droite
this.player.setVelocityX(this.velocityX);
// Joue l'animation de droite
this.player.anims.play('run', true);
// Direction du personnage (regarde à droite initialement)
this.player.flipX = false;
}
// Si aucune touche enfoncée
else
{
// Le joueur ne bouge plus
this.player.setVelocityX(0);
// Joue l'animation du milieu
this.player.anims.play('idle', true);
}
// Si le joueur saute et que le joueur touche bien le sol
if (this.cursors.up.isDown && this.player.body.touching.down)
{
// Le joueur saute
this.player.setVelocityY(-this.velocityY);
}
if (this.player.y > this.heightCamera) {
this.player.y = 100;
}
}
// ------------------ Caméra --------------------------------------------
// Empeche la camera de revenir vers la gauche
this.cameras.main.removeBounds();
this.cameras.main.setBounds(this.cameras.main.worldView.x, this.cameras.main.worldView.y, 5000, 100);
// Déplacement du sol
//
// EXEMPLE D'UN RECTANGLE
//
//
// x, y x+width, y
// ____________________________
// | |
// | |
// | |
// |____________________________|
// x, y+height x+width, y+height
//
// Si la coordonnée en x+width de la 1ère platforme sort de la vision de la caméra
// Alors on replace la sol tout a droite
if (this.platform1.x+1000 <= this.cameras.main.worldView.x) {
// On modifie la position en x de la 1ère plpatforme en la mettant tout à droite , cad pour x egal au cote droit de la camera
this.platform1.setPosition(this.cameras.main.worldView.x+this.cameras.main.worldView.width, this.heightCamera-100).refreshBody();
}
if (this.platform2.x+1000 <= this.cameras.main.worldView.x) {
// On modifie la position en x de la 2eme plpatforme en la mettant tout à droite , cad pour x egal au cote droit de la camera
this.platform2.setPosition(this.cameras.main.worldView.x+this.cameras.main.worldView.width, this.heightCamera-100).refreshBody();
}
}
}
J’espère que vous serez m’aider. En attendant je vous remercie grandement si vous arrivez à trouver mon erreur