AS3贝塞尔曲线类

发布时间:2019-09-14 09:45:54编辑:auto阅读(1514)

    贝塞尔曲线被广泛用于塔防类的游戏,当然一些特殊的缓动效果有些 也用 到这个 , 目前 这个没必要我们担心 , TweenMax 为我们提供了这些功能.

    package com.ainy.benz
    {
        import flash.geom.Point;
                                       
        public class Bezier{
                                           
            //  =====================================  属性
                                           
            //  对外变量
            private  var p0:Point;                  // 起点
            private  var p1:Point;                  // 控制点
            private  var p2:Point;                  // 终点
            private  var step:uint;                 // 分割份数
                                           
            //  辅助变量
            private  var ax:int;
            private  var ay:int;
            private  var bx:int;
            private  var by:int;
                                           
            private  var A:Number;
            private  var B:Number;
            private  var C:Number;
                                           
            private  var total_length:Number;           // 长度
                                           
            private static var $instance : Bezier;
            public static function instance() : Bezier{
                if(null == $instance){
                    $instance = new Bezier();
                }
                return $instance;
            }
            public function Bezier(){
                if($instance != null ){
                    throw new Error("Bezier 类被设计成单例了!!!");
                }else{
                    $instance = this;
                }
            }
                                           
            //  =====================================  方法
                                           
            //  速度函数
            private  function s (t:Number):Number
            {
                return Math.sqrt(A * t * t + B * t + C);
            }
                                           
            //  长度函数
            private  function L (t:Number):Number
            {
                var temp1:Number = Math.sqrt(C + t * (B + A * t));
                var temp2:Number = (2 * A * t * temp1 + B *(temp1 - Math.sqrt(C)));
                var temp3:Number = Math.log(B + 2 * Math.sqrt(A) * Math.sqrt(C));
                var temp4:Number = Math.log(B + 2 * A * t + 2 * Math.sqrt(A) * temp1);
                var temp5:Number = 2 * Math.sqrt(A) * temp2;
                var temp6:Number = (B * B - 4 * A * C) * (temp3 - temp4);
                                               
                return (temp5 + temp6) / (8 * Math.pow(A, 1.5));
            }
                                           
            //  长度函数反函数,使用牛顿切线法求解
            private  function InvertL (t:Number, l:Number):Number{
                var t1:Number = t;
                var t2:Number;
                do{
                    t2 = t1 - (L(t1) - l)/s(t1);
                    if (Math.abs(t1-t2) < 0.000001) break;
                    t1 = t2;
                }while(true);
                return t2;
            }
                                           
                                           
            //  返回所需总步数
            /**
             *获得所需步数
             * @param $p0 ->起始点
             * @param $p1 ->控制点
             * @param $p2 ->结束点
             * @param $speed ->速度
             * @return
             *
             */    
            public  function init ($p0:Point, $p1:Point, $p2:Point, $speed:Number):uint
            {
                p0   = $p0;
                p1   = $p1;
                p2   = $p2;
                //step = 30;
                                               
                ax = p0.x - 2 * p1.x + p2.x;
                ay = p0.y - 2 * p1.y + p2.y;
                bx = 2 * p1.x - 2 * p0.x;
                by = 2 * p1.y - 2 * p0.y;
                                               
                A = 4*(ax * ax + ay * ay);
                B = 4*(ax * bx + ay * by);
                C = bx * bx + by * by;
                                               
                //  计算长度
                total_length = L(1);
                                               
                //  计算步数
                step = Math.floor(total_length / $speed);
                if (total_length % $speed > $speed / 2)  step ++;
                                               
                return step;
            }
                                           
            // 根据指定nIndex位置获取锚点:返回坐标和角度
            public  function getAnchorPoint (nIndex:Number):Array
            {
                if (nIndex >= 0 && nIndex <= step)
                {
                    var t:Number = nIndex/step;
                    //  如果按照线行增长,此时对应的曲线长度
                    var l:Number = t*total_length;
                    //  根据L函数的反函数,求得l对应的t值
                    t = InvertL(t, l);
                                                   
                    //  根据贝塞尔曲线函数,求得取得此时的x,y坐标
                    var xx:Number = (1 - t) * (1 - t) * p0.x + 2 * (1 - t) * t * p1.x + t * t * p2.x;
                    var yy:Number = (1 - t) * (1 - t) * p0.y + 2 * (1 - t) * t * p1.y + t * t * p2.y;
                                                   
                    //  获取切线
                    var Q0:Point = new Point((1 - t) * p0.x + t * p1.x, (1 - t) * p0.y + t * p1.y);
                    var Q1:Point = new Point((1 - t) * p1.x + t * p2.x, (1 - t) * p1.y + t * p2.y);
                                                   
                    //  计算角度
                    var dx:Number = Q1.x - Q0.x;
                    var dy:Number = Q1.y - Q0.y;
                    var radians:Number = Math.atan2(dy, dx);
                    var degrees:Number = radians * 180 / Math.PI;
                                                   
                    return new Array(xx, yy, degrees);
                }
                else
                {
                    return [];
                }
            }
        }
    }

    应用:

    steps = Bezier.instance().init(startPoint,controlPoint,endPoint,8);
                var tmpArr:Array = Bezier.instance().getAnchorPoint(crtStep);
                arrow.x =  tmpArr[0];
                arrow.y =  tmpArr[1];
                arrow.rotation =  tmpArr[2];
                this.crtStep++;
                if(crtStep>steps){
                    crtStep=0;
                    if(Math.random()>0.5){
                        tower.shooterLeft.gotoAndPlay(2);
                    }else{
                        tower.shooterRight.gotoAndPlay(2);
                    }
                }

    http://blog.sqstudio.com/as3/algorithm/768.html#codesyntax_2


关键字