Cocos2dx学习笔记(16)——数学类

对于之前出现的ccp,你是不是不了解呢?没关系,这一章我们将学习Cocos中的数学类。

本文仅供个人记录和复习,不用于其他用途

常用数学类

在2.x版本中,我们使用setPosition()时经常要使用到ccp()这样一个宏。那么事实上,这个ccp()是有关于向量的运算。在3.x版本中,各种类型的ccp()都整合到了Vec2这个类中。一般来讲,我们用到的有下面几个类:

  • Vec2
  • Size
  • Rect

Vec2

Vec2类的介绍

Vec2表示一个二维坐标点,也可以表示一个二维向量。2.x版本中的ccp()整合到了Vec2中,所以坐标和向量我们可以使用这个类。当然,我们还可以使用Vec3Vec4来表示三维坐标和四维坐标。

1
2
3
4
5
Vec2(); // 设置为(0, 0)
Vec2(float xx, float yy);
Vec2(const float* array);
Vec2(const Vec2& copy);
Vec2(const Vec2& p1, const Vec2& p2); // p2-p1的位置

上面是Vec2类的几种不同的构造方法,另外,这个类只有xy两个float变量来存储位置信息。

1
2
3
4
void set(float xx, float yy);
void set(const float* array);
void set(const Vec2& v);
void set(const Vec2& p1, const Vec2& p2);

使用set()方法可以重新设定坐标值。

向量运算

这里罗列了各种向量有关的运算,代码注释是借用了别人的,感兴趣的可以自己查看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
/**
* 向量运算
* 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();
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)

运算符重载

1
2
3
4
5
6
7
8
9
10
11
12
13
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;

静态函数与常量

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
/**
* 静态方法
*/
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)

线段相交检测

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
/**
线段相交检测 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类很简单,类似于2.x的CCSize,只有widthheight两个成员变量。SizeVec2可以转换。

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
/**
* 构造函数
*/
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()这个参数。那么事实上,Rect的意思是矩形。也就是说,我们可以规定精灵的显示内容有多少。Rect以左下角为原点,注意,之前我们在纹理一章提到过Rect,不过那个Rect使用的是UI坐标系,以左上角为原点。

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
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;
};