回 帖 发 新 帖 刷新版面

主题:[AnyPlay游戏引擎代码] String模版,字符串操作的封装

前言:
由于本人还是在校学生,不可能拥有一个成熟的游戏开发团队。单靠一人的力量开发游戏引擎,我有种力不从心的感觉。因此,我希望广大的网友——不论你水平如何,经验多少——都能够参与到AnyPlay游戏引擎的开发工作当中。我将陆续把游戏引擎的各个模块发布到http://bbs.bccn.net/中,希望大家共同探讨,共同进步,同时也希望让更多的人加入到开放源代码的行列!

说明:
AnyPlay是我从今年(2008年)9月开始着手的一款2D游戏引擎,目前有以下模块:

A:基本类型
1. String(字符串)
2. Color(颜色)
3. Vector(向量)
4. Rect, Quad(矩形、四边形)
5. Node(节点)

B:框架
1. Singleton(单件类,其子类对象在全局被访问,但是只能创建一个实体)
2. Application(应用程序基类,以后做游戏的游戏框架要继承这个类)
3. Event, EventSet(事件集,使用类内回调来反馈信息)
4. Logger(日志记录器,记录发出的事件并输出)

C:系统
1.渲染系统:RenderSystem 派生出 D3D9RenderSystem 和 OGLRenderSystem(尚未完成)。
2.文件系统:FileSystem 可访问磁盘上的文件和资源包(*.zip)里的文件。
3.音频系统:AudioSystem 使用开源的WMp3代码实现mp3文件以及内存中的音频流的播放。
4.输入系统:InputSystem 派生出的 APIInputSystem 通过调用WinAPI来获得鼠标、键盘的状态。
5.计时系统:Timer 使用 WinAPI “QueryPerformanceCounter” 来实现高精度计时。

D:管理器
1.RenderSystem(纹理管理器,作为渲染系统的同时也包含管理纹理的功能)
2.ImageManager(图片管理器,载入和释放图片)
3.SpriteManager(精灵动画管理器,载入和释放精灵动画)
4.SceneManager(场景管理器,管理场景内的精灵动画,并向其发出用户事件)

E:动画
1.Animation(动画基类,借鉴Adobe Flash的帧/层思想做的)
2.Image(单个图片,一个纹理内可能含有多个图片)
3.Sprite(精灵动画,派生于Animation,用来真正实现游戏动画的播放)

[color=Red][size=4][b]一个人的思维,难免会有Bug或不完善的地方,
如果你对以下代码有什么意见或建议,欢迎发帖回复,非常感谢!
我坚信,好代码是改出来的[/b][/size][/color][em2] 

完整源代码下载:http://bbs.bccn.net/thread-238896-1-1.html

AnyPlay.h
[quote][font=新宋体][color=008000]/************************************************************************/[/color]
[color=008000]// 创建时间: 080906
[/color][color=008000]// 最后确定: 081017
[/color]
[color=800080]#ifndef[/color] _AnyPlay_h_
[color=800080]#define[/color] _AnyPlay_h_

[color=800080]#pragma[/color] warning (disable : 4786)

[color=800080]#include[/color] <windows.h>
[color=800080]#include[/color] <tchar.h>
[color=800080]#include[/color] <stdio.h>
[color=800080]#include[/color] <iostream>
[color=800080]#include[/color] <vector>
[color=800080]#include[/color] <list>
[color=800080]#include[/color] <map>
[color=800080]#include[/color] <math.h>

[color=008000]// 求大小
[/color][color=800080]#define[/color] APMax(a,b)        (((a) > (b)) ? (a) : (b))
[color=800080]#define[/color] APMin(a,b)        (((a) < (b)) ? (a) : (b))
[color=008000]// 安全释放指针, COM接口
[/color][color=800080]#define[/color] SAFE_DELETE(p)    { [color=0000ff]if[/color](p) { [color=0000ff]delete[/color] (p); (p) = NULL; } }
[color=800080]#define[/color] SAFE_RELEASE(p)    { [color=0000ff]if[/color](p) { (p)->Release(); (p) = NULL; } }
[color=008000]// 修正像素坐标
[/color][color=800080]#define[/color] PIXEL_ALIGNED(x)(([color=0000ff]float[/color])((x) + ((x) >= 0.0f ? 0.5f : -0.5f)))
[color=008000]// 退出程序
[/color][color=800080]#define[/color] QUIT_PROGRAM    { PostMessage(GetActiveWindow(), WM_CLOSE, 0, 0); }

[color=0000ff]typedef[/color] [color=0000ff]unsigned[/color] [color=0000ff]char[/color]    byte;
[color=0000ff]typedef[/color] [color=0000ff]unsigned[/color] [color=0000ff]long[/color]    dword;
[color=0000ff]typedef[/color] [color=0000ff]unsigned[/color] [color=0000ff]short[/color]    ushort;
[color=0000ff]typedef[/color] [color=0000ff]unsigned[/color] [color=0000ff]short[/color]    wchar;

[color=800080]#define[/color] NULL 0
[color=008000]// 迭代器是否在范围内
[/color][color=800080]#define[/color] IN_RANGE(_iter, _lst) ((_iter) >= (_lst).begin() && (_iter) < (_lst).end())
[color=008000]// 向Logger发出记录事件消息
[/color][color=800080]#define[/color] LOG(_s, _lv) { Logger::GetSingleton().LogEvent(_s, _lv); }

[color=800080]#endif[/color][/font][/quote]


String.h
[quote][font=新宋体][color=008000]/************************************************************************/[/color]
[color=008000]// 创建时间: 081005
[/color][color=008000]// 最后确定: 081017
[/color]
[color=800080]#ifndef[/color] _String_h_
[color=800080]#define[/color] _String_h_

[color=800080]#include[/color] [color=ff0000]"AnyPlay.h"[/color]

[color=008000]//////////////////////////////////////////////////////////////////////////
[/color][color=008000]// AnyPlay名称空间
[/color][color=0000ff]namespace[/color] AnyPlay
{
    [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]    [color=008000]// 字符串模版类
[/color]    [color=008000]// 之所以要写成一个模版, 是因为以后做游戏输入框可能会用到
[/color]    [color=0000ff]template[/color]<[color=0000ff]typename[/color] T> [color=0000ff]class[/color] StringT
    {
    [color=0000ff]public[/color]:
        StringT() { m_pTmpStr = NULL; m_bChanged = [color=0000ff]false[/color]; }
        StringT([color=0000ff]const[/color] StringT<T>& str) { m_pTmpStr = NULL; SetString(str); }
        StringT([color=0000ff]const[/color] T* str) { m_pTmpStr = NULL; SetString(str); }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 析构函数, 释放分配的内存
[/color]        [color=0000ff]virtual[/color] ~StringT() { SAFE_DELETE(m_pTmpStr); }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 清空字符列表
[/color]        [color=0000ff]virtual[/color] [color=0000ff]void[/color] Clear() { [color=0000ff]if[/color](m_String.size()) { m_String.clear(); m_bChanged = [color=0000ff]true[/color]; } }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 获得字符串长度
[/color]        [color=0000ff]virtual[/color] dword GetLength() [color=0000ff]const[/color] { [color=0000ff]return[/color] (dword)m_String.size(); }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 设置StringT字符串
[/color]        [color=0000ff]virtual[/color] [color=0000ff]void[/color] SetString([color=0000ff]const[/color] StringT<T>& str)
        {
            [color=0000ff]if[/color](&str == [color=0000ff]this[/color]) [color=0000ff]return[/color];    [color=008000]// 如果是自己则返回
[/color]            m_bChanged = [color=0000ff]true[/color];
            Clear();
            dword slen = str.GetLength();
            [color=0000ff]for[/color](dword i = 0; i < slen; i++)
                m_String.push_back(str.m_String[i]);
        }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 设置字符串指针
[/color]        [color=0000ff]virtual[/color] [color=0000ff]bool[/color] SetString([color=0000ff]const[/color] T* str)
        {
            [color=0000ff]if[/color](str)
            {
                m_bChanged = [color=0000ff]true[/color];
                Clear();
                dword i = 0;
                [color=0000ff]while[/color](str[i] != 0)
                {
                    m_String.push_back(str[i]);
                    i++;
                }
                [color=0000ff]return[/color] [color=0000ff]true[/color];
            }
            [color=0000ff]return[/color] [color=0000ff]false[/color];
        }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 寻找字符串
[/color]        [color=0000ff]virtual[/color] dword FindString([color=0000ff]const[/color] StringT<T>& str, dword begin) [color=0000ff]const[/color]
        {
            dword localLen = GetLength();
            dword targetLen = str.GetLength();
            [color=0000ff]for[/color](dword i = begin; i <= localLen - targetLen; i++)
            {
                [color=0000ff]for[/color](dword j = 0; j < targetLen; j++)
                {
                    [color=0000ff]if[/color](m_String[i + j] != str.m_String[j]) [color=0000ff]break[/color];
                    [color=0000ff]else[/color] [color=0000ff]if[/color](j == targetLen - 1) [color=0000ff]return[/color] i;
                }
            }
            [color=0000ff]return[/color] -1;
        }
        
    

回复列表 (共7个回复)

沙发

[quote]    [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 逆向寻找字符串
[/color]        [color=0000ff]virtual[/color] dword InverseFindString([color=0000ff]const[/color] StringT<T>& str, dword begin) [color=0000ff]const[/color]
        {
            dword localLen = GetLength();
            dword targetLen = str.GetLength();
            [color=0000ff]for[/color](dword i = localLen - targetLen; i >= begin; i--)
            {
                [color=0000ff]for[/color](dword j = 0; j < targetLen; j++)
                {
                    [color=0000ff]if[/color](m_String[i + j] != str.m_String[j]) [color=0000ff]break[/color];
                    [color=0000ff]else[/color] [color=0000ff]if[/color](j == targetLen - 1) [color=0000ff]return[/color] i;
                }
            }
            [color=0000ff]return[/color] -1;
        }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 从pos位置插入字符串
[/color]        [color=0000ff]virtual[/color] [color=0000ff]bool[/color] InsertString([color=0000ff]const[/color] StringT<T>& str, dword pos)
        {
            [color=0000ff]if[/color](IN_RANGE(m_String.begin() + pos, m_String) || (m_String.begin() + pos == m_String.end()))
            {
                m_bChanged = [color=0000ff]true[/color];
                m_String.insert(m_String.begin() + pos, str.m_String.begin(), str.m_String.begin() + str.GetLength());
                [color=0000ff]return[/color] [color=0000ff]true[/color];
            }
            [color=0000ff]return[/color] [color=0000ff]false[/color];
        }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 从begin开始删除长度为len的字符串
[/color]        [color=0000ff]virtual[/color] [color=0000ff]bool[/color] RemoveString(dword begin, dword len)
        {
            [color=0000ff]if[/color]( IN_RANGE(m_String.begin() + begin, m_String) &&
                IN_RANGE(m_String.begin() + begin + len - 1, m_String))
            {
                m_bChanged = [color=0000ff]true[/color];
                m_String.erase(m_String.begin() + begin, m_String.begin() + begin + len);
                [color=0000ff]return[/color] [color=0000ff]true[/color];
            }
            [color=0000ff]return[/color] [color=0000ff]false[/color];
        }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 获得字符串指针
[/color]        [color=0000ff]virtual[/color] T* GetBuffer() [color=0000ff]const[/color]
        {
            [color=0000ff]if[/color](m_bChanged || !m_pTmpStr)
            {
                SAFE_DELETE([color=0000ff]const_cast[/color]<T*>(m_pTmpStr));
                [color=0000ff]const_cast[/color]<T*>(m_pTmpStr) = [color=0000ff]new[/color] T[m_String.size() + 1];
                dword i = 0;
                [color=0000ff]while[/color](m_String.begin() + i != m_String.end())
                {
                    m_pTmpStr[i] = m_String[i];
                    i++;
                }
                m_pTmpStr[i] = 0;    [color=008000]// 0结尾
[/color]                [color=008000]// 关闭已经改变的标记
[/color]                [color=0000ff]const_cast[/color]<StringT<T>*>([color=0000ff]this[/color])->m_bChanged = [color=0000ff]false[/color];
            }
            [color=0000ff]return[/color] m_pTmpStr;
        }

    [/quote]

板凳

    [quote][color=008000]    //////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 字符串相加, 就是从尾部插入
[/color]        [color=0000ff]virtual[/color] StringT<T> [color=0000ff]operator[/color] + ([color=0000ff]const[/color] StringT<T>& str) [color=0000ff]const[/color]
        {
            StringT<T> strTmp = *[color=0000ff]this[/color];
            strTmp.InsertString(str, strTmp.GetLength());
            [color=0000ff]return[/color] strTmp;
        }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 自身的字符串相加
[/color]        [color=0000ff]virtual[/color] [color=0000ff]void[/color] [color=0000ff]operator[/color] += ([color=0000ff]const[/color] StringT<T>& str)
        {
            InsertString(str, GetLength());
        }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 从尾部添加字符
[/color]        [color=0000ff]virtual[/color] StringT<T> [color=0000ff]operator[/color] + ([color=0000ff]const[/color] T ch) [color=0000ff]const[/color]
        {
            StringT<T> strTmp = *[color=0000ff]this[/color];
            strTmp.m_bChanged = [color=0000ff]true[/color];
            strTmp.m_String.push_back(ch);
            [color=0000ff]return[/color] strTmp;
        }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 自身从尾部添加字符
[/color]        [color=0000ff]virtual[/color] [color=0000ff]void[/color] [color=0000ff]operator[/color] += ([color=0000ff]const[/color] T ch)
        {
            m_bChanged = [color=0000ff]true[/color];
            m_String.push_back(ch);
        }

    
    [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 比较两字符串是否相等
[/color]        [color=0000ff]virtual[/color] [color=0000ff]bool[/color] [color=0000ff]operator[/color] == ([color=0000ff]const[/color] StringT<T>& str) [color=0000ff]const[/color]
        {
            [color=0000ff]if[/color](&str == [color=0000ff]this[/color]) [color=0000ff]return[/color] [color=0000ff]true[/color];
            dword slen = GetLength();
            [color=0000ff]if[/color](slen == str.GetLength())
            {
                [color=0000ff]for[/color](dword i = 0; i < slen; i++)
                {
                    [color=0000ff]if[/color](str.m_String[i] != m_String[i]) [color=0000ff]return[/color] [color=0000ff]false[/color];
                }
                [color=0000ff]return[/color] [color=0000ff]true[/color];
            }
            [color=0000ff]return[/color] [color=0000ff]false[/color];
        }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 取字符串中间从start开始, 长度为len的字符
[/color]        [color=0000ff]virtual[/color] StringT<T> Mid(dword start, dword len) [color=0000ff]const[/color]
        {
            StringT<T> strTmp;
            strTmp.m_bChanged = [color=0000ff]true[/color];
            [color=0000ff]for[/color](dword i = 0; i < len; i++)
            {
                [color=0000ff]if[/color](IN_RANGE(m_String.begin() + i + start, m_String))
                    strTmp.m_String.push_back(m_String[i + start]);
                [color=0000ff]else[/color] [color=0000ff]break[/color];
            }
            [color=0000ff]return[/color] strTmp;
        }

    [/quote]

3 楼

    [quote][color=008000]    //////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 取字符串左边len个字符
[/color]        [color=0000ff]virtual[/color] StringT<T> Left(dword len) [color=0000ff]const[/color]
        {
            StringT<T> strTmp;
            strTmp.m_bChanged = [color=0000ff]true[/color];
            [color=0000ff]for[/color](dword i = 0; i < len; i++)
            {
                [color=0000ff]if[/color](IN_RANGE(m_String.begin() + i, m_String))
                    strTmp.m_String.push_back(m_String[i]);
                [color=0000ff]else[/color] [color=0000ff]break[/color];
            }
            [color=0000ff]return[/color] strTmp;
        }

        [color=008000]// 取字符串右边len个字符
[/color]        [color=0000ff]virtual[/color] StringT<T> Right(dword len) [color=0000ff]const[/color]
        {
            StringT<T> strTmp;
            strTmp.m_bChanged = [color=0000ff]true[/color];
            dword localLen = GetLength();
            [color=0000ff]for[/color](dword i = 0; i < len; i++)
            {
                [color=0000ff]if[/color](i >= localLen) [color=0000ff]break[/color];
                strTmp.m_String.insert(strTmp.m_String.begin(), m_String[localLen - i - 1]);
            }
            [color=0000ff]return[/color] strTmp;
        }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 不相等判断
[/color]        [color=0000ff]virtual[/color] [color=0000ff]bool[/color]        [color=0000ff]operator[/color] != ([color=0000ff]const[/color] StringT<T>& str) [color=0000ff]const[/color] { [color=0000ff]return[/color] !(*[color=0000ff]this[/color] == str); }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 赋值字符串指针
[/color]        [color=0000ff]virtual[/color] StringT<T>& [color=0000ff]operator[/color] = ([color=0000ff]const[/color] T* str) { SetString(str); [color=0000ff]return[/color] *[color=0000ff]this[/color]; }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 赋值StringT
[/color]        [color=0000ff]virtual[/color] StringT<T>& [color=0000ff]operator[/color] = ([color=0000ff]const[/color] StringT<T>& str) { SetString(str); [color=0000ff]return[/color] *[color=0000ff]this[/color]; }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 获得字符串指针
[/color]        [color=0000ff]virtual[/color] T*            [color=0000ff]operator[/color] () () [color=0000ff]const[/color] { [color=0000ff]return[/color] GetBuffer(); }

        [color=008000]//////////////////////////////////////////////////////////////////////////
[/color]        [color=008000]// 快速比较
[/color]        [color=0000ff]struct[/color] FastLessCompare
        {
            [color=0000ff]bool[/color] [color=0000ff]operator[/color] () ([color=0000ff]const[/color] StringT<T>& a, [color=0000ff]const[/color] StringT<T>& b) [color=0000ff]const[/color]
            {
                [color=0000ff]const[/color] dword la = a.GetLength();
                [color=0000ff]const[/color] dword lb = b.GetLength();
                [color=0000ff]if[/color](la == lb)
                    [color=0000ff]return[/color] (memcmp(a(), b(), la * [color=0000ff]sizeof[/color](T)) < 0);
                [color=0000ff]return[/color] (la < lb);
            }
        };

    [color=0000ff]protected[/color]:
        std::vector<T>    m_String;    [color=008000]// 字符列表
[/color]        T*                m_pTmpStr;    [color=008000]// 字符串指针
[/color]        [color=0000ff]bool[/color]            m_bChanged;    [color=008000]// 字符串是否已被改变
[/color]    };

    [color=0000ff]typedef[/color] StringT<TCHAR> String;    [color=008000]// TCHAR型字符串(常用)
[/color]}

[color=800080]#endif[/color][/font][/quote]

4 楼


QQ:421910745我很感兴趣,不知能加入不?

5 楼

关注:)

6 楼

非常感谢,源代码请到
http://bbs.pfan.cn/post-287296.html
下载[em2]

7 楼

一个问题,上述StringT<>既然依赖std::vector<>为什么不直接使用std::string或者std::wstring?


一个建议供参考:
        获得字符串指针的GetBuffer应该为非const语义,即应该做如下改动:
        virtual T* GetBuffer() const
====>
        virtual T* GetBuffer()
        
另外提供一个const语义的GetString,其定义如下:
        const T* GetString() const

可参考MFC中提供的CString相关接口定义


另外,模板实现方案一般不推荐使用虚函数定义接口或方法,除非真的有必要。参考stl的basic_string和MFC的CAtlStringT都不曾提供虚方法,我认为这是相当有道理的。

作为一个通用的游戏引擎实现方案,我觉得在设计上考虑严谨一些不会有什么坏处。
同时,楼主也表示欢迎提出意见和建议,因此,本人冒昧提出粗浅个人意见,仅供参考。

我来回复

您尚未登录,请登录后再回复。点此登录或注册