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


    <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声名的内部
     函数的声名+实现=内敛函数 不须要加入inlinekeyword机器自己主动优化
     当然有些函数的实现较复杂时即使使用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时加入一个位存储''
     max number of digits in an int (-2147483647 = 11 digits, +1 for the '') */
    #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' 即将源字符分解为去掉第一个
    的两个字符
     
     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('
    ');
    	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('
    ', 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] = ''; 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''; 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] = ''; 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''; 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, ''); 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, ''); 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>
    以上就是游戏中经常使用的工具集合。

    下一篇是游戏通信 ~~








  • 相关阅读:
    直接插入排序
    安卓突击:隐式、显式Intent
    安卓突击:Android 动画有哪几种?
    安卓突击:ANR
    安卓突击:系统上安装了多种浏览器,能否指定某浏览器访问指定页面
    安卓突击:系统上安装了多种浏览器,能否指定某浏览器访问指定页面
    Android:BroadcastReceiver的基础知识
    安卓突击:service的基础知识
    安卓突击:数据存储方式
    Android突击:常用的五种布局
  • 原文地址:https://www.cnblogs.com/llguanli/p/8680886.html
Copyright © 2020-2023  润新知