SDL_Engine游戏引擎制作 2-Point Size Rect

Point Size 和Rect都是在游戏中经常使用到的类。Point为坐标,经常用来标示一个对象的位置。Size为尺寸,用来标示一个对象的大小。Rect则是Point 和Size的集合体,可以认为是一个包围盒,经常用来判断是否发生碰撞。

SEMath.h

#ifndef __SDL_Math_H__
#define __SDL_Math_H__
/*SDL_Engine Math*/
#include<cstdlib>
#include<cmath>
#include "PlatformMarcos.h"
NS_SDL_BEGIN

#ifndef FLT_EPSILON
#define FLT_EPSILON 1.192092896e-07F        /* smallest such that 1.0+FLT_EPSILON != 1.0 */
#endif
#define MAX_UINT 0xffffffff
#define SDL_REPEAT_FOREVER (MAX_UINT - 1)
#define MAX(x,y) ((x)>(y)?(x):(y))
#define MIN(x,y) ((x)>(y)?(y):(x))
#define RANDOM(start,end) (fmodf((float)rand(),(end)-(start))+(start))/*[start,end) 不需要自己手动调用srand,已经在Director中调用*/
#define RANDOM_0_1() (rand()/double(RAND_MAX))
#define SDL_ANGLE_TO_DEGREE(angle) (3.1415926/180 * (angle))/*角度转弧度*/
#define SDL_DEGREE_TO_ANGLE(degree) (180.0/3.1415926 *(degree))/*弧度转角度*/

NS_SDL_END
#endif
SEMath.h包含了游戏开发中一些常用的功能,并用宏函数实现。另外这个文件名称一开始是Math.h,但是在移植android平台时,会报错,原因是与c语言提供的math.h发生了冲突,故而添加了一个前缀 SE(SDL_Engine)

Point.h

#ifndef __SDL_Point_H__
#define __SDL_Point_H__
#include<cmath>
#include<string>
#include "SDL.h"
#include "PlatformMarcos.h"

NS_SDL_BEGIN
class Point
{
public:
	float x;
	float y;
public:
	static const Point ZERO;
public:
	Point(float x = 0.f, float y = 0.f):x(x), y(y){}
	Point(const Point&point);
	Point(const SDL_Point&point);

	~Point(){}

	float getX()const;
	void setX(float x);
	float getY()const;
	void setY(float y);

	void set(float x,float y);
	float length()const
	{
		return sqrt(x * x + y * y);
	}
	void normalize()
	{
		float l = length();
		if (l > 0)
		{
			(*this) *= 1/l;
		}
	}
	/*重载*/
	//+
	Point operator+(const Point &v2) const
	{
		return Point(x + v2.x,y + v2.y);
	}
	//*
	Point operator*(float scalar)
	{
		return Point(x * scalar,y * scalar);
	}
	//*=
	Point& operator*=(float scalar)
	{
		x *= scalar;
		y *= scalar;

		return *this;
	}
	//-
	Point operator-(const Point& v2) const
	{
		return Point(x - v2.x,y - v2.y);
	}
	// /÷
	Point operator/(float scalar)
	{
		return Point(x /scalar,y/scalar);
	}
	//  /=
	Point& operator/=(float scalar)
	{
		x /= scalar;
		y /= scalar;

		return *this;
	}
	/*友元*/
	//+=
	friend Point& operator+=(Point &v1,const Point &v2)
	{
		v1.x += v2.x;
		v1.y += v2.y;

		return v1;
	}
	//-=
	friend Point& operator-=(Point& v1,const Point& v2)
	{
		v1.x -= v2.x;
		v1.y -= v2.y;

		return v1;
	}
	friend bool operator!=(const Point&p1,const Point&p2)
	{
		return !p1.equals(p2);
	}
	friend bool operator==(const Point&p1,const Point&p2)
	{
		return p1.equals(p2);
	}
	inline Point rotate(const Point& other) const {
        return Point(x*other.x - y*other.y, x*other.y + y*other.x);
    };
    Point rotateByAngle(const Point& pivot, float angle) const;

	bool equals(const Point &point) const;

	inline Point lerp(const Point& other, float alpha) const 
	{
		return Point(x*(1.f - alpha) + other.x*alpha,y*(1.f - alpha) + other.y*alpha);
    }
	static inline Point forAngle(const float a)
    {
        return Point(cosf(a), sinf(a));
    }
	    /** A general line-line intersection test
     @param A   the startpoint for the first line L1 = (A - B)
     @param B   the endpoint for the first line L1 = (A - B)
     @param C   the startpoint for the second line L2 = (C - D)
     @param D   the endpoint for the second line L2 = (C - D)
     @param S   the range for a hitpoint in L1 (p = A + S*(B - A))
     @param T   the range for a hitpoint in L2 (p = C + T*(D - C))
     @return    whether these two lines intersects.

     Note that to truly test intersection for segments we have to make
     sure that S & T lie within [0..1] and for rays, make sure S & T > 0
     the hit point is        C + T * (D - C);
     the hit point also is   A + S * (B - A);
     */
    static bool 
isLineIntersect(const Point& A, const Point& B,
const Point& C, const Point& D, float *S = nullptr, float *T = nullptr);//return SDL_PointSDL_Point getSDL_Point()const;};NS_SDL_END#endif

Point.cpp

#include "Point.h"
#include "SEMath.h"
NS_SDL_BEGIN
const Point Point::ZERO=Point(0.0f,0.0f);

Point::Point(const Point &point)
	:x(point.x),y(point.y)
{
}

Point::Point(const SDL_Point&point)
	:x((float)point.x),y((float)point.y)
{
}

float Point::getX()const
{
	return x;
}

void Point::setX(float x)
{
	this->x = x;
}

float Point::getY()const
{
	return y;
}

void Point::setY(float y)
{
	this->y = y;
}

void Point::set(float x,float y)
{
	this->x = x;
	this->y = y;
}

Point Point::rotateByAngle(const Point& pivot, float angle) const
{
	 return pivot + (*this - pivot).rotate(Point::forAngle(angle));
}

bool Point::equals(const Point &point) const
{
	return fabs(x - point.x) < FLT_EPSILON
		&& fabs(y - point.y) < FLT_EPSILON;
}

// cross product of 2 vector. A->B X C->D
float crossProduct2Vector(const Point& A, const Point& B, const Point& C, const Point& D)
{
    return (D.y - C.y) * (B.x - A.x) - (D.x - C.x) * (B.y - A.y);
}

bool Point::isLineIntersect(const Point& A, const Point& B,
                            const Point& C, const Point& D,
                            float *S, float *T)
{
    // FAIL: Line undefined
    if ( (A.x==B.x && A.y==B.y) || (C.x==D.x && C.y==D.y) )
    {
        return false;
    }
    
    const float denom = crossProduct2Vector(A, B, C, D);
    
    if (denom == 0)
    {
        // Lines parallel or overlap
        return false;
    }
    
    if (S != nullptr) *S = crossProduct2Vector(C, D, C, A) / denom;
    if (T != nullptr) *T = crossProduct2Vector(A, B, C, A) / denom;
    
    return true;
}

SDL_Point Point::getSDL_Point()const
{
	SDL_Point point={(int)x,(int)y};
	return point;
}

NS_SDL_END

值得注意的是,Point类的x,y属性是public,这也就意味着,其他对象可以直接访问。Point对象有一个ZERO静态常量成员对象,ZERO主要是为了方便赋值,这点同Size Rect。然后就是getSDL_Point()函数,能返回SDL_Point结构体,这个结构体是SDL所定义。可以简单地认为Point和SDL_Point相对应。

Size.h

#ifndef __SDL_Size_H__
#define __SDL_Size_H__
#include<cmath>
#include<string>
#include "SDL.h"
#include "PlatformMarcos.h"
NS_SDL_BEGIN
class Size
{
public:
	float width;
	float height;
	
	static const Size ZERO;
public:
	Size(float w=0.f,float h = 0.f);
	~Size(){}
	//复制构造函数
	Size(const Size& s);
	Size&operator=(const Size &other);

	Size operator+(Size &size);
	Size operator-(Size &size);
	Size operator*(float a) const;
	Size operator/(float a) const;
	Size operator/(const Size&other)const;
	bool operator==(const Size&other)const;
	bool operator!=(const Size&other)const;

	void setSize(float width,float height);
	bool equals(const Size &s) const;
};
NS_SDL_END
#endif

Size.cpp

#include "Size.h"
#include "SEMath.h"
NS_SDL_BEGIN
const Size Size::ZERO = Size(0.f,0.f);

Size::Size(float w,float h)
	:width(w),height(h)
{
}

Size::Size(const Size &s)
	:width(s.width),height(s.height)
{
}

Size &Size::operator=(const Size&other)
{
	setSize(other.width,other.height);
	return *this;
}

Size Size::operator+(Size &size)
{
	return Size(width + size.width,height + size.height);
}

Size Size::operator-(Size &size)
{
	return Size(width - size.width,height - size.height);
}

Size Size::operator*(float a) const
{
	return Size(width * a,height * a);
}

Size Size::operator/(float a) const
{
	SDLASSERT(a != 0,"CCSize division by 0.");

	return Size(width / a,height / a);
}

Size Size::operator/(const Size&other)const
{
	return Size(width / other.width,height / other.height);
}

bool Size::operator==(const Size&other)const
{
	return width == other.width&&
		height == other.height;
}

bool Size::operator!=(const Size&other)const
{
	return width != other.width ||
		height != other.height;
}

void Size::setSize(float width,float height)
{
	this->width = width;
	this->height = height;
}

bool Size::equals(const Size & s) const
{
	return fabs(width - s.width) < FLT_EPSILON
		&& fabs(height - s.height) < FLT_EPSILON;
}

NS_SDL_END

Size在SDL中没有对应的结构体。

Rect.h

#ifndef __SDL_Rect_H__
#define __SDL_Rect_H__
#include<string>
#include "SDL.h"
#include "PlatformMarcos.h"
#include "Point.h"
#include "Size.h"
NS_SDL_BEGIN

class Rect
{
public:
	Point origin;
	Size size;

	static const Rect ZERO;
public:
	Rect(float x=0.f,float y=0.f,float w=0.f,float h=0.f);
	Rect(const Rect&rect);
	Rect(const SDL_Rect&other);
	Rect(const Point&origin,const Size&size);
	Rect(float x,float y,const Size&size);
	Rect(const Point&origin,float w,float h);
	~Rect(){}
	//重载运算符
	Rect&operator=(const Rect&rect);
	void setRect(float x,float y,float w,float h);
	void setRect(const Rect&rect);

	float getMinX() const {return origin.x;}
	float getMidX() const {return origin.x + size.width/2;}
	float getMaxX() const {return origin.x + size.width;}

	float getMinY() const {return origin.y;}
	float getMidY() const {return origin.y + size.height/2;}
	float getMaxY() const {return origin.y + size.height;}
	//是否相等
	bool equals(const Rect &rect) const;
	//是否包含点
	bool containsPoint(const Point &point)const;
	//两rect是否相交或包含
	bool intersectRect(const Rect&rect)const;
	//矩形是否和线段交叉
	bool intersectLine(const Point&pos1,const Point&pos2)const;
	//返回SDL_Rect
	SDL_Rect getSDL_Rect()const;
};
NS_SDL_END
#endif

Rect.cpp

#include "Rect.h"
NS_SDL_BEGIN
const Rect Rect::ZERO = Rect(0.f,0.f,0.f,0.f);

Rect::Rect(float x,float y,float w,float h)
	:origin(x,y),size(w,h)
{
}

Rect::Rect(const Rect&rect)
	:origin(rect.origin),size(rect.size)
{
}

Rect::Rect(const SDL_Rect&other)
	:origin(other.x,other.y),size(other.w,other.h)
{
}

Rect::Rect(const Point&origin,const Size&size)
	:origin(origin),size(size)
{
}

Rect::Rect(float x,float y,const Size&size)
	:origin(x,y),size(size)
{
}

Rect::Rect(const Point&origin,float w,float h)
	:origin(origin),size(w,h)
{
}

Rect& Rect::operator=(const Rect &rect)
{
	setRect(rect.origin.x,rect.origin.y,rect.size.width,rect.size.height);

	return *this;
}

void Rect::setRect(float x,float y,float w,float h)
{
	origin.x = x;
	origin.y = y;
	size.width = w;
	size.height = h;
}

void Rect::setRect(const Rect&rect)
{
	setRect(rect.origin.x,rect.origin.y,rect.size.width,rect.size.height);
}

bool Rect::equals(const Rect&rect) const
{
	return origin.equals(rect.origin)
		&&size.equals(rect.size);
}

bool Rect::containsPoint(const Point&point)const
{
	return (point.x > getMinX() && point.x < getMaxX())
		&&(point.y > getMinY() && point.y < getMaxY());
}

bool Rect::intersectRect(const Rect&rect)const
{
	return !(     getMaxX() < rect.getMinX() ||
             rect.getMaxX() <      getMinX() ||
                  getMaxY() < rect.getMinY() ||
             rect.getMaxY() <      getMinY());
}

bool Rect::intersectLine(const Point&pos1,const Point&pos2)const
{
	SDL_Rect rect;

	rect.x = (int)origin.x;
	rect.y = (int)origin.y;
	rect.w = (int)size.width;
	rect.h = (int)size.height;

	int x1 = (int)pos1.x;
	int y1 = (int)pos1.y;

	int x2 = (int)pos2.x;
	int y2 = (int)pos2.y;

	return SDL_IntersectRectAndLine(&rect
		,&x1,&y1,&x2,&y2) == SDL_TRUE;
}

SDL_Rect Rect::getSDL_Rect()const
{
	SDL_Rect rect = { (int)origin.x,(int)origin.y
		,(int)size.width,(int)size.height};

	return rect;
}

NS_SDL_END

Rect是Point和Size的集合体。它使用相当广泛,从简单的矩形碰撞,再到以后的按钮检测等等,都是使用Rect 的containsPoint或者intersectRect函数进行判断的。Rect内部的一些函数有的使用了SDL提供的部分函数(也可以自己实现)。需要注意的是,上面三个类是没有继承自Object的

本节只是简单添加了3个类。不再进行测试。


本节代码:链接:https://pan.baidu.com/s/1IfGemOPg21OGVs6Ch060Hg 密码:eblp

猜你喜欢

转载自blog.csdn.net/bull521/article/details/79693585