【文章标题】用面向对象的思想探讨游戏“魔兽争霸”(1

【文章作者】曾健生

【作者邮箱】zengjiansheng1@126.com

【作者QQ】190678908

【作者博客】http://blog.csdn.net/newjueqi

【编程环境】JDK 1.6.0_01

【作者声明】欢迎转载文章,但转载请保留文章的完整性以及注明文章的出处。

*******************************************************************************

前言:面向对象思想是学习java, .net等计算机语言的核心思想,在本人学习的过程中,本人直到最近对面向对象思想有了一个大突破后才发现原来在玩 “魔兽争霸”这个游戏的过程中就已经包含了深刻的面向对象的思想,现在根据自己对面向对象思想的理解结合“魔兽争霸”这个游戏进行相关的阐述(本人知道很多兄弟们对“魔兽争霸”等相关即时战略游戏相当沉迷,用“魔兽争霸”举例说明能减少学习的枯燥性,看完本文后就能发现其实面向对象的思想我们早已熟悉了,只是没发现而已),希望能对各位理解面向对象的思想有所帮助。阅读本文前最好对即时战略游戏有所理解,即时战略游戏指魔兽争霸,星际(当然也包括帝国时代,红色警戒等游戏),有所理解是指起码也要知道游戏是怎么玩的。最后,请原谅由于本人对“魔兽争霸”不太熟悉而在魔兽的专业术语的使用上有所错误,其实本人只是“魔兽争霸”菜鸟(勉强能打赢初级电脑),而且本人也有半年多没玩,很多内容都忘记,阅读本文的“魔兽”玩家请原谅我吧^-^

本人才疏学浅,对于文中出现的各种错误,敬请各位大侠指出!!!

这里也简单阐述一下面向对象的概念(详细的定义读者可参考相关的书籍或文章):

面向对象的思想力图使计算机中描述的事物和现实生活中的尽量相近,其中类是指具有相同属性,相同行为的一类事物;实例是指该类事物的具体例子

首先开始就文中的一些概念进行约定以减少阅读的困难:

(1)       我们玩“魔兽争霸”游戏是在一个地图(是指2D地图)中进行,如果现在有一个人族的农民站在地图上,那么这个农民在地图上有个坐标(坐标的原点是地图左下角),譬如是农民的坐标(200,100),那么在地图上的标识如下(图1),这个坐标概念在下文中经常用到,各位读者必须要理解是怎么一回事

(2)       全文中都是假设玩家选的种族是精灵族

其实我们在玩魔兽的过程中对类的概念已经耳熟能详了(对于这一点,是本人在前几天对面向对象有了一个更深刻的认识后才发现,各位玩家看了后一定会恍然大悟^-^)

下面就面向对象中的属性,行为,类,实例等概念用游戏的例子说明一下

(1)       属性:是说明某个物体的基本特征,通过一系列的属性数据,我们就能得出结论某个物体是什么?譬如一个精灵族的小精灵,它的生命是120,防御是0,看起来像是发红光的物体,知道了小精灵的以上数据,就对小精灵有所了解。如图1

图1

(2)       行为:说明某个物体能干什么?譬如小精灵能采矿(),能建造生命之树(),能移动()等,这都是小精灵的能干的事情。如图2

图2

(3)       类:是某一种事物的描述。我们知道在精灵族种小精灵的生命值120,防御力是0,小精灵能采矿(),能建造生命之树(),能移动(),但我们不需要知道具体到底指的是哪个小精灵,反正小精灵这个概率就有以上的内容。所以小精灵就是一个类,它可以存在于抽象层次(知道是什么一回事),但不需要实体。在精灵古树种有个生产小精灵的按钮,我们知道这个按钮能生产小精灵,生产的小精灵除了位置和内部ID号外其他都是一样的。所以这个生产小精灵的按钮就是已经蕴含了面向对象中的“小精灵”类的概念。如图3

图3

(4)       实例:类只是某一种事物的抽象的概念。就正如“小精灵”类一样,如果不训练一个小精灵去采矿,那么小精灵类永远不会采矿。如果我们需要一个小精灵去采矿,我们就必需点击一下训练小精灵的按钮训练一个小精灵出来点击训练小精灵按钮创造一个小精灵,用面向对象的术语描述就是用小精灵类产生了一个小精灵的实例。训练出来的小精灵就是小精灵类一个实例。图4就是用小精灵类创造的多个实例:

图4

经过以上的论述,本人得出了一个结论每个玩家都已很熟悉面向对象思想。玩魔兽的过程就像是一个面向对象编程的过程:我们玩游戏就是用暴雪公司提供的各种类和方法,思考用那些类(英雄类,小精灵类,战士类等),创造多少个实例(训练多少各精灵,生产多少个弓箭手,需要用哪个英雄),调用哪些方法(小精灵去采矿(),小精灵建造生命之树(),弓箭手攻击())来获取胜利,在这个基础上玩家们创造出不同的战术获取胜利。

所以正在学习面向对象的各位玩家,其实我们早已对面向对象的那套思想非常熟悉,只是我们不知道这就是面向对象思想而已。希望阅读完本文的各位玩家能根据本文的内容及时把思维转换过来,更快地迈入面向对象的世界。

现在我们开始在程序的角度用“魔兽争霸”游戏阐述面向对象的思想(以下的代码进行了最大程度的简化,只阐述最核心的部分,各位读者要明白,真正的游戏编程没有这么简单^-^,Let’ Go!!!

那么现在我们从程序员的角度思考一下,如果现在有这么一个场景:玩家生产了一个弓箭手去攻击对手不死族的食尸鬼。如果你是一个程序员,应该怎么用面向对象编程完成这个场景动作?

根据我们玩“魔兽争霸”的经验,第一步是生产一个弓箭手,这个不难,但如果玩家是生产2个,3个,4个……,如果每次生产一个弓箭手都要把弓箭手的所有代码重写一遍,那不是把我们写程序的活活累死!!!

不要着急,我们可以分析一下每个弓箭手有什么不同。现在我们再回顾一下类的概念:类是指具有相同属性,相同行为的一类事物。对于弓箭手,就正如我们玩家所熟悉的,每个弓箭手相对于其他弓箭手唯一的不同就是所在的位置(也就是在地图上的坐标)还有一个ID,其它的什么攻击力,防御力,生命值,移动的方法:步行,攻击的方法:用弓箭射击 ,受到攻击的防御行为等都是一样的。那么对于所有的弓箭手来说,除了所在的位置不同外的所有属性(攻击力,防御力,生命值),所有行为(移动的方法:步行,攻击的方法:弓箭射击,受到攻击的行为)是不是一样啊!这不是已经符合了类的定义吗?所以把弓箭手抽象为一个类Bower。

类的定义如下:

//这是一个弓箭手类

class Bower

{

private int posX;    //弓箭手在地图上X的坐标

private int posY;    //弓箭手在地图上Y的坐标

private int ID;        //弓箭手在地图上Y的坐标

private int lifeNum;   //弓箭手的生命值

private int attackNum;      //弓箭手的攻击力

private int untenNum;      //弓箭手的防御力

//构造函数,生产一个弓箭手,传入参数为在地图中的坐标

public Bower( int IDNum, int x, int y )

{

posX=x;         //弓箭手生产出来后在地图上X的坐标

posY=y;         //弓箭手生产出来后在地图上Y的坐标

lifeNum= 245; //弓箭手的默认生命值

attackNum=16;      //弓箭手的默认攻击力

untenNum=0;  //弓箭手的默认防御力

ID=IDNum;    //弓箭手的ID

System.out.println("弓箭手 "+ID+"生产完毕了");

}

//默认构造函数

public Bower(  )

{

}

/******

一般来说,生命值,攻击力,防御力等都属于对象的核心数据,对它们

的访问必须要严格控制,所以设计出getLifeNum(),getAttackNum(),

getUntenNum()这三个方法

*/

//获取弓箭手的剩余生命值

public int getLifeNum()

{

return lifeNum;

}

//获取弓箭手的攻击力

public int getAttackNum()

{

return attackNum;

}

//获取弓箭手的防御力

public int getUntenNum()

{

return untenNum;

}

//获取弓箭手的ID号

public int getID()

{

return ID;

}

//获取弓箭手的X坐标

public int getX()

{

return posX;

}

//获取弓箭手的Y坐标

public int getY()

{

return posY;

}

//弓箭手移动的行为,就是一般情况下用点击了

//一个弓箭手后命令弓箭手移动到某个位置所用的方法

//传入参数为要移动到的对象

public void moveTo( Ghost gs )

{

posX=gs.getX();

posY=gs.getY();

System.out.println( "弓箭手"+ID+"移动到地点 "+posX+","+posY );

}

//用弓箭手攻击食尸鬼的方法,传入的参数为攻击的对象

//附:本人感觉这个攻击行为抽象的设计非常差,如果有好的方法,

//敬请指教

public void attackByBow( Ghost gs )

{

gs.getHunt( this );

}

//受到攻击时调用这个方法计算伤害值

public void getHunt( Ghost gs )

{

//只有在食尸鬼和弓箭手都没死亡的前提下会攻击

if( gs.getLifeNum()>0 && getLifeNum()>0 )

{

//如果受到的攻击值大于自身的生命值表示对象死亡

if( (gs.getAttackNum()-getUntenNum())>=lifeNum )

{

lifeNum=0;

System.out.print("弓箭手"+getID()+"受到食尸鬼"+gs.getID());

System.out.print("的攻击力"+gs.getAttackNum());

System.out.println(",弓箭手"+ID+"死亡");

}

else //用生命值减去受到的伤害值

{

lifeNum=lifeNum-(gs.getAttackNum()-getUntenNum());

System.out.print("弓箭手"+getID()+"受到食尸鬼"+gs.getID());

System.out.print("的攻击力"+gs.getAttackNum());

System.out.println(",剩余生命值为"+getLifeNum());

}

}

}

}

对于食尸鬼,可以用同样的抽象方法成一个食尸鬼类

//这是一个食尸鬼类

class Ghost

{

private int posX;    //食尸鬼在地图上X的坐标

private int posY;    //食尸鬼在地图上Y的坐标

private int ID;        //食尸鬼在地图上Y的坐标

private int lifeNum;   //食尸鬼的生命值

private int attackNum;      //食尸鬼的攻击力

private int untenNum;      //食尸鬼的防御力

//构造函数,生产一个食尸鬼,传入参数为在地图中的坐标

public Ghost( int IDNum,int x, int y )

{

posX=x;         //食尸鬼生产出来后在地图上X的坐标

posY=y;         //食尸鬼生产出来后在地图上Y的坐标

lifeNum= 245; //食尸鬼的默认生命值

attackNum=12;      //食尸鬼的默认攻击力

untenNum=0;  //食尸鬼的默认防御力

ID=IDNum;    //食尸鬼的ID

System.out.println("食尸鬼 "+ID+"生产完毕了");

}

//默认构造函数

public Ghost(  )

{

}

//获取食尸鬼的剩余生命值

public int getLifeNum()

{

return lifeNum;

}

//获取食尸鬼的攻击力

public int getAttackNum()

{

return attackNum;

}

//获取食尸鬼的防御力

public int getUntenNum()

{

return untenNum;

}

//获取食尸鬼的ID号

public int getID()

{

return ID;

}

//获取食尸鬼的X坐标

public int getX()

{

return posX;

}

//获取食尸鬼的Y坐标

public int getY()

{

return posY;

}

//食尸鬼移动的行为,就是一般情况下用点击了

//一个食尸鬼后命令食尸鬼移动到某个位置所用的方法

//传入参数为要移动到的对象

public void moveTo( Bower bo )

{

posX=bo.getX();

posY=bo.getY();

System.out.println( "食尸鬼"+ID+"移动到地点 "+posX+","+posY );

}

//用食尸鬼攻击弓箭手的方法,传入的参数为攻击的对象

//附:本人感觉这个攻击行为抽象的设计非常差,如果有好的方法,

//敬请指教

public void attackByWater( Bower bo )

{

bo.getHunt( this );

}

//受到攻击时调用这个方法计算伤害值

public void getHunt( Bower bo )

{

//只有在食尸鬼和弓箭手都没死亡的前提下会攻击

if( bo.getLifeNum()>0 && getLifeNum()>0 )

{

//如果受到的攻击值大于自身的生命值表示对象死亡

if( (bo.getAttackNum()-getUntenNum())>=lifeNum )

{

lifeNum=0;

System.out.print("食尸鬼"+getID()+"受到弓箭手"+bo.getID());

System.out.print("的攻击力"+bo.getAttackNum());

System.out.println(",食尸鬼"+ID+"死亡");

}

else //用生命值减去受到的伤害值

{

lifeNum=lifeNum-

(bo.getAttackNum()-getUntenNum());

System.out.print("食尸鬼"+getID()+"受到弓箭手"+bo.getID());

System.out.print("的攻击力"+bo.getAttackNum());

System.out.println(",剩余生命值为"+getLifeNum() );

}

}

}

}

那么现在我们根据上面写的类,用一段代码模拟玩家生产了一个弓箭手去攻击对手不死族的食尸鬼这个过程

程序运行后结果如下图所示

class GameStart

{

public static void main( String args[] )

{

//下面一段代码产出了一个食尸鬼

Ghost gs= new Ghost( 1, 90, 90 );

//下面这两行代码表示玩家创建了两个弓箭手,相当于玩家按了两下生产弓箭手的按钮

Bower bo1= new Bower( 1, 180, 180 );

Bower bo2= new Bower( 2, 180, 180 );

//这里的设计就能体现面向对象的好处:

//1.直观,把弓箭手移动到食尸鬼的位置代码为bo1.moveTo( gs ),

//  从字面上就能理解这句代码的含义

//2.把程序员从繁琐的移动细节中解放出来,我们只需要调用弓箭手的

//  方法命令弓箭手移动,至于弓箭手移动时走路的方式如何,是走直线还是

//  曲线,这些都不需要在这里写代码,因为这些内容都是封装在类的内部处理

//下面这两行代码表示玩家指挥两个弓箭手移动到要攻击的食尸鬼的位置,

//相当于玩家指挥两个弓箭手走向食尸鬼

bo1.moveTo( gs );

bo2.moveTo( gs );

//这里也同样体现了面向对象编程的好处,我们只需要给弓箭手发出

//攻击的命令就行,至于攻击的细节(用手还是用脚,攻击的力度等)都是

//封装在类的内部实现,程序员调用这个方法时不需要理会里面的细节

//下面的while循环是两个弓箭手开始攻击食尸鬼攻击的过程

//为了编写代码的方便性,假设弓箭手和食尸鬼相遇时才互相攻击,

//没有远程攻击手段,只站在原地互相攻击,请各位魔兽玩家原谅我吧^-^

//攻击过程抽象如下(有点像回合制的RPG游戏^-^)

//1.弓箭手1攻击食尸鬼后食尸鬼反击弓箭手1

//2.弓箭手2攻击食尸鬼后食尸鬼反击弓箭手2

//3.如果食尸鬼或两个弓箭手都没死亡就重复1,2的过程

while( true )

{

//弓箭手1攻击食尸鬼

bo1.attackByBow( gs );

//如果食尸鬼没死亡就反击

gs.attackByWater( bo1 );

//弓箭手2攻击食尸鬼

bo2.attackByBow( gs );

//如果食尸鬼没死亡就反击

gs.attackByWater( bo2 );

//攻击结束的条件是以下两个条件之一(当生命值等于0时表示死亡)

//1.食尸鬼死亡

//2.两个弓箭手死亡

if( (gs.getLifeNum()==0) || (bo1.getLifeNum()==0 && bo2.getLifeNum()==0) )

{

break;

}

}

//根据食尸鬼的生命值是否等于0判断任何

if( gs.getLifeNum()>0 )

{

System.out.println("两个弓箭手死亡,任务失败");

}

else

{

System.out.println("食尸鬼死亡,任务成功");

}

}

}

图5

后记:

面向对象思想是贴近于生活的,但生活中的内容实在是太多太复杂,不容易从中学习面向对象的思想,本人偶然的机会下发现“魔兽争霸”这个包含了丰富面向对象思想的游戏(严格意义上生活中的每个东西或多或少都包含了面向对象的思想),而且面向对象的元素特别清晰,正如在本文中论述的一样,行为,熟悉,类,实例等面向对象的元素在游戏中都有清晰的表示(很多都是在游戏画面显示出来的,告诉你哪些是对象的属性,哪些是对象的方法),而且很多同学对这个游戏有相当的感性认识,用这个游戏讲解面向对象,能增加亲切感,减少学习的难度。

声明一下,本人不是鼓励各位只要玩游戏就能学好编程,初学编程最重要的是动手实践写程序,阅读本文的读者请切记切记切记!!!

最后说一下,本文中所写的代码可以改进的内容实在太多!!!我们知道面向对象有三大特性:封装,继承,多态,本文的代码只是用到了封装这个特性,而继承和多态都没有涉及到。我们仔细审视一遍所有的代码可发现,弓箭手类Bower和食尸鬼类Ghost还是有相当多的相同之处,但代码中却把他们相同的内容重复写了一遍,其实我们可以用面向对象中的继承的思想,把弓箭手类Bower和食尸鬼类Ghost相同的属性和行为都抽象为一个战士基类,使弓箭手类Bower和食尸鬼类Ghos都继承于这个战士基类; 另外在弓箭手类Bower和食尸鬼类Ghost的攻击方法中,其实无论是攻击谁,攻击的手段都是一样的,没必要为不同的攻击对象单独写一个方法,这时就能用到多态的思想改进代码。

上面论述的改进内容,将在下篇文章《用面向对象的思想探讨游戏“魔兽争霸”(2)》中实现。

本人才疏学浅,对于文中出现的各种错误,敬请各位大侠指出!!!个人的联系方式:zengjiansheng1@126.com 或者在博客上留言

最后附上本文的思维导图:

(图片博客上不能显示完整,请保存到本地后再查看)

用面向对象的思想探讨游戏“魔兽争霸”(1)相关推荐

  1. Silverlight游戏设计(Game Design):(五)面向对象的思想塑造游戏对象

    传说,面向对象的开发模式最初是因为程序员偷懒而不小心诞生的.发展至今,人们从最初的热忠于讨论某某语言是否足够面向对象到现在开始更广泛的关注面向对象的思想而不是具体内容.面向对象的思想其实并不深奥,它存 ...

  2. 某公司要开发新游戏,请用面向对象的思想,设计游戏中的蛇怪和蜈蚣精

    某公司要开发新游戏,请用面向对象的思想,设计游戏中的蛇怪和蜈蚣精 设定 蛇怪类: 属性包括:怪物名字,生命值,攻击力 方法包括:攻击,移动(曲线移动),补血(当生命值<10时,可以补加20生命值 ...

  3. 【用C++面向对象的思想以及STL完成贪吃蛇游戏】

    1. 前言 1.1 目的 以前对STL的知识不怎么关心,最近在工作中觉得工程代码用到STL的地方太多了,没看懂,再不补一补就快秃头了,于是秉承着学习的态度,重温了C++ STL,然后就想到了可以写个贪 ...

  4. U3D 飞机大战(MVC模式)解析--面向对象编程思想

    在自己研究U3D游戏的时候,看过一些人的简单的游戏开发视频,写的不错,只是个人是java web 开发的人,所以结合着MVC思想,对游戏开发进行了一番考虑. 如果能把游戏更加的思想化,分工化,开发便明 ...

  5. 基于STM32F103移植华为LiteOS_任务挂起与恢复_面向对象编程思想之按键状态机

    华为LiteOS_任务挂起与恢复_面向对象编程思想之按键状态机 因为在做华为LiteOS任务挂起和恢复需要使用到按键去触发任务挂起和恢复动作,因为我就萌发出使用状态机这种架构做一个按键检测触发.回想已 ...

  6. 面向对象编程java小游戏_JavaScript面向对象编程小游戏---贪吃蛇代码实例

    1 面向对象编程思想在程序项目中有着非常明显的优势: 1- 1 代码可读性高.由于继承的存在,即使改变需求,那么维护也只是在局部模块 1-2 维护非常方便并且成本较低. ​2 这个demo是采用了面向 ...

  7. JS用面向对象的思想实现的购物车

    JS用面向对象的思想实现的购物车 首先先了解面向对象的编写思想. 有面向过程的编程和面向对象的编程. 面向过程:举一个经典例子:把大象放进冰箱里. 首先第一个过程是先打开冰箱,2.然后就是把大象放进去 ...

  8. 《黄帝内经》从养生到面向对象的思想!

    "是以志闲而少欲,心安而不惧,形劳而不倦,气从以顺,各从其欲,皆得所愿." 我们不能简单地以现在的白话文来理解古文.而最简单理解古文的方法是按汉字的象形意思来解, 还有一种方法就是 ...

  9. 信不信?以面向对象的思想是可以写好高并发程序的!

    来自:冰河技术 前言 面向对象思想与并发编程有关系吗?本来二者是没有什么鸟关系的!它们是分属两个不同的领域,但是,Java却将二者融合在一起了!而且融合的效果不错:我们利用Java的面向对象的思想能够 ...

最新文章

  1. 嫌Terminal终端太单调?快收下这几个有趣的改造工具!
  2. 呼之欲出的量子计算机和漫长的最后一公里
  3. 宏基因组序列物种分类之kraken 1/2和Bracken的使用
  4. js 原生跨页面通信_DOM操作是跨线程的你知道吗?
  5. linux nfs搭建
  6. 手机号验证_国际手机号收不到微博验证短信,微博验证短信一直提示超过上限怎么办?...
  7. shell实例第7讲:awk命令
  8. JSP response request 中文乱码
  9. java 日期处理 口诀_java时间处理常用方法工具类
  10. 软件开发生命周期模型
  11. vlc_for_android(基于git-3.0.0)快速集成并播放电视节目直播
  12. 使用JSON和Jersey的Java RESTful Web服务
  13. AntDesign前端分页
  14. 分销系统开发 三级分销技术开发
  15. java 两点间距离_Java实现控制台输出两点间距离
  16. Selenium与phantomjs安装与环境配置,以及易班网站模拟登陆操作
  17. 公告栏模板php代码,destoon调用自定义模板及样式的公告栏_PHP教程
  18. 复化辛浦生求积算法C++实现
  19. 算法导论第三章思考题
  20. java毕业论文云笔记_《毕业设计指导的系统设计与实现》论文笔记(八)

热门文章

  1. android p 华为p10,华为P10测评:市场上真心没有比华为更强劲的安卓机了
  2. 使用vue实现网上电影票购票选座
  3. 可调电容器调谐调频原理介绍
  4. 东哥套现,大佬隐退?
  5. 2022年上半年电影、书
  6. 一级造价工程师(安装)- 计价笔记
  7. 二叉搜索树(BST)删除节点--思路清晰
  8. Python字符与ASCII码的相互转换函数
  9. c语言位与运算的作用,c语言位运算符的用法
  10. 屏蔽优酷广告手动修改方法 (xp win7均有效)