博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

   文章若非特别注明转载,皆是原创,转载请注明出处。

  本文地址:http://www.cnblogs.com/bobolive/p/3538606.html

 

 在2d游戏中,模型动画一般是按帧播放的,通常我们希望我们的模型足够“智能”, 在一段动画过程里面可以精准地触发一系列事件,或做出一些调整。比如说一个模型的攻击动作是举起大刀往下砍,这里我们希望它把刀举过头顶往下砍的时候出现一刀光特效,在刀挥至胸前时砍中对方,配合特效在某处停留一两秒等等。这时就需要模型内部有“芯片”供我们预设或动态的输入指令。

  这可以做一个不依赖资源的,适用于任何有帧系列概念的自建类。这作用有点类似ActionScript 中 MovieClip的 addFrameScript, 但要它是独立的,更灵活、可扩展。

  这样,模型资源里面加上一些标签, 在Flash中是这样的:

  

  要植入的“芯片”: FrameScript

  它提供根据标签植入脚本接口 addLabelIndexScript

  

addLabelIndexScript("attack", fillSkill, [hitId, ...]);

 

        /**
         * 如果FrameScript设置了labelIndex的标签映射字典, 则可以根据标签来执行script
         * @param label_ script执行的标签
         * @param callback_ 具体的script
         * @param param_ script 的参数
         * @param once_ 为true时,执行一次会清除,默认为true
         * 
         */        
        public function addLabelIndexScript(label_:String, callback_:Function,
                                            param_:Object=null, once_:Boolean=true):void
        {
            var frame_:int= _excuteIndex;
            if(!_hasSetLabel)
            {
                _preLabelDic[label_] = {call:callback_, param:param_, once:once_};
            }
            else
            {
                if(_labelIndexDic.hasOwnProperty(label_)) {
                    frame_ = int(_labelIndexDic[label_]);
                }
                addFrameScript(frame_, callback_, param_, once_);
                _preLabelDic[frame_] = {call:callback_, param:param_, once:once_};
            }
        }

        /**
         * 增加一个script 
         * @param frame_ 执行的计数值
         * @param callback_ 
         * @param param_
         * @param once_ 为true时,执行一次会清除,默认为true
         */        
        public function addFrameScript(frame_:int, callback_:Function, param_:Object=null, once_:Boolean=true):void
        {
            var callbacks_:Array = [];
            var frameStr_:String = frame_.toString();
            if(_frameScriptDic.hasOwnProperty(frameStr_))
            {
                callbacks_ = _frameScriptDic[frameStr_] as Array;
            }
            else
            {
                callbacks_ = _frameScriptDic[frameStr_] = [];
            }
            callbacks_.push({call:callback_, param:param_, once:once_});
        }

   这里还应该可以接受即时插入的脚本。

        /**
         * 增加从当前计数往前的计数的script 
         * @param forwardFrame_ 从当前计数起多少个计数后执行
         * @param callback_ 具体的script
         * @param param_ script 的参数
         * @param once_ 为true时,执行一次会清除,默认为true
         */        
        public function addForwardFrameScript(forwardFrame_:int, callback_:Function,
                                              param_:Object=null, once_:Boolean=true):void
        {
            var frame_:int = forwardFrame_ + _excuteIndex;
            addFrameScript(frame_, callback_, param_, once_);
        }

  插入的脚本由自定义的帧数来触发。

 

frameScript.excuteIndex++;//帧计数完全自控制

 

        /**
         * 更新FrameScript的计数 
         * @param value_ value_为0时表示清除FrameScript
         * 当value_大于当前计数时,会从当前计数开始执行(value_ - excuteIndex)次
         * 并把excuteIndex 赋值为 value_
         */        
        public function set excuteIndex(value_:int):void
        {
            if(!value_) 
            {
                clear();
            }
            else
            {
                var dis:int = value_ - _excuteIndex;
                while(dis)
                {
                    step();
                    dis--;
                }
            }
        }
        
        /**
         * 执行下一次计数的script 
         * 同时excuteIndex 加 1
         */        
        private function step():void
        {
            excuteFrameScript(_excuteIndex);
            _excuteIndex++;
        }

  这里如果要实现加速机制,改成:

frameScript.excuteIndex += multiple;//multiple 是倍数

 

  完整代码:

package utils.display
{
    import events.CacheEvent;
    
    import flash.display.Bitmap;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.geom.Point;
    import flash.utils.Dictionary;
    import flash.utils.getTimer;
    
    import modules.scene.interfaces.IRender;
    
    import tools.time.CallBack;
    import tools.time.FrameScript;
    import tools.time.TimerManage;
    
    import utils.cache.SourceCacheManage;
    import utils.consts.MovieClipDataType;
    import utils.loader.LoadLevel;
    import utils.loader.LoadType;
    import utils.loader.LoadUrlUtils;
    import utils.loader.ResourceLoaderPool;
    import utils.loader.items.DgLoaderItem;
    import utils.loader.items.GifLoaderItem;
    import utils.loader.items.NdgLoaderItem;
    import utils.render.ModelRenderManager;
    
    public class MultiBodydisplayer extends Sprite implements IRender
    {
        public var resourceKey:String;
        public var centerPoint:Point;
        public var frameScript:FrameScript;
        public var stepFrame:int;
        private var _needLoadNum:int;
        private var _resourceDic:Dictionary;
        private var _bitmapDic:Array;
        private var _displayIndexs:Array;
        
        private var _currentLabel:String;
        private var _loopDic:Dictionary;
        private var _delay:int;
        private var _currentIndex:int;
        private var _scaleX:int;
        private var _mainHeight:int;
        private var _mainWidth:int;
        private var _everyStep:Boolean;
        private var _bitmapNum:int;
        public function MultiBodydisplayer()
        {
            frameScript = new FrameScript;
            _bitmapNum = 0;
        }
        
        public function set everyStep(value_:Boolean):void
        {
            _everyStep = value_;
            ModelRenderManager.getInstance().remove(this);
            
            ModelRenderManager.getInstance().add(this, _everyStep);
        }
        
        public function getPostion(centerPoint_:Point):Point
        {
            if(!centerPoint)
            {
                centerPoint = centerPoint_;
                this.x = (scaleX == 1) ? -centerPoint.x : centerPoint.x;// - (-1*scaleX)*
                this.y = -centerPoint.y;
            }
            
            return new Point(centerPoint.x - centerPoint_.x, centerPoint.y - centerPoint_.y);
        }
        
        private function setBodyXY(x_:Number, y_:Number):void
        {
            if(!centerPoint)
            {
                this.x = (scaleX == 1) ? -x_ : x_;// - (-1*scaleX)*
                this.y = -y_;
                centerPoint = new Point(x_, y_);
            }
        }
        
        private function clearResourceDic():void
        {
            for (var url_:String in _resourceDic)
            {
                SourceCacheManage.getInstance().resBack(url_);
            }
            _resourceDic = new Dictionary;
            ModelRenderManager.getInstance().remove(this);
        }
        
        public function setResourceUrls(urls_:Array, LoadLevel_:int=LoadLevel.LOW):Boolean
        {
            var hasResource:Boolean = false;
            
            _needLoadNum = 0;//urls_.length;
            clearResourceDic();
            var loaderItem:NdgLoaderItem;
            for each(var url:String in urls_)
            {
                _needLoadNum++;
                _resourceDic[url] = null;
                if(LoadUrlUtils.getType(url) == LoadType.NDG_TYPE)
                {
                    loaderItem = new NdgLoaderItem(url, LoadLevel_, true, loadCompletedHandler, url);
                    hasResource = ResourceLoaderPool.getInstance().loadResourceByItem(loaderItem, true) || hasResource;
                }
                else if(LoadUrlUtils.getType(url) == LoadType.GIF_TYPE)
                {
                    var gifItem:GifLoaderItem = new GifLoaderItem(url, LoadLevel_, true, loadCompletedHandler, url);
                    hasResource = ResourceLoaderPool.getInstance().loadResourceByItem(gifItem, true) || hasResource;
                }
                else if(LoadUrlUtils.getType(url) == LoadType.DG_TYPE)
                {
                    var dgLoaderItem:DgLoaderItem = new DgLoaderItem(url, LoadLevel_, true, loadCompletedHandler, url);
                    hasResource = ResourceLoaderPool.getInstance().loadResourceByItem(dgLoaderItem, true) || hasResource;
                    dgLoaderItem = null;
                }
            }
            loaderItem = null;
            
            return hasResource;
        }
        
        private function loadCompletedHandler(content_:MovieClipData, url:String):void
        {
            if(!_resourceDic.hasOwnProperty(url)) return;
            
            _resourceDic[url] = content_;
            _needLoadNum--;
        }
        
        public function set delay(value_:int):void
        {
            _delay = value_;
        }
        
        /**
         * 得到一张已经摆放好层次的位图
         */        
        public function getBitmapByIndex(type_:Object, index_:Object):Bitmap
        {
            var index:int = int(index_);
            
            var bitmap:Bitmap;
            if(!_bitmapDic) _bitmapDic = [];
            if(null != _bitmapDic[type_]) bitmap = _bitmapDic[type_] as Bitmap;
            else bitmap = _bitmapDic[type_] = new Bitmap;
            
            appendNewBitmap(index, bitmap);
            
            return bitmap;
        }
        
        public function appendNewBitmap(index_:int, bitmap_:Bitmap):void
        {
            if(!_displayIndexs) _displayIndexs = [];
            if(_displayIndexs.indexOf(index_) == -1) 
            {
                var hasAdd_:Boolean = contains(bitmap_);
                if(hasAdd_)
                {
                    var oIndex_:int = getChildIndex(bitmap_);
                    if(_displayIndexs.length > oIndex_ && _displayIndexs.length == _bitmapNum) _displayIndexs.splice(oIndex_, 1);
                }
                
                _displayIndexs.push(index_);
                _displayIndexs.sort(Array.NUMERIC);
                var index:int = _displayIndexs.indexOf(index_);
                
                if(!hasAdd_)
                {
                    _bitmapNum ++;
                    addChildAt(bitmap_, index);
                }
                else if(oIndex_ != index)
                {
                    setChildIndex(bitmap_, index);
                }
            }
        }
        
        public function isCopy():Boolean
        {
            for each(var data:MovieClipData in _resourceDic)
            {
                if(!data) continue;
                if(null == data.labelDic[_currentLabel])
                {
                    var reLabel:String = _currentLabel.substr(0,2) + "6";
                    if(null != data.labelDic[reLabel]) _currentLabel = reLabel;
                }
                var frame:BitmapFrame = data.getFrame(_currentLabel, frameScript.excuteIndex);
                if(frame)
                {
                    return frame.isCopy;
                }
            }
            return true;
        }
        
        public function step():void
        {
//            if(resourceKey == "10148")
//                trace("catch");
//            trace(TimerManage.currentFrame + " enter multiBody time dis is " + (getTimer() - TimerManage.frameStartTime));
            var isRender:Boolean = false;
            var needStop:Boolean = false;
            for each(var data:MovieClipData in _resourceDic)
            {
                if(!data) continue;
                if(null == data.labelDic[_currentLabel])
                {
                    var reLabel:String = _currentLabel.substr(0,2) + "6";
                    if(null != data.labelDic[reLabel]) _currentLabel = reLabel;
                }
                var frame:BitmapFrame = data.getFrame(_currentLabel, frameScript.excuteIndex);
                if(frame)
                {
                    var bitmap:Bitmap = getBitmapByIndex(data.type, frame.index);
                    if(scaleX != _scaleX) scaleX = _scaleX;
                    
                    if(!frame.isCopy)
                    {
                        setBodyXY(frame.rx, frame.ry);
                        bitmap.x = centerPoint.x - frame.rx;
                        bitmap.y = centerPoint.y - frame.ry;
                        
                        bitmap.bitmapData = frame.bitmapData;
                    }
                    
                    isRender = true;
                    
                    if(data.type == MovieClipDataType.BODY)
                    {
                        _mainHeight = bitmap.height;
                        _mainWidth  = bitmap.width;
                        if(frameScript.excuteIndex == 0) frameScript.setLabelIndexDic(data.labelDic);
                        if(frame.isLastFrame) needStop = checkLoopEnd();
                    }
                }
            }
            _currentIndex++;
            if(isRender) {frameScript.excuteIndex++;}
            if(needStop) {stop();}
//            trace(TimerManage.currentFrame + " end multiBody time dis is " + (getTimer() - TimerManage.frameStartTime));
        }
        
        public function imitateStep(isCopy_:Boolean):void
        {
            _currentIndex++;
            if(isCopy_) {frameScript.excuteIndex++;}
        }
        
        private var _startT:Number;
        public function play(label_:String, scale_:Number, delay_:int):void
        {
            _startT = getTimer();
            clearBitmapData();
            frameScript.excuteIndex = _currentIndex = 0;
            _currentLabel = label_;//ModelConst.formatFrame(label_);
            delay = delay_;
            _scaleX = scale_;
            playBack();
        }
        
        public function playBack():void
        {
            ModelRenderManager.getInstance().add(this, _everyStep);
        }
        
        public function stop():void
        {
            ModelRenderManager.getInstance().remove(this);
        }
        
        public function setLoopInfo(label_:String, loopEndFunc_:Function, loopTime_:int=1, param:Array = null):void
        {
            if(!_loopDic) _loopDic = new Dictionary;
            _loopDic[label_] =  
                {endFunc: new CallBack(loopEndFunc_, param, true), loopTime:loopTime_};
        }
        
        private function checkLoopEnd():Boolean
        {
            if(_loopDic && _loopDic.hasOwnProperty(_currentLabel))
            {
                var obj:Object = _loopDic[_currentLabel];
                obj.loopTime --;
                if(obj.loopTime <= 0) 
                {
                    var callBack:CallBack = obj.endFunc as CallBack;
                    if(callBack) callBack.execute();
                    delete _loopDic[_currentLabel];
                    return true;
                }
            }
            return false;
        }
        
        public function get isHit():Boolean
        {
            var pixel:Number;
            var result:Boolean = false;
            for each(var bitmap:Bitmap in _bitmapDic)
            {
                if(contains(bitmap) && bitmap.bitmapData)
                {
                    pixel = bitmap.bitmapData.getPixel32(bitmap.mouseX, bitmap.mouseY);
                    result = result || pixel > 0;
                }
            }
            return result;
        }
        
        public function get mainHeight():int
        {
            return _mainHeight;
        }
        
        public function get mainWidth():int
        {
            return _mainWidth;
        }
        
        public function clearBitmapData():void
        {
            for each(var bitmap:Bitmap in _bitmapDic)
            {
                bitmap.bitmapData = null;
            }
            _displayIndexs = [];
            centerPoint = null;
        }
        
        public function clear():void
        {
            stop();
            
            for each(var bitmap:Bitmap in _bitmapDic)
            {
                if(contains(bitmap)) removeChild(bitmap);
            }
            
            _displayIndexs = [];
            
            centerPoint = null;
            
            _bitmapNum = 0;
        }
        
        public function dispose():void
        {
            clear();
            clearResourceDic();
            ModelRenderManager.getInstance().remove(this);
        }
    }
}
FrameScript