让pv3d(papervision3D)支持单帧前进、后退(nextFrame)。

下载最新的源码,找到animationController.

修改如下:

package org.papervision3d.core.controller 
{
	import flash.events.EventDispatcher;
	import flash.utils.getTimer;
	
	import org.papervision3d.core.animation.IAnimatable;
	import org.papervision3d.core.animation.channel.Channel3D;
	import org.papervision3d.core.animation.clip.AnimationClip3D;
	import org.papervision3d.events.AnimationEvent;
	
	/**
	 * The AnimationController class controls an animation.
	 * 
	 * @author Tim Knip / floorplanner.com
	 */
	public class AnimationController extends EventDispatcher implements IObjectController, IAnimatable
	{
		/**
		 * Start time of animation in seconds. 
		 */
		public var startTime : Number;
		
		/**
		 * End time of animation in seconds. 
		 */
		public var endTime : Number;
		
		/**
		 * 
		 */
		private var _channels : Array;
		
		/**
		 * 
		 */
		private var _isPlaying : Boolean;
		
		/**
		 * 
		 */
		private var _isPaused : Boolean;
		
		/**
		 * 
		 */
		private var _isStepping : Boolean = false;
		
		/**
		 * 
		 */
		private var _currentTime : Number;
		
		/**
		 * 
		 */
		private var _currentTimeStamp : int;
		
		/**
		 * 
		 */
		private var _pauseTime : Number;
		
		/**
		 * 
		 */
		private var _loop : Boolean;
		
		/** */
		private var _clip : AnimationClip3D;
		
		/** */
		private var _clips : Array;
		
		/** */
		private var _clipByName : Object;
		
		/** */
		private var _dispatchEvents : Boolean;
		
		/** 帧计算 */
		private var _frameIndex:int = 0;
		
		/**
		 * Constructor.
		 */
		public function AnimationController(dispatchEvents:Boolean=true) 
		{
			super();
			
			_dispatchEvents = dispatchEvents;
			
			init();			
		}

		/**
		 * 
		 */
		public function addChannel(channel : Channel3D) : Channel3D 
		{
			if(_channels.indexOf(channel) == -1)
			{
				_channels.push(channel);
				updateStartAndEndTime();
				return channel;
			}
			return null;
		}

		/**
		 * 
		 */
		public function addClip(clip : AnimationClip3D) : AnimationClip3D
		{
			if(_clips.indexOf(clip) == -1)
			{
				_clips.push(clip);
				_clipByName[clip.name] = clip;
				return clip;
			}
			return null;	
		}

		/**
		 * 
		 */
		public function clone() : AnimationController
		{
			var controller : AnimationController = new AnimationController();
			var channel : Channel3D;
			var cloned : Channel3D;
			var i : int;
			
			for(i = 0; i < _channels.length; i++)
			{
				channel = _channels[i];
				cloned = channel.clone();
				controller.addChannel(cloned);
			}
			return controller;
		}

		/**
		 * Initialize.
		 */
		protected function init() : void
		{
			_channels = new Array();
			_clips = new Array();
			_clipByName = new Object();
			_isPlaying = false;
			_isPaused = false;
			_currentTime = 0;
			_loop = false;
			updateStartAndEndTime();
		}
		
		/**
		 * Pause the animation.
		 */
		public function pause() : void
		{
			_pauseTime = _currentTime;
			_isPaused = true;
			_isPlaying = false;
			
			if (_dispatchEvents)
			{
				var clipName :String = _clip ? _clip.name : "all";

				dispatchEvent(new AnimationEvent(AnimationEvent.PAUSE, _pauseTime, clipName));
			}
		}
		/**
		 * Plays the animation.
		 * 
		 * @param 	clip	Clip to play. Default is "all"
		 * @param 	loop	Whether the animation should loop. Default is true.
		 */ 
		public function play(clip:String="all", loop:Boolean=true) : void 
		{
			if(clip && clip.length && _clipByName[clip] is AnimationClip3D) 
			{	
				_clip = _clipByName[clip];
			}
			else
			{
				_clip = null;
			}
			
			if(_channels.length)
			{
				_loop = loop;
				_currentTimeStamp = getTimer();
				if(_clip)
				{
					_currentTimeStamp -= (_clip.startTime * 1000);	
				}
				_isPlaying = true;
				_isPaused = false;
			}
			
			if (_dispatchEvents)
			{
				var clipName :String = _clip ? _clip.name : "all";
				var time :Number = _clip ? _clip.startTime : 0;
				
				dispatchEvent(new AnimationEvent(AnimationEvent.START, time, clipName));
			}
		}

		/**
		 * 显示下一帧
		 */
		public function next():void{
			_frameIndex++;
			if(_frameIndex >= totalFrames)
			{
				_frameIndex = 0;
			}
			_currentTime =  endTime / totalFrames * _frameIndex;
			this._isStepping = true;
		}
		
		public function get totalFrames():int{
			var count:int = 0;
			if(!this._channels)
				return count;
			for each(var _channel:Channel3D in this._channels)
			{
				if(_channel.output == null)
					continue;
				count = Math.max(_channel.output.length, count);
			}
			return count;
		}
		
		/**
		 * 
		 */
		public function removeAllChannels() : void
		{
			while(_channels.length)
			{
				_channels.pop();
			}
			updateStartAndEndTime();
		}
		
		/**
		 * 
		 */
		public function removeChannel(channel : Channel3D) : Channel3D
		{
			var pos : int = _channels.indexOf(channel);
			if(pos >= 0)
			{
				_channels.splice(pos, 1);
				updateStartAndEndTime();
				return channel;
			}
			return null;
		}
		
		/**
		 * Removes a clip.
		 * 
		 * @param clip
		 * 
		 * @return	The removed clip or null on failure.
		 */
		public function removeClip(clip : AnimationClip3D) : AnimationClip3D
		{
			var pos : int = _clips.indexOf(clip);
			if(pos >= 0)
			{
				_clips.splice(pos, 1);
				_clipByName[clip.name] = null;
				return clip;
			}
			return null;
		}
		
		/**
		 * Resumes the animation.
		 * 
		 *  @param loop	Whether the animation should loop. Defaults to true;
		 */
		public function resume(loop:Boolean=true) : void
		{
			if(_channels.length)
			{
				_loop = loop;
				_currentTimeStamp = getTimer();
				if(_isPaused)
				{
					_currentTimeStamp = getTimer() - _pauseTime * 1000;	
				}
				_isPlaying = true;
				_isPaused = false;
				
				if (_dispatchEvents)
				{
					var clipName :String = _clip ? _clip.name : "all";

					dispatchEvent(new AnimationEvent(AnimationEvent.RESUME, _pauseTime, clipName));
				}
			}
		}

		/**
		 * Stops the animation.
		 */
		public function stop() : void
		{	
			_isPlaying = false;
			
			if (_dispatchEvents)
			{
				var endTime :Number = _clip ? _clip.endTime : this.endTime;
				var clipName :String = _clip ? _clip.name : "all";
			
				dispatchEvent(new AnimationEvent(AnimationEvent.STOP, endTime, clipName));
			}
		}
		
		/**
		 * Update.
		 */
		public function update() : void 
		{
			if(_isStepping)
			{
				stepping();
				_isStepping = false;
				return;	
			}
			
			if(!_isPlaying || _isPaused || !_channels.length)
			{
				return;
			}
			
			var t : int = getTimer();
			var elapsed : int = t - _currentTimeStamp;
			var channel : Channel3D;
			var et : Number = _clip ? _clip.endTime : endTime;
			var clipName :String = _clip ? _clip.name : "all";
			
			_currentTime =  (elapsed * 0.001);

			if(_currentTime > et) 
			{
				if (_dispatchEvents)
				{
					dispatchEvent(new AnimationEvent(AnimationEvent.COMPLETE, et, clipName));
				}
					
				if(!_loop)
				{
					stop();
					return;
				}
				_currentTimeStamp = t;
				if(_clip)
				{
					_currentTimeStamp -= (_clip.startTime * 1000);
				}
				_currentTime = _clip ? _clip.startTime : startTime;
			}
			
			for each(channel in _channels)
			{
				channel.update(_currentTime);
			}
			
			if (_isPlaying && _dispatchEvents)
			{
				dispatchEvent(new AnimationEvent(AnimationEvent.NEXT_FRAME, _currentTime, clipName));
			}
		}
		
		private function stepping():void
		{
			var channel : Channel3D;
			var et : Number = _clip ? _clip.endTime : endTime;
			var clipName :String = _clip ? _clip.name : "all";
			
			if(_currentTime > et) 
			{
				if (_dispatchEvents)
				{
					dispatchEvent(new AnimationEvent(AnimationEvent.COMPLETE, et, clipName));
				}
				
				if(!_loop)
				{
					stop();
					return;
				}
				if(_clip)
				{
					_currentTimeStamp -= (_clip.startTime * 1000);
				}
				_currentTime = _clip ? _clip.startTime : startTime;
			}
			
			for each(channel in _channels)
			{
				channel.update(_currentTime);
			}
			
			if (_isPlaying && _dispatchEvents)
			{
				dispatchEvent(new AnimationEvent(AnimationEvent.NEXT_FRAME, _currentTime, clipName));
			}
		}
		
		/**
		 * Updates the startTime and endTime of this animation controller.
		 */
		protected function updateStartAndEndTime() : void
		{
			var channel : Channel3D;
			
			if(_channels.length == 0)
			{
				startTime = endTime = 0;
				return;
			}
			
			startTime = Number.MAX_VALUE;
			endTime = -startTime;
		
			for each(channel in _channels)
			{
				startTime = Math.min(startTime, channel.startTime);
				endTime = Math.max(endTime, channel.endTime);
			}
		}
		
		/**
		 * 
		 */
		override public function toString() : String
		{
			return "[AnimationController] #channels: " + _channels.length + " startTime: " + startTime + " endTime: " + endTime;
		}
		
		public function set channels(value : Array) : void
		{
			_channels = value;	
		}
		
		public function get channels() : Array
		{
			return _channels;
		}
		
		public function get currentTime():Number
		{
			return _currentTime;	
		}

		/**
		 * Gets all defined clip names. This property is read-only.
		 * 
		 * @return Array containing clip names.
		 */
		public function get clipNames() : Array
		{
			var names : Array = new Array();	
			var clip : AnimationClip3D;
			
			for each(clip in _clips)
			{
				names.push(clip.name);
			}
			return names;
		}
		
		/**
		 * Gets all defined clips. This property is read-only.
		 * 
		 * @return Array containing clips.
		 * 
		 * @see org.papervision3d.core.animation.clip.AnimationClip3D
		 */
		public function get clips() : Array
		{
			return _clips;
		}
		
		/**
		 * 
		 */
		public function get dispatchEvents():Boolean
		{
			return _dispatchEvents;
		} 
		
		/**
		 * 
		 */
		public function set dispatchEvents(value:Boolean):void
		{
			_dispatchEvents = value;	
		}
		
		/**
		 * Number of channels.
		 */
		public function get numChannels() : uint
		{
			return _channels.length;
		}
		
		/**
		 * Whether the animation is playing. This property is read-only.
		 */
		public function get playing() : Boolean
		{
			return _isPlaying;
		}
	}
}

  

增加了next方法。每次调用,就会进入下一帧。然后调用 onRenderTick即可。

posted @ 2013-12-23 23:05    阅读(636)  评论(0编辑  收藏  举报
IT民工