C++ 学习之旅三 我和超级玛丽有个约会

首先,我说说对C++的最直观的感受吧!熟悉了.net 智能提示,开始一开始发现C++根本没有提示了。后来google了一下,下载了一个visual assist 这个插件,比vs自动提示强多了。 然后,就是习惯了在.net中,把所有的声明和方法实现写在同一文件中。可是C++不是这么回事。 他一个声明在头文件中,实现 在源文件中,说实在话,一开始并怎么习惯。后来渐渐就习惯了。然后,写C++的文件就是真他妈的痛苦,他不比.net,微软已经比你封装好了,在C++中,好多东西需要自己写。  首先,一个析构函数,需要自己释放资源。而.net有一个gc自动进行垃圾回收,资源释不释放,关你鸟事。没办法,只有自己释放.做一个遵守规则的好程序员。这是我对C++最直观感受。
言归正卷,说一说这个超级玛丽的游戏。 先看看,我对游戏的类结构的分类,如果有不妥的地方,恳请大家指正。

从层次结构来看,分成这几个层①图像层,②逻辑层,③结构和表。

图像层包括①图像基类MYBITMAP,②游戏背景MYBKSKYàMYBITMAP,③游戏图片MYANIOBJàMYBITMAP,④魔法攻击MYANIMAGICàMYBITMA.
逻辑层包括①游戏逻辑GAMEMAP,②时钟处理MYCLOCK,③字体处理MYFONT,④跟踪打印FILEREPORT,⑥玩家控制MYROLEàMYBITMAP。
结构和表包括①精灵结构ROLE,②物品结构MapObject,③地图信息表MAPINFO。
那每个类的结构又是那么样子的,是骡子还是马拉出来溜溜。我们在往下看一看。
图像层的结构就这样简单,逻辑层只需要确定“哪个图像,哪一帧”这两个参数,就能在屏幕上绘制出所有图片。
 说一说一个图片的基类。他的源代码的架构又是这个样子的。
今天先讲最基础的图像类 MYBITMAP:
成员函数功能列表:


代码如下:

//功能 根据一个位图文件,初始化图像
//入参 应用程序实例句柄 资源ID 横向位图个数 纵向位图个数
void Init(HINSTANCE hInstance,int iResource,int row,int col);
//功能 设置环境信息
//入参 目的DC(要绘制图像的DC),临时DC,要绘制区域的宽 高
void SetDevice(HDC hdest,HDC hsrc,int wwin,int hwin);--妈的,C++中画图需要一个hdc,设备上下文需要是一种包含有关某个设备(如显示器或打印机)的绘制属性信息的 Windows 数据结构。所有绘制调用都通过设备上下文对象进行,这些对象封装了用于绘制线条、形状和文本的 Windows API。设备上下文允许在 Windows 中进行与设备无关的绘制。设备上下文可用于绘制到屏幕、打印机或者图元文件。.net不需要了这个 上下文对象,他有了一个.netframework  就不需要这个屁玩意了。
//功能 设置图片位置1
//入参 设置方法 横纵坐标
void SetPos(int istyle,int x,int y);
//功能 图片显示
//入参 图片显示方式
void Draw(DWORD dwRop);
//功能 图片缩放显示
//入参 横纵方向缩放比例
void Stretch(int x,int y);
//功能 图片缩放显示
//入参 横纵方向缩放比例 缩放图像ID(纵向第几个)
void Stretch(int x,int y,int id);
//功能 在指定位置显示图片
//入参 横纵坐标
void Show(int x,int y);
//功能 横向居中显示图片
//入参 纵坐标
void ShowCenter(int y);
//功能 将某个图片平铺在一个区域内
//入参 左上右下边界的坐标 图片ID(横向第几个)
void ShowLoop(int left,int top,int right,int bottom,int iframe);
//功能 不规则图片显示
//入参 横纵坐标 图片ID(横向第几个)
void ShowNoBack(int x,int y,int iFrame);
//功能 不规则图片横向平铺
//入参 横纵坐标 图片ID(横向第几个) 平铺个数
void ShowNoBackLoop(int x,int y,int iFrame,int iNum);
 //动画播放
//功能 自动播放该图片的所有帧,函数没有实现,但以后肯定要用:)
//入参 无
void ShowAni();
//功能 设置动画坐标
//入参 横纵坐标
void SetAni(int x,int y);
成员数据
//跟踪打印类
// FILEREPORT f;
//图像句柄
HBITMAP hBm;
//按照行列平均分成几个
int inum;
int jnum;
//按行列分割后,每个图片的宽高(显然各个图片大小一致,派生后,这里的宽高已没有使用意义)
int width;
int height;
//屏幕宽高
int screenwidth;
int screenheight;
//要绘制图片的dc
HDC hdcdest;
//用来选择图片的临时dc
HDC hdcsrc;
//当前位置
int xpos;
int ypos;
//是否处于动画播放中(功能没有实现)
int iStartAni;

这个基类的部分函数和变量,在这个游戏中没有使用,是从前几个游戏中保留下来的,所以看起来有些零乱.这个游戏的主要图像功能,由它的派生类完成.由于基类封装了物理层信息(dc和句柄),派生类的编写就容易一些,可以让我专注于逻辑含义.
基类的函数实现上,很简单,主要是以下几点:
1.图片初始化:


代码如下:

//根据程序实例句柄,位图文件的资源ID,导入该位图,得到位图句柄
hBm=LoadBitmap(hInstance,MAKEINTRESOURCE(iResource));
//获取该位图文件的相关信息
GetObject(hBm,sizeof(BITMAP),&bm);
//根据横纵方向的图片个数,计算出每个图片的宽高(对于超级玛丽,宽高信息由派生类处理)
width=bm.bmWidth/inum;
height=bm.bmHeight/jnum;

下面再来说一说 游戏背景 类MYBKSKY
类说明:这是一个专门处理游戏背景的类。在横版游戏或射击游戏中,都有一个背景画面,如山、天空、云、星空等等。这些图片一般只有1到2倍屏幕宽度,然后像一个卷轴一样循环移动,连成一片,感觉上像一张很长的图片。这个类就是专门处理这个背景的。在超级玛丽增强版中,主要关卡是3关,各有一张背景图片;从水管进去,有两关,都用一张全黑图片。共四张图。这四张图大小一致,纵向排列在一个位图文件中。MYBKSKY这个类,派生于MYBITMAP。由于背景图片只需要完成循环移动的效果,只需要实现一个功能,而无需关心其他任何问题(例如句柄、dc)。编码起来很简单,再次反映出面向对象的好处。
 实现的原理:
怎样让一张图片像卷轴一样不停移动呢?很简单,假设有一条垂直分割线,把图片分成左右两部分。先显示右边部分,再把左边部分接到图片末尾。不停移动向右移动分割线,图片就会循环地显示。
 成员函数功能列表:
 

代码如下:

class MYBKSKY:public MYBITMAP
{
public:
MYBKSKY();
~MYBKSKY();--析构函数,怎么样 C++中,你有了资源 自己释放。我们.net 有一个终结者函数也有点析构函数的味道,但不一定自己释放资源吗。
//show
//功能 显示一个背景.
//入参 无
void DrawRoll(); //循环补空
//功能 显示一个背景,并缩放图片
//入参 横纵方向缩放比例
void DrawRollStretch(int x,int y);
//功能 指定显示某一个背景,并缩放图片,游戏中用的就是这个函数
//入参 横纵方向缩放比例 背景图片ID(纵向第几个)
void DrawRollStretch(int x,int y,int id);--进行中横坐标的操作
//功能 设置图片位置
//入参 新的横纵坐标
void MoveTo(int x,int y);
//功能 循环移动分割线
//入参 分割线移动的距离
void MoveRoll(int x);
 //data
//分割线横坐标
int xseparate;
};

看一看图片显示 类MYANIOBJ
类说明:这个类负责游戏中的图片显示。菜单背景、通关和游戏结束的提示图片,由MYBITMAP处理(大小一致的静态图片)。游戏背景由MYBKSKY处理。其余图片,也就是游戏过程中的所有图片,都是MYANIOBJ处理。
技术原理:游戏中的图片大小不一致,具体在超级玛丽中,可以分成两类:矩形图片和不规则图片。在位图文件中,都是纵向排列各个图片,横向排列各帧。用两个数组存储各个图片的宽和高。为了方便显示某一个图片,用一个数组存储各个图片的纵坐标(即位图文件中左上角的位置)。使用时,由逻辑层指定“哪个图片”的“哪一帧”,显示在“什么位置”。这样图片的显示功能就实现了。
成员函数功能列表:


代码如下:

class MYANIOBJ:public MYBITMAP
{
public:
MYANIOBJ();
~MYANIOBJ();
//init list
//功能 初始化宽度数组 高度数组 纵坐标数组 是否有黑白图
//入参 宽度数组地址 高度数组地址 图片数量 是否有黑白图(0 没有, 1 有)
//(图片纵坐标信息由函数计算得出)
void InitAniList(int *pw,int *ph,int inum,int ismask);
//功能 初始化一些特殊的位图,例如各图片大小一致,或者有其他规律
//入参 初始化方式 参数1 参数2
//(留作以后扩展, 目的是为了省去宽高数组的麻烦)
void InitAniList(int style,int a,int b);
//show
//功能 显示图片(不规则图片)
//入参 横纵坐标(要显示的位置) 图片id(纵向第几个), 图片帧(横向第几个)
void DrawItem(int x,int y,int id,int iframe);
//功能 显示图片(矩形图片)
//入参 横纵坐标(要显示的位置) 图片id(纵向第几个), 图片帧(横向第几个)
void DrawItemNoMask(int x,int y,int id,int iframe);
//功能 指定宽度, 显示图片的一部分(矩形图片)
//入参 横纵坐标(要显示的位置) 图片id(纵向第几个), 显示宽度 图片帧(横向第几个)
void DrawItemNoMaskWidth(int x,int y,int id,int w,int iframe);
//功能 播放一个动画 即循环显示各帧
//入参 横纵坐标(要显示的位置) 图片id(纵向第几个)
void PlayItem(int x,int y,int id);
//宽度数组 最多支持20个图片
int wlist[20];
//高度数组 最多支持20个图片
int hlist[20];
//纵坐标数组 最多支持20个图片
int ylist[20];
//动画播放时的当前帧
int iframeplay;
};

看一看 魔法攻击 类MYANIMAGIC
类说明:玩家有两种攻击方式:普通攻击(子弹),魔法攻击(旋风)。这个类是专门处理旋风的。我最初的想法是用一些特殊的bitblt方法制造特效,例如或、与、异或。试了几次,都失败了。最后只能用“先与后或”的老方法。这个类可看成MYANIOBJ的一个简化版,只支持不规则图片的显示。
成员函数功能列表:


代码如下:

class MYANIMAGIC:public MYBITMAP
{
public:
MYANIMAGIC();
~MYANIMAGIC();
//init list
//功能 初始化宽度数组 高度数组 纵坐标数组(必须有黑白图)
//入参 宽度数组地址 高度数组地址 图片数量
//(图片纵坐标信息由函数计算得出)
void InitAniList(int *pw,int *ph,int inum);
//功能 设置dc
//入参 显示dc 临时dc(用于图片句柄选择) 临时dc(用于特效实现)
void SetDevice(HDC hdest,HDC hsrc,HDC htemp);
//show
//功能 显示某个图片的某帧
//入参 横纵坐标(显示位置) 图片id(纵向第几个) 帧(横向第几个)
void DrawItem(int x,int y,int id,int iframe);
//宽度数组
int wlist[20];
//高度数组
int hlist[20];
//纵坐标数组
int ylist[20];
//用于特效的临时dc, 功能没有实现L
HDC hdctemp;
};

这就是我的一些架构

(0)

相关推荐

  • C++ 学习之旅二 说一说C++头文件

    一.C++头文件究竟是什么,你怎么看? 每个C++/C程序通常分为两个文件.一个文件用于保存程序的声明(declaration),称为头文件.另一个文件用于保存程序的实现(implementation),称为定义(definition)文件.C++/C程序的头文件以".h"为后缀,C程序的定义文件以".c"为后缀,C++程序的定义文件通常以".cpp"为后缀(像linux等系统以".cc"或".cxx"为后

  • C++ 学习之旅 Windows程序内部运行原理

    学习C++与.net不同的是,一定要搞清楚Windows程序内部运行原理,因为他所涉及大多数是操作系统的调用,而.net毕竟是在.netFrameWork上唱戏. 那Windows应用程序,操作系统,计算机硬件之间的相互关系究竟什么了,下面的图就给予很好的解释. 向下箭头①是 应用程序运行判断处理的结果,输出到输出的设备. 向上箭头②是输入设备,输入到操作系统中. 向下箭头③代表API,我们要解释以下API是什么.API是应用程序接口, 表示应用程序可以通知操作系统执行某个具体的动作,如操作系统

  • C++ 学习之旅三 我和超级玛丽有个约会

    首先,我说说对C++的最直观的感受吧!熟悉了.net 智能提示,开始一开始发现C++根本没有提示了.后来google了一下,下载了一个visual assist 这个插件,比vs自动提示强多了. 然后,就是习惯了在.net中,把所有的声明和方法实现写在同一文件中.可是C++不是这么回事. 他一个声明在头文件中,实现 在源文件中,说实在话,一开始并怎么习惯.后来渐渐就习惯了.然后,写C++的文件就是真他妈的痛苦,他不比.net,微软已经比你封装好了,在C++中,好多东西需要自己写.  首先,一个析

  • 开启BootStrap学习之旅

    本文总结了Bootstrap之所以广泛流传的11大原因.如果你还没有使用Twitter Bootstrap,建议你去了解一下.我也是最近才有所发现的,不过有更好的消息,在前两天微软发布的VS2013正式版中,也已经将BootStrap3.0的版本加入了额,连微软都看到bootStrap的强大,而且它的确很不错,所以我也不得不学习.这里有我对VS2013更新的简要介绍,有兴趣的话你可以看一眼Visual Studio 2013更新内容简介 bootstrap深受广大屌丝喜爱的原因到底是什么呢 1.

  • Spring+SpringMVC+MyBatis深入学习及搭建(三)之MyBatis全局配置文件解析

    前面有写到Spring+SpringMVC+MyBatis深入学习及搭建(二)--MyBatis原始Dao开发和mapper代理开发 MyBatis的全局配置文件SqlMapConfig.xml,配置内容和顺序如下: properties(属性) setting(全局配置参数) typeAliases(类名别名) typeHandlers(类名处理器) objectFactory(对象工厂) plugins(插件) environments(环境集合属性对象) environment(环境子属性

  • JavaScript事件学习小结(三)js事件对象

    相关阅读: JavaScript事件学习小结(五)js中事件类型之鼠标事件 http://www.jb51.net/article/86259.htm JavaScript事件学习小结(一)事件流 http://www.jb51.net/article/86261.htm javaScript事件学习小结(四)event的公共成员(属性和方法) http://www.jb51.net/article/86262.htm JavaScript事件学习小结(二)js事件处理程序 http://www

  • linux Shell学习笔记第三天

    第三天:条件选择 大 纲 应用实例分析 条件测试 if-else-fi case-in-esac 实现功能菜单: 执行脚本后 按1,显示当前时间 按2,显示CPU负载 按3,显示剩余内存 按0,退出脚本 按其他字符,提示超出选择范围后退出 分析步骤. #date +%T uptime awk截取 free –m 条件测试格式 #test –option obj #[ -option obj ] 返回结果 表达式内容测试结果是真的 表达式内容测试结果是假的 测试的对象分类 执行结果(执行成功或失败

  • Java8深入学习系列(三)你可能忽略了的新特性

    前言 我们之前已经介绍了关于java8中lambda和函数式编程的相关内容,虽然我们开始了Java8的旅程,但是很多人直接从java6上手了java8, 也许有一些JDK7的特性你还不知道,在本章节中带你回顾一下我们忘记了的那些特性. 尽管我们不能讲所有特性都讲一遍,挑出常用的核心特性拎出来一起学习. 异常改进 try-with-resources 这个特性是在JDK7种出现的,我们在之前操作一个流对象的时候大概是这样的: try { // 使用流对象 stream.read(); stream

  • servlet监听器的学习使用(三)

    本文为大家分享了servlet监听器的具体学习内容,供大家参考,具体内容如下 1.什么是servlet监听器? servlet监听器也叫web监听器.是servlet中一种特殊类.能够帮助开发者监听web应用中的特定事件.比如ServletContext,ServletSession,ServletRequest的创建和销毁,变量的创建和销毁等. 2 监听器常用的用途 通常使用Web监听器做以下的内容: 统计在线人数,利用HttpSessionLisener 加载初始化信息:利用ServletC

  • extjs 学习笔记(三) 最基本的grid

    jquery在这方面则正好相反,它的UI都以插件形式提供,可以需要什么就引用什么,所以非常小巧灵活,但由于插件往往是由不同的人或者团队来提供,界面和接口往往就不那么一致.反正是各有千秋吧. 今天学习extjs中的grid,它可以说是功能强大,无出其右,只有你想不到的,没有它做不到的,呵呵,好像是有点夸张了.好,不说废话了,我们就从最简单的grid开始,一步步来看看extjs给我们提供的grid究竟给我们提供了哪些功能. 一个grid包括一些行和列,在extjs里边,列由Ext.grid.Colu

  • javascript学习笔记(三)BOM和DOM详解

    js组成 我们都知道, javascript 有三部分构成,ECMAScript,DOM和BOM,根据宿主(浏览器)的不同,具体的表现形式也不尽相同,ie和其他的浏览器风格迥异. 1. DOM 是 W3C 的标准: [所有浏览器公共遵守的标准] 2. BOM 是 各个浏览器厂商根据 DOM 在各自浏览器上的实现;[表现为不同浏览器定义有差别,实现方式不同] 3. window 是 BOM 对象,而非 js 对象: DOM(文档对象模型)是 HTML 和 XML 的应用程序接口(API). BOM

  • php学习笔记(三)操作符与控制结构

    一.字符串插入 为了给开发人员处理字符串值提供最大的灵活性,PHP 为字面插入和内容插入提供了 一种方法. 双引号提供了最大的灵活性,原因是变量和转移序列都会得到相应的解析. 复制代码 代码如下: <?php $userName = "张三"; echo "His name is $userName "; echo "<br />"; //中文会出现一些问题 echo "他的名字叫$userName ,他19岁了,已经

随机推荐