SDL Game Development-第2章-5.实现纹理管理器Texture Manager

[复制链接]

该用户从未签到

2380

主题

2433

帖子

9139

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
9139
QQ
跳转到指定楼层
楼主
发表于 2017-12-19 09:27:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

想要查看内容赶紧注册登陆吧!

您需要 登录 才可以下载或查看,没有帐号?立即注册

x
1.创建TextureManager.h
//首先是load()方法,用来根据文件名装载纹理
  1. bool load(std::string fileName, std::string id, SDL_Renderer* pRenderer);
  2. //三个参数:文件名,字串ID,渲染器指针
复制代码
2.创建绘制draw()和绘制帧drawFrame()方法
  1. //draw()方法,根据ID识别纹理,x,y是位置,w,h是高宽
  2. void draw(std::string id,
  3.     int x, int y,
  4.     int width, int height,
  5.     SDL_Renderer* pRenderer,
  6.     SDL_RendererFlip flip = SDL_FLIP_NONE);    //默认为不翻转
复制代码
  1. //drawFrame()绘制指定帧
  2. void drawFrame(std::string id,
  3.     int x, int y,
  4.     int width, int height,
  5.     int currentRow,    //指当前行
  6.     int CurrentFrame,    //指当前帧
  7.     SDL_Renderer* pRenderer,
  8.     SDL_RendererFlip flip = SDL_FLIP_NONE);    //默认为不翻转
复制代码
3.使用标准容器map存储纹理指针
  1. //使用std::map容器放置纹理,键key为std::string指向的ID
  2. std::map<std::string, SDL_Texture*> m_textureMap;
复制代码
====================完整的TextureManager.h内容:====================
  1. #ifndef __TEXTURE_MANAGER__
  2.     #define __TEXTURE_MANAGER__
  3. #include <string>
  4. #include <map>

  5. #include <SDL.h>
  6. #include <SDL_image.h>

  7. class TextureManager
  8. {
  9. public:
  10.     bool load(std::string fileName, std::string id, SDL_Renderer* pRenderer);
  11.     void draw(std::string id, int x, int y, int width, int height, SDL_Renderer* pRenderer, SDL_RendererFlip flip = SDL_FLIP_NONE);        //默认为不翻转
  12.     void drawFrame(std::string id, int x, int y, int width, int height, int currentRow, int CurrentFrame, SDL_Renderer* pRenderer, SDL_RendererFlip flip = SDL_FLIP_NONE);  //参数中指定行和帧

  13. private:
  14.     std::map <std::string, SDL_Texture*> m_textureMap;

  15. };
  16. #endif // __TEXTURE_MANAGER__
复制代码
====================
4.在TextureManager.cpp中实现
//TextureManager.cpp实现load()
  1. bool TextureManager::load(std::string fileName, std::string id, SDL_Renderer* pRenderer)
  2. {
  3. SDL_Surface* pTempSurface = IMG_Load(fileName.c_str());
  4. if(pTempSurface == 0)    //图片装载失败
  5.         return false;
  6. SDL_Texture* pTexture = SDL_CreateTextureFromSurface(pRenderer, pTempSurface);
  7. SDL_FreeSurface(pTempSurface);
  8. //将新的纹理指针放入map中
  9. if(pTexture != 0)
  10. {
  11.   m_textureMap[id] = pTexture;
  12.   return true;
  13. }
  14. return false;    //运行到这里表示错误,处理错误
  15. }
复制代码
5.绘制整个图片的方法实现
//实现draw()
  1. void TextureManager::draw(std::string id, int x, int y, int width, int height,
  2.     SDL_Renderer* pRenderer, SDL_RendererFlip flip)
  3. {
  4. SDL_Rect srcRect;
  5. SDL_Rect destRect;
  6. srcRect.x = 0;
  7. srcRect.y = 0;
  8. srcRect.w = destRect.w = width;
  9. srcRect.h = destRect.h = height;
  10. destRect.x = x;
  11. destRect.y = y;
  12. SDL_RenderCopyEx(pRenderer, m_textureMap[id], &srcRect, &destRect, 0, 0, flip);
  13. }
复制代码
6.单帧绘制方法的实现
//实现drawFrame()
  1. void TextureManager::drawFrame(std::string id, int x, int y, int width, int height,
  2.     int currentRow, int currentFrame, SDL_Renderer* pRenderer, SDL_RendererFlip flip)
  3. {
  4. SDL_Rect srcRect;
  5. SDL_Rect destRect;
  6. srcRect.x = width * currentFrame;
  7. srcRect.y = height * (currentRow - 1);    //这句局限于图片帧动画的每排必须等高
  8. srcRect.w = destRect.w = width;
  9. srcRect.h = destRect.h = height;
  10. destRect.x = x;
  11. destRect.y = y;
  12. SDL_RenderCopyEx(pRenderer, m_textureMap[id], &srcRect, &destRect, 0, 0, flip);
  13. }
复制代码
7.使用定义好的纹理管理类
1).在Game.h中,包含:
#include "TextureManager.h"

2).私有成员修改为:
  1.     //SDL_Texture* m_pTexture;    //纹理指针
  2.     //SDL_Rect m_srcRect; //纹理的矩形位置
  3.     //SDL_Rect m_destRect;    //绘制到屏幕上的位置矩形
  4.     int m_currentFrame;
  5.     TextureManager m_textureManager;
复制代码

3).Game.cpp的init()方法中,删除原有的图片装载和方框赋值,添加代码为:
//使用新的纹理管理类进行图片装载
  1. m_textureManager.load("assets/animate-alpha.png", "animate", m_pRenderer);
  2. //load()方法是bool值,可以在这里加入判断,失败直接返回
  3.     std::cout << "init success\n";
  4.     m_bRunning = true;  //所有初始都成功,可以开始主循环了
  5.     return true;
复制代码
4).渲染方法的修改:
  1.     //绘制纹理对象,调用纹理管理类的draw方法
  2.     //注意参数的使用
  3.     m_textureManager.draw("animate", 0, 0, 128, 82, m_pRenderer);
  4.     m_textureManager.drawFrame("animate", 100, 100, 128, 82, 1, m_currentFrame, m_pRenderer);
复制代码
5).更新方法的修改:
  1.     //直接计算Game类的私有成员:当前帧
  2.     m_currentFrame = int(((SDL_GetTicks() / 100) % 6));
复制代码

测试运行:

优势:将纹理的装载和绘制封装,以后只需要循环遍历纹理指针,即可实现图片在屏幕上的呈现。
最后,将TextureManager类定义为单例,在程序中保证只有一个实例在运行,实现重复性使用。
1).在TextureManager.h类定义中,将构造函数声明为私有
  1. private:
  2.     std::map <std::string, SDL_Texture*> m_textureMap;
  3.     static TextureManager* s_pInstance;
  4.     TextureManager() {} //将构造声明为私有
复制代码

2).定义静态内联函数Instance()
  1. public:

  2. ...

  3.     static TextureManager* Instance()   //静态实例
  4.     {
  5.         if(s_pInstance == 0)
  6.         {
  7.             s_pInstance = new TextureManager();
  8.             return s_pInstance;
  9.         }
  10.         return s_pInstance; //如果实例已存在,直接返回实例指针
  11.     }
复制代码
3).类型定义,提示实例
  1. };

  2. typedef TextureManager TheTextureManager;
复制代码
4)..cpp中声明全局实例
  1. #include "TextureManager.h"

  2. TextureManager* TextureManager::s_pInstance = 0;
复制代码

5).使用://Game.h中注释掉m_textureManager成员变量

//Game.cpp中修改调用的方法:init()中
  1. //m_textureManager.load("assets/animate-alpha.png", "animate", m_pRenderer);
  2. if(!TheTextureManager::Instance()->load("assets/animate-alpha.png", "animate", m_pRenderer))
  3.     return false;
复制代码
//render()中
  1.     //m_textureManager.draw("animate", 0, 0, 128, 82, m_pRenderer);
  2.     //m_textureManager.drawFrame("animate", 100, 100, 128, 82, 1, m_currentFrame, m_pRenderer);
  3.     TheTextureManager::Instance()->draw("animate", 0, 0, 128, 82, m_pRenderer);
  4.     TheTextureManager::Instance()->drawFrame("animate", 0, 100, 128, 82, 1, m_currentFrame, m_pRenderer);
复制代码
运行,查看效果








分享到:  QQ好友和群QQ好友和群
收藏收藏
回复

使用道具 举报

快速回复高级模式
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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