⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 simulation.as

📁 用于flash/flex的 as3的 2D图形图像图表的动态生成
💻 AS
字号:
package flare.physics
{
	import flash.geom.Rectangle;
	
	/**
	 * A physical simulation involving particles, springs, and forces.
	 * Useful for simulating a range of physical effects or layouts.
	 */
	public class Simulation
	{
		private var _particles:Array = new Array();
		private var _springs:Array = new Array();
		private var _forces:Array = new Array();
		private var _bounds:Rectangle = null;
		
		/** The default gravity force for this simulation. */
		public function get gravityForce():GravityForce {
			return _forces[0] as GravityForce;
		}
		
		/** The default n-body force for this simulation. */
		public function get nbodyForce():NBodyForce {
			return _forces[1] as NBodyForce;
		}
		
		/** The default drag force for this simulation. */
		public function get dragForce():DragForce {
			return _forces[2] as DragForce;
		}
		
		/** The default spring force for this simulation. */
		public function get springForce():SpringForce {
			return _forces[3] as SpringForce;
		}
		
		/** Sets a bounding box for particles in this simulation.
		 *  Null (the default) indicates no boundaries. */
		public function get bounds():Rectangle { return _bounds; }
		public function set bounds(b:Rectangle):void {
			if (_bounds == b) return;
			if (b == null) { _bounds = null; return; }
			if (_bounds == null) { _bounds = new Rectangle(); }
			// ensure x is left-most and y is top-most
			_bounds.x = b.x + (b.width < 0 ? b.width : 0);
			_bounds.width = (b.width < 0 ? -1 : 1) * b.width;
			_bounds.y = b.y + (b.width < 0 ? b.height : 0);
			_bounds.height = (b.height < 0 ? -1 : 1) * b.height;
		}
		
		/**
		 * Creates a new physics simulation.
		 * @param gx the gravitational acceleration along the x dimension
		 * @param gy the gravitational acceleration along the y dimension
		 * @param drag the default drag (viscosity) co-efficient
		 * @param attraction the gravitational attraction (or repulsion, for
		 *  negative values) between particles.
		 */
		public function Simulation(gx:Number=0, gy:Number=0,
			drag:Number=0.1, attraction:Number=-5)
		{
			_forces.push(new GravityForce(gx, gy));
			_forces.push(new NBodyForce(attraction));
			_forces.push(new DragForce(drag));
			_forces.push(new SpringForce());
		}
		
		// -- Init Simulation -------------------------------------------------
		
		/**
		 * Adds a custom force to the force simulation.
		 * @param force the force to add
		 */
		public function addForce(force:IForce):void
		{
			_forces.push(force);
		}
		
		/**
		 * Returns the force at the given index.
		 * @param idx the index of the force to look up
		 * @return the force at the specified index
		 */ 
		public function getForceAt(idx:int):IForce
		{
			return _forces[idx];
		}
		
		/**
		 * Adds a new particle to the simulation.
		 * @param mass the mass (charge) of the particle
		 * @param x the particle's starting x position
		 * @param y the particle's starting y position
		 * @return the added particle
		 */
		public function addParticle(mass:Number, x:Number, y:Number):Particle
		{
			var p:Particle = getParticle(mass, x, y);
			_particles.push(p);
			return p;
		}
		
		/**
		 * Removes a particle from the simulation. Any springs attached to
		 * the particle will also be removed.
		 * @param idx the index of the particle in the particle list
		 * @return true if removed, false otherwise.
		 */
		public function removeParticle(idx:uint):Boolean
		{
			var p:Particle = _particles[idx];
			if (p == null) return false;
			
			// remove springs
			for (var i:uint = _springs.length; --i >= 0; ) {
				var s:Spring = _springs[i];
				if (s.p1 == p || s.p2 == p)
					removeSpring(i);
			}
			// remove from particles
			reclaimParticle(p);
			_particles.splice(idx, 1);
			return true;
		}
		
		/**
		 * Adds a spring to the simulation
		 * @param p1 the first particle attached to the spring
		 * @param p2 the second particle attached to the spring
		 * @param restLength the rest length of the spring
		 * @param tension the tension of the spring
		 * @param damping the damping (friction) co-efficient of the spring
		 * @return the added spring
		 */
		public function addSpring(p1:Particle, p2:Particle, restLength:Number,
							      tension:Number, damping:Number):Spring
		{
			var s:Spring = getSpring(p1, p2, restLength, tension, damping);
			p1.degree++;
			p2.degree++;
			_springs.push(s);
			return s;
		}
		
		
		/**
		 * Removes a spring from the simulation.
		 * @param idx the index of the spring in the spring list
		 * @return true if removed, false otherwise
		 */
		public function removeSpring(idx:uint):Boolean
		{
			if (idx >= _springs.length) return false;
			var s:Spring = _springs[idx];
			s.p1.degree--;
			s.p2.degree--;
			reclaimSpring(s);
			_springs.splice(idx, 1);
			return true;
		}
		
		/**
		 * Returns the particle list. This is the same array instance backing
		 * the simulation, so edit the array with caution.
		 * @return the particle list
		 */
		public function get particles():Array {
			return _particles;
		}
		
		/**
		 * Returns the spring list. This is the same array instance backing
		 * the simulation, so edit the array with caution.
		 * @return the spring list
		 */
		public function get springs():Array {
			return _springs;
		}
		
		// -- Run Simulation --------------------------------------------------
		
		/**
		 * Advance the simulation for the specified time interval.
		 * @param dt the time interval to step the simulation (default 1)
		 */
		public function tick(dt:Number=1):void
		{	
			var p:Particle, s:Spring, i:uint, ax:Number, ay:Number;
			var dt1:Number = dt/2, dt2:Number = dt*dt/2;
			
			// remove springs connected to dead particles
			for (i=_springs.length; --i>=0;) {
				s = _springs[i];
				if (s.die || s.p1.die || s.p2.die) {
					s.p1.degree--;
					s.p2.degree--;
					reclaimSpring(s);
					_springs.splice(i, 1);
				}
			}
			
			// update particles using Verlet integration
			for (i=_particles.length; --i>=0;) {
				p = _particles[i];
				p.age += dt;
				if (p.die) { // remove dead particles
					reclaimParticle(p);
					_particles.splice(i, 1);
				} else if (p.fixed) {
					p.vx = p.vy = 0;
				} else {
					ax = p.fx / p.mass; ay = p.fy / p.mass;
					p.x  += p.vx*dt + ax*dt2;
					p.y  += p.vy*dt + ay*dt2;
					p._vx = p.vx + ax*dt1;
					p._vy = p.vy + ay*dt1;
				}
			}
			// evaluate the forces
			eval();
			// update particle velocities
			for (i=_particles.length; --i>=0;) {
				p = _particles[i];
				if (!p.fixed) {
					ax = dt1 / p.mass;
					p.vx = p._vx + p.fx * ax;
					p.vy = p._vy + p.fy * ax;
				}
			}
			
			// enfore bounds
			if (_bounds) enforceBounds();
		}
		
		private function enforceBounds():void {
			var minX:Number = _bounds.x;
			var maxX:Number = _bounds.x + _bounds.width;
			var minY:Number = _bounds.y;
			var maxY:Number = _bounds.y + _bounds.height;
			
			for each (var p:Particle in _particles) {
				if (p.x < minX) {
					p.x = minX; p.vx = 0;
				} else if (p.x > maxX) {
					p.x = maxX; p.vx = 0;
				}
				if (p.y < minY) {
					p.y = minY; p.vy = 0;
				}
				else if (p.y > maxY) {
					p.y = maxY; p.vy = 0;
				}
			}
		}
		
		/**
		 * Evaluates the set of forces in the simulation.
		 */
		public function eval():void {
			var i:uint, p:Particle;
			// reset forces
			for (i=_particles.length; --i >= 0; ) {
				p = _particles[i];
				p.fx = p.fy = 0;
			}
			// collect forces
			for (i=0; i<_forces.length; ++i) {
				IForce(_forces[i]).apply(this);
			}
		}
		
		// -- Particle Pool ---------------------------------------------------
		
		/** The maximum number of items stored in a simulation object pool. */
		public static var objectPoolLimit:int = 5000;
		protected static var _ppool:Array = new Array();
		protected static var _spool:Array = new Array();
		
		/**
		 * Returns a particle instance, pulling a recycled particle from the
		 * object pool if available.
		 * @param mass the mass (charge) of the particle
		 * @param x the particle's starting x position
		 * @param y the particle's starting y position
		 * @return a particle instance
		 */
		protected static function getParticle(mass:Number, x:Number, y:Number):Particle
		{
			if (_ppool.length > 0) {
				var p:Particle = _ppool.pop();
				p.init(mass, x, y);
				return p;
			} else {
				return new Particle(mass, x, y);
			}
		}
		
		/**
		 * Returns a spring instance, pulling a recycled spring from the
		 * object pool if available.
		 * @param p1 the first particle attached to the spring
		 * @param p2 the second particle attached to the spring
		 * @param restLength the rest length of the spring
		 * @param tension the tension of the spring
		 * @param damping the damping (friction) co-efficient of the spring
		 * @return a spring instance
		 */
		protected static function getSpring(p1:Particle, p2:Particle,
			restLength:Number, tension:Number, damping:Number):Spring
		{
			if (_spool.length > 0) {
				var s:Spring = _spool.pop();
				s.init(p1, p2, restLength, tension, damping);
				return s;
			} else {
				return new Spring(p1, p2, restLength, tension, damping);
			}
		}
		
		/**
		 * Reclaims a particle, adding it to the object pool for recycling
		 * @param p the particle to reclaim
		 */
		protected static function reclaimParticle(p:Particle):void
		{
			if (_ppool.length < objectPoolLimit) {
				_ppool.push(p);
			}
		}
		
		/**
		 * Reclaims a spring, adding it to the object pool for recycling
		 * @param s the spring to reclaim
		 */
		protected static function reclaimSpring(s:Spring):void
		{
			if (_spool.length < objectPoolLimit) {
				_spool.push(s);
			}
		}
		
	} // end of class Simulation
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -