在背景中用到了一个自定义的类 VectArr :
class VectArr { public: VectArr( const Bezier & bz, int conut = 30 ) : _bezier( bz ) , _count( conut ) , _bottom( 0 ) { _lines = new Vect[ _count + 2 ]; getBezier( bz ); } VectArr( int count = 30 ) : _count( count ) , _bottom( 0 ) { _lines = new Vect[ count + 2]; } VectArr( Vect * point ) : _count( 2 ) { _lines = new Vect[ _count + 2 ]; _lines[ 0 ] = Vect( point->x, 0 ); _lines[ 1 ] = Vect( point->x, Director::getInstance( )->getVisibleSize( ).height ); } ~VectArr( ) { delete[ ]_lines; } private: Bezier _bezier; Vect * _lines; int _count; int _bottom; public: Bezier getBezier( ) const; Color4F getColor( ) const; void setColor(const Color4F & c ); Vect * getLines( ) const; void setCountToBottom( int count ); int getCountToBottom( ); void setCount( int count ); int getCount( ) const; VectArr * stiching( VectArr * other ); };
类中保存一个Bezier(自定义,在Data文件夹下)变量 _bezier,一个Vect(cocos2d-x 中的二维向量,通常表示点)数组指针 _lines,一个整数 _count 对应的数组大小,一个整数 _bottom 附加点个数
两点一直线,一个有N个点的数组可以看成是N-1条线段的数组,除了开头和结尾的两个点,其他点都与前后的连成两条线段,为了方便,我把这个类的每个对象叫一条线,一条弯弯曲曲的线
这个类中还有几个处理,线段的函数,比如计算线段交点的函数,上面没给出,完整代码点这里查看。
回过头来说下 Bezier 这个结构:
typedef struct Bezier { Vect begin; Vect end; Vect control1; Vect control2; Color4F color; Bezier( ) { } Bezier( Vect b, Vect e, Vect c1, Vect c2, Color4F c ) : begin( b ) , end( e ) , control1( c1 ) , control2( c2 ) , color( c ) { } ~Bezier( ) { } void offset( const Vect & offset ); }Bezier;
Bezier 有四个点和一个颜色(Color4F是cocos2d-x中保存颜色的类,颜色的四个分量:r,g,b,a,数值在0〜1之间)
这个结构体保存一个贝赛尔曲线和对应的颜色,贝赛尔曲线由一个或两个控制点,贝赛尔曲线可以画出平滑的曲线,山体看起来更自然,也可以简化数据存储,不用保存每一个点,只需要四个点就可以了,程序中在 VectArr 中转化为绘图所需的点数组:
Vect * VectArr::getBezier( const Vect & from, const Vect & to, const Vect & control1, const Vect & control2 ) { float t = 0.0f; if( control2.isZero( ) ) { for( unsigned int i = 0; i < _count; i++ ) { _lines[ i ].x = powf( 1 - t, 2 ) * from.x + 2.0f * ( 1 - t ) * t * control1.x + t * t * to.x; _lines[ i ].y = powf( 1 - t, 2 ) * from.y + 2.0f * ( 1 - t ) * t * control1.y + t * t * to.y; t += 1.0f / _count; } _lines[ _count ].x = to.x; _lines[ _count ].y = to.y; } else { for( unsigned int i = 0; i < _count; i++ ) { _lines[ i ].x = powf( 1 - t, 3 ) * from.x + 3.0f * powf( 1 - t, 2 ) * t * control1.x + 3.0f * ( 1 - t ) * t * t * control2.x + t * t * t * to.x; _lines[ i ].y = powf( 1 - t, 3 ) * from.y + 3.0f * powf( 1 - t, 2 ) * t * control1.y + 3.0f * ( 1 - t ) * t * t * control2.y + t * t * t * to.y; t += 1.0f / _count; } _lines[ _count ].x = to.x; _lines[ _count ].y = to.y; } _count += 1; return _lines; }
画一座山需要多条线才有层次,用 LineLayer 保存一座山的所有线段;而整个背景中有两座山,用 BgLayerData 保存这个两座山的数据:
class LineLayer { public: LineLayer( ); ~LineLayer( ); void AddBezier( float b1, float b2, float e1, float e2, float c11, float c12, float c21, float c22 ); void AddBezier( float b1, float b2, float e1, float e2, float c11, float c12, float c21, float c22, float r, float g, float b, float a ); std::vector<Bezier> getLines( ) const; bool isEmpty( )const; private: std::vector<Bezier> _lines; }; class BgLayerData { public: BgLayerData( ); ~BgLayerData( ); void AddLineLayer( LineLayer * l ); std::vector<LineLayer*> * getLineLayer( ) const; private: std::vector<LineLayer*> * _lineLayer; };
这样就把背景的数据保存好,这画背景时,用 VectArr 类的几个方法处理下,就可以绘制背景了。