游戏编程二:精灵的处理

来源:互联网 发布:jstor知乎 编辑:程序博客网 时间:2024/05/22 11:59
游戏编程二:精灵的处理
 
    先前我们介绍了我们小组对于位图的处理,现在我们将介绍我们对于精灵类的处理。
    我们把一些贴图零件统称为精灵,对于一个游戏场景来说,就是在地图上贴上不同的精灵,包括物体object,角色player,敌人enemy,其实一个精灵就是一个位图,结合先前我们对位图的处理,就可以很方便的处理场景。
    首先我们定义一个精灵base类,以后所有的精灵将继承该类,由于对于可以移动的精灵,以角色为例,我们参考RPG Maker里面的做法,人物在四个方向上都有停--左脚--停--右脚四个状态,依次调用四个状态就可以让人物移动,而在程序里的做法就是通过bitblt函数不断改变ox,oy里的值。
    精灵类CSprite的定义为下:
#ifndef    __sprite_h__
#define    __sprite_h__
 
class CDibSection;
class CSprite {
 public:
       CSprite();
       CSprite(CDibSection *dib, CPoint pos, CSize _size, int d=0);
       CSprite(CDibSection *dib, CPoint pos, CPoint src, CSize _size, int d=0);
       virtual ~CSprite();
 
       void Set(CDibSection *dib, CPoint pos, CSize _size, int d=0);
       void Set(CDibSection *dib, CPoint pos, CPoint src, CSize _size, int d=0);
       void Draw(CDibSection &image);
       void Draw(CDibSection &image, const CRect &rect);
       void GetRect(CRect *r) const;
       void SetDrawPos(int x, int y);
       void SetDrawPos(CPoint point);
       CPoint GetDrawPos() const;
       void SetSrcPos(int x, int y);
       int GetDepth() const;
       void SetDepth(int d);
       BOOL PtIn(POINT pt);
 
 protected:
       CPoint     draw_pos;                     //绘制位置
       CPoint     src_pos;                      //CG显示位置的坐标
       CSize      size;                         //显示尺寸的大小
       CDibSection *dib;                     //指向CG数据的指针
       int           depth;                        //sprite层次0, 1, 2.......
} ;
首先,draw_pos是将把精灵绘制到map的位置,我们小组的处理不是直接将精灵绘制到client表面,而是首先将其绘制到缓存里的背景上,在绘制到表面,所以draw_pos是相对于背景的坐标,而src_pos则是cg坐标,通过该坐标来定位需要绘制的精灵,因为我们为了方便,通常将一个精灵的不同状态做成一张图,这样就方便管理,至于绘图时就通过src_pos来定位,具体参见bitblt函数说明,而size就是需要显示的尺寸大小,对于一个player来说,我们通常会用一个4*4的图片来表示他的移动状态。
所以他的尺寸大小为图片的宽度与高度除以4。
在sprite里,我们不把位图放进去,只是用了一个CDibSection *dib指针,位图的处理我们将放在另一个类里处理,这里不再说明。
对于depth,我们设定的是精灵的层次,在一个场景里,精灵的显示是有顺序的,精灵的前后关系很重要,不然在重迭时可能会出现在前面的精灵跑到后面的情况,这里我们先做一个约定,我们会将整个地图分成格子,每个格子为32*32像素。
这样在显示精灵时,我们约定,对于同一个格子上的,层次越低的,越先绘制,对于同一个y轴上的,y坐标越小得越先绘制。这样精灵重叠时就不会发生错误。
下面是函数的具体实现:
//
//sprite设置
//
inline void CSprite::Set(CDibSection *_dib, CPoint pos, CSize _size, int d)
{
       draw_pos = pos;
       size = _size;
       dib = _dib;
       depth = d;
}
 
inline void CSprite::Set(CDibSection *_dib, CPoint pos, CPoint src, CSize _size, int d)
{
       draw_pos = pos;
       src_pos = src;
       size = _size;
       dib = _dib;
       depth = d;
}
 
//
//sprite CG显示位置坐标设定
//
inline void CSprite::SetSrcPos(int x, int y)
{
       src_pos.x = x;
       src_pos.y = y;
}
 
 
//
//sprite 绘制位置坐标设定
//
inline void CSprite::SetDrawPos(int x, int y)
{
       draw_pos.x = x;
       draw_pos.y = y;
}
 
inline void CSprite::SetDrawPos(CPoint point)
{
       draw_pos = point;
}
 
//
//取得绘制坐标
//
inline CPoint CSprite::GetDrawPos() const
{
       return draw_pos;
}
 
//
//取得层次
//
inline int CSprite::GetDepth() const
{
       return depth;
}
 
//
//设置层次
//
inline void CSprite::SetDepth(int d)
{
       depth = d;
}
 
//
//得到绘制位置区域
//
inline void CSprite::GetRect(CRect *r) const
{
       r->left = draw_pos.x;
       r->top = draw_pos.y;
       r->right = draw_pos.x + size.cx;
       r->bottom = draw_pos.y + size.cy;
}
 
 
inline BOOL CSprite::PtIn(POINT pt)
{
       return CRect(draw_pos, size).PtInRect(pt);
}
 
//精灵混合
void CSprite::Draw(CDibSection &image)
{
       image.Mix(*dib, draw_pos, size, src_pos, RGB(255, 255, 255));
}
 
 
void CSprite::Draw(CDibSection &image, const CRect &rect)
{
       CRect r(draw_pos, size);
       r &= rect;
       if (!r.IsRectEmpty()) {
              CPoint     src = src_pos;
              CPoint     dest = draw_pos;
              if (dest.x < r.left) {
                     src.x += r.left - dest.x;
                     dest.x = r.left;
              }
              if (dest.y < r.top) {
                     src.y += r.top - dest.y;
                     dest.y = r.top;
              }
              image.Mix(*dib, dest, r.Size(), src);
       }
}
这里面重点关注的是set函数,它将设定精灵的显示位置,以及贴图所需的图片,而对于图像,则是通过指针操纵。
所以操纵精灵时,我们先用set函数将其设定到指定位置,在用draw函数与背景贴图重叠,这样就可以了。
精灵包括物体,敌人,还有角色,而在某一方面来说,敌人与角色也可以算得上物体,所以我们先写一个CMapSprite类,继承自CSprite
class CMapSprite: public CSprite
{
public:
      
 
public:
       CMapSprite();
       CMapSprite(CDibSection *dib, CPoint pos, CSize size, int d);
 
       void SetMapPoint(CPoint point);
       CPoint GetMapPoint() const { return map_point; }
       void SetMapIndex(CPoint point);
       CPoint GetMapIndex() const {return map_index; }
 
       bool operator==(CPoint p);
       bool operator<(const CMapSprite &x) const;
 
protected:
       CPoint map_point;          //地图坐标
       CPoint map_index;          //地图索引坐标
};
 
在这里,map_point表示的是地图坐标,用来表明该精灵相对于背景地图的坐标,而map_index则是地图索引坐标,我们先前说过,将地图分成了32*32的格子,我们就用map_index表明该精灵所在的格子坐标,当然地图坐标和索引坐标可以互相转换,函数如下
enum      {
       MAPGRID_WIDTH = 32,
       MAPGRID_HEIGHT = 32,
} ;
 
inline CPoint PointToIndex(int x, int y)
{
       return CPoint(x / MAPGRID_WIDTH, y / MAPGRID_WIDTH);
}
 
inline CPoint PointToIndex(CPoint point)
{
       return PointToIndex(point.x, point.y);
}
 
inline CPoint IndexToPoint(int x, int y)
{
       return CPoint(x * MAPGRID_WIDTH, y * MAPGRID_HEIGHT);
}
 
inline CPoint IndexToPoint(CPoint point)
{
       return IndexToPoint(point.x, point.y);
}
 
而对于CMapSprite类的函数实现,如下
//设置地图坐标
void CMapSprite::SetMapPoint(CPoint point)
{
       map_point = point;
       SetDrawPos(IndexToPoint(point) + CPoint((MAPGRID_WIDTH - size.cx) / 2, MAPGRID_HEIGHT - size.cy));
}
 
 
//设置地图索引
void CMapSprite::SetMapIndex(CPoint point)
{
       map_index = PointToIndex(point - CPoint((MAPGRID_WIDTH - size.cx) / 2, MAPGRID_HEIGHT - size.cy));
}
 
bool CMapSprite::operator==(CPoint p)
{
       return map_point.x == p.x && map_point.y == p.y;
}
 
// 为了要决定显示顺序,要比较大小关系和坐标
//
bool CMapSprite::operator<(const CMapSprite &x) const
{
       if (draw_pos.y + size.cy == x.draw_pos.y + x.size.cy) {
              if (draw_pos.x == x.draw_pos.x) {
                     return depth < x.depth;
              }
              return draw_pos.x < x.draw_pos.x;
       }
       return draw_pos.y + size.cy < x.draw_pos.y + x.size.cy;
}
 
在这里,由于精灵可能不是32*32一个格子大,所以我们在绘制的时候,还要经过一些处理。
 
人物的的绘制坐标其实应为人物的理论地图坐标加上CPoint((MAPGRID_WIDTH - size.cx) / 2, MAPGRID_HEIGHT - size.cy),而人物的索引坐标则是人物实际坐标减去CPoint((MAPGRID_WIDTH - size.cx) / 2, MAPGRID_HEIGHT - size.cy)在转换得来的。
然后我们再写一个CCharacter类继承自CMapSprite,该类实现敌人与角色,其实敌人与角色就可以看成会动的物体,而且多了一些属性罢了,但是在该类中,由于我们小组还没实现战斗系统,所以属性没有定义,以后会慢慢说明。
class CCharacter: public CMapSprite
{
public:
       CCharacter(CDibSection *dib, CPoint pos, CSize size, int d);
 
       bool ClearStatus();
 
       bool operator==(const CCharacter &x);
 
public:
       CString name; // 名称
};
是函数实现如下:
bool CCharacter::operator==(const CCharacter &x)
{
       return name == x.name;
}
这个类很简单,只是因为我们还没有添加一些属性,具体实现等以后再说。
 
 
 
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 贴了乳贴过免痒怎么办 yy别人听见我打游戏的声音怎么办 微信的聊天记录发错邮箱怎么办 百度云盘文件有违规内容怎么办 天籁一键启动钥匙没电怎么办 中兴手机系统界面已停止运行怎么办 怎么办可以复制成不关联的文档 希捷400g硬盘电机不转怎么办 金立手机微信语音播放失败怎么办 手机4g网络变2g怎么办 生存战争2吃了腐烂的食物后怎么办 古筝调音 d的显示为b怎么办 消防建审没有原有的结构图纸怎么办 生石灰弄到脸上用水洗后发热怎么办 吃了没熟的鹅肝怎么办 蹲式厕所被袜子堵了怎么办 自热包的水喝了怎么办 火锅发热包不小心吃了怎么办 塑料螺旋饭盒盖子被吸住了怎么办 昨晚喝太多酒今天排尿拍不出怎么办 开光过的貔貅摔坏一点嘴巴怎么办 诺基亚6第二代忘记解屏密码怎么办 工厂搬迁已经般空了工人怎么办 被上司强行换了一个岗位该怎么办 上司要调整我岗位我该怎么办 我被别人打伤了警察不管怎么办 郑州共享汽车小黄车路上坏了怎么办 爱跟别人聊朋友的事怎么办 任职履历上学历写错了怎么办 六个月的宝宝老长婴儿湿疹怎么办 入伍前驾照没考完退伍后过期怎么办 在电脑上玩英雄联盟没有声音怎么办 梦幻西游新区抢不到副本积分怎么办 倒车时遇上机动车碰瓷的怎么办 电瓶车相撞对方全责但不赔偿怎么办 轻微刮蹭逃逸对方想多要钱怎么办 正常开车撞伤了闯红灯的人怎么办 发现小事故要保持现场堵车怎么办 私处刮毛外面皮肤不小心弄伤怎么办 老婆骂孩子不准老公带饿小孩怎么办 结婚3年妻子不让丈夫碰怎么办