下载最新的源码,找到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即可。