Code edit (1 edits merged)
Please save this source code
Code edit (6 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of undefined (reading 'length')' in or related to this line: 'scoreTest = this.pushers.length;' Line Number: 816
Code edit (4 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: scoreTest is not defined' in or related to this line: 'updateScoreTest(scoreTest);' Line Number: 1028
Code edit (1 edits merged)
Please save this source code
Code edit (18 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'sprite')' in or related to this line: 'this.vitesseEnCours = this.sprite.x < rocher.sprite.x ? this.vitessePS : -this.vitessePS; //on donne le sens du deplacement horizontal' Line Number: 765
Code edit (2 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: rocher is not defined' in or related to this line: 'rocher[i].sortPushers();' Line Number: 1003
Code edit (1 edits merged)
Please save this source code
Code edit (10 edits merged)
Please save this source code
User prompt
Please fix the bug: 'TypeError: Cannot read properties of null (reading 'sprite')' in or related to this line: 'this.vitesseEnCours = this.sprite.x < rocher.sprite.x ? this.vitessePS : -this.vitessePS; //on donne le sens du deplacement horizontal' Line Number: 634
Code edit (1 edits merged)
Please save this source code
Code edit (7 edits merged)
Please save this source code
User prompt
Please fix the bug: 'Uncaught TypeError: Cannot set properties of undefined (setting 'x')' in or related to this line: 'this.sprite.x = x;' Line Number: 439
Code edit (1 edits merged)
Please save this source code
Code edit (21 edits merged)
Please save this source code
User prompt
Migrate to the latest version of LK
Code edit (1 edits merged)
Please save this source code
Code edit (5 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: rochers is not defined' in or related to this line: 'for (var i = 0; i < rochers.length; i++) {' Line Number: 956
Code edit (7 edits merged)
Please save this source code
User prompt
Please fix the bug: 'ReferenceError: scoreZone is not defined' in or related to this line: 'victoireText.y = scoreZone.height;' Line Number: 798
Code edit (1 edits merged)
Please save this source code
/**** 
* Initialize Game
****/ 
var game = new LK.Game({
	backgroundColor: 0xAAAAAA
});
/**** 
* Game Code
****/ 
/* 
Game Zones:
- The game is played on a 2048x2732 pixels screen.
0. let playersZoneWidth = 200;
1. let ScoreZone = {x: 0, y: 0, width: app.screen.width, height: 200};
2. let OptionsZone = {x: 0, y: app.screen.height-200, width: app.screen.width, height: 200};
3. let HumanZone = {x: 0, y: 200, width: playersZoneWidth, height: app.screen.height-OptionsZone.height-ScoreZone.height};
4. let ComputerZone = {x: app.screen.width-playersZoneWidth, y: 200, width: playersZoneWidth, height: app.screen.height-OptionsZone.height-ScoreZone.height};
5. let RoadZone = {x: playersZoneWidth, y: 200, width: app.screen.width-HumanZone.width-OrdiZone.width, height: app.screen.height-OptionsZone.height-ScoreZone.height};
Game settings:
- At the start of the game, 10 rocks of three different sizes (small, medium, large) are randomly placed in the RoadZone.
- The rocks have square 100x100 pixels sprites centered (anchor 0.5, 0.5).
- The Rocks have a front and a back zone to simulate a contact area with the Buldos.
- Each rock is on its own horizontal 100 pixels wide line.
- There are two players: the human player and the computer.
- Each player has two Buldos to move the rocks, a kind of bulldozer.
- The human Buldos are called "buldoRocks" and the computer Buldos are called "buldoZers".
- The buldoRocks have a 100x100 pixels sprite centered (anchor 0.5, 0.5).
- The buldoZers have a 100x100 pixels sprite centered (anchor 0.5, 0.5).
- The Buldos have a front and a back zone to simulate the pushing of the rocks.
- At the start of the game, the buldoRocks are placed in the HumanZone and the buldoZers are placed in the ComputerZone (abscissa centered and ordinate equally spaced 1/3, 2/3).
- The buldoRocks are facing right and the buldoZers are facing left.
Game rules:
- The buldoZers are controlled by the computer and will move randomly (or futher with AI) to push the rocks towards the HumanZone.
- The buldoRocks are controlled by the human player and will move when the player clicks or taps to push the rocks towards the ComputerZone.
- The human player selects a buldoRock by clicking or tapping on it, then selects a rock to push by clicking or tapping on it.
- The Buldos may only move in lignes, horizontally or vertically, and may not move diagonally.
- When a Buldo is selected to push a rock, the Buldo must move to the ordonnate of the rock
- To move to the ordonnate of the rock, the Buldo will probably have to make a 90 degres rotation, then move vertically up or down to the ordonnate of the rock, then make a 90 degres rotation to face the rock.
- When a rock is entirely into the HumanZone or the ComputerZone, it is out of the game (loss of visibility of its sprite or destruction of the object Rock).
- When a Buldo has finished pushing a rock, it comes back to its camp (HumanZone or ComputerZone) horizontally and once in its camp, it turns at 180 degres to face the RoadZone.
- A Buldo moving without pushing anything has a base speed V (to futher adjust).
- When a bulldozer pushes a small rock, the combined speed is V/2.
- When a bulldozer pushes a medium rock, the combined speed is V/4.
- When a bulldozer pushes a large rock, the combined speed is V/8.
- When two bulldozers push a rock together, one behind the other, the pushing speeds are doubled compared to the speed of a single bulldozer.
- It is possible to push a rock that is being pushed by the opponent to block or slow down its movement.
- If a second Buldo is added in this situation, the rock will be pushed in the direction where there are fewer Buldos.
- When a rock is blocked, it splits into smaller rocks depending of its size.
- A large rock splits into a small and a medium one.
- A medium rock splits into two small rocks.
- A small rock is destroyed and disappears.
- The splitted new rocks are thrown from the position of the blocked rock to a free ligne.
- The game ends when all rocks have been moved out of the RoadZone.
- The winner is the one with the highest score, based on the number and size of rocks successfully moved to the opposing zone (small rock is 1 point, medium rock is 2 points, large rock is 3 points).
- The goal for the human player is to move all the rocks to the ComputerZone while preventing the computer from doing the same.
- There is no time limit in this game, and players must use their judgment to determine the best way to move rocks and use their Buldos to win the game.
*/ 
/* 
Game Zones:
- The game is played on a 2048x2732 pixels screen.
0. let playersZoneWidth = 200;
1. let ScoreZone = {x: 0, y: 0, width: app.screen.width, height: 200};
2. let OptionsZone = {x: 0, y: app.screen.height-200, width: app.screen.width, height: 200};
3. let HumanZone = {x: 0, y: 200, width: playersZoneWidth, height: app.screen.height-OptionsZone.height-ScoreZone.height};
4. let ComputerZone = {x: app.screen.width-playersZoneWidth, y: 200, width: playersZoneWidth, height: app.screen.height-OptionsZone.height-ScoreZone.height};
5. let RoadZone = {x: playersZoneWidth, y: 200, width: app.screen.width-HumanZone.width-OrdiZone.width, height: app.screen.height-OptionsZone.height-ScoreZone.height};
- At the start of the game, 10 rocks of three different sizes are randomly placed in the RoadZone.
- Each player has two bulldozers to move the rocks.
- A bulldozer moving without pushing anything has a base speed V.
- When a bulldozer pushes a small rock, the combined speed is V/2.
- When a bulldozer pushes a medium rock, the combined speed is V/4.
- When a bulldozer pushes a large rock, the combined speed is V/8.
- When two bulldozers push a rock together, one behind the other, the pushing speeds are doubled compared to the speed of a single bulldozer.
- The human player clicks on a rock to command the nearest free bulldozer to push it towards the ComputerZone.
- The computer-controlled bulldozers randomly choose a rock and push it towards the HumanZone.
- If a human bulldozer is free, the player can click on a rock already being pushed to have the bulldozer move behind the first one and push the rock faster.
- It is possible to push a rock that is being pushed by the opponent to block or slow down its movement. If a second bulldozer is added in this situation, the rock will be pushed in the direction where there are fewer bulldozers.
- The game ends when all rocks have been moved out of the RoadZone. The winner is the one with the highest score, based on the number and size of rocks successfully moved to the opposing zone.
- The goal for the human player is to move all the rocks to the ComputerZone while preventing the computer from doing the same. Effective strategy and skillful bulldozer management are necessary to maximize the score.
There is no time limit in this game, and players must use their judgment to determine the best way to move rocks and use their bulldozers to win the game.
*/ 
//PARAMETRES DIVERS DU JEU 
function _typeof2(o) {
	"@babel/helpers - typeof";
	return _typeof2 = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
		return typeof o;
	} : function (o) {
		return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
	}, _typeof2(o);
}
function __defineProperties(target, props) {
	for (var i = 0; i < props.length; i++) {
		var descriptor = props[i];
		descriptor.enumerable = descriptor.enumerable || false;
		descriptor.configurable = true;
		if ("value" in descriptor) {
			descriptor.writable = true;
		}
		Object.defineProperty(target, _toPropertyKey2(descriptor.key), descriptor);
	}
}
function _createClass2(Constructor, protoProps, staticProps) {
	if (protoProps) {
		__defineProperties(Constructor.prototype, protoProps);
	}
	if (staticProps) {
		__defineProperties(Constructor, staticProps);
	}
	Object.defineProperty(Constructor, "prototype", {
		writable: false
	});
	return Constructor;
}
function _toPropertyKey2(t) {
	var i = _toPrimitive2(t, "string");
	return "symbol" == _typeof2(i) ? i : String(i);
}
function _toPrimitive2(t, r) {
	if ("object" != _typeof2(t) || !t) {
		return t;
	}
	var e = t[Symbol.toPrimitive];
	if (void 0 !== e) {
		var i = e.call(t, r || "default");
		if ("object" != _typeof2(i)) {
			return i;
		}
		throw new TypeError("@@toPrimitive must return a primitive value.");
	}
	return ("string" === r ? String : Number)(t);
}
function _classCallCheck2(instance, Constructor) {
	if (!(instance instanceof Constructor)) {
		throw new TypeError("Cannot call a class as a function");
	}
}
function _typeof(o) {
	"@babel/helpers - typeof";
	return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) {
		return typeof o;
	} : function (o) {
		return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o;
	}, _typeof(o);
}
function _defineProperties(target, props) {
	for (var i = 0; i < props.length; i++) {
		var descriptor = props[i];
		descriptor.enumerable = descriptor.enumerable || false;
		descriptor.configurable = true;
		if ("value" in descriptor) {
			descriptor.writable = true;
		}
		Object.defineProperty(target, _toPropertyKey(descriptor.key), descriptor);
	}
}
function _createClass(Constructor, protoProps, staticProps) {
	if (protoProps) {
		_defineProperties(Constructor.prototype, protoProps);
	}
	if (staticProps) {
		_defineProperties(Constructor, staticProps);
	}
	Object.defineProperty(Constructor, "prototype", {
		writable: false
	});
	return Constructor;
}
function _toPropertyKey(t) {
	var i = _toPrimitive(t, "string");
	return "symbol" == _typeof(i) ? i : String(i);
}
function _toPrimitive(t, r) {
	if ("object" != _typeof(t) || !t) {
		return t;
	}
	var e = t[Symbol.toPrimitive];
	if (void 0 !== e) {
		var i = e.call(t, r || "default");
		if ("object" != _typeof(i)) {
			return i;
		}
		throw new TypeError("@@toPrimitive must return a primitive value.");
	}
	return ("string" === r ? String : Number)(t);
}
function _classCallCheck(instance, Constructor) {
	if (!(instance instanceof Constructor)) {
		throw new TypeError("Cannot call a class as a function");
	}
}
var nbRochers = 10; //nombre de rochers
var nbBuldoRocks = 0; //nombre de buldoRocks
var nbBuldoZers = 0; //nombre de buldoZers
var delta = 1;
var vitesseBuldo = 8.0; //vitesse de déplacement des buldos a vide, vitesse/2 quand ils poussent un petit rocher, vitesse/4 pour un moyen, vitesse/8 pour un gros
var humanCamp = 1; //camp du joueur humain
var ordiCamp = -1; //camp du joueur ordinateur
var ancrageMedian = 0.5; //ancrage median des sprites
var buldoRockHotSpotX = 40 * 2; //hotspot X du sprite buldoRock, offset du sprite par rapport à l'ancrage
var buldoRockHotSpotY = 0; //hotspot Y du sprite buldoRock
var buldoRockBkHotSpotX = -28 * 2; //hotspot arriere du buldoRock
var buldoRockBkHotSpotY = 0;
var buldoZerHotSpotX = 40 * 2; //hotspot X du sprite buldoZer, offset du sprite par rapport à l'ancrage
var buldoZerHotSpotY = 0; //hotspot Y du sprite buldoZer
var buldoZerBkHotSpotX = 28 * 2; //hotspot arriere du buldoZer
var buldoZerBkHotSpotY = 0;
var ordonneesRestantes = []; //liste des ordonnees non encore utilisees pour le placement des rochers
var petitRocher = 2; //taille du rocher (2=petit, 4=moyen, 8=gros)
var petitRocherDxHotLeft = -25 * 2; //hotspot X du sprite petitRocher, offset du sprite par rapport à l'ancrage
var petitRocherDyHotLeft = 0; //hotspot Y du sprite petitRocher
var petitRocherDxHotRight = 25 * 2; //hotspot X du sprite petitRocher, offset du sprite par rapport à l'ancrage
var petitRocherDyHotRight = 0; //hotspot Y du sprite petitRocher
var moyenRocher = 4; //taille du rocher (2=petit, 4=moyen, 8=gros)
var moyenRocherDxHotLeft = -30 * 2; //hotspot X du sprite moyenRocher, offset du sprite par rapport à l'ancrage
var moyenRocherDyHotLeft = 0; //hotspot Y du sprite moyenRocher
var moyenRocherDxHotRight = 30 * 2; //hotspot X du sprite moyenRocher, offset du sprite par rapport à l'ancrage
var moyenRocherDyHotRight = 0; //hotspot Y du sprite moyenRocher
var grosRocher = 8; //taille du rocher (2=petit, 4=moyen, 8=gros)
var grosRocherDxHotLeft = -45 * 2; //hotspot X du sprite grosRocher, offset du sprite par rapport à l'ancrage
var grosRocherDyHotLeft = 0; //hotspot Y du sprite grosRocher
var grosRocherDxHotRight = 45 * 2; //hotspot X du sprite grosRocher, offset du sprite par rapport à l'ancrage
var grosRocherDyHotRight = 0; //hotspot Y du sprite grosRocher
var typeRotation = 1; //Type 1 = rotation
var typeLigneHtoX = 2; //Type 2 = déplacement horizontal vers une position X
var typeLigneVtoY = 3; //Type 3 = déplacement vertical vers une position Y
var typeLigneHtoR = 4; //Type 4 = déplacement horizontal vers un rocher
var scoreHumain = 0;
var scoreOrdi = 0;
var ScoreZone = {
	x: 0,
	y: 0,
	width: game.width,
	height: 200
};
var OptionsZone = {
	x: 0,
	y: game.height - 200,
	width: game.width,
	height: 200
};
var HumanZone = {
	x: 0,
	y: ScoreZone.height,
	width: game.width / 10,
	height: game.height - ScoreZone.height - OptionsZone.height
};
var ComputerZone = {
	x: game.width - game.width / 10,
	y: ScoreZone.height,
	width: game.width / 10,
	height: HumanZone.height
};
var RoadZone = {
	x: HumanZone.width,
	y: ScoreZone.height,
	width: game.width - HumanZone.width - ComputerZone.width,
	height: game.height - OptionsZone.height - ScoreZone.height
};
//CLASS ROCHER
var Rocher = /*#__PURE__*/_createClass(function Rocher() {
	var tailleRocher = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : petitRocher;
	var x = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : RoadZone.width / 2;
	var y = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : RoadZone.height / 2;
	_classCallCheck(this, Rocher);
	var self = this; // Initialize self to refer to the Rocher instance
	self.name = "rocher";
	self.dxHotLeftSpot = petitRocherDxHotLeft; //Offset du point chaud du sprite (point de contact avec le rocher a gauche) décalage par rapport au point d'ancrage
	self.dyHotLeftSpot = petitRocherDyHotLeft;
	self.dxHotRightSpot = petitRocherDxHotRight; //Offset du point chaud du sprite (point de contact avec le rocher a droite) décalage par rapport au point d'ancrage
	self.dyHotRightSpot = petitRocherDyHotRight;
	self.isBeingPushed = false; //Flag qui indique si le rocher est pousse par un buldo
	self.isBlocked = false; //Flag qui indique si le rocher est bloque
	self.vitesse = 0.0;
	self.pushers = []; //Liste des buldos qui vont pousser ou qui poussent le rocher
	self.pushedByHuman = null; //BuldoRock qui pousse le rocher
	self.pushedByOrdi = null; //BuldoZer qui pousse le rocher
	self.totalForce = 0; //Somme des forces qui poussent le rocher (+1 pour un buldoRock, -1 pour un buldoZer)
	self.totalBuldos = 0; //Nombre de Buldos qui poussent le rocher
	var rocher_petit_sprite = game.addChild(LK.getAsset('small_rock', {
		anchorX: 0.5,
		anchorY: 0.5
	}));
	var rocher_moyen_sprite = game.addChild(LK.getAsset('medium_rock', {
		anchorX: 0.5,
		anchorY: 0.5
	}));
	var rocher_gros_sprite = game.addChild(LK.getAsset('large_rock', {
		anchorX: 0.5,
		anchorY: 0.5
	}));
	self.tailleRocher = tailleRocher;
	if (self.tailleRocher == petitRocher) {
		self.sprite = rocher_petit_sprite;
	}
	if (self.tailleRocher == moyenRocher) {
		self.sprite = rocher_moyen_sprite;
	}
	if (self.tailleRocher == grosRocher) {
		self.sprite = rocher_gros_sprite;
	}
	self.sprite.x = x;
	self.sprite.y = y;
	self.sprite.anchor.set(0.5);
	self.sprite.scale.set(1.5);
	self.sprite.visible = false;
	if (self.tailleRocher == petitRocher) {
		self.dxHotLeftSpot = petitRocherDxHotLeft;
		self.dyHotLeftSpot = petitRocherDyHotLeft;
		self.dxHotRightSpot = petitRocherDxHotRight;
		self.dyHotRightSpot = petitRocherDyHotRight;
	}
	if (self.tailleRocher == moyenRocher) {
		self.dxHotLeftSpot = moyenRocherDxHotLeft;
		self.dyHotLeftSpot = moyenRocherDyHotLeft;
		self.dxHotRightSpot = moyenRocherDxHotRight;
		self.dyHotRightSpot = moyenRocherDyHotRight;
	}
	if (self.tailleRocher == grosRocher) {
		self.dxHotLeftSpot = grosRocherDxHotLeft;
		self.dyHotLeftSpot = grosRocherDyHotLeft;
		self.dxHotRightSpot = grosRocherDxHotRight;
		self.dyHotRightSpot = grosRocherDyHotRight;
	}
	if (self.tailleRocher == petitRocher) {
		self.name = "Petit Rocher";
	}
	if (self.tailleRocher == moyenRocher) {
		self.name = "Moyen Rocher";
	}
	if (self.tailleRocher == grosRocher) {
		self.name = "Gros Rocher";
	}
	this.onClickRocherBuldo = function (buldos) {
		//Action à effectuer lorsqu'on clique sur un rocher            
		//Récupération des coordonnées du sprite rocher cliqué		
		var x = this.sprite.x;
		var y = this.sprite.y;
		this.sprite.tint = 0xF0D0E0; //on ajoute un filtre coloré 
		//Parcours de la liste des buldos pour trouver le buldo selectionne
		if (buldos) {
			var buldo = null;
			buldos.forEach(function (buldoCheck) {
				if (buldoCheck != null) {
					if (buldoCheck.isSelected) {
						buldo = buldoCheck;
					}
				}
			});
			//Si le buldo selectionne est trouve, on le deplace vers le sprite rocher        
			if (buldo != null && !buldo.isMoving) {
				buldo.moveToRock(this); //On deplace le buldo vers le rocher
			}
		}
	}; //fin onClickRocherBuldo
	this.destroy = function () {
		//On previent les eventuels buldos qui poussent le rocher que le rocher est detruit
		if (this.pushers) {
			this.pushers.forEach(function (buldo) {
				if (buldo != null) {
					buldo.rocherDestination = null;
					buldo.rocherPushed = null;
					buldo.isPushing = false;
				}
			});
		}
		//On vide la liste des buldos qui poussent le rocher
		this.pushers = [];
		//On recupere l'ordonnee du rocher pour une potentielle reutilisation
		ordonneesRestantes.push(this.sprite.y);
		nbRochers = nbRochers - 1; //Decrement du nombre de rochers
		//Invisibilite du sprite rocher
		this.sprite.visible = false;
	}; //fin destroy
	this.onOutRocher = function () {
		var outRight = this.sprite.x + this.dxHotLeftSpot >= ComputerZone.x; //L'abscisse du point chaud de gauche est superieur a l'abscisse de la zone ordi
		var outLeft = this.sprite.x + this.dxHotRightSpot <= HumanZone.x + HumanZone.width; //L'abscisse du point chaud de droite est inferieur a l'abscisse de la zone humaine
		if (outRight || outLeft) {
			//Si le sprite rocher sort de la zone route  
			//Incrementation du score en fonction de la taille du rocher (1 pour petit, 2 pour moyen, 3 pour gros)
			//Sachant que tailleRocher = 2 pour petit, 4 pour moyen, 8 pour gros
			if (outRight) {
				scoreHumain = Number(scoreHumain) + Math.log2(this.tailleRocher);
			}
			if (outLeft) {
				scoreOrdi = Number(scoreOrdi) + Math.log2(this.tailleRocher);
			}
			this.vitesse = 0.0; //Arret du rocher (et donc des buldos qui le poussent)
			this.isBeingPushed = false; //Le rocher n'est plus pousse
			this.totalForce = 999; //On annule la poussee
			this.totalBuldos = 0; //Plus aucun Buldo ne pousse le rocher
			//Destruction du sprite rocher
			this.destroy();
		}
	}; //fin onOutRocher
	this.checkPushed = function () {
		if (this == null) {
			return;
		}
		if (this.sprite.visible == false) {
			return;
		}
		if (this.isBeingPushed) {
			//Si le rocher est pousse par un bul              
			this.sprite.x += this.vitesse; //Deplacement du rocher           
			this.onOutRocher(); //Si le rocher sort de la zone route, on le detruit (invisible)
		}
	}; //fin checkPushed
	this.sortPushers = function () {
		//Tri du tableau this.pushers des buldos qui poussent le rocher par ordre croissant de distance au rocher (distance entre le centre du rocher et le centre du buldo)
		var actualPushers = []; //Liste des buldos qui poussent le rocher
		var nonPushers = []; //Liste des buldos qui ne poussent pas le rocher
		this.pushers.forEach(function (buldo) {
			if (buldo.isPushing) {
				actualPushers.push(buldo);
				scoreHumain = actualPushers.length;
			} else {
				nonPushers.push(buldo);
				scoreOrdi = nonPushers.length;
			}
		});
		actualPushers.sort(function (a, b) {
			var distA = dist(a.sprite.x, a.sprite.y, self.sprite.x, self.sprite.y);
			var distB = dist(b.sprite.x, b.sprite.y, self.sprite.x, self.sprite.y);
			return distA - distB;
		});
		this.pushers = actualPushers.concat(nonPushers);
	}; //fin sortPushers
}); //fin class Rocher
//CLASS BULDO
var Buldo = /*#__PURE__*/_createClass2(function Buldo(x, y, camp) {
	_classCallCheck2(this, Buldo);
	var self = this; // Ensure 'self' is defined to refer to the Buldo instance
	this.name = "buldo";
	this.camp = camp; //Camp du buldo (1=Human buldoRock ou 2=Ordi buldoZer)
	this.isSelected = false; //Flag qui indique si le Buldo est selectionne
	var buldorock_sprite = game.addChild(LK.getAsset('bulldorock', {
		anchorX: 0.5,
		anchorY: 0.5
	}));
	var buldozer_sprite = game.addChild(LK.getAsset('bulldozer', {
		anchorX: 0.5,
		anchorY: 0.5
	}));
	if (this.camp == humanCamp) {
		this.sprite = buldorock_sprite;
	} else if (this.camp == ordiCamp) {
		this.sprite = buldozer_sprite;
	}
	this.sprite.x = x;
	this.sprite.y = y;
	this.sprite.anchor.set(0.5);
	this.sprite.scale.set(2.0);
	this.sprite.visible = false;
	this.xBase = x; //Position de base du sprite
	this.yBase = y;
	this.stack = []; //Pile des points x,y destination cliqués par la souris
	this.movesStack = []; //Pile des mouvements a effectuer (types de mouvements : 1 : rotation, 2 : horizontal, 3 : vertical, 4 : xy)
	this.vitessePS = vitesseBuldo; //vitesse de deplacement du sprite en pixels par secondes
	this.vitesseEnCours = 0.0; //vitesse de deplacement en cours en pixels par secondes en cours de deplacement
	this.isMoving = false; //Flag qui indique si le Buldo est en mouvement
	this.isMovingH = false; //Flag qui indique si le Buldo est en mouvement horizontal
	this.isMovingV = false; //Flag qui indique si le Buldo est en mouvement vertical
	this.isMovingR = false; //Flag qui indique si le Buldo est en mouvement horizontal vers un rocher
	this.xDestination = 0.0; //Abscisse x du point x,y destination
	this.yDestination = 0.0; //Ordonnee y du point x,y destination
	this.rocherDestination = null; //Rocher destination du Buldo
	this.isPushing = false; //Flag qui indique si le Buldo est en train de pousser un rocher
	this.rocherPushed = null; //Rocher pousse par le Buldo
	this.isRotating = false; //Flag qui indique si le Buldo est en rotation
	this.sprite.rotation = 0.0;
	this.angleRadiansLeft = 0.0; //Angle restant a tourner en radians
	this.vitesseAngulaireDS = 2.0; //vitesse de rotation du sprite en degres par secondes
	this.vitesseAngulaireRms = 0.0; //vitesse angulaire en radians par millisecondes
	this.onClickBuldo = function (buldos) {
		//On commence par deselectionne tous les sprites Buldo 
		for (var i = 0; i < buldos.length; i++) {
			if (buldos[i].name != this.name) {
				buldos[i].isSelected = false;
				buldos[i].sprite.tint = 0xFFFFFF; //on enleve le filtre coloré   
			}
		}
		//Gestion du clic sur le sprite Buldo
		if (this.isSelected) {
			//Si le sprite est deja selectionne, on le deselectionne
			this.isSelected = false;
			this.sprite.tint = 0xFFFFFF; //on enleve le filtre coloré            
		} else {
			//Sinon on le selectionne s'il n'est pas en mouvement ou en rotation
			var isNotMoving = !this.isRotating && !this.isMovingH && !this.isMovingV;
			if (isNotMoving) {
				this.isSelected = true;
				this.sprite.tint = 0xD0D00D; //on ajoute un filtre coloré             
			}
		}
	}; //fin onClickBuldo
	this.addMoveToStack = function (type, x, y) {
		//type = 1 : rotation, type = 2 : deplacement horizontal, type = 3 : deplacement vertical, type = 4 : deplacement horizontal vers un rocher, type = 6 : combinaison        
		this.movesStack.push([type, x, y]); //On ajoute le mouvement a la pile des mouvements a effectuer
	}; //fin addMoveToStack
	this.checkMovesStack = function (delta) {
		//Verification d'un mouvement en cours
		if (this.isRotating || this.isMovingH || this.isMovingV || this.isMovingR) {
			if (this.isRotating) {
				this.tourneMoi(delta);
			} //Si le Buldo est en rotation, on continue la rotation
			if (this.isMovingH) {
				this.deplaceHtoX(delta);
			} //Si le Buldo est en deplacement horizontal, on continue le deplacement
			if (this.isMovingV) {
				this.deplaceVtoY(delta);
			} //Si le Buldo est en deplacement vertical, on continue le deplacement
			if (this.isMovingR) {
				this.deplaceHtoR(delta);
			} //Si le Buldo est en deplacement horizontal vers un rocher, on continue le deplacement
			return;
		}
		if (this.movesStack.length > 0) {
			//Si la pile des mouvements a effectuer n'est pas vide
			var move = this.movesStack.shift(); //On recupere le premier mouvement de la pile
			var type = move[0]; //Type de mouvement (1 : rotation, 2 : deplacement horizontal, 3 : deplacement vertical)            
			var x = move[1]; //Abscisse x du point x,y destination ou angle de rotation ou fonction de deplacement
			var y = move[2]; //Ordonnee y du point x,y destination ou fonction de deplacement
			switch (type) {
				case typeRotation:
					//Si le mouvement est une rotation, on effectue la rotation
					this.setRotation(x); //On effectue la rotation
					break;
				case typeLigneHtoX:
					//Si le mouvement est un deplacement horizontal, on effectue le deplacement
					this.setLigneHtoX(x); //On effectue le deplacement horizontal
					break;
				case typeLigneVtoY:
					//Si le mouvement est un deplacement vertical, on effectue le deplacement
					this.setLigneVtoY(y);
					break;
				case typeLigneHtoR:
					//Si le mouvement est un deplacement horizontal vers un rocher, on effectue le deplacement
					this.setLigneHtoR(this.rocherDestination);
				default:
					break;
			}
		}
	}; //fin checkMovesStack
	this.setRotation = function (alphaDegres) {
		//Fonction d'initialisation de la rotation
		this.isRotating = true; //on indique que le Buldo est en rotation
		this.angleRadiansLeft = Math.abs(alphaDegres * Math.PI / 180); //on indique l'angle restant a tourner en radians
		var sens = alphaDegres > 0 ? 1 : -1; //sens de rotation
		this.vitesseAngulaireRms = sens * this.vitesseAngulaireDS * Math.PI / 180 / 1000; //vitesse angulaire
	}; //fin setRotation
	this.tourneMoi = function (delta) {
		//Fonction de rotation du Buldo       
		if (this.isRotating) {
			//Si le Buldo est en rotation    
			// Si l'angle total à tourner est atteint, on arrête la rotation
			// et on ajoute à la rotation du sprite la valeur en radians de l'angle qu'il reste à tourner
			if (this.angleRadiansLeft <= Math.abs(this.vitesseAngulaireRms * delta * 1000)) {
				this.isRotating = false;
				this.sprite.rotation += this.vitesseAngulaireRms > 0 ? this.angleRadiansLeft : -this.angleRadiansLeft; // ajout de l'angle alphaDegresMS (en radians) à la rotation du sprite
				return;
			} else {
				// Ajout à la rotation du sprite la valeur en radians de l'angle alphaDegresMS (vitesse angulaire en radians par millisecondes * delta * 1000)
				this.sprite.rotation += this.vitesseAngulaireRms * delta * 1000; // ajout de l'angle alphaDegresMS (en radians) à la rotation du sprite
				// Calcul de l'angle restant à tourner
				this.angleRadiansLeft -= Math.abs(this.vitesseAngulaireRms * delta * 1000); // soustraction de l'angle alphaDegresMS à l'angle restant à tourner
			}
		}
	}; //fin tourneMoi
	this.setLigneHtoX = function (x) {
		//Fonction d'initialisation du deplacement horizontal du Buldo
		//Si la distance AD est inferieure a la distance HD, le point D est derriere le point A, le Buldo ne se deplace pas
		this.isMovingH = true; //on indique que le Buldo est en mouvement
		this.xDestination = x - this.camp * this.dxAvHotSpot; //le point d'ancrage doit s'arreter un peu avant x pour superposer le point chaud AV (rappel : dxAvHotSpot est negatif pour les buldoZer de l'ordi)
		var sens = this.xDestination > this.sprite.x ? 1 : -1; //Calcul du sens du deplacement horizontal : 1=droite, -1=gauche
		this.vitesseEnCours = sens * this.vitessePS; //on indique la vitesse de deplacement en cours en pixels par secondes
	}; //fin setLigneHtoX
	this.deplaceHtoX = function (delta) {
		//Fonction de deplacement horizontal du Buldo       
		// Vérifie si le Buldo est en mouvement
		if (this.isMovingH) {
			// Si la distance entre le sprite et le point destination est inférieure à la vitesse en cours, on arrête le déplacement
			// et on donne à l'abscisse du sprite la valeur qui superpose avec le point destination
			var dx = Math.abs(this.xDestination - this.sprite.x);
			if (dx < this.vitessePS * delta) {
				this.sprite.x = this.xDestination;
				this.isMovingH = false; //Fin du mouvement H simple
				return;
			} else {
				// Sinon on déplace le sprite horizontalement
				// Déplacement du sprite
				this.sprite.x += this.vitesseEnCours * delta;
				return;
			}
		}
	}; // fin deplaceHtoX
	this.setLigneVtoY = function (y) {
		this.isMovingV = true; //on indique que le Buldo est en mouvement		 	
		this.yDestination = y; //le point d'ancrage doit s'arreter sur y 
		//Calcul du sens du deplacement verticale : 1=bas, -1=haut
		this.vitesseEnCours = this.sprite.y < y ? this.vitessePS : -this.vitessePS; //on donne le sens du deplacement vertical
	}; //fin setLigneVtoY
	this.deplaceVtoY = function (delta) {
		// Vérifie si le Buldo est en mouvement
		if (this.isMovingV) {
			var AD = dist(0, this.sprite.y, 0, this.yDestination);
			if (AD <= Math.abs(this.vitesseEnCours * delta)) {
				// Si la distance entre l'ordonnee du sprite et l'ordonnee y destination est inférieure à la vitesse en cours, on arrête le déplacement
				this.sprite.y = this.yDestination; // on donne à l'ordonnée du sprite la valeur y destination
				this.isMovingV = false; // on indique que le Buldo n'est plus en mouvement
				return;
			} else {
				// Sinon on déplace le sprite verticalement
				var sensAngleBuldo = sensRotation(this.sprite.rotation * 180 / Math.PI % 360); //Sens de rotation du Buldo (1=horaire, -1=antihoraire) (0=meme ordonnee)
				var HD = dist(0, this.sprite.y + sensAngleBuldo * this.dxAvHotSpot, 0, y);
				// Déplacement du sprite
				//if (AD < HD) {
				this.sprite.y += this.vitesseEnCours * delta;
				//} //Si la distance AD est inferieure a la distance HD, le point D est derriere le point A, le Buldo ne se deplace pas
				return;
			}
		}
	}; // fin deplaceVtoY
	this.checkForce = function () {
		//Choix de la cible : point chaud du rocher ou point chaud arriere du Buldo allie poussant
		var targetX = this.rocherDestination.sprite.x; //Cible principale par defaut
		var dxHotSpotR = this.camp == humanCamp ? this.rocherDestination.dxHotLeftSpot : this.rocherDestination.dxHotRightSpot; //Point chaud du rocher
		switch (this.rocherDestination.totalForce) {
			case 999:
				//Rocher detruit
				targetX = this.sprite.x; //La cible principale est l'endroit ou se trouve le Buldo
				dxHotSpotR = this.camp * this.dxAvHotSpot;
				this.rocherDestination = null; //Plus de rocher a pousser
				this.isMovingR = false; //Fin du mouvement
				break;
			case 0:
				//Trois cas possibles : zero pousseur ou un pousseur de chaque cote ou deux pousseurs de chaque cotes
				if (this.rocherDestination.pushedByHuman == null && this.rocherDestination.pushedByOrdi == null) {
					//Aucun pousseur present quand j'arrive
					break;
				} //On ne fait rien, on cible le point chaud du rocher par defaut
				else if (this.rocherDestination.pushedByHuman == this || this.rocherDestination.pushedByOrdi == this) {
					//Un pousseur de chaque cote dont moi
					break;
				} //On ne fait rien, on cible le point chaud du rocher par defaut
				else if (this.rocherDestination.pushedByHuman != null && this.rocherDestination.pushedByOrdi != null) {
					//Si un Buldo de chaque cote mais pas moi
					targetX = this.camp == humanCamp ? this.rocherDestination.pushedByHuman.sprite.x : this.rocherDestination.pushedByOrdi.sprite.x; //La cible principale est le Buldo allie poussant
					dxHotSpotR = this.camp == humanCamp ? this.rocherDestination.pushedByHuman.dxBkHotSpot : this.rocherDestination.pushedByOrdi.dxBkHotSpot;
				}
				break;
			case 1:
				//Un pousseur cote humain ou bien deux pousseurs humains et un seul pousseur ordi
				if (this.camp == humanCamp && this.rocherDestination.pushedByHuman != this) {
					//Si le Buldo poussant le rocher est un Buldo humain mais pas this
					targetX = this.rocherDestination.pushedByHuman.sprite.x; //La cible principale est le Buldo humain poussant
					dxHotSpotR = this.rocherDestination.pushedByHuman.dxBkHotSpot; //Le point chaud est l'arriere du Buldo humain poussant
				} else if (this.camp == humanCamp && this.rocherDestination.pushedByHuman == this) {
					//Si le Buldo poussant le rocher est this
					break; //La cible est le point chaud du rocher
				} else if (this.camp == ordiCamp && this.rocherDestination.pushedByOrdi == null) {
					//Si il n'y a pas encore de Buldo ordi poussant le rocher
					break; //La cible principale est le rocher
				} else if (this.camp == ordiCamp && this.rocherDestination.pushedByOrdi == this) {
					//Si le Buldo poussant le rocher est this
					break; //Le point chaud est le point chaud du rocher
				} else if (this.camp == ordiCamp && this.rocherDestination.pushedByOrdi != this) {
					//Si le Buldo poussant le rocher est un autre Buldo ordi
					targetX = this.rocherDestination.pushedByOrdi.sprite.x; //La cible principale est le Buldo ordi poussant
					dxHotSpotR = this.rocherDestination.pushedByOrdi.dxBkHotSpot; //Le point chaud est l'arriere du Buldo ordi poussant
				}
				break;
			case -1:
				//Un pousseur cote ordi ou bien deux pousseurs ordi et un seul pousseur humain 
				if (this.camp == ordiCamp && this.rocherDestination.pushedByOrdi != this) {
					//Si le Buldo poussant le rocher est un Buldo ordi mais pas this
					targetX = this.rocherDestination.pushedByOrdi.sprite.x; //La cible principale est le Buldo ordi poussant
					dxHotSpotR = this.rocherDestination.pushedByOrdi.dxBkHotSpot; //Le point chaud est l'arriere du Buldo ordi poussant
				} else if (this.camp == ordiCamp && this.rocherDestination.pushedByOrdi == this) {
					//Si le Buldo poussant le rocher est this
					break; //La cible est le point chaud du rocher
				} else if (this.camp == humanCamp && this.rocherDestination.pushedByHuman == null) {
					//Si il n'y a pas encore de Buldo humain poussant le rocher
					break; //Le point chaud est le point chaud du rocher
				} else if (this.camp == humanCamp && this.rocherDestination.pushedByHuman == this) {
					//Si le Buldo poussant le rocher est deja this
					break; //Le point chaud est le point chaud du rocher
				} else if (this.camp == humanCamp && this.rocherDestination.pushedByHuman != this) {
					//Si le Buldo poussant le rocher est un autre Buldo humain
					targetX = this.rocherDestination.pushedByHuman.sprite.x; //La cible principale est le Buldo humain poussant
					dxHotSpotR = this.rocherDestination.pushedByHuman.dxBkHotSpot; //Le point chaud est l'arriere du Buldo humain poussant
				}
				break;
			case 2:
				//Deux pousseurs humains : on cible le point chaud du rocher si on est le pousseur principal, sinon on cible le point chaud arriere du Buldo allie poussant              
				if (this.camp == humanCamp && this.rocherDestination.pushedByHuman != this) {
					//Si le Buldo poussant est un autre Buldo humain
					targetX = this.rocherDestination.pushedByHuman.sprite.x; //La cible principale est le buldo allie poussant
					dxHotSpotR = this.rocherDestination.pushedByHuman.dxBkHotSpot; //Le point chaud est l'arriere du Buldo allie poussant
				}
				break;
			case -2:
				//Deux pousseurs ordi : on cible le point chaud du rocher si on est le pousseur principal, sinon on cible le point chaud arriere du Buldo allie poussant
				if (this.camp == ordiCamp && this.rocherDestination.pushedByOrdi != this) {
					//Si le Buldo poussant est un autre Buldo ordi
					targetX = this.rocherDestination.pushedByOrdi.sprite.x; //La cible principale est le buldo allie poussant
					dxHotSpotR = this.rocherDestination.pushedByOrdi.dxBkHotSpot; //Le point chaud est l'arriere du Buldo allie poussant
				}
				break;
			default:
				//Cas impossible pour l'instant car on ne peut pas avoir plus de deux pousseurs du meme camp
				break;
			//On ne fait rien, on cible le point chaud du rocher par defaut
		}
		return targetX + dxHotSpotR;
	}; //fin checkForce
	this.checkPushers = function () {
		//Meme fonction que checkForce mais en utilisant le tableau pushers
		if (this.rocherDestination != null && this.rocherDestination.pushers != null) {
			if (this.rocherDestination.pushers.length == 0) {
				return;
			}
			var targetX = this.rocherDestination.sprite.x; //Cible principale par defaut
			var dxHotSpotR = this.camp == humanCamp ? this.rocherDestination.dxHotLeftSpot : this.rocherDestination.dxHotRightSpot; //Point chaud du rocher
			if (this.rocherDestination.pushers.length == 1) {
				scoreHumain += 1; //Test passage dans la fonction
				if (this.rocherDestination.pushers[0] == this) {
					//Si le Buldo poussant le rocher est this
					return targetX + dxHotSpotR; //La cible est le point chaud du rocher
				}
				if (this.rocherDestination.pushers[0].camp == this.camp) {
					//Si le Buldo poussant le rocher est du meme camp
					targetX = this.rocherDestination.pushers[0].sprite.x; //La cible principale est le Buldo allie poussant
					dxHotSpotR = this.rocherDestination.pushers[0].dxBkHotSpot; //Le point chaud est l'arriere du Buldo allie poussant
				}
			}
			if (this.rocherDestination.pushers.length == 2) {
				if (this.rocherDestination.pushers[0].camp == this.camp) {
					//Si le Buldo poussant le rocher est du meme camp
					targetX = this.rocherDestination.pushers[0].sprite.x; //La cible principale est le buldo allie poussant
					dxHotSpotR = this.rocherDestination.pushers[0].dxBkHotSpot; //Le point chaud est l'arriere du Buldo allie poussant
				}
			}
			return targetX + dxHotSpotR;
		}
	}; //fin checkPushers
	this.setLigneHtoR = function (rocher) {
		this.isMovingR = true; //on indique que le Buldo est en mouvement		 	
		this.rocherDestination = rocher; //le point d'ancrage doit s'arreter sur le rocher
		//Calcul du sens du deplacement horizontale : 1=droite, -1=gauche
		if (rocher && rocher.sprite) {
			this.vitesseEnCours = this.sprite.x < rocher.sprite.x ? this.vitessePS : -this.vitessePS; //on donne le sens du deplacement horizontal
		} else {
			this.vitesseEnCours = 0; // Set to 0 if rocher or rocher.sprite is null to avoid errors
		}
	}; //fin setLigneHtoR
	this.deplaceHtoR = function (delta) {
		// Vérifie si le Buldo est en mouvement
		if (this.rocherDestination != null || this.rocherPushed != null) {
			this.isMovingR = true; // on indique que le Buldo est en mouvement
		} else {
			this.isMovingR = false; // on indique que le Buldo n'est plus en train de pousser un rocher
			return;
		}
		if (this.isMovingR) {
			if (this.rocherDestination && this.rocherDestination.sprite != null) {
				var xTarget = this.checkForce(); //Abscisse x du point chaud AV du rocher ou du point chaud arriere du Buldo allie poussant
				//var xTarget = this.checkPushers(); //Abscisse x du point chaud AV du rocher ou du point chaud arriere du Buldo allie poussant
			} else {
				return; // Exit the function if rocherDestination or its sprite is null
			}
			var HD = dist(this.sprite.x + this.camp * this.dxAvHotSpot, 0, xTarget, 0); //Distance entre le point chaud AV du sprite et l'abscisse x destination
			if (HD <= Math.abs(this.vitesseEnCours * delta)) {
				// Si la distance entre l'abscisse du sprite et l'abscisse x destination est inférieure à la vitesse en cours, on atteint l'objectif
				this.sprite.x = xTarget - this.camp * this.dxAvHotSpot; // on donne à l'abscisse du sprite la valeur x destination
				if (this.rocherDestination != null && !this.isPushing) {
					this.isPushing = true; // on indique que le Buldo est en train de pousser un rocher					
					this.rocherPushed = this.rocherDestination; // on indique le rocher pousse par le Buldo
					this.rocherPushed.totalForce += this.camp; // on indique le Buldo qui pousse le rocher
					this.rocherPushed.totalBuldos += 1; // on ajoute un pousseur au rocher
					this.rocherDestination.isBeingPushed = true; // on indique que le rocher est pousse par un Buldo
					if (this.camp == humanCamp && this.rocherDestination.pushedByHuman == null) {
						this.rocherDestination.pushedByHuman = this; // on indique le Buldo qui pousse le rocher
					}
					if (this.camp == ordiCamp && this.rocherDestination.pushedByOrdi == null) {
						this.rocherDestination.pushedByOrdi = this; // on indique le Buldo qui pousse le rocher
					}
				}
			} else {
				// Sinon on déplace le sprite horizontalement
				this.sprite.x += this.vitesseEnCours * delta;
			}
		}
		return;
	}; // fin deplaceHtoR
	this.moveToRock = function (rocher) {
		x = this.camp == humanCamp ? x + rocher.dxHotLeftSpot : x + rocher.dxHotRightSpot;
		y = rocher.sprite.y;
		this.rocherDestination = rocher; //Le buldo a pour destination le sprite rocher cliqué
		rocher.pushers.push(this); //On ajoute le Buldo a la liste des Buldos qui poussent le rocher
		var sens = this.sprite.y < y ? 1 : -1; //Test Calcul du sens de deplacement horizontale : 1=droite, -1=gauche            
		sens = this.camp == humanCamp ? sens : -sens; //Test Si le Buldo est humain, il doit arriver horizontalement par la gauche (abscisse croissante), sinon par la droite (abscisse decroissante)
		this.addMoveToStack(typeRotation, sens * 90, 0); //Test rotation Buldo
		this.addMoveToStack(typeLigneVtoY, 0, y); //Test mouvement Buldo
		this.addMoveToStack(typeRotation, -sens * 90, 0); //Test rotation Buldo				   
		this.addMoveToStack(typeLigneHtoR, rocher, 0); //Test mouvement Buldo vers le rocher
		this.addMoveToStack(typeRotation, 180, 0); //Test rotation Buldo
		this.addMoveToStack(typeLigneHtoX, this.xBase + this.camp * this.dxAvHotSpot, 0); //Test mouvement Buldo vers la position de base
		this.addMoveToStack(typeRotation, -180, 0); //Test rotation Buldo;
	}; //fin moveToRock
}); //fin constructor
function sensRotation(angleDegres) {
	//03/03/2024//entre 0 et 180: 1, entre 180 et 360: -1, 0:0
	var sens = Math.sin(angleDegres * Math.PI / 180);
	var signeSens = sens > 0 ? 1 : sens < 0 ? -1 : 0;
	return signeSens;
} //fin sensRotation
function dist(x1, y1, x2, y2) {
	//fonction distance entre deux points
	var dx = x2 - x1;
	var dy = y2 - y1;
	var distance = Math.sqrt(dx * dx + dy * dy);
	return distance;
} //fin distance
// Fonction pour mettre à jour le score du camp humain
function updateScoreHumain(nouveauScore) {
	scoreHumainText.setText(nouveauScore);
} //fin updateScoreHumain
// Fonction pour mettre à jour le score du camp ordinateur
function updateScoreOrdi(nouveauScore) {
	scoreOrdiText.setText(nouveauScore);
} //fin updateScoreOrdi
// Fonction pour afficher la victoire d'une equipe en fonction de sa couleur
function afficheVictoire(camp) {
	var victoireText = game.addChild(new Text2('WINNER!', {
		size: 90,
		fill: camp == humanCamp ? 'blue' : 'red'
	}));
	LK.gui.topLeft.addChild(victoireText);
	victoireText.x = camp == humanCamp ? HumanZone.width : game.width / 2;
	victoireText.y = ScoreZone.height;
} //fin afficheVictoire
function generateRandomRock(nombreRochers) {
	//Calcul de positions aléatoire pour les rochers dans la zone de route
	var zoneMiniy = RoadZone.y;
	var zoneMaxiy = RoadZone.y + RoadZone.height;
	//Calcul des ordonnees possibles pour les rochers entre zoneMiniy + 50 et zoneMaxiy - 50
	var ordonneesPossibles = [];
	for (var i = zoneMiniy + 50 * 1.5; i < zoneMaxiy - 50 * 1.5; i += 100 * 1.5) {
		ordonneesPossibles.push(i);
	}
	//Securite : si le nombre de rochers demande est superieur au nombre d'ordonnees possibles, on ajuste le nombre de rochers
	if (nombreRochers > ordonneesPossibles.length) {
		nombreRochers = ordonneesPossibles.length;
	}
	var rochers = [];
	//Creation des rochers
	for (var i = 0; i < nombreRochers; i++) {
		// Choisir une taille de rocher aléatoire
		var sizes = [petitRocher, moyenRocher, grosRocher];
		var size = sizes[Math.floor(Math.random() * sizes.length)];
		// Choisir une abscisse aléatoire pour le rocher
		var zoneMinix = RoadZone.x + 100;
		var zoneMaxix = RoadZone.x + RoadZone.width - 100;
		var x = Math.random() * (zoneMaxix - zoneMinix) + zoneMinix;
		//Choix d'une ordonnee aleatoire en supprimant l'ordonnee choisie precedemment
		var index = Math.floor(Math.random() * ordonneesPossibles.length);
		var y = ordonneesPossibles[index];
		ordonneesPossibles.splice(index, 1);
		// Créer le rocher
		var rock = new Rocher(size, x, y);
		rock.sprite.visible = true;
		rock.sprite.anchor.set(0.5, 0.5);
		if (size == petitRocher) {
			rock.dxHotLeftSpot = petitRocherDxHotLeft;
			rock.dyHotLeftSpot = petitRocherDyHotLeft;
			rock.dxHotRightSpot = petitRocherDxHotRight;
			rock.dyHotRightSpot = petitRocherDyHotRight;
		}
		if (size == moyenRocher) {
			rock.dxHotLeftSpot = moyenRocherDxHotLeft;
			rock.dyHotLeftSpot = moyenRocherDyHotLeft;
			rock.dxHotRightSpot = moyenRocherDxHotRight;
			rock.dyHotRightSpot = moyenRocherDyHotRight;
		}
		if (size == grosRocher) {
			rock.dxHotLeftSpot = grosRocherDxHotLeft;
			rock.dyHotLeftSpot = grosRocherDyHotLeft;
			rock.dxHotRightSpot = grosRocherDxHotRight;
			rock.dyHotRightSpot = grosRocherDyHotRight;
		}
		//Initialisation de parametres
		rock.totalForce = 0;
		rochers.push(rock);
	}
	//On ajoute les evenements de clic sur les sprites rocher
	for (var i = 0; i < rochers.length; i++) {
		rochers[i].sprite.on('down', rochers[i].onClickRocherBuldo.bind(rochers[i], buldos));
	}
	ordonneesRestantes = ordonneesPossibles; //On stocke les ordonnees restantes pour une utilisations ulterieure
	return rochers;
} //fin generateRandomRock
function createSingleBuldo(x, y, camp) {
	//CREATION D'OBJETS A PARTIR DES SPRITES //constructor(x, y, camp)
	var buldo = new Buldo(x, y, camp);
	buldo.sprite.anchor.set(0.5, 0.5);
	buldo.xBase = buldo.sprite.x;
	buldo.yBase = buldo.sprite.y;
	buldo.vitessePS = vitesseBuldo;
	buldo.sprite.visible = true;
	//On ajoute les evenements de clic sur le sprite Buldo
	buldo.sprite.on('down', function () {
		buldo.onClickBuldo(buldos);
	});
	buldo.rocherDestination = null;
	buldo.rocherPushed = null;
	//On donne leurs hotspots
	if (buldo.camp == humanCamp) {
		buldo.dxAvHotSpot = buldoRockHotSpotX; //Hotspot avant du sprite (point de contact avec un rocher) décalage par rapport au point d'ancrage
		buldo.dyAvHotSpot = buldoRockHotSpotY;
		buldo.dxBkHotSpot = buldoRockBkHotSpotX * 2; //Offset du point chaud arriere du sprite (point de contact avec un autre Buldo) décalage par rapport au point d'ancrage
		buldo.dyBkHotSpot = buldoRockBkHotSpotY;
	} else if (buldo.camp == ordiCamp) {
		buldo.dxAvHotSpot = buldoZerHotSpotX; //Hotspot avant du sprite (point de contact avec un rocher) décalage par rapport au point d'ancrage
		buldo.dyAvHotSpot = buldoZerHotSpotY;
		buldo.dxBkHotSpot = buldoZerBkHotSpotX * 2; //Offset du point chaud arriere du sprite (point de contact avec un autre Buldo) décalage par rapport au point d'ancrage
		buldo.dyBkHotSpot = buldoZerBkHotSpotY;
	}
	//On initialise la position de base
	buldo.sprite.x = buldo.xBase;
	buldo.sprite.y = buldo.yBase;
	return buldo;
} //fin createSingleBuldo
function createBuldos() {
	//CREATION D'OBJETS A PARTIR DES SPRITES //constructor(x, y, camp)       
	var buldoRock1 = createSingleBuldo(HumanZone.x + HumanZone.width / 2, HumanZone.y + HumanZone.height / 3, humanCamp);
	var buldoRock2 = createSingleBuldo(HumanZone.x + HumanZone.width / 2, HumanZone.y + 2 * HumanZone.height / 3, humanCamp);
	var buldoZer1 = createSingleBuldo(ComputerZone.x + ComputerZone.width / 2, ComputerZone.y + ComputerZone.height / 3, ordiCamp);
	var buldoZer2 = createSingleBuldo(ComputerZone.x + ComputerZone.width / 2, ComputerZone.y + 2 * ComputerZone.height / 3, ordiCamp);
	//On stocke les objets dans un tableau
	var buldos = [];
	buldos.push(buldoRock1);
	buldos.push(buldoRock2);
	buldos.push(buldoZer1);
	buldos.push(buldoZer2);
	//On donne un nom aux objets
	buldoRock1.name = 'buldoRock1';
	buldoRock2.name = 'buldoRock2';
	buldoZer1.name = 'buldoZer1';
	buldoZer2.name = 'buldoZer2';
	return buldos;
} //fin de createBuldos
var buldos = createBuldos(); //Creation des Buldos
var rochers = generateRandomRock(nbRochers); //création des rochers
// Création de l'objet de texte pour le score du camp humain
var scoreHumainText = new Text2('0', {
	size: 70,
	fill: "#0000ff",
	anchorX: 0.5,
	anchorY: 0
});
// Positionnement du score du camp humain dans la zone score au depart de la zone humaine
LK.gui.top.addChild(scoreHumainText); //Point de depart (game.width/2,0)
scoreHumainText.x -= HumanZone.width / 2; //puis decalage vers la gauche
// Création de l'objet de texte pour le score du camp ordinateur
var scoreOrdiText = new Text2('0', {
	size: 70,
	fill: "#ff0000",
	anchorX: 0.5,
	anchorY: 0
});
// Positionnement du score du camp ordinateur dans la zone score au depart de la zone ordi
LK.gui.top.addChild(scoreOrdiText); //Point de reference (game.width/2,0)
scoreOrdiText.x += ComputerZone.width / 2; //Puis decalage a drote
// Fonction de rappel pour le tick
function onGameTick() {
	// Autres mises à jour du jeu ici en cours de test..
}
// Instead of directly calling checkMovesStack, iterate over buldos and call checkMovesStack for each
LK.on('tick', function () {
	//Animation des Buldos
	if (buldos) {
		buldos.forEach(function (buldo) {
			buldo.isMoving = buldo.isMovingH || buldo.isMovingV || buldo.isMovingR || buldo.isRotating;
			buldo.checkMovesStack(delta);
		});
	}
	//Animation des rochers
	for (var i = 0; i < rochers.length; i++) {
		if (rochers[i] == null || rochers[i].sprite.visible == false) {
			//si le rocher n'existe pas, ou est sorti de la route on passe au suivant
			continue;
		}
		rochers[i].sortPushers();
		rochers[i].vitesse = rochers[i].totalForce * vitesseBuldo / rochers[i].tailleRocher; //vitesse de déplacement du rocher            
		if (rochers[i].isBeingPushed) {
			rochers[i].checkPushed();
		} //déplacement du rocher
	}
	//Mise à jour des scores	
	updateScoreHumain(scoreHumain);
	updateScoreOrdi(scoreOrdi);
	//Fin de partie
	if (nbRochers <= 0) {
		if (scoreHumain >= scoreOrdi) {
			afficheVictoire(humanCamp);
		} else {
			afficheVictoire(ordiCamp);
		}
		LK.setTimeout(function () {
			LK.showGameOver();
		}, 8000);
	}
}); ===================================================================
--- original.js
+++ change.js
@@ -196,15 +196,15 @@
 var vitesseBuldo = 8.0; //vitesse de déplacement des buldos a vide, vitesse/2 quand ils poussent un petit rocher, vitesse/4 pour un moyen, vitesse/8 pour un gros
 var humanCamp = 1; //camp du joueur humain
 var ordiCamp = -1; //camp du joueur ordinateur
 var ancrageMedian = 0.5; //ancrage median des sprites
-var buldoRockHotSpotX = 45; //hotspot X du sprite buldoRock, offset du sprite par rapport à l'ancrage
+var buldoRockHotSpotX = 40 * 2; //hotspot X du sprite buldoRock, offset du sprite par rapport à l'ancrage
 var buldoRockHotSpotY = 0; //hotspot Y du sprite buldoRock
-var buldoRockBkHotSpotX = -45; //hotspot arriere du buldoRock
+var buldoRockBkHotSpotX = -28 * 2; //hotspot arriere du buldoRock
 var buldoRockBkHotSpotY = 0;
-var buldoZerHotSpotX = 45; //hotspot X du sprite buldoZer, offset du sprite par rapport à l'ancrage
+var buldoZerHotSpotX = 40 * 2; //hotspot X du sprite buldoZer, offset du sprite par rapport à l'ancrage
 var buldoZerHotSpotY = 0; //hotspot Y du sprite buldoZer
-var buldoZerBkHotSpotX = 45; //hotspot arriere du buldoZer
+var buldoZerBkHotSpotX = 28 * 2; //hotspot arriere du buldoZer
 var buldoZerBkHotSpotY = 0;
 var ordonneesRestantes = []; //liste des ordonnees non encore utilisees pour le placement des rochers
 var petitRocher = 2; //taille du rocher (2=petit, 4=moyen, 8=gros)
 var petitRocherDxHotLeft = -25 * 2; //hotspot X du sprite petitRocher, offset du sprite par rapport à l'ancrage
@@ -412,10 +412,12 @@
 		var nonPushers = []; //Liste des buldos qui ne poussent pas le rocher
 		this.pushers.forEach(function (buldo) {
 			if (buldo.isPushing) {
 				actualPushers.push(buldo);
+				scoreHumain = actualPushers.length;
 			} else {
 				nonPushers.push(buldo);
+				scoreOrdi = nonPushers.length;
 			}
 		});
 		actualPushers.sort(function (a, b) {
 			var distA = dist(a.sprite.x, a.sprite.y, self.sprite.x, self.sprite.y);
@@ -628,9 +630,9 @@
 				//Rocher detruit
 				targetX = this.sprite.x; //La cible principale est l'endroit ou se trouve le Buldo
 				dxHotSpotR = this.camp * this.dxAvHotSpot;
 				this.rocherDestination = null; //Plus de rocher a pousser
-				this.isMovingR = null; //Fin du mouvement
+				this.isMovingR = false; //Fin du mouvement
 				break;
 			case 0:
 				//Trois cas possibles : zero pousseur ou un pousseur de chaque cote ou deux pousseurs de chaque cotes
 				if (this.rocherDestination.pushedByHuman == null && this.rocherDestination.pushedByOrdi == null) {
@@ -745,9 +747,13 @@
 	this.setLigneHtoR = function (rocher) {
 		this.isMovingR = true; //on indique que le Buldo est en mouvement		 	
 		this.rocherDestination = rocher; //le point d'ancrage doit s'arreter sur le rocher
 		//Calcul du sens du deplacement horizontale : 1=droite, -1=gauche
-		this.vitesseEnCours = this.sprite.x < rocher.sprite.x ? this.vitessePS : -this.vitessePS; //on donne le sens du deplacement horizontal
+		if (rocher && rocher.sprite) {
+			this.vitesseEnCours = this.sprite.x < rocher.sprite.x ? this.vitessePS : -this.vitessePS; //on donne le sens du deplacement horizontal
+		} else {
+			this.vitesseEnCours = 0; // Set to 0 if rocher or rocher.sprite is null to avoid errors
+		}
 	}; //fin setLigneHtoR
 	this.deplaceHtoR = function (delta) {
 		// Vérifie si le Buldo est en mouvement
 		if (this.rocherDestination != null || this.rocherPushed != null) {
:quality(85)/https://cdn.frvr.ai/65e6262de1e74b7a4e8f2ade.png%3F3) 
 A small rock
:quality(85)/https://cdn.frvr.ai/65e626c9e1e74b7a4e8f2aea.png%3F3) 
 a rock without any shadow and four time smaller than the original.
:quality(85)/https://cdn.frvr.ai/65e62db6e1e74b7a4e8f2c18.png%3F3) 
 Blue color
:quality(85)/https://cdn.frvr.ai/662e608a2a374391362a0467.png%3F3) 
 a rock is being crunched so there is smoke and peaces of rocks viewed from top.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/663931c70253c16e5819988e.png%3F3) 
 Un trophée de victoire sous forme d'une coupe d'où s'échappe un feu d'artifice.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/663b675bbec26945c0451f20.png%3F3) 
 Red bulldozer viewed strictly from top. Top view as if we are a drone.. Single Game Texture. In-Game asset. 2d. Blank background. High contrast. No shadows.
:quality(85)/https://cdn.frvr.ai/663cfef5b29f600a2e809c0d.png%3F3) 
 Remove yellow lines.