APE : Le moteur physique grand public

Un des gros avantages de APE, c’est sa logique de fonctionnement !
Toute personne connaissant la programmation objet sera en terrain connu, d’où une relative facilité d’apprentissage, pas de perte de temps !
Il sera parfait pour toutes les utilisations ou le nombre d’objets a tester pour collision sera dans une fourchette relativement basse, une 50aine d’objets sera certainement un grand maximum.


Vous pouvez tester les possibilités de APE dans cette animation.

Attention, les objets qui sortent de la scène continuent a exister, faut donc appuyer de temps en temps sur le bouton d’effacement.

Le clique de la souris + déplacement place un objet cercle sur la scène, le type de ce objet peut être modifié en appuyant sur une touche du clavier :

  • CTRL = un tricycle avec liaison souple entre chaque roue  (a placer un par un pour éviter de les imbriquer)
  • SHIFT = une roue

Si vous ne voyez pas de différence entre un cercle et une roue, c’est normal, la seule différence entre les 2, c’est la possibilité de définir un coefficient de traction (ici a 0) pour la roue afin qu’elle ce comporte comme une roue de voiture.

code utilisé dans le SWF :

/* ----------------------------------------------------------------------------
*
*                            classe Main v1.0
*
 ------------------------------------------------------------------------------- */
package {
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
 
	import org.cove.ape.*;
 
	import lol.controle.Bouton;
 
	/**
	*
	* @author Lorenzo
	*/
	public class Main extends Sprite {
		// -----------------------------------------------------------------------------------
		// DECLARATIONS
		// -----------------------------------------------------------------------------------
 
		// le groupe des objets a tester pour collision.
		// un objet peut faire partie de plusieurs groupe
		private var _apeGroupDyn:Group = new Group(true);
 
		// le groupe des objets statiques -> ne bouge pas et pas de test
		// de collision entre eux !
		private var _apeGroupStatiq:Group = new Group();
 
		// definition du vecteur de gravité du monde
		private var _apeVectorGravite:Vector = new Vector(0, 10);
 
		// -----------------------------------------------------------------------------------
		// CONSTRUCTEUR
		// -----------------------------------------------------------------------------------
 
		/**
		* Constructeur de Main
		*/
		public function Main():void {
			if (stage){
				init();
			}else{
				addEventListener(Event.ADDED_TO_STAGE, init);
			}
		}
 
		private function init(e:Event = null):void {
			removeEventListener(Event.ADDED_TO_STAGE, init);
			// entry point
 
			stage.scaleMode = "noScale";
			//stage.align = "LB";
 
			var bt:Bouton = new Bouton();
			bt.texte = "Effacer objets utilisateur";
			bt.x = 798;
			bt.y = 2;
			bt.aligne = "droite";
			this.addChild(bt);
			bt.addEventListener(MouseEvent.MOUSE_DOWN, evtBtEffacerDynamiqueMouseDown);
 
			// Initialisation du moteur physique
			APEngine.init(1/6);
			APEngine.container = this;
			APEngine.addMasslessForce(this._apeVectorGravite);
 
			APEngine.damping = 0.99;
			APEngine.constraintCollisionCycles = 1;
			APEngine.constraintCycles = 1;
 
			this._apeGroupStatiq = new Group();
			this._apeGroupDyn = new Group(true);
 
			// definition des rectangles statiques
			var floor:RectangleParticle;
 
			floor = new RectangleParticle(250,200,500,20,Math.PI/16,true,1,0,0);
			floor.setStyle(0,0,0,0x006699);
			this._apeGroupStatiq.addParticle(floor);
			floor = new RectangleParticle(8,120,10,100,0,true,1,0,0);
			floor.setStyle(0,0,0,0x006699);
			this._apeGroupStatiq.addParticle(floor);
 
			floor = new RectangleParticle(550,400,500,20,-Math.PI/16,true,1,0,0);
			floor.setStyle(0,0,0,0x006699);
			this._apeGroupStatiq.addParticle(floor);
			floor = new RectangleParticle(792,320,10,100,0,true,1,0,0);
			floor.setStyle(0,0,0,0x006699);
			this._apeGroupStatiq.addParticle(floor);
 
			APEngine.addGroup(this._apeGroupStatiq);
			APEngine.addGroup(this._apeGroupDyn);
 
			// on indique au moteur que les membres du groupe "this._apeGroupDyn" seront testé pour collision
			// avec "this._apeGroupStatiq"
			this._apeGroupDyn.addCollidable(this._apeGroupStatiq);
 
			this.addEventListener(Event.ENTER_FRAME, evtThisEnterFrame);
			this.stage.addEventListener(MouseEvent.MOUSE_DOWN, evtStageMouseDown);
			this.stage.addEventListener(MouseEvent.MOUSE_UP, evtStageMouseUp);
		}
 
		// -----------------------------------------------------------------------------------
		// EVENEMENTS
		// -----------------------------------------------------------------------------------
 
		/**
		 */
		private function evtStageMouseDown(ev:MouseEvent):void {
			stage.addEventListener(MouseEvent.MOUSE_MOVE, evtThisMouseMove);
		}
 
		/**
		 */
		private function evtStageMouseUp(ev:MouseEvent):void {
			stage.removeEventListener(MouseEvent.MOUSE_MOVE, evtThisMouseMove);
		}
 
		/**
		 */
		private function evtThisMouseMove(ev:MouseEvent):void {
			if ( ev.target != this.stage ) {
				return;
			}
 
			var masseRayon:Number;
			if ( ev.ctrlKey ) {
				// Ajouter un espece de tricycle avec liaison souple entre les roues
				masseRayon = Math.random() * 10 + 5;
				var wa:WheelParticle = new WheelParticle(ev.stageX, ev.stageY, masseRayon, false, masseRayon, 0.3, 0, 1);
				this._apeGroupDyn.addParticle(wa);
				var wb:WheelParticle = new WheelParticle(ev.stageX + masseRayon * 4, ev.stageY - masseRayon * 4, masseRayon, false, masseRayon, 0.3, 0, 1);
				this._apeGroupDyn.addParticle(wb);
				var wc:WheelParticle = new WheelParticle(ev.stageX + masseRayon * 8, ev.stageY, masseRayon, false, masseRayon, 0.3, 0, 1);
				this._apeGroupDyn.addParticle(wc);
				var sca:SpringConstraint = new SpringConstraint(wa, wb, 0.1, true, masseRayon  >> 1);
				this._apeGroupDyn.addConstraint(sca);
				var scb:SpringConstraint = new SpringConstraint(wb, wc, 0.1, true, masseRayon >> 1);
				this._apeGroupDyn.addConstraint(scb);
				var scc:SpringConstraint = new SpringConstraint(wa, wc, 0.1, true, masseRayon >> 1);
				this._apeGroupDyn.addConstraint(scc);
			}else if ( ev.shiftKey ) {
				// Ajouter une roue
				masseRayon = Math.random() * 15 + 5;
				var cercle:WheelParticle = new WheelParticle(ev.stageX, ev.stageY, masseRayon, false, masseRayon, 0.3, 0);
				cercle.setStyle(0, 0, 1, Math.random() * 0xFFFFFF);
				this._apeGroupDyn.addParticle(cercle);
			}else {
				// Ajouter un cercle
				masseRayon = Math.random() * 15 + 5;
				var cercle2:CircleParticle = new CircleParticle(ev.stageX, ev.stageY, masseRayon, false, masseRayon);
				cercle2.setStyle(0, 0, 1, Math.random() * 0xFFFFFF);
				this._apeGroupDyn.addParticle(cercle2);
			}
		}
 
		private function evtThisEnterFrame(evt:Event):void {
			// moteur du moteur physique : calcul position/collision
			APEngine.step();
			// affichage
			APEngine.paint();
		}
 
		/**
		 * @param	ev
		 */
		private function evtBtEffacerDynamiqueMouseDown(ev:MouseEvent):void {
			while ( this._apeGroupDyn.constraints.length > 0 ) {
				this._apeGroupDyn.removeConstraint(this._apeGroupDyn.constraints[0]);
			}
			while ( this._apeGroupDyn.particles.length > 0 ) {
				this._apeGroupDyn.removeParticle(this._apeGroupDyn.particles[0]);
			}
		}
	}
}

Laisser un commentaire

*