cocos2dx[3.2](9) ——數學類Vec2/Size/Rect

【嘮叨】

    數學類Vec2SizeRect,是cocos2dx中比較常用的類。

    比如設置圖片位置,設置圖片大小,兩圖片的碰撞檢測等等。

    比起2.x版本,在3.x中本質上其實沒有太大的變化,主要的變化就是將全局宏定義相關的操作封裝到各自的類中而已。比如:Vec2的向量運算宏定義ccp***(),現在都已經封裝到Vec2類裏面去了。


【番外】

    在V2.x中,底層數學庫使用的是:Kazmath數學庫

    而在 V3.1 中,由於 Sprite3D 需要我們提供更多的API給開發者,這是Kazmath庫所不能提供的,而cocos2d-x內部擁有多個數學庫是沒有意義的。

    所以V3.1中,底層選擇了新的數學庫:GamePlay3D數學庫




【Vec2】

    Vec2原名Point,它既可以表示一個二維座標點,又可以表示一個二維向量。

    同時Vec2對運算符進行了重載,可以很方便的完成Vec2的賦值、加減乘除等操作。另外還有與座標向量相關的:距離、角度、點積、叉積、投影、標準化等操作。

    此外在3.x中,還將2.x裏的函數定義ccp***(如ccp,ccpAdd,ccpSub)相關的操作都封裝到了這個Vec2的類中,這樣就可以更加系統化地管理向量的運算操作了。

    此外,除了Vec2。還有兩個座標類:Vec3、Vec4,分別代表了三維、四維座標向量。

    查看2.x與3.x的變化請移步:http://shahdza.blog.51cto.com/2410787/1549850

    Vec2可以是一個二維座標點,也可以是一個二維向量。

wKioL1Ps8TCROQmnAAAu3KSrIzs480.jpg


1、創建方式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//
/**
 * Vec2只有兩個成員變量x , y
 */
    float x; //X座標
    float y; //Y座標
 
 
/**
 * 構造函數
 */ 
    Vec2();                                   //(0 , 0)
    Vec2(float xx, float yy);                 //(xx , yy)
    Vec2(const float* array);                 //(array[0] , array[1])
    Vec2(const Vec2& copy);                   //copy
    Vec2(const Vec2& p1, const Vec2& p2);     //p2 - p1
//


2、設置向量座標

    使用set可以給向量重新設置新座標值。

1
2
3
4
5
6
//
    void set(float xx, float yy);             //(xx , yy)
    void set(const float* array);             //(array[0] , array[1])
    void set(const Vec2& v);                  //v
    void set(const Vec2& p1, const Vec2& p2); //p2 - p1
//


3、向量運算

    其中包含了一些2.x中的ccp***()宏定義的函數,都全部封裝到了Vec2類中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
//
/**
 * 向量運算
 *     void     : 自身運算    , 值會改變
 *     有返回值 : 返回運算結果, 值不會改變
 */
    void add(const Vec2& v);                      //相加( x+v.x , y+v.y )
    void subtract(const Vec2& v);                 //相減( x-v.x , y-v.y )
    void clamp(const Vec2& min, const Vec2& max); //將向量值限制在[min,max]區間內
    void negate();                                //向量取負( -x , -y )
    void normalize();                             //標準化向量. 若爲零向量,忽略
    void scale(float scalar);                     //x,y座標同時放縮
    void scale(const Vec2& scale);                //x,y座標分別放縮
    void rotate(const Vec2& point, float angle);  //繞point點, 旋轉angle弧度
 
    float dot(const Vec2& v) const;               //點積: x*v.x + y*v.y
    float cross(const Vec2& v) const;             //叉積: x*v.y - y*v.x
    Vec2  project(const Vec2& v) const;           //投影: 向量在v上的投影向量
 
    float distance(const Vec2& v) const;          //與v的距離.
    float distanceSquared(const Vec2& v) const;   //與v的距離平方.
    float length() const;                         //向量長度.     即與原點的距離
    float lengthSquared() const;                  //向量長度平方. 即與原點的距離平方
     
    Vec2 getNormalized() const;                   //獲取向量的標準化形式. 若爲零向量,返回(0,0)
 
    inline Vec2 getPerp() const;                  //逆時針旋轉90度. Vec2(-y, x);
    inline Vec2 getRPerp() const                  //順時針旋轉90度. Vec2(y, -x);
     
    inline float getAngle() const;                //與X軸的夾角(弧度)
    float        getAngle(const Vec2& v) const;   //與v向量的夾角(弧度)
     
    inline Vec2 getMidpoint(const Vec2& v) const//計算兩點間的中點
     
 
    //將向量值限制在[min,max]區間內,返回該點
    inline Vec2 getClampPoint(const Vec2& min, const Vec2& max) const
    {
        return Vec2(clampf(x, min.x, max.x), clampf(y, min.y, max.y));
    }
     
     
    bool isZero() const//是否爲(0,0)
    bool isOne() const;  //是否爲(1,1)
 
 
    //判斷target是否在座標點模糊偏差爲var的範圍內.
    //if( (x - var <= target.x && target.x <= x + var) && 
    //    (y - var <= target.y && target.y <= y + var) ) 
    //      return true;
    bool fuzzyEquals(const Vec2& target, float variance) const;
 
 
    //以pivot爲軸, 逆時針旋轉angle度(弧度)
    Vec2 rotateByAngle(const Vec2& pivot, float angle) const;
 
 
    //繞other向量旋轉
    //返回向量: 角度 this.getAngle() +other.getAngle();
    //          長度 this.getLength()*other.getLength();
    inline Vec2 rotate(const Vec2& other) const {
        return Vec2(x*other.x - y*other.y, x*other.y + y*other.x);
    };
 
 
    //繞other向量旋轉前的向量值
    //返回向量: 角度 this.getAngle() -other.getAngle(); 
    //          長度 this.getLength()*other.getLength();
    //(這裏是不是有點問題,難道不應該是this.getLength()/other.getLength()麼?)
    inline Vec2 unrotate(const Vec2& other) const {
        return Vec2(x*other.x + y*other.y, y*other.x - x*other.y);
    };
 
 
    //兩個點a和b之間的線性插值
    //alpha ==0 ? a alpha ==1 ? b 否則爲a和b之間的一個值
    inline Vec2 lerp(const Vec2& other, float alpha) const {
        return *this * (1.f - alpha) + other * alpha;
    };
 
     
    //平滑更新向量的當前位置,指向目標向量target.
    //responseTime定義了平滑時間量,該值越大結果越平滑,相應的延遲時間越長。
    //如果希望向量緊跟target向量,提供一個相對elapsedTime小很多的responseTime值即可。
    //參數
    //target        目標值
    //elapsedTime   消逝時間
    //responseTime  響應時間
    void smooth(const Vec2& target, float elapsedTime, float responseTime);
 
 
/**
 * 自定義運算
 *     compOp 
 */
    //對該點向量形式的各分量進行function參數來指定的運算, 
    //如absf,floorf,ceilf,roundf等,
    //任何函數擁有如下形式:float func(float)均可。
    //例如:我們對x,y進行floor運算,則調用方法爲p.compOp(floorf);
    //3.0
    inline Vec2 compOp(std::function<float(float)> function) const
    {
        return Vec2(function(x), function(y));
    }
 
 
/**
 * 兼容代碼
 *     估計是要被拋棄了~(>_<)~
 */
    void  setPoint(float xx, float yy);           //同set(float xx, float yy)
    bool  equals(const Vec2& target) const;       //同==
    float getLength() const;                      //同length()
    float getLengthSq() const;                    //同lengthSquared()
    float getDistance(const Vec2& other) const;   //同distance(const Vec2& v)
    float getDistanceSq(const Vec2& other) const//同distanceSquared(const Vec2& v)
//


4、運算符重載

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//
    inline const Vec2 operator+(const Vec2& v) const//( x+v.x , y+v.y )
    inline const Vec2 operator-(const Vec2& v) const//( x-v.x , y-v.y )
    inline const Vec2 operator*(float s) const;       //( x*s , y*s )
    inline const Vec2 operator/(float s) const;       //( x/s , y/s )
    inline const Vec2 operator-() const;              //( -x , -y )
 
    inline Vec2& operator+=(const Vec2& v);           //(x,y) = ( x+v.x , y+v.y )
    inline Vec2& operator-=(const Vec2& v);           //(x,y) = ( x-v.x , y-v.y )
    inline Vec2& operator*=(float s);                 //(x,y) = ( x*s , y*s )
 
    inline bool operator<(const Vec2& v) const;
    inline bool operator==(const Vec2& v) const;
    inline bool operator!=(const Vec2& v) const;
//


5、靜態函數與常量

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//
/**
 * 靜態方法
 */
    static void add(const Vec2& v1, const Vec2& v2, Vec2* dst);                    //dst = v1 + v2
    static void subtract(const Vec2& v1, const Vec2& v2, Vec2* dst);               //dst = v1 - v2
    static void clamp(const Vec2& v, const Vec2& min, const Vec2& max, Vec2* dst); //將向量v限制在[min,max]區間內,結果存入dst
 
    static float angle(const Vec2& v1, const Vec2& v2);                            //兩向量夾角(弧度)
    static float dot(const Vec2& v1, const Vec2& v2);                              //兩向量點積
    static inline Vec2 forAngle(const float a);                                    //返回向量座標 x=cos(a) , y=sin(a)
 
 
/**
 * 靜態常量
 */
    static const Vec2 ZERO;                 //Vec2(0, 0)
    static const Vec2 ONE;                  //Vec2(1, 1)
    static const Vec2 UNIT_X;               //Vec2(1, 0)
    static const Vec2 UNIT_Y;               //Vec2(0, 1)
    static const Vec2 ANCHOR_MIDDLE;        //Vec2(0.5, 0.5)
    static const Vec2 ANCHOR_BOTTOM_LEFT;   //Vec2(0, 0)
    static const Vec2 ANCHOR_TOP_LEFT;      //Vec2(0, 1)
    static const Vec2 ANCHOR_BOTTOM_RIGHT;  //Vec2(1, 0)
    static const Vec2 ANCHOR_TOP_RIGHT;     //Vec2(1, 1)
    static const Vec2 ANCHOR_MIDDLE_RIGHT;  //Vec2(1, 0.5)
    static const Vec2 ANCHOR_MIDDLE_LEFT;   //Vec2(0, 0.5)
    static const Vec2 ANCHOR_MIDDLE_TOP;    //Vec2(0.5, 1)
    static const Vec2 ANCHOR_MIDDLE_BOTTOM; //Vec2(0.5, 0)
//


6、線段相交檢測

    這些用於檢測線段相交的函數,也都是靜態的成員函數

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
//
/**
    線段相交檢測 v3.0
    參數:
        A   爲線段L1起點. L1 = (A - B)
        B   爲L1終點    . L1 = (A - B)
        C   爲線段L2起點. L2 = (C - D)
        D   爲L2終點    . L2 = (C - D)
        S   爲L1上計算各點的插值參數,計算方法爲:p = A + S*(B - A)
        T   爲L2上計算各點的插值參數,計算方法爲:p = C + T*(D - C)
 */
 
    //直線AB與線段CD是否平行
    static bool isLineParallel(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D);
    //直線AB與線段CD是否重疊
    static bool isLineOverlap(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D);
    //直線AB與直線CD是否相交    
    static bool isLineIntersect(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D,
                                 float *S = nullptr, float *T = nullptr);
 
    //線段AB與線段CD是否重疊
    static bool isSegmentOverlap(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D,
                                 Vec2* S = nullptr, Vec2* E = nullptr);
    //線段AB與線段CD是否相交
    static bool isSegmentIntersect(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D);
 
    //返回直線AB與直線CD的交點
    static Vec2 getIntersectPoint(const Vec2& A, const Vec2& B, const Vec2& C, const Vec2& D);
     
//




【Size】

    Size比較簡單,只是一個用來表示尺寸大小的類。寬爲width,高爲height

    和Vec2一樣,也對一些運算符進行了重載。

    與2.x相比,沒有太大的變化。

    PS: 因爲和Vec2一樣,都只有兩個成員變量,所以Size和Vec2之間可以相互轉換。


1、主要函數如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
//
class CC_DLL Size
{
/**
 * Size只有兩個成員變量width , height
 */
    float width;   //寬
    float height;  //高
 
 
/**
 * 構造函數
 */
    Size();                           //(0, 0)
    Size(float width, float height);  //(width, height)
    Size(const Size& other);          //other
    explicit Size(const Vec2& point); //(顯式)構造函數. 構造時Size size = Size(Vec2&), 而不能Size size = vec2;
 
 
/**
 * 相關操作
 *     - setSize
 *     - equals
 *     - Vec2()
 */
    void setSize(float width, float height); //設置尺寸
    bool equals(const Size& target) const;   //判斷是否等於target
 
    //Size::Vec2()
    //返回類型爲Vec2
    operator Vec2() const return Vec2(width, height); }  
 
 
/**
 * 靜態常量
 */
    static const Size ZERO; //(0, 0)
 
 
/**
 * 運算符重載
 */
    Size& operator= (const Size& other);
    Size& operator= (const Vec2& point); //可以用Vec2賦值
    Size operator+(const Size& right) const;
    Size operator-(const Size& right) const;
    Size operator*(float a) const;
    Size operator/(float a) const;
 
};
//




【Rect】

    Rect是一個矩形類。包含兩個成員屬性:起始座標(左下角)Vec2、矩陣尺寸大小Size

    Rect只對“=”運算符進行了重載。

    與2.x相比,多了一個函數unionWithRect,用於合併兩個矩形。

    值得注意的是Rect類中:

        intersectsRect函數,可以用作兩個Rect矩形是否相交,即碰撞檢測。

        containsPoint 函數,可以用作判斷點Vec2是否在Rect矩形中。

        unionWithRect 函數,可以用做將兩矩形進行合併操作。

wKiom1Ps83TytTN3AABEUdrO2HE928.jpg


1、主要函數如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
//
class CC_DLL Rect
{
public:
    Vec2 origin; //起始座標: 矩形左下角座標
    Size  size;  //尺寸大小
 
 
/**
 * 構造函數
 */
    Rect();
    Rect(float x, float y, float width, float height);
    Rect(const Rect& other);
 
 
/**
 * 運算符重載
 *     只重載了 “=” 運算符
 */
    Rect& operator= (const Rect& other);
 
 
/**
 * 相關操作
 *     - setRect
 *     - getMinX , getMidX , getMaxX
 *     - getMinY , getMidY , getMaxY
 *     - equals , containsPoint , intersectsRect
 *     - unionWithRect
 */
    //設置矩形
    void setRect(float x, float y, float width, float height);
 
 
    //獲取矩形信息
    float getMinX() const//origin.x
    float getMidX() const//origin.x + size.width/2
    float getMaxX() const//origin.x + size.width
 
    float getMinY() const//origin.y
    float getMidY() const//origin.y + size.height/2
    float getMaxY() const//origin.y + size.height
 
 
    //判斷是否與rect相同. 原點相同,尺寸相同.
    bool equals(const Rect& rect) const;
 
    //判斷point是否包含在矩形內或四條邊上
    bool containsPoint(const Vec2& point) const;
 
    //判斷矩形是否相交. 常常用作碰撞檢測.
    bool intersectsRect(const Rect& rect) const;
 
 
    //與rect矩形合併. 並返回結果. v3.0
    //不會改變原矩形的值
    Rect unionWithRect(const Rect & rect) const;
 
 
/**
 * 靜態常量
 *     Rect::ZERO
 */
    static const Rect ZERO;
 
};
//


2、精靈創建中的一種方式

    還記得Sprite的幾種創建方式嗎?裏面有一種創建方式如下:

        > Sprite::create(const std::string& filename, const Rect& rect)

    若用Rect來作爲創建Sprite精靈的參數,需要注意,從大圖中截取某一區域的圖片的Rect rect的構造應該是這樣的:

        > Rect("小圖左上角座標x", "小圖左上角座標y", 小圖寬, 小圖高);

    使用的是UIKit座標系,而不是cocos2dx的OpenGL座標系是不一樣的。

    如下圖所示:

wKioL1P1nT-juGOSAADARBo6V0E608.jpg


3、矩形合併函數unionWithRect

    看幾張圖,你應該就會明白了。

    兩個黑色矩形區域,使用unionWithRect合併後,變成紅色矩形區域。

wKiom1QQfLmCIoAKAAAlCjm-LGs378.jpg    wKioL1QQfMjC1DonAAAnGQOvBgQ102.jpg

wKiom1QQfLryF2_LAAAx6SbIZwo368.jpg






本文出自 “夏天的風” 博客,請務必保留此出處http://shahdza.blog.51cto.com/2410787/1550972

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章