Suppression d'un enfant dans un groupe

Bonjour,

Je réalise en ce moment même un mini jeux 2D avec phaser 3 :smile:

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 :pensive:

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 :blush:

Tu devrais utiliser .each au lieu de .iterate si tu veux destroy un enfant.

Daccord merci je vais tester ça sur le champ :wink:

Ca fonctionne parfaitement. Merci beaucoup :blush:

1 Like