游戏开发论坛

 找回密码
 立即注册
搜索
查看: 4728|回复: 17

一种新的 get/set 模式

[复制链接]

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
发表于 2008-10-2 08:22:00 | 显示全部楼层 |阅读模式
传统的 get/set 模式是:

Type get_Prop() const;
void put_Prop( Type val );

我的新模式是:

// 在 class CClass 中

Type get_Prop() const;
template <class T> void put_Prop( T *instance, Type (T:: *func)(const CClass *) );
void put_Prop( Type (*func)(const CClass *) );

这是从函数型语言中学到的东西。。。这么一来, get/set 两者就  对  称  了(都是函数调用了)

这样,你可以安全,方便,轻松,同步,正确地,使一些自己的功能,和别人的类库交互。
比如,我写了一个示例,Sprite类库中并没有处理坐标的层级关系(parent/child),而这些东西通过用户的函数处理----不需要关系,如何同步local坐标和world坐标的值(就像手工同步网络中的源代码一样麻烦!而现在这些麻烦没有了!而且安全!)。

友情提示:
代码的编译,需要vc++2005

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2008-10-2 08:26:00 | 显示全部楼层

Re: 一种新的 get/set 模式



  1. // Func.cpp

  2. #include "stdafx.h"

  3. using namespace inst;
  4. using namespace inst::i2d;
  5. using namespace std;

  6. class CScene;
  7. class CSprite;
  8. struct MYSPRITE;

  9. Bool g_bExit = False;
  10. Bool g_bMyMsgLoop = True;
  11. SmartPtr<CGameWnd> g_pWnd;
  12. Int2 g_Mouse = { 0, 0 };
  13. SmartPtr<CBuffer> g_pBuf;
  14. SmartPtr<CScene> g_pScene;

  15. void Wnd_WndProc(UINT msg,WPARAM wparam,LPARAM lparam);
  16. void Update(){}
  17. void Render();
  18. void OnReset(){}
  19. void Init();
  20. void Destroy(){}
  21. Bool MsgLoop();

  22. const Int N = 10; // the num of sprites
  23. const POS SZ = 20; // the size of a block for drawing a sprite

  24. MYSPRITE *selected; // current selected sprite by the mouse
  25. COLOR old_color_selected; // store the old colr of the selected sprite

  26. // Float2 is a typedef of inst::MATRIX<inst::Float,2,1>

  27. class CSprite:virtual public IDynamic
  28. {
  29.         INST_DYNAMIC1(L"CSprite");
  30. public:
  31.         typedef Float2 (* WORLDPOS)(const CSprite *);
  32. private:
  33.         COLOR m_Color;
  34.         // - - - - - - - - -
  35.         void *m_instWorldPos; // instances
  36.         WORLDPOS m_funcWorldPos;
  37. public:
  38.         CSprite(){ m_instWorldPos = m_funcWorldPos = null; m_Color = 0xFFFFFFFF; }
  39. public:
  40.         void put_Color(COLOR color){ m_Color = color; }
  41.         Int get_Color()const{ return m_Color; }
  42.         // - - - - - - - - - - - - - - - - - - - - -
  43.         template <class T> void put_WorldPos(T *inst, Float2 (T:: *func)(const CSprite *))
  44.         {
  45.                 m_instWorldPos = reinterpret_cast<void *>(inst);
  46.                 m_funcWorldPos = union_cast<WORLDPOS>(func);
  47.         }
  48.         void put_WorldPos(WORLDPOS func)
  49.         {
  50.                 m_instWorldPos = null;
  51.                 m_funcWorldPos = func;
  52.         }
  53.         Float2 get_WorldPos()const
  54.         {
  55.                 if(null==m_funcWorldPos) return Float2();
  56.                 if(null==m_instWorldPos) return (*m_funcWorldPos)(this);
  57.                 return INST_THISCALLBACK(m_instWorldPos, m_funcWorldPos, Float2, (const CSprite *), (this));
  58.         }
  59.         void Render(Int2 pos, const Int2 *next_pos)
  60.         {
  61.                 if(next_pos)
  62.                         g_pBuf->DrawLine(pos.x, pos.y, next_pos->x, next_pos->y, 0xFF00FF00);
  63.                 g_pBuf->FillRect(POS(pos.x) - SZ/2, POS(pos.y) - SZ/2, SZ, SZ, get_Color());
  64.                 g_pBuf->DrawRect(POS(pos.x) - SZ/2, POS(pos.y) - SZ/2, SZ, SZ, ~get_Color());
  65.         }
  66. };

  67. class CScene:virtual public IDynamic
  68. {
  69.         INST_DYNAMIC1(L"CScene");
  70. public:
  71.         typedef Float2 (* CAMERA)(const CScene *);
  72.         typedef Array< SmartPtr<CSprite> > SpritesList;
  73.         SpritesList m_Sprites;
  74. private:
  75.         void *m_instCamera; // instance
  76.         CAMERA m_funcCamera;
  77. public:
  78.         CScene(){ m_instCamera = m_funcCamera = null; }
  79. public:
  80.         template <class T> void put_Camera(T *inst, Float2 (T:: *func)(const CScene *))
  81.         {
  82.                 m_instCamera = reinterpret_cast<void *>(inst);
  83.                 m_funcCamera = union_cast<CAMERA>(func);
  84.         }
  85.         void put_Camera(CAMERA func)
  86.         {
  87.                 m_instCamera = null;
  88.                 m_funcCamera = func;
  89.         }
  90.         Float2 get_Camera()const
  91.         {
  92.                 if(null==m_funcCamera) return Float2();
  93.                 if(null==m_instCamera) return (*m_funcCamera)(this);
  94.                 return INST_THISCALLBACK(m_instCamera, m_funcCamera, Float2, (const CScene *), (this));
  95.         }
  96.         Int2 CalcScreenPos(const CSprite *sprite)
  97.         {
  98.                 if(!sprite) return Int2();
  99.                 Float2 tmp = sprite->get_WorldPos() - get_Camera();
  100.                 return Int2().Set((Int)tmp.x, (Int)tmp.y);
  101.         }
  102.         void RenderAll()
  103.         {
  104.                 for(Int32 i = 0; i < m_Sprites.Count() - 1; i++)
  105.                 {
  106.                         if(m_Sprites.Get(i))
  107.                                 m_Sprites.Get(i)->Render(CalcScreenPos(m_Sprites.Get(i)), &CalcScreenPos(m_Sprites.Get(i+1)));
  108.                 }
  109.                 if(m_Sprites.GetEnd())
  110.                         m_Sprites.GetEnd()->Render(CalcScreenPos(m_Sprites.GetEnd()), null);
  111.         }
  112. };

  113. struct MYSPRITE
  114. {
  115.         MYSPRITE *Parent;
  116.         SmartPtr<CSprite> Sprite;
  117.         Float2 LocalPos;
  118.         MYSPRITE(){ Parent = null; }
  119.         Float2 WorldPos(const CSprite *sender)
  120.         {
  121.                 INST_ASSERT(Is(sender, Sprite));
  122.                 Float2 ret = LocalPos;
  123.                 MYSPRITE *tmp = Parent;
  124.                 while(tmp)
  125.                 {
  126.                         ret += tmp->LocalPos;
  127.                         tmp = tmp->Parent;
  128.                 }
  129.                 return ret;
  130.         }
  131. } MySprite[N];

  132. Float2 Camera(const CScene *sender)
  133. {
  134.         return Float2();
  135. }

  136. void Init()
  137. {
  138.         g_pWnd = new CGameWnd(L"Test Window");
  139.         g_pWnd->SetCallback(&Wnd_WndProc);
  140.         g_pWnd->Show();
  141.         g_pWnd->Activate();

  142.         CGraphics::CreateGraphics(640,480,g_pWnd->GetHWnd());
  143.         g_pBuf = CGraphics::GetGraphics()->GetBackBuffer();

  144.         g_pScene = new CScene;
  145.         g_pScene->put_Camera(&Camera);

  146.         MySprite[0].Parent = null;
  147.         MySprite[0].LocalPos.Set(g_pBuf->GetW()/3, g_pBuf->GetH()/3);

  148.         for(MYSPRITE *i = MySprite + 1; i < MySprite + N; i++)
  149.         {
  150.                 i->LocalPos.Set(SZ*1.5, SZ);
  151.                 i->Parent = i - 1;
  152.         }

  153.         for(MYSPRITE *i = MySprite; i < MySprite + N; i++)
  154.         {
  155.                 i->Sprite = new CSprite;
  156.                 i->Sprite->put_Color(Rgb(255 - Float(i-MySprite) / N * 255, 0, 0));
  157.                 i->Sprite->put_WorldPos(i, &MYSPRITE::WorldPos);
  158.                 g_pScene->m_Sprites.AddEnd(i->Sprite);
  159.         }
  160. }

  161. void Render()
  162. {
  163.         g_pBuf->FillRect(0,0,g_pBuf->GetW(),g_pBuf->GetH(),Rgb(0,0,0));
  164.         g_pScene->RenderAll();
  165.         CGraphics::GetGraphics()->Present();
  166. }

  167. void Wnd_WndProc(UINT msg,WPARAM wparam,LPARAM lparam)
  168. {
  169.         switch(msg)
  170.         {
  171.         case WM_KEYDOWN:
  172.                 if(selected)
  173.                         switch(wparam)
  174.                         {
  175.                         case 'A': selected->LocalPos.x -= SZ*0.33; break;
  176.                         case 'D': selected->LocalPos.x += SZ*0.33; break;
  177.                         case 'W': selected->LocalPos.y -= SZ*0.33; break;
  178.                         case 'S': selected->LocalPos.y += SZ*0.33; break;
  179.                         }
  180.                 break;
  181.         case WM_LBUTTONDOWN:
  182.                 if(selected) selected->Sprite->put_Color( old_color_selected );
  183.                 for(MYSPRITE *i = MySprite + N; i >= MySprite ; i--)
  184.                 {
  185.                         Int2 pos = g_pScene->CalcScreenPos(i->Sprite);
  186.                         if( pos.x - SZ/2 <= g_Mouse.x && pos.x + SZ/2 >= g_Mouse.x
  187.                          && pos.y - SZ/2 <= g_Mouse.y && pos.y + SZ/2 >= g_Mouse.y)
  188.                         {
  189.                                 selected = i;
  190.                                 old_color_selected = i->Sprite->get_Color();
  191.                                 i->Sprite->put_Color(Rgb(0,255,0));
  192.                                 break;
  193.                         }
  194.                 }
  195.                 break;
  196.         case WM_DESTROY:
  197.                 g_bExit=True;
  198.                 break;
  199.         case WM_DISPLAYCHANGE:
  200.                 CGraphics::GetGraphics()->Reset();
  201.                 OnReset();
  202.                 break;
  203.         case WM_PAINT:
  204.                 if(False==g_bMyMsgLoop) Render();
  205.                 break;
  206.         }
  207. }

  208. int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
  209. {
  210.         Init();

  211.         while(1)
  212.                 if(MsgLoop()) break;

  213.         Destroy();
  214.         return 0;
  215. }

  216. Bool MsgLoop()
  217. {
  218.         g_bMyMsgLoop = True;

  219.         if(g_bExit) return True;
  220.         ::MSG msg = {0};
  221.         while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  222.         {
  223.                 g_Mouse.Set(msg.pt.x, msg.pt.y);
  224.                 POS tx=0, ty=0, tw=1, th=1;
  225.                 g_pWnd->GetClientPos(null, null, &tw, &th);
  226.                 g_pWnd->ClientToScreen(0, 0, &tx, &ty);
  227.                 g_Mouse.Add(-tx, -ty);
  228.                 g_Mouse.x /= (Float)tw / g_pBuf->GetW();
  229.                 g_Mouse.y /= (Float)th / g_pBuf->GetH();
  230.                 TranslateMessage(&msg);
  231.                 DispatchMessage(&msg);
  232.         }
  233.         Update();
  234.         Render();
  235.         return False;
  236. }

  237. /* NOTE to me:
  238. class ISprite:virtual public IDynamic
  239. {
  240.         INST_DYNAMIC1(L"ISprite"):
  241. protected:
  242.         virtual ~CSprite(){}
  243. public:
  244.         virtual COLOR Color()=0;
  245.         // - - - - - - - - - - - - - - - - - - - - -
  246.         virtual Float2 WorldPos()=0;
  247. };

  248. // 把可变属性 Color 按照数学思想(无可变值)只能用 覆盖 表示。
  249. // 如果函数能够返回函数指针,那么把函数指针属性按照数学思想(覆盖)表示就是:返回函数指针的可覆盖函数,讨论一下这和 普通返回值的可覆盖函数 的关系!
  250. */

复制代码

sf_200810282557.rar

83.48 KB, 下载次数:

6

主题

49

帖子

49

积分

注册会员

Rank: 2

积分
49
QQ
发表于 2008-10-3 10:18:00 | 显示全部楼层

Re:一种新的 get/set 模式

看不明白,为什么get/set就对称了? 对称是什么意思?
这个模板函数有两个参数,两个参数分别是什么意思??
template <class T> void put_Prop( T *instance, Type (T:: *func)(const CClass *) );

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2008-10-4 08:26:00 | 显示全部楼层

Re:一种新的 get/set 模式

对称:

get 和 set 都是函数

template <class T> void put_Prop( T *instance, Type (T:: *func)(const CClass *) );
instance 和 func 构成一个delegate

14

主题

156

帖子

158

积分

注册会员

Rank: 2

积分
158
QQ
发表于 2008-10-4 09:10:00 | 显示全部楼层

Re:一种新的 get/set 模式

没看明白...

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2008-10-4 09:35:00 | 显示全部楼层

Re: Re:一种新的 get/set 模式

liuzewei: Re:一种新的 get/set 模式

没看明白...


这都是 C++ 语法的原因

template <class T> void put_Prop( T *instance, Type (T:: *func)(const CClass *) );

本质上是对下面的伪代码的实现:

put_Prop( your_func );

比如:

my_func() { return jhfksajklfskgskljksajfksajklf; }

精灵->put_坐标X ( my_func );

只不过为了支持动态成员函数,所以需要 instance. 为了类型安全和使用方便,需要template

89

主题

4036

帖子

4132

积分

论坛元老

Rank: 8Rank: 8

积分
4132
发表于 2008-10-4 13:58:00 | 显示全部楼层

Re:一种新的 get/set 模式

哎。。。

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2008-10-4 14:52:00 | 显示全部楼层

Re: Re:一种新的 get/set 模式

xpertsoft: Re:一种新的 get/set 模式

哎。。。


我用这种设计模式,一会功夫就完成了上面的代码。而且修改也方便。
否则,到处都需要手工设置那些数值,还要保证同步可靠。

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2008-10-17 18:18:00 | 显示全部楼层

Re: 一种新的 get/set 模式

截图
sf_20081017181731.jpg

362

主题

3023

帖子

3553

积分

论坛元老

Rank: 8Rank: 8

积分
3553
 楼主| 发表于 2009-1-4 22:08:00 | 显示全部楼层

Re:一种新的 get/set 模式

http://bbs.gameres.com/showthread.asp?page=end&threadid=121850
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2026-1-20 13:39

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表