游戏架构其一:常用工具集合

<span style="font-size:18px;">2D游戏中写出3D效果没什么神秘的,我们都会有的~~~</span>
<span style="font-size:18px;">常用工具集合:</span>
<span style="font-size:18px;">I. 游戏中的几何图形:点和矩形相关操作</span>
<span style="font-size:18px;">#pragma once
/* 
 #pragma once
        DO YOUR FAVOURITE
 等价于下面
 #ifndef XXX
 #define XXX
         do something
 #endif

 
 #define XXX
        DO SOMETHING
 #undef XXX //取消宏定义

 
 #ifdef XXX
  do something
 #endif
 
 
 当然了我们还可以对struct使用自定义的内存数据对齐方式
 如:
 情况一:
 struct test {
    char a;
    int  b;
 };
 情况二:
 #pragma pack(push,1) 1的这个参数位置必须是2的幂 1 2 4 8 16 .....  as so on
 struct test {
    char a;
    int  b;
 };
 #pragma pack(pop)

 struct test t;
 情况一:
 sizeof(t) = 8;
 情况二:
 sizeof(t) = 5;
 
 以上有时可以帮助我们节省宝贵的内存资源

 
 另外在class声名的内部
 函数的声名+实现=内敛函数 不需要添加inline关键字机器自动优化
 当然有些函数的实现较复杂时即使使用inline也会被编译器“优化”为不是内敛的
*/


#include <math.h>

//---------------------------------------------------------------------------------------------------------
// This class represents a single point in 2D space
//---------------------------------------------------------------------------------------------------------
class Point
{
public:
	long x, y;
	
	// 构造函数 class声名内部实现的函数全是inline funcs
	Point(void) { x = y = 0; }
	Point(const long newX, const long newY) { x = newX; y = newY; }
	Point(const Point& newPoint) { x = newPoint.x; y = newPoint.y; }
	Point(const Point* pNewPoint) { x = pNewPoint->x; y = pNewPoint->y; }

	// 赋值函数
	Point& operator=(const Point& newPoint) { x = newPoint.x; y = newPoint.y; return (*this); }
	Point& operator=(const Point* pNewPoint) { x = pNewPoint->x; y = pNewPoint->y; return (*this); }

	// 加减等函数 必须返回这个数的引用 否则+= -=无效
	Point& operator+=(const Point& newPoint) { x += newPoint.x; y += newPoint.y; return (*this); }
	Point& operator-=(const Point& newPoint) { x -= newPoint.x; y -= newPoint.y; return (*this); }
	Point& operator+=(const Point* pNewPoint) { x += pNewPoint->x; y += pNewPoint->y; return (*this); }
	Point& operator-=(const Point* pNewPoint) { x -= pNewPoint->x; y -= pNewPoint->y; return (*this); }
    // 使用上面的拷贝构造函数
	Point operator+(const Point& other) { Point temp(this); temp += other; return temp; }
    // operator overloading(操作符重载)
	Point operator-(const Point& other) { Point temp(this); temp -= other; return temp; }
    // operator casting(操作隐式转换)***** inline 有无都一样 *****
    inline Point operator-(const Point& left, const Point& right) { Point temp(left); temp -= right; return temp; }
	// 比较函数
	bool operator==(const Point& other) const { return ((x == other.x) && (y == other.y)); }
	bool operator!=(const Point& other) const { return ((x != other.x) || (y != other.y)); }

	// 访问内部成员变量 可用于Lua
	long GetX() const { return x; }
	long GetY() const { return y; }
	void SetX(const long newX) { x = newX; }
	void SetY(const long newY) { y = newY; }
	void Set(const long newX, const long newY) { x = newX; y = newY; }
	
    // 距离原点的长度
	float Length() const { return sqrt((float)(x*x+y*y)); }
};</span>

Note:以上是一个点的相关操作,我想在游戏中没有比这个更基础的基础了。你认为呢?

接着点的相关操作,自然会想到矩形的相关操作,毕竟这方面需求也是刚性的,下面是一个矩形的相关操作:

<span style="font-size:18px;">//-------------------------------------------------------------------------------------------------------
// This class represents a rectangle
//-------------------------------------------------------------------------------------------------------
class Rect
{
public:
    // 代表一个矩形的最上面 最左边 最右面 和最下面的 相当于 Ymax , Xmin , Xmax, Ymin
    long top,left,right,bottom;
    

	enum RectCorner { INVALID_CORNER = 0, TOPLEFT_CORNER, TOPRIGHT_CORNER, BOTTOMLEFT_CORNER, BOTTOMRIGHT_CORNER };
	
	// 构造矩形 包括默认的构造,直接的构造,引用拷贝构造,指针拷贝构造和利用点来构造
	Rect(void) { left = top = right = bottom = 0; }
	Rect(long newLeft, long newTop, long newRight, long newBottom) { Set(newLeft,newTop,newRight,newBottom); }
	Rect(const Rect& newRect) { left = newRect.left; top = newRect.top; right = newRect.right; bottom = newRect.bottom; }
	Rect(Rect* pNewRect) { left = pNewRect->left; top = pNewRect->top; right = pNewRect->right; bottom = pNewRect->bottom; }
	Rect(const Point& topLeft, const Point& bottomRight) { top = topLeft.y; left = topLeft.x; right = bottomRight.x; bottom = bottomRight.y; }

	// 操作符重载
	Rect& operator=(const Rect& newRect) { left = newRect.left; top = newRect.top; right = newRect.right; bottom = newRect.bottom; return (*this); }
	Rect& operator=(const Rect* pNewRect) { left = pNewRect->left; top = pNewRect->top; right = pNewRect->right; bottom = pNewRect->bottom; return (*this); }
	Rect& operator+=(const Rect& newRect) { left += newRect.left; top += newRect.top; right += newRect.right; bottom += newRect.bottom; return (*this); }
	Rect& operator-=(const Rect& newRect) { left -= newRect.left; top -= newRect.top; right -= newRect.right; bottom -= newRect.bottom; return (*this); }
	Rect& operator+=(const Rect* pNewRect) { left += pNewRect->left; top += pNewRect->top; right += pNewRect->right; bottom += pNewRect->bottom; return (*this); }
	Rect& operator-=(const Rect* pNewRect) { left -= pNewRect->left; top -= pNewRect->top; right -= pNewRect->right; bottom -= pNewRect->bottom; return (*this); }
	Rect operator+(Rect& other) { Rect temp(this); temp += other; return temp; }
	Rect operator-(Rect& other) { Rect temp(this); temp -= other; return temp; }

	// 矩形对一个点做运算
	Rect& operator+=(const Point& delta) { left += delta.x; top += delta.y; right += delta.x; bottom += delta.y; return (*this); }
	Rect& operator-=(const Point& delta) { left -= delta.x; top -= delta.y; right -= delta.x; bottom -= delta.y; return (*this); }
	Rect& operator+=(const Point* pDelta) { left += pDelta->x; top += pDelta->y; right += pDelta->x; bottom += pDelta->y; return (*this); }
	Rect& operator-=(const Point* pDelta) { left -= pDelta->x; top -= pDelta->y; right -= pDelta->x; bottom -= pDelta->y; return (*this); }
	Rect operator+(Point& delta) { Rect temp(this); temp += delta; return temp; }
	Rect operator-(Point& delta) { Rect temp(this); temp -= delta; return temp; }

	// 矩形是否相等
	bool operator==(const Rect& other) const { return ((left == other.left) && (top == other.top) && (right == other.right) && (bottom == other.bottom)); }
	bool operator!=(const Rect& other) const { return (!((left == other.left) && (top == other.top) && (right == other.right) && (bottom == other.bottom))); }

	// collision 碰撞检测
    // 矩形和矩形是否有重合 即判断是否Collide
	bool Collide(const Rect& other) const { if (other.bottom < top || other.right < left || other.left > right || other.top > bottom) {return false;} else {return true;} }
    // 矩形和一个点 判断点与矩形的关系
	bool Collide(const Point& p) const { if (p.x > left && p.x < right && p.y < bottom && p.y > top) {return true;} else {return false;} }
    // 矩形是否包含关系
	bool IsWithin(const Rect& other) const { return ( (left >= other.left && top >= other.top && right <= other.right && bottom <= other.bottom) || (other.left >= left && other.top >= top && other.right <= right && other.bottom <= bottom) ); }
    // 矩形是否包含点
	bool IsWithin(const Point& other) const { return (other.x >= left && other.x <= right && other.y >= top && other.y <= bottom); }
    // 创建的矩形是否是合法的   判断矩形是否为空矩形(姑且把原点作为空矩形)
	bool IsValid(void) const { return (left <= right && top <= bottom); }
	bool IsNull(void) const { return (left == 0 && right == 0 && top == 0 && bottom == 0); }
	
	// convenience functions
    // 相对与原来的X方向移动dx 相对与原来的Y方向移动dy 相对值
	void ShiftX(int dx) { left += dx; right += dx; }
	void ShiftY(int dy) { top += dy; bottom += dy; }
    // 移动到x, 移动到y 绝对值
	void SetX(int x) { int dx = x - left; ShiftX(dx); }
	void SetY(int y) { int dy = y - top; ShiftY(dy); }

	// accessors for Lua
	long GetTop(void) const { return top; }
	long GetLeft(void) const { return left; }
	long GetRight(void) const { return right; }
	long GetBottom(void) const { return bottom; }
	Point GetCenter(void) const
	{
		if (IsValid())
			return (Point(left + ((right - left) / 2), top + ((bottom - top) / 2)));
		GCC_ERROR("Attempting to get the center of an invalid Rect");
		return Point();
	}
    // 矩形四个角的点
    Point TopLeft(void) const { return Point(left, top); }
    Point TopRight(void) const { return Point(right, top); }
    Point BottomLeft(void) const { return Point(left, bottom); }
    Point BottomRight(void) const { return Point(right, bottom); }
    long GetWidth(void) const { return right - left; }
    long GetHeight(void) const { return bottom - top; }
	void Set(long newLeft, long newTop, long newRight, long newBottom) { left = newLeft; top = newTop; right = newRight; bottom = newBottom; }
    // 相对与ShiftX(int dx)他是全部移动
	void MoveDelta(long dx, long dy) { left += dx; top += dy; right += dx; bottom += dy; }
	void MoveDelta(const Point deltaPoint) { MoveDelta(deltaPoint.x, deltaPoint.y); }
	void MoveTo(long x, long y)
	{
		long width = right - left;
		long height = bottom - top;
		left = x;
		right = left + width;
		top = y;
		bottom = top + height;
	}
	void MoveTo(const Point& point) { MoveTo(point.x, point.y); }
};</span>
<span style="font-size:18px;"><span style="font-size: 18px; font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">以上就是一个点和矩形的相关操作了。</span>
</span>


II. 一些有用的模版:Some useful templates

C++的信徒对模版估计是爱恨交加了,以下是一些常见模版的实现:

<span style="font-size:18px;">#pragma once
//------------------------------------------------------------------------------
// singleton template manages setting/resettting global variables.
//------------------------------------------------------------------------------</span>
<span style="font-size:18px;">template <class T>
</span>
<span style="font-size:18px;">class singleton
{
	T m_OldValue;
	T* m_pGlobalValue;

public:
	singleton(T newValue, T* globalValue)
	{ 
		m_pGlobalValue = globalValue;
		m_OldValue = *globalValue; 
		*m_pGlobalValue = newValue;
	}

	virtual ~singleton() { *m_pGlobalValue = m_OldValue; }
};</span>
以上是一个单体模版,负责设置或者重新设置全局变量。

<span style="font-size:18px;">template <class Type>
shared_ptr<Type> MakeStrongPtr(weak_ptr<Type> pWeakPtr)
{
    if (!pWeakPtr.expired()) //判断这个若引用的指针是否已经被delete
        return shared_ptr<Type>(pWeakPtr);
    else
        return shared_ptr<Type>();
}</span>

以上是将一个弱引用指针转化为强引用,若引用和强引用的区别是:( 没有翻译,仔细看还是没问题的)

Weak pointers just "observe" the managed object; they don't "keep it alive" or affect its lifetime. Unlike shared_ptrs, when the last weak_ptr goes out of scope or disappears, the pointed-to object can still exist because the weak_ptrs do not affect the lifetime of the object - they have no ownership rights. But the weak_ptr can be used to determine whether the object exists, and to provide a shared_ptr that can be used to refer to it. The definition of weak_ptr is designed to make it relatively foolproof, so as a result there is very little you can do directly with a weak_ptr. For example, you can't dereference it; neither operator* nor operator-> is defined for a weak_ptr. You can't access the pointer to the object with it - there is no get() function. There is a comparison function defined so that you can store weak_ptrs in an ordered container; but that's all.

以下是实现了一个可选初始化的模版:

<span style="font-size:18px;">#include <new>
class optional_empty { };

template <unsigned long size> // size表示存储数据的长度
class optional_base
{
public:
    // Default - invalid.
    optional_base() : m_bValid(false) { }

    optional_base & operator = (optional_base const & t)
    {
		m_bValid = t.m_bValid;
		return * this;
    }
	//Copy constructor
    optional_base(optional_base const & other) : m_bValid(other.m_bValid)  { }

	//utility functions
    bool const valid() const		{ return m_bValid; }
    bool const invalid() const		{ return !m_bValid; }

protected:
    bool m_bValid;
    char m_data[size];  // storage space for T
};

</span>
<span style="font-size:18px;">/* 使用情况:</span>
<span style="font-size:18px;">函数返回无效对象 有时根据某个条件去查找对象时,如果查找不到对象时就会返回一个无效值,这不表明函数执行失败,而是表明函数正确执行了,但是结果却不是有用的值,这时就可以返回一个未初始化的optional对象出去,在外面判断这个optional对象是否有效对象是否被初始化,如果没有被初始化就表明这个值是无效的</span>
<span style="font-size:18px;">template <class T>
class optional : public optional_base<sizeof(T)>
{</span>
<span style="font-size:18px;">private:
    T const * const GetT() const { return reinterpret_cast<T const * const>(m_data); }
    T * const GetT()	         { return reinterpret_cast<T * const>(m_data);}
    void construct(T const & t)  { new (GetT()) T(t); }//使用GetT()返回的指针数据来初始化T(t)
    void destroy()               { GetT()->~T(); }</span>
<span style="font-size:18px;">public: </span>
<span style="font-size:18px;">// Default - invalid.</span>
<span style="font-size:18px;">   optional() { } </span>
<span style="font-size:18px;">   optional(T const & t) { construct(t); m_bValid = (true); } </span>
<span style="font-size:18px;">    optional(optional_empty const &) { }</span>

          // 运算符函数

 
 
<span style="font-size:18px;">optional & operator = (T const & t)
    {
        if (m_bValid)
        {
            * GetT() = t;
        }
        else
        {
            construct(t);
	    m_bValid = true;	// order important for exception safety.
        }

        return * this;
    }

	//Copy constructor
    optional(optional const & other)
    {
		if (other.m_bValid)
		{
			construct(* other);
            m_bValid = true;	// order important for exception safety.
		}
    }

    optional & operator = (optional const & other)
    {
		GCC_ASSERT(! (this == & other));	// don't copy over self!
		if (m_bValid)
		{						// first, have to destroy our original.
			m_bValid = false;	// for exception safety if destroy() throws.
								// (big trouble if destroy() throws, though)
			destroy();
		}

		if (other.m_bValid)
		{
			construct(* other);
			m_bValid = true;	// order vital.

		}
		return * this;
    }


    bool const operator == (optional const & other) const
    {
	if ((! valid()) && (! other.valid())) { return true; }
	if (valid() ^ other.valid()) { return false; }
        	return ((* * this) == (* other));
    }

    bool const operator < (optional const & other) const
    {
	// equally invalid - not smaller.
	if ((! valid()) && (! other.valid()))   { return false; }

	// I'm not valid, other must be, smaller.
	if (! valid())	{ return true; }

	// I'm valid, other is not valid, I'm larger
	if (! other.valid()) { return false; }

</span>
<span style="font-size:18px;"><span style="white-space:pre">	</span>return ((* * this) < (* other));
    }

    ~optional() { if (m_bValid) destroy(); }

    T const & operator * () const			{ GCC_ASSERT(m_bValid); return * GetT(); }
    T & operator * ()	  					{ GCC_ASSERT(m_bValid); return * GetT(); }
    T const * const operator -> () const	{ GCC_ASSERT(m_bValid); return GetT(); }
    T	* const operator -> ()			{ GCC_ASSERT(m_bValid); return GetT(); }

    //This clears the value of this optional variable and makes it invalid once again.
    void clear()
    {</span>
<span style="font-size:18px;">	if (m_bValid)</span>
<span style="font-size:18px;">	{
		m_bValid = false;
		destroy();
	}
    }

    //utility functions
    bool const valid() const		{ return m_bValid; }
    bool const invalid() const		{ return !m_bValid; }
};
</span>

以下是实现了范型对象工厂,这在其他场合非常有用比如MMORPG中:

<span style="font-size:18px;"><span style="font-size:18px;">template <class BaseType, class SubType>
BaseType* GenericObjectCreationFunction(void) { return new SubType; }

template <class BaseClass, class IdType>
class GenericObjectFactory
{
    typedef BaseClass* (*ObjectCreationFunction)(void);
    std::map<IdType, ObjectCreationFunction> m_creationFunctions;

public:
    template <class SubClass>
    bool Register(IdType id)
    { 
        auto findIt = m_creationFunctions.find(id);
        if (findIt == m_creationFunctions.end())
        {
            m_creationFunctions[id] = &GenericObjectCreationFunction<BaseClass, SubClass>;  // insert() is giving me compiler errors
            return true;
        }

        return false;
    }

    BaseClass* Create(IdType id)
    {
        auto findIt = m_creationFunctions.find(id);
        if (findIt != m_creationFunctions.end())
        {
            ObjectCreationFunction pFunc = findIt->second;
            return pFunc();
        }

        return NULL;
    }
};</span></span>
第一个模版根据基类和子类来创建一个对象,下面的模版是一个生产范型对象的工厂。在其二(事件管理)中将看到范型对象工厂的威力。

III. 自定义字符串操作:

<span style="font-size:18px;">/*
 String.h 头文件定义
 */

#pragma once

/* int最大数的十进制的数字个数  转化为String时添加一个位存储'\0'
 max number of digits in an int (-2147483647 = 11 digits, +1 for the '\0') */
#define MAX_DIGITS_IN_INT 12  

typedef std::vector<std::string> StringVec;

#ifdef   UNICODE
typedef   wchar_t   TCHAR;
#else
typedef   unsigned   char   TCHAR;
#endif
typedef   unsigned   char   CHAR;
typedef   unsigned   wchar_t   WCHAR;

enum HRESULT {
    E_INVALIDARG,
    E_FAIL,
    S_OK,
};


/* Removes characters up to the first '\n'
 删除字符,直到达到第一个'\ n' 即将源字符分解为去掉第一个\n的两个字符
 
 string? wstring?
 std::string is a basic_string templated on a char, and std::wstring on a wchar_t.
 
 char vs. wchar_t
 char is supposed to hold a character, usually a 1-byte character. wchar_t is supposed to hold a wide character, and then, things get tricky: On Linux, a wchar_t is 4-bytes, while on Windows, it's 2-bytes */
extern void RemoveFirstLine(std::wstring &src, std::wstring &result);

// Removes leading white space 删除前面的空格直到非空格
extern void TrimLeft(std::wstring &s);

// Counts the number of lines in a block of text
extern int CountLines(const std::wstring &s);

// Does a classic * & ? pattern match on a file name - this is case sensitive!
extern BOOL WildcardMatch(const char *pattern, const char *filename);

// converts a regular string to a wide string
extern void StringToWideString(const std::string& source, std::wstring& outDest);

extern HRESULT AnsiToWideCch( WCHAR* dest, const CHAR* src, int charCount);  
extern HRESULT WideToAnsiCch( CHAR* dest, const WCHAR* src, int charCount);  
extern HRESULT GenericToAnsiCch( CHAR* dest, const TCHAR* src, int charCount); 
extern HRESULT GenericToWideCch( WCHAR* dest, const TCHAR* src, int charCount); 
extern HRESULT AnsiToGenericCch( TCHAR* dest, const CHAR* src, int charCount); 
extern HRESULT WideToGenericCch( TCHAR* dest, const WCHAR* src, int charCount);

extern std::string ToStr(int num, int base = 10);
extern std::string ToStr(unsigned int num, int base = 10);
extern std::string ToStr(unsigned long num, int base = 10);
extern std::string ToStr(float num);
extern std::string ToStr(double num);
extern std::string ToStr(bool val);
extern std::string ToStr(const Vec3& vec);

extern std::string ws2s(const std::wstring& s);
extern std::wstring s2ws(const std::string &s);

// Splits a string by the delimeter into a vector of strings.  For example, say you have the following string:
// std::string test("one,two,three");
// You could call Split() like this:
// Split(test, outVec, ',');
// outVec will have the following values:
// "one", "two", "three"
void Split(const std::string& str, StringVec& vec, char delimiter);


#pragma warning(push)
#pragma warning(disable : 4311)//省略4311类型的警告

// A hashed string.  It retains the initial (ANSI) string in addition to the hash value for easy reference.
class HashedString
{
public:
	explicit HashedString( char const * const pIdentString )
		: m_ident( hash_name( pIdentString ) )
	, m_identStr( pIdentString )
	{
	}

	unsigned long getHashValue( void ) const
	{

		return reinterpret_cast<unsigned long>( m_ident );
	}

	const std::string & getStr() const
	{
		return m_identStr;
	}

	static
	void * hash_name( char const *  pIdentStr );

	bool operator< ( HashedString const & o ) const
	{
		bool r = ( getHashValue() < o.getHashValue() );
		return r;
	}

	bool operator== ( HashedString const & o ) const
	{
		bool r = ( getHashValue() == o.getHashValue() );
		return r;
	}

private:

	// note: m_ident is stored as a void* not an int, so that in
	// the debugger it will show up as hex-values instead of
	// integer values. This is a bit more representative of what
	// we're doing here and makes it easy to allow external code
	// to assign event types as desired.

	void *             m_ident;
	std::string		   m_identStr;
};
//Remove the warning for warning #4311...
#pragma warning(pop)<span style="color:#ff0000;">
</span></span></span>

<span style="font-size:18px;"><span style="font-size:18px;">#include "GameCodeStd.h"
#include "string.h"

using std::string;

// Remove all leading whitespace
void TrimLeft(std::wstring &s)
{
	// find first non-space character
	int i = 0;
	int len = (int)s.length();
	while( i <  len )
	{
		TCHAR ch = s[i];			
		int white = 
		#ifdef UNICODE
				iswspace( ch );
		#else
				isspace( ch );
		#endif
		if (!white)
			break;
		++i;
	}

	if (i<len)
		s = s.substr(i);
}


typedef std::wstring& _T;
void RemoveFirstLine(std::wstring &src, std::wstring &result)
{
	int breakPosition = (int)src.find('\n');
	result = _T("");
	if(breakPosition != string::npos)	//if found...
	{
		int len = (int)src.length();
		result = src.substr(0, breakPosition);
		src = src.substr(breakPosition+1, (len-breakPosition)-1);		// skip the '/n'
	}
	else
	{
		result = src;
		src = _T("");
	}
}



int CountLines(const std::wstring &s)
{
	int lines = 0;
	int breakPos = 0;

	do 
	{
		++lines;
		breakPos = (int)s.find('\n', breakPos+1);
	} while (breakPos != string::npos);

	return lines;
}	

typedef bool BOOL;

BOOL WildcardMatch(const char *pattern, const char *filename)
{
   int i, star;

new_segment:

   star = 0;
   if (*pattern == '*') {
      star = 1;
      do { pattern++; } while (*pattern == '*'); /* enddo */
   } /* endif */

test_match:

   for (i = 0; pattern[i] && (pattern[i] != '*'); i++) {
      //if (mapCaseTable[str[i]] != mapCaseTable[pat[i]]) {
	  if (filename[i] != pattern[i]) {
         if (!filename[i]) return 0;
         if ((pattern[i] == '?') && (filename[i] != '.')) continue;
         if (!star) return 0;
         filename++;
         goto test_match;
      }
   }
   if (pattern[i] == '*') {
      filename += i;
      pattern += i;
      goto new_segment;
   }
   if (!filename[i]) return 1;
   if (i && pattern[i - 1] == '*') return 1;
   if (!star) return 0;
   filename++;
   goto test_match;
}


//-----------------------------------------------------------------------------
// Name: AnsiToWideCch()
// Desc: This is a UNICODE conversion utility to convert a CHAR string into a
//       WCHAR string. 
//       cchDestChar is the size in TCHARs of wstrDestination.  Be careful not to 
//       pass in sizeof(strDest)
//       如果 Win32 ANSI Api 用于 Windows NT 系统中获取文件名,使用 CP_ACP 将转换字符串时。Windows NT 检索        从物理设备的名称,并将 OEM 名称转换为 Unicode。Unicode 名称被转换成 ANSI 如果 ANSI API 调用,然后可将它翻  译回使用 MultiByteToWideChar() 的 Unicode。
// http://support.microsoft.com/kb/108450
//
//-----------------------------------------------------------------------------
int CP_ACP;
HRESULT AnsiToWideCch( WCHAR* wstrDestination, const CHAR* strSource, 
                                     int cchDestChar )
{
    if( wstrDestination==NULL || strSource==NULL || cchDestChar < 1 )
        return E_INVALIDARG;

    int nResult = MultiByteToWideChar( CP_ACP, 0, strSource, -1, 
                                       wstrDestination, cchDestChar );
    wstrDestination[cchDestChar-1] = 0;
    
    if( nResult == 0 )
        return E_FAIL;
    return S_OK;
}



//-----------------------------------------------------------------------------
// Name: WideToAnsi()
// Desc: This is a UNICODE conversion utility to convert a WCHAR string into a
//       CHAR string. 
//       cchDestChar is the size in TCHARs of strDestination
//-----------------------------------------------------------------------------
HRESULT WideToAnsiCch( CHAR* strDestination, const WCHAR* wstrSource, 
                                     int cchDestChar )
{
    if( strDestination==NULL || wstrSource==NULL || cchDestChar < 1 )
        return E_INVALIDARG;

    int nResult = WideCharToMultiByte( CP_ACP, 0, wstrSource, -1, strDestination, 
                                       cchDestChar*sizeof(CHAR), NULL, NULL );
    strDestination[cchDestChar-1] = 0;
    
    if( nResult == 0 )
        return E_FAIL;
    return S_OK;
}





//-----------------------------------------------------------------------------
// Name: GenericToAnsi()
// Desc: This is a UNICODE conversion utility to convert a TCHAR string into a
//       CHAR string. 
//       cchDestChar is the size in TCHARs of strDestination
//-----------------------------------------------------------------------------
HRESULT GenericToAnsiCch( CHAR* strDestination, const TCHAR* tstrSource, 
                                           int cchDestChar )
{
    if( strDestination==NULL || tstrSource==NULL || cchDestChar < 1 )
        return E_INVALIDARG;

#ifdef _UNICODE
    return WideToAnsiCch( strDestination, tstrSource, cchDestChar );
#else
    strncpy( strDestination, tstrSource, cchDestChar );
    strDestination[cchDestChar-1] = '\0';
    return S_OK;
#endif   
}




//-----------------------------------------------------------------------------
// Name: GenericToWide()
// Desc: This is a UNICODE conversion utility to convert a TCHAR string into a
//       WCHAR string. 
//       cchDestChar is the size in TCHARs of wstrDestination.  Be careful not to 
//       pass in sizeof(strDest) 
//-----------------------------------------------------------------------------
HRESULT GenericToWideCch( WCHAR* wstrDestination, const TCHAR* tstrSource, 
                                           int cchDestChar )
{
    if( wstrDestination==NULL || tstrSource==NULL || cchDestChar < 1 )
        return E_INVALIDARG;

#ifdef _UNICODE
    wcsncpy( wstrDestination, tstrSource, cchDestChar );
    wstrDestination[cchDestChar-1] = L'\0';
    return S_OK;
#else
    return AnsiToWideCch( wstrDestination, tstrSource, cchDestChar );
#endif    
}



//-----------------------------------------------------------------------------
// Name: AnsiToGeneric()
// Desc: This is a UNICODE conversion utility to convert a CHAR string into a
//       TCHAR string. 
//       cchDestChar is the size in TCHARs of tstrDestination.  Be careful not to 
//       pass in sizeof(strDest) on UNICODE builds
//-----------------------------------------------------------------------------
HRESULT AnsiToGenericCch( TCHAR* tstrDestination, const CHAR* strSource, 
                                           int cchDestChar )
{
    if( tstrDestination==NULL || strSource==NULL || cchDestChar < 1 )
        return E_INVALIDARG;
        
#ifdef _UNICODE
    return AnsiToWideCch( tstrDestination, strSource, cchDestChar );
#else
    strncpy( tstrDestination, strSource, cchDestChar );
    tstrDestination[cchDestChar-1] = '\0';
    return S_OK;
#endif    
}





//-----------------------------------------------------------------------------
// Name: AnsiToGeneric()
// Desc: This is a UNICODE conversion utility to convert a WCHAR string into a
//       TCHAR string. 
//       cchDestChar is the size in TCHARs of tstrDestination.  Be careful not to 
//       pass in sizeof(strDest) on UNICODE builds
//-----------------------------------------------------------------------------
HRESULT WideToGenericCch( TCHAR* tstrDestination, const WCHAR* wstrSource, 
                                           int cchDestChar )
{
    if( tstrDestination==NULL || wstrSource==NULL || cchDestChar < 1 )
        return E_INVALIDARG;

#ifdef _UNICODE
    wcsncpy( tstrDestination, wstrSource, cchDestChar );
    tstrDestination[cchDestChar-1] = L'\0';    
    return S_OK;
#else
    return WideToAnsiCch( tstrDestination, wstrSource, cchDestChar );
#endif
}



std::string ws2s(const std::wstring& s)
{
    int slength = (int)s.length() + 1;
    int len = WideCharToMultiByte(CP_ACP, 0, s.c_str(), slength, 0, 0, 0, 0)-1; 
    std::string r(len, '\0');
    WideCharToMultiByte(CP_ACP, 0, s.c_str(), slength, &r[0], len, 0, 0); 
    return r;
}


std::wstring s2ws(const std::string &s)
{
    int slength = (int)s.length() + 1;
	int len = MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, 0, 0)-1;
    std::wstring r(len, '\0');
	MultiByteToWideChar(CP_ACP, 0, s.c_str(), slength, &r[0], len);
    return r;
}





string ToStr(int num, int base)
{
    char str[MAX_DIGITS_IN_INT];
    memset(str,0,MAX_DIGITS_IN_INT);
    _itoa_s(num,str,MAX_DIGITS_IN_INT,base);
    return (string(str));
}  // end ToStr()

string ToStr(unsigned int num, int base)
{
    char str[MAX_DIGITS_IN_INT];
    memset(str, 0, MAX_DIGITS_IN_INT);
    _ultoa_s((unsigned long)num, str, MAX_DIGITS_IN_INT, base);
    return (string(str));
}

string ToStr(unsigned long num, int base)
{
    char str[MAX_DIGITS_IN_INT];
    memset(str,0,MAX_DIGITS_IN_INT);
    _ultoa_s(num,str,MAX_DIGITS_IN_INT,base);
    return (string(str));
}

string ToStr(float num)
{
    char str[64];  // I'm sure this is overkill
    memset(str,0,64);
    _sprintf_p(str,64,"%f",num);
    return (string(str));
}

string ToStr(double num)
{
    char str[64];  // I'm sure this is overkill
    memset(str,0,64);
    _sprintf_p(str,64,"%fL",num);
    return (string(str));
}

string ToStr(bool val)
{
    return (string( (val == true ? "true" : "false") ));
}

string ToStr(const Vec3& vec)
{
    return string("(" + ToStr(vec.x) + "," + ToStr(vec.y) + "," + ToStr(vec.z) + ")");
}


<span style="color:#ff0000;">
//-------------------------------------------------------------------------------------
// This is basically like the Perl split() function.  It splits str into substrings by cutting it at each delimiter.  
// The result is stored in vec.
//--------------------------------------------------------------------------------------
void Split(const string& str, StringVec& vec, char delimiter)
{
	vec.clear();
	size_t strLen = str.size();
	if (strLen == 0)
		return;

	size_t startIndex = 0;
	size_t indexOfDel = str.find_first_of(delimiter, startIndex);
	while (indexOfDel != string::npos)
	{
		vec.push_back(str.substr(startIndex, indexOfDel-startIndex));
		startIndex=indexOfDel + 1;
		if (startIndex >= strLen)
			break;
		indexOfDel = str.find_first_of(delimiter, startIndex);
	}
	if(startIndex < strLen)
		vec.push_back(str.substr(startIndex));
}</span>



void *
HashedString::hash_name( char const * pIdentStr )
{
	// Relatively simple hash of arbitrary text string into a
	// 32-bit identifier Output value is
	// input-valid-deterministic, but no guarantees are made
	// about the uniqueness of the output per-input
	//
	// Input value is treated as lower-case to cut down on false
	// separations cause by human mistypes. Sure, it could be
	// construed as a programming error to mix up your cases, and
	// it cuts down on permutations, but in Real World Usage
	// making this text case-sensitive will likely just lead to
	// Pain and Suffering.
	//
	// This code lossely based upon the adler32 checksum by Mark
	// Adler and published as part of the zlib compression
	// library sources.

	// largest prime smaller than 65536
	unsigned long BASE = 65521L;

	// NMAX is the largest n such that 255n(n+1)/2 +
	// (n+1)(BASE-1) <= 2^32-1
	unsigned long NMAX = 5552;

#define DO1(buf,i)  {s1 += tolower(buf[i]); s2 += s1;}
#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
#define DO16(buf)   DO8(buf,0); DO8(buf,8);

    if (pIdentStr == NULL)
		return NULL;

    unsigned long s1 = 0;
    unsigned long s2 = 0;

	for ( size_t len = strlen( pIdentStr ); len > 0 ; )
	{
        unsigned long k = len < NMAX ? len : NMAX;

		len -= k;

		while (k >= 16)
		{
            DO16(pIdentStr);
			pIdentStr += 16;
            k -= 16;
        }
		
        if (k != 0) do
		{
			s1 += tolower( *pIdentStr++ );
			s2 += s1;
        } while (--k);
		
        s1 %= BASE;
        s2 %= BASE;
    }

#pragma warning(push)
#pragma warning(disable : 4312)

    return reinterpret_cast<void *>( (s2 << 16) | s1 );

#pragma warning(pop)
#undef DO1
#undef DO2
#undef DO4
#undef DO8
#undef DO16
}
</span></span>
 以上是一个自负串的相关操作,包括分割字符串这个非常好用的工具。


IV. 这部分主要是实现数学常用的函数

<span style="font-size:18px;">#pragma once

#include <functional>
#include <vector>
#include "types.h"
#include "Geometry.h"


/* Period parameters */  
#define CMATH_N 624
#define CMATH_M 397
#define CMATH_MATRIX_A 0x9908b0df   /* constant vector a */
#define CMATH_UPPER_MASK 0x80000000 /* most significant w-r bits */
#define CMATH_LOWER_MASK 0x7fffffff /* least significant r bits */

/* Tempering parameters */   
#define CMATH_TEMPERING_MASK_B 0x9d2c5680
#define CMATH_TEMPERING_MASK_C 0xefc60000
#define CMATH_TEMPERING_SHIFT_U(y)  (y >> 11)
#define CMATH_TEMPERING_SHIFT_S(y)  (y << 7)
#define CMATH_TEMPERING_SHIFT_T(y)  (y << 15)
#define CMATH_TEMPERING_SHIFT_L(y)  (y >> 18)

#define RADIANS_TO_DEGREES(x) ((x) * 180.0f / GCC_PI)
#define DEGREES_TO_RADIANS(x) ((x) * GCC_PI / 180.0f)


class GCCRandom
{
private:
	// DATA
	unsigned int		rseed;
	unsigned int		rseed_sp;
	unsigned long mt[CMATH_N]; /* the array for the state vector  */
	int mti; /* mti==N+1 means mt[N] is not initialized */

	// FUNCTIONS
public:
	GCCRandom(void);	

	unsigned int	Random( unsigned int n );
	float			Random( );
	void			SetRandomSeed(unsigned int n);
	unsigned int	GetRandomSeed(void);
	void			Randomize(void);
};

typedef Point POINT;
typedef Rect  RECT;
typedef std::vector<Point> Poly;


class Math
{
	// DATA
private:
	static const unsigned short angle_to_sin[90];

public:
	static GCCRandom		random;

	// FUNCTIONS
public:
	static int				Cos(short angle, int length);
	static int				Sin(short angle, int length);
	static unsigned int		Sqrt( unsigned int n );
	static void				InterpolateLine(int *x, int *y, int end_x, int end_y, int step_size);
	static unsigned short	GetAngle(int x, int y);
	static bool PointInPoly( Point const &test, const Poly & polygon);
    // 判断一个点是否在一个多边形内
	static bool				PointInPoly
							(
								int const			x,
								int const			y,
								int const * const	vertex,
								int const			nvertex
							);
	static RECT				BoundingBox
							( 
								const POINT &pt1,
								const POINT &pt2,
								const POINT &pt3,
								const POINT &pt4
							);
	static RECT				BoundingBox
							(
								const POINT *verts,
								const unsigned int nverts
							);
	static float const		GetDistanceBetween(POINT const & pt1, POINT const & pt2);

	// Used to determine the bounding box for a range of point-like objects.
	// This includes POINTS, CPoints, and VertexUV to name a few.
	// This works on any range which includes all STL containers as well as C style arrays.
	// See BoundingBox(const POINT*, const unsigned int) in cpp for example usage.
	template <typename PointType>
	class BoundingBoxFinder : std::unary_function<PointType, void>
	{
	public:
		void operator()(PointType const & item)
		{
			if (mBoundingBox.invalid())
			{
				RECT initialValue = { item.x, item.y, item.x, item.y };
				mBoundingBox = initialValue;
			}
			else
			{
				mBoundingBox->left = std::min(mBoundingBox->left, item.x);
				mBoundingBox->top = std::min(mBoundingBox->top, item.y);
				mBoundingBox->right = std::max(mBoundingBox->right, item.x);
				mBoundingBox->bottom = std::max(mBoundingBox->bottom, item.y);
			}
		}

		RECT const & BoundingBox() { return *mBoundingBox; }

	private:
		optional<RECT> mBoundingBox;
	};


};

#define	DONT_INTERSECT    0
#define	DO_INTERSECT      1
#define COLLINEAR         2

// 线段定义
struct LineSegment
{
	Point m_begin, m_end;
	LineSegment(const Point &begin, const Point &end) { m_begin=begin; m_end=end; }
	LineSegment() { m_begin = m_end = Point(0,0); }
};


int lines_intersect( Point one,   /* First line segment */
					 Point two,

					Point three,   /* Second line segment */
					Point four,

					Point &result
               );

bool Intersect(const Rect &rect, const Point ¢er, double const radius);

float WrapPi(float wrapMe);  // wraps angle so it's between -PI and PI
float Wrap2Pi(float wrapMe);  // wraps angle so it's between 0 and 2PI
float AngleDiff( float lhs, float rhs );
// vec3 Graphics3D中
Vec3 GetVectorFromYRotation(float angleRadians);
float GetYRotationFromVector(const Vec3& lookAt);

//--------------------------------------------------------------------------------</span>
<span style="font-size:18px;">#include "GameCodeStd.h"
#include <math.h>
#include <vector>
#include <algorithm>
#include "Math.h"


//--------------------------------------------------------------------------------
// static members must be initialized before use

const unsigned short Math::angle_to_sin[90] = 
{
       0, 1144, 2287, 3430, 4572, 5712, 6850, 7987, 9121,10252,
   11380,12505,13626,14742,15855,16962,18064,19161,20252,21336,
   22415,23486,24550,25607,26656,27697,28729,29753,30767,31772,
   32768,33754,34729,35693,36647,37590,38521,39441,40348,41243,
   42126,42995,43852,44695,45525,46341,47143,47930,48703,49461,
   50203,50931,51643,52339,53020,53684,54332,54963,55578,56175,
   56756,57319,57865,58393,58903,59396,59870,60326,60764,61183,
   61584,61966,62328,62672,62997,63303,63589,63856,64104,64332,
   64540,64729,64898,65048,65177,65287,65376,65446,65496,65526,
};

GCCRandom Math::random; 

//--------------------------------------------------------------------------------
// NOTE: % 的运算速度竟然比 -= 的速度慢了许多  如下:
int Math::Sin(short angle, int length)
{
   int result;

   // normalize to 0..359
   if (length < 0) {
      length *= -1;
      angle += 180;
   }
   if (360 <= angle) {
      do {
         angle -= 360;
      } while (360 <= angle);
      //angle = angle % 360; // correct, but slower on average
   } else if (angle < 0) {
      do {
         angle += 360;
      } while (angle < 0);
      //angle = (u16)((angle + 33120) % 360); // correct, but slower on average
   }

   if (angle < 180) {
      if (angle < 90) {
         result = (int)(((unsigned int)length * angle_to_sin[angle] + 32768UL) / 65536UL);
      } else if (angle == 90) {
         result = length;
      } else {
         result = (int)(((unsigned int)length * angle_to_sin[180 - angle] + 32768UL) / 65536UL);
      }
   } else {
      if (angle < 270) {
         result = -(int)(((unsigned int)length * angle_to_sin[angle - 180] + 32768UL) / 65536UL);
      } else if (angle == 270) {
         result = -length;
      } else {
         result = -(int)(((unsigned int)length * angle_to_sin[360 - angle] + 32768UL) / 65536UL);
      }
   }
   return result;
}

int Math::Cos(short angle, int length)
{
   return Sin(angle + 90, length);
}

//--------------------------------------------------------------------------------
// 二分法查找
unsigned int Math::Sqrt( unsigned int n )
{
   unsigned int lo;
   unsigned int hi;

   if (65535U * 65535U <= n)
      return 65535;

   if( n <= 65535 )
   {
      lo = 0;
      hi = 256;
   }
   else
   {
      lo = 256;
      hi = 65535;
   }

   do
   {
      const unsigned int mid = (lo + hi) / 2;

      if( mid * mid <= n )
         lo = mid;
      else
         hi = mid;
   }
   while( lo + 1 < hi );

   return lo;
}


void Math::InterpolateLine(int *x, int *y, int end_x, int end_y, int step_size)
{
   short delta_x, delta_y, angle;

   if ( step_size <= 0 || ( *x == end_x && *y == end_y ) ) return;

   delta_x = short(end_x - *x);
   delta_y = short(end_y - *y);

   if ( abs(delta_x) > 255 || abs(delta_y) > 255 )
      angle    = GetAngle( delta_x/2, delta_y/2 );
   else
      angle    = GetAngle( delta_x, delta_y );

   if ( *x < end_x )
   {
      *x += Cos( angle, step_size );
      if ( *x > end_x ) *x = end_x;
   }
   else
   { 
      *x += Cos( angle, step_size );
      if ( *x < end_x ) *x = end_x;
   }

   if ( *y < end_y )
   {
      *y += Sin( angle, step_size );
      if ( *y > end_y ) *y = end_y;
   }
   else
   { 
      *y += Sin( angle, step_size );
      if ( *y < end_y ) *y = end_y;
   }
   return;
}

/*  给出随意的两点 在X-Y坐标系中获取一个角度  借助X轴正方向实现
	Math::Get_Angle()

	Given arbitrary x, y, this returns angle in degrees 0..359
	(Not 0..360 as old asm version did.)

	E.g. Get_Angle(3,3) returns 45; Get_Angle(-4,0) returns 180

	If passed in (0,0), returns 0; could easily be modified to crash.
	(And perhaps should.)

	This has been tested vs the old asm Get_Angle;
	it agrees, differing at most by 1 from the old result, and
	in all such cases I checked, this one was the more accurate
	result (this version rounds rather than truncates).
	It was also tested for all x,y from -1000 to 1000 versus atan2 function
	and never differed by more than 2 from "true" result (which often
	varied a little from my HP calculator...).

	This C actually runs a little faster than the old asm code
	(without even turning on compiler optimizations).

	It also accepts ints, not just short ints, to plan for possible future use.
	(If very large ints are ever used, some additional checking must be added.)

	Written in standard vanilla C, compiles under Watcom or Borland.

	Most importantly, it gives correct results on inputs where
	the old version crashes (e.g. -1, 376), which prompted Russ to
	rewrite this in clear C to begin with.
*/

unsigned short Math::GetAngle(int x, int y)
{
   short result = -1;

   if (x == 0) {
      if (y < 0) {
         result = 270;
      } else if (0 < y) {
         result = 90;
      } else {
         result = 0;
      }
   } else if (y == 0) {
      if (x < 0) {
         result = 180;
      } else {
         result = 0;
      }
   } else {
      int correction;

      if (x < 0) {
         if (y < 0) {
            x = -x;
            y = -y;
            correction = 180;
         } else {
            const int old_x = x;
            x = y;
            y = -old_x;
            correction = 90;
         }
      } else {
         if (y < 0) {
            const int old_x = x;
            x = -y;
            y = old_x;
            correction = 270;
         } else {
            correction = 0;
         }
      }

      //GCC_ASSERT(0 < x);
      //GCC_ASSERT(0 < y);
      if (x == y) {
         result = 45;
      } else {
         /*
            For y < x, this table takes quotient y * 128 / x
            (which will be 0..127)
            and tells corresponding angle 0..45
         */
         static const unsigned char quotient_to_angle[128] = {
             0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 4, 5, 5, 6, 6, 7,
             7, 8, 8, 8, 9, 9,10,10,11,11,11,12,12,13,13,14,
            14,14,15,15,16,16,16,17,17,18,18,18,19,19,20,20,
            20,21,21,22,22,22,23,23,24,24,24,25,25,25,26,26,
            26,27,27,27,28,28,29,29,29,30,30,30,31,31,31,32,
            32,32,32,33,33,33,34,34,34,35,35,35,36,36,36,36,
            37,37,37,38,38,38,38,39,39,39,39,40,40,40,40,41,
            41,41,41,42,42,42,42,43,43,43,43,44,44,44,44,45,
         };

         if (x < y) {
            const unsigned int quotient = ((unsigned int)x * 128) / (unsigned int)y;
            result = 90 - quotient_to_angle[quotient];
         } else {
            const unsigned int quotient = ((unsigned int)y * 128) / (unsigned int)x;
            result = quotient_to_angle[quotient];
         }
      }
	  result = short(result + correction);
      if (result == 360) {
         result = 0;
      }
   }
   return result;
}

//
// Math::PointInPoly					
//
bool Math::PointInPoly
(
	int const			xt,
	int const			yt,
	int const * const	vertex,
	int const			nvertex
)
{
	int xnew,ynew;     
	int xold,yold;     
	int x1,y1;
    int x2,y2;     
	int i;     
	bool inside=false;     
	
	if (nvertex < 3) 
	{
          return(0);     
	}     
	xold=vertex[(nvertex-1)*2];
    yold=vertex[(nvertex-1)*2+1];     
	for (i=0 ; i < nvertex ; i++) 
	{
		xnew = vertex[i*2];
		ynew = vertex[i*2+1];
		if (xnew > xold) 
		{
			x1=xold;               
			x2=xnew;               
			y1=yold;
            y2=ynew;          
		}          
		else 
		{               
			x1=xnew;
            x2=xold;               
			y1=ynew;               
			y2=yold;          
		}
        if ((xnew < xt) == (xt <= xold)         /* edge "open" at left end */
           && ((long)yt-(long)y1)*(long)(x2-x1)
            < ((long)y2-(long)y1)*(long)(xt-x1)) 
		{               
			inside=!inside;
		}          
		xold=xnew;          
		yold=ynew;     
	}     
	return(inside);
}

RECT Math::BoundingBox
( 
 const POINT &pt1,
 const POINT &pt2,
 const POINT &pt3,
 const POINT &pt4
 )
{
	RECT bounding;
	bounding.top = std::min( pt1.y, std::min( pt2.y, std::min( pt3.y, pt4.y ) ) );
	bounding.bottom = std::max( pt1.y, std::max( pt2.y, std::max( pt3.y, pt4.y ) ) );
	bounding.left = std::min( pt1.x, std::min( pt2.x, std::min( pt3.x, pt4.x ) ) );
	bounding.right = std::max( pt1.x, std::max( pt2.x, std::max( pt3.x, pt4.x ) ) );
	return bounding;
}

RECT Math::BoundingBox
(
 const POINT *verts,
 const unsigned int nverts
)
{
	GCC_ASSERT (nverts > 0);
	return std::for_each(verts, verts + nverts, BoundingBoxFinder<POINT>()).BoundingBox();
}

float const Math::GetDistanceBetween(POINT const & pt1, POINT const & pt2)
{
	float const xDiff = fabsf(float(pt2.x) - float(pt1.x));
	float const yDiff = fabsf(float(pt2.y) - float(pt1.y));
	return sqrtf(xDiff * xDiff + yDiff * yDiff);
}

//
// Math::PointInPoly
//
bool Math::PointInPoly( Point const &test, const Poly & polygon)
{
	Point newPoint, oldPoint;
	Point left, right;

	bool inside=false;     

	size_t points = polygon.size();

	// The polygon must at least be a triangle
	if (points < 3) 
          return false;     

	oldPoint = polygon[points-1];

	for (unsigned int i=0 ; i < points; i++) 
	{
		newPoint = polygon[i];
		if (newPoint.x > oldPoint.x) 
		{
			left = oldPoint;               
			right = newPoint;
		}          
		else 
		{               
			left = newPoint;               
			right = oldPoint;
		}

		// A point exactly on the left side of the polygon
		// will not intersect - as if it were "open"
        if ((newPoint.x < test.x) == (test.x <= oldPoint.x)         
           && (test.y-left.y) * (right.x-left.x)
            < (right.y-left.y) * (test.x-left.x) ) 
		{               
			inside=!inside;
		}

		oldPoint = newPoint;
	}     
	return(inside);
}



/* lines_intersect:  AUTHOR: Mukesh Prasad
 *
 *   This function computes whether two line segments,
 *   respectively joining the input points (x1,y1) -- (x2,y2)
 *   and the input points (x3,y3) -- (x4,y4) intersect.
 *   If the lines intersect, the output variables x, y are
 *   set to coordinates of the point of intersection.
 *
 *   All values are in integers.  The returned value is rounded
 *   to the nearest integer point.
 *
 *   If non-integral grid points are relevant, the function
 *   can easily be transformed by substituting floating point
 *   calculations instead of integer calculations.
 *
 *   Entry
 *        x1, y1,  x2, y2   Coordinates of endpoints of one segment.
 *        x3, y3,  x4, y4   Coordinates of endpoints of other segment.
 *
 *   Exit
 *        x, y              Coordinates of intersection point.
 *
 *   The value returned by the function is one of:
 *
 *        DONT_INTERSECT    0
 *        DO_INTERSECT      1
 *        COLLINEAR         2
 *
 * Error condititions:
 *
 *     Depending upon the possible ranges, and particularly on 16-bit
 *     computers, care should be taken to protect from overflow.
 *
 *     In the following code, 'long' values have been used for this
 *     purpose, instead of 'int'.
 *
 * Changes from the original code:
 *     
 *     Used ATL Point classes instead of straight integers (MLM)
 */


/****************************************************************
 *                                                              *
 *    NOTE:  The following macro to determine if two numbers    *
 *    have the same sign(有相同的符号), is for 2's complement     *
 *    number representation.  It will need to be modified for   *
 *    other number systems.                                     *
 *                                                              *
 ****************************************************************/

#define SAME_SIGNS( a, b )	\
		(((long) ((unsigned long) a ^ (unsigned long) b)) >= 0 )

int lines_intersect( 
	Point one, Point two,				  /* First line segment */
	Point three, Point four,			  /* Second line segment */
	Point &result)
{
    long a1, a2, b1, b2, c1, c2; /* Coefficients of line eqns. */
    long r1, r2, r3, r4;         /* 'Sign' values */
    long denom, offset, num;     /* Intermediate values */

    /* Compute a1, b1, c1, where line joining points 1 and 2
     * is "a1 x  +  b1 y  +  c1  =  0".
     */

    a1 = two.y - one.y; //y2 - y1;
    b1 = one.x - two.x; //x1 - x2;
    c1 = two.x * one.y - one.x * two.y; //x2 * y1 - x1 * y2;

    /* Compute r3 and r4.
     */


    r3 = a1 * three.x + b1 * three.y + c1;  //a1 * x3 + b1 * y3 + c1;
    r4 = a1 * four.x + b1 * four.y + c1;			//a1 * x4 + b1 * y4 + c1;

    /* Check signs of r3 and r4.  If both point 3 and point 4 lie on
     * same side of line 1, the line segments do not intersect.
     */

    if ( r3 != 0 &&
         r4 != 0 &&
         SAME_SIGNS( r3, r4 ))
        return ( DONT_INTERSECT );

    /* Compute a2, b2, c2 */

    a2 = four.y - three.y; //y4 - y3;
    b2 = three.x - four.x; //x3 - x4;
    c2 = four.x * three.y - three.x * four.y; //x4 * y3 - x3 * y4;

    /* Compute r1 and r2 */

    r1 = a2 * one.x + b2 * one.y + c2; //a2 * x1 + b2 * y1 + c2;
    r2 = a2 * two.x + b2 * two.y + c2; //a2 * x2 + b2 * y2 + c2;

    /* Check signs of r1 and r2.  If both point 1 and point 2 lie
     * on same side of second line segment, the line segments do
     * not intersect.
     */

    if ( r1 != 0 &&
         r2 != 0 &&
         SAME_SIGNS( r1, r2 ))
        return ( DONT_INTERSECT );

    /* Line segments intersect: compute intersection point. 
     */

    denom = a1 * b2 - a2 * b1;
    if ( denom == 0 )
        return ( COLLINEAR );
    offset = denom < 0 ? - denom / 2 : denom / 2;

    /* The denom/2 is to get rounding instead of truncating.  It
     * is added or subtracted to the numerator, depending upon the
     * sign of the numerator.
     */

    num = b1 * c2 - b2 * c1;
    result.x = ( num < 0 ? num - offset : num + offset ) / denom;

    num = a2 * c1 - a1 * c2;
    result.y = ( num < 0 ? num - offset : num + offset ) / denom;

    return ( DO_INTERSECT );
    } /* lines_intersect */


//
// bool Intersect - (not in the book) Returns true if the supplied rect is inside a circular radius.
//
bool Intersect(const Rect &rect, const Point ¢er, double const radius)
{
	Rect r = rect;
	double radiusiusSquared = radius * radius;

	/* Translate coordinates, placing C at the origin. */
	r.left -= center.x;  r.bottom -= center.y;
	r.right -= center.x;  r.top -= center.y;

	if (r.right < 0) 			/* R to left of circle center */
	{
   		if (r.bottom < 0) 		/* R in lower left corner */
     		return ((r.right * r.right + r.bottom * r.bottom) < radiusiusSquared);
   		else if (r.top > 0) 	/* R in upper left corner */
   			return ((r.right * r.right + r.top * r.top) < radiusiusSquared);
   		else 					/* R due West of circle */
   			return(abs(r.right) < radius);
	}
	else if (r.left > 0)  	/* R to right of circle center */
	{
 		if (r.bottom < 0) 	/* R in lower right corner */
     				return ((r.left * r.left) < radiusiusSquared);
   		else if (r.top > 0)  	/* R in upper right corner */
     			return ((r.left * r.left + r.top + r.top) < radiusiusSquared);
   		else 				/* R due East of circle */
     			return (r.left < radius);
	}
	else				/* R on circle vertical centerline */
	{
   		if (r.bottom < 0) 	/* R due South of circle */
     			return (abs(r.bottom) < radius);
   		else if (r.top > 0)  	/* R due North of circle */
     			return (r.top < radius);
   		else 				/* R contains circle centerpoint */
     			return(true);
	}
}

//
// void Interpolate								
//
float Interpolate(float normalizedValue, float begin, float end)
{
	// first check input values
	GCC_ASSERT(normalizedValue>=0.0f);
	GCC_ASSERT(normalizedValue<=1.0f);
	GCC_ASSERT(end>begin);

	return ( normalizedValue * (end - begin) ) + begin;
}


//
// void MapYDeadZone			
//
void MapYDeadZone(Vec3 &input, float deadZone)
{
	if (deadZone>=1.0f)
		return;

	// The dead zone is assumed to be zero close to the origin
	// so we have to interpolate to find the right dead zone for
	// our current value of X.
	float actualDeadZone = Interpolate(fabs(input.x), 0.0f, deadZone);

	if (fabs(input.y) < actualDeadZone)
	{	
		input.y = 0.0f;
		return;
	}

	// Y is outside of the dead zone, but we still need to 
	// interpolate it so we don't see any popping.

	// Map Y values [actualDeadZone, 1.0f] to [0.0f, 1.0f]
	float normalizedY = (input.y - actualDeadZone) / (1.0f - actualDeadZone);
	input.y = normalizedY;
}


//
// WrapPi, Wrap2Pi, AngleDiff - returns the smallest angle - useful for knowing which way around the circle to turn
//
float WrapPi(float wrapMe)
{
    float result = Wrap2Pi(wrapMe + GCC_PI);
    return (result - GCC_PI);
}

float Wrap2Pi(float wrapMe)
{
    if (wrapMe > GCC_2PI)
        wrapMe = fmod(wrapMe, GCC_2PI);
    else if (wrapMe < 0)
        wrapMe = GCC_2PI - fmod(fabs(wrapMe), GCC_2PI);
    return wrapMe;
}

float AngleDiff( float lhs, float rhs )
{
	lhs = WrapPi( lhs );
	rhs = WrapPi( rhs );

	return WrapPi( lhs - rhs );
}

//----------------------------------------------------------------------------------------------------------------
// This function returns the look-at vector for a given orientation, which is assumed to be on the Y axis.  Thus, 
// the Y component of the returned vector will always be 0.  This function is used by the AI system which doesn't
// care about orientation along any other axis.
//----------------------------------------------------------------------------------------------------------------
Vec3 GetVectorFromYRotation(float angleRadians)
{
	Vec3 lookAt;
	WrapPi(angleRadians);
	lookAt.x = cos(angleRadians);
	lookAt.y = 0;
	lookAt.z = sin(angleRadians);
	lookAt.Normalize();  // just in case
	return lookAt;
}

//---------------------------------------------------------------------------------------------------------------
// This function returns the target orientation for a given look-at vector.  The orientation will be along the Y
// axis so the Y component of the look-at vector is ignored.  This function is used by the AI system which doesn't
// care about orientation along any other axis.
//----------------------------------------------------------------------------------------------------------------
float GetYRotationFromVector(const Vec3& lookAt)
{
	Vec3 zUnit(0.f,0.f,1.f);  // 0 orientation means staring down the positive Z axis
    float angle = (atan2(lookAt.z,-lookAt.x) - atan2(zUnit.z,zUnit.x));
	return Wrap2Pi(angle);
}
</span>

V. 这部分主要是实现一个随机数

<span style="font-size:14px;">#include "GameCodeStd.h"
#include <time.h>
#include "Math.h"

/////////////////////////////////////////////////////////////////////////////
// DEBUG info
/////////////////////////////////////////////////////////////////////////////

//--------------------------------------------------------------------------------

GCCRandom::GCCRandom(void)
{
	rseed = 1;
	// safe0 start
	rseed_sp = 0;
	mti=CMATH_N+1;
	// safe0 end
}	
	
// Returns a number from 0 to n (excluding n)
unsigned int GCCRandom::Random( unsigned int n )
{
    unsigned long y;
    static unsigned long mag01[2]={0x0, CMATH_MATRIX_A};

	if(n==0)
		return(0);

    /* mag01[x] = x * MATRIX_A  for x=0,1 */

    if (mti >= CMATH_N) { /* generate N words at one time */
        int kk;

        if (mti == CMATH_N+1)   /* if sgenrand() has not been called, */
            SetRandomSeed(4357); /* a default initial seed is used   */

        for (kk=0;kk<CMATH_N-CMATH_M;kk++) {
            y = (mt[kk]&CMATH_UPPER_MASK)|(mt[kk+1]&CMATH_LOWER_MASK);
            mt[kk] = mt[kk+CMATH_M] ^ (y >> 1) ^ mag01[y & 0x1];
        }
        for (;kk<CMATH_N-1;kk++) {
            y = (mt[kk]&CMATH_UPPER_MASK)|(mt[kk+1]&CMATH_LOWER_MASK);
            mt[kk] = mt[kk+(CMATH_M-CMATH_N)] ^ (y >> 1) ^ mag01[y & 0x1];
        }
        y = (mt[CMATH_N-1]&CMATH_UPPER_MASK)|(mt[0]&CMATH_LOWER_MASK);
        mt[CMATH_N-1] = mt[CMATH_M-1] ^ (y >> 1) ^ mag01[y & 0x1];

        mti = 0;
    }
  
    y = mt[mti++];
    y ^= CMATH_TEMPERING_SHIFT_U(y);
    y ^= CMATH_TEMPERING_SHIFT_S(y) & CMATH_TEMPERING_MASK_B;
    y ^= CMATH_TEMPERING_SHIFT_T(y) & CMATH_TEMPERING_MASK_C;
    y ^= CMATH_TEMPERING_SHIFT_L(y);

	// ET - old engine added one to the result.
	// We almost NEVER wanted to use this function
	// like this.  So, removed the +1 to return a 
	// range from 0 to n (not including n).
    return (y%n);
}

const unsigned int MAXINT = ((1 << sizeof(int)) - 1);
float GCCRandom::Random( )
{
	float r = (float)Random(MAXINT);
	float divisor = (float)MAXINT;
	return (r / divisor);
}



void GCCRandom::SetRandomSeed(unsigned int n)
{
	/* setting initial seeds to mt[N] using         */
	/* the generator Line 25 of Table 1 in          */
	/* [KNUTH 1981, The Art of Computer Programming */
	/*    Vol. 2 (2nd Ed.), pp102]                  */
	mt[0]= n & 0xffffffff;
	for (mti=1; mti<CMATH_N; mti++)
		mt[mti] = (69069 * mt[mti-1]) & 0xffffffff;

	rseed = n;
}

unsigned int GCCRandom::GetRandomSeed(void)
{
	return(rseed);
}

void GCCRandom::Randomize(void)
{
	SetRandomSeed((unsigned int)time(NULL));
}

//-------------------------------------------------------------------------------</span>
以上就是游戏中常用的工具集合。

下一篇是游戏通信 ~~








你可能感兴趣的:(游戏,技术,引擎,cocos2d-x)