Collision problem with a body physics

Bonjour à vous,

Je suis confronté à un problème qui est que le corps physique d’un de mes personnages (chauve souris) est à un endroit qu’il ne devrait pas être. Il y a d’ailleurs le même problème avec la boule d’énergie que lance le magicien. En gros voici 2 images du jeu :

En faite ma chauve souris est soumis à la physics car je veux qu’elle puisse rentrer en collision avec le zombie mais je ne veux pas qu’elle tombe au sol car je veux qu’elle reste dans les airs pour ça dans UPDATE() je dis que sa position en y = const pour qu’elle reste à la même position mais pourtant le rectangle violet tombe jusqu’à se stabiliser comme sur la 2ème image :pensive:

Quand ma chauve souris spawn le rectangle violet est positionné autour de mon image:

Mais il descend en fur est à mesure, jusqu’à se stabiliser à un moment pourtant l’image elle reste positionné comme il faut :

Voici le code de mon jeu (seulement la partie de gameplay) :

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.velocityXBat = 200;

	this.shootMageVelocity = 1.7;

	this.shieldActive = false;
	this.shootActive = false;
	
	this.frequenceShield = 3000;
	this.frequenceHeart = 3000;
	this.frequenceShoot = 3000;
	this.frequenceCoin= 1000;

	this.distanceShootMage = 200;
	this.timeBetweenShoot = 2000;

	this.frequencePersoMage= 300;
	this.frequencePersoBat= 1;

	this.positionYBat = 300;


	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);
    // BAT
	this.persoBat = this.physics.add.sprite(Phaser.Math.Between(200, 300), this.heightCamera-this.positionYBat, 'bat');
	this.persoBat.flipX = true;






    // ------------------ 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
	});



	// Bat
	this.anims.create({
	    key: 'fly-bat',
	    frames: this.anims.generateFrameNumbers('bat', { start: 0, end: 1 }),
	    frameRate: 10,
	    repeat: -1
	});




    // 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);
	this.physics.add.collider(this.persoBat, 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.collisionPlayer2 = this.physics.add.collider(this.player, this.persoBat, 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.collisionPlayer2.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 jeu fini
		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;
					that.collisionPlayer2.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);
	}

	// Pour Bat
	if (this.persoBat.x+this.persoBat.width <= this.cameras.main.worldView.x) {
		this.persoBat.setPosition(Phaser.Math.Between(this.positionRightCamera, this.positionRightCamera+this.frequencePersoBat), this.heightCamera-this.positionYBat);
	}
	

	// Il y a un bug lors de l'apparition 
	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.each(function (shoot) {


		shoot.y = that.persoMage.y;
		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();
		}




	});










	// ------------------ Déplacement des ennemis --------------------------------------------
	this.persoMage.setVelocityX(-this.velocityXMage);
	this.persoMage.anims.play('run-mage', true);

	this.persoBat.y = this.heightCamera-this.positionYBat;
	this.persoBat.setVelocityX(-this.velocityXBat);
	this.persoBat.anims.play('fly-bat', 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();
	}




}

}

Mon problème a été réglé :slight_smile: