`
newjueqi
  • 浏览: 12051 次
  • 性别: Icon_minigender_1
  • 来自: 广州
社区版块
存档分类
最新评论

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

    博客分类:
  • java
阅读更多

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

【文章作者】曾健生

【作者邮箱】zengjiansheng1@126.com

【作者QQ190678908

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

                     http://newjueqi.iteye.com/

【编程环境】JDK 1.6.0_01

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

 

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

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

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

 

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

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

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

(1)       我们玩“魔兽争霸”游戏是在一个地图(是指2D地图)中进行,如果现在有一个人族的农民站在地图上,那么这个农民在地图上有个坐标(坐标的原点是地图左下角),譬如是农民的坐标(200100),那么在地图上的标识如下(图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坐标

<span style

  • 大小: 17.3 KB
  • 大小: 97.8 KB
  • 大小: 115.3 KB
  • 大小: 43.5 KB
  • 大小: 164.8 KB
  • 大小: 137.3 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics