php开发面试题---游戏面向对象设计与分析实例

一、总结

一句话总结:

不要光空想,多看几个实例就知道自己的游戏该怎么设计了
根据实例去理解面向对象编程的的六大原则

1、英雄种类分别有:战士、法师、牧师、刺客等,那么对应的英雄类如何设计?

英雄基类,战士、法师、牧师、刺客分别是这个类的子类

2、购买道具方法和出售道具方法为什么在道具类中而不在玩家类中?

只能道具才知道自己能卖出多少钱:每个对象的数据只能由自己来访问和处理,如果其他对象想修改某个对象里的状态(数据),则只能调用其提供的public方法

在前面的所有类图中,我们可以看到,每个类中的属性都不是public的,如果是父类中,使用protected,这样子类才能访问,而如果是在子类中,则使用的是private,意思为这属性是我特有的,且其他类不能直接访问。这是类设计的一个基本原则:每个对象的数据只能由自己来访问和处理,如果其他对象想修改某个对象里的状态(数据),则只能调用其提供的public方法。

而我们需要出售道具时,需要把卖出价格增加到玩家的钱包中。而玩家是不应该可以访问道具的卖出价格的,因而,出售功能应由道具来提供,因为只能道具才知道自己能卖出多少钱!同样,购买功能也是如此,应由道具来提供。

3、戒指增加的属性很多但是总属性条数有限,那么戒指类如何设计?

戒指基类包含全部【加成属性方式】,然后如果没有这种【加成属性方式】的话,就把该【加成属性方式】置为空

4、引起类膨胀的实例?

每种不同的戒指都设置为一个不同的类

每款戒指都继承于戒指类。但这种设计有很大的缺陷,由于加成方式有很多,如一款戒指的功能为【攻击力加30%,每秒加3点血】,而另一款戒指的功能为【增加100%的爆击率】。这两款戒指的属性的数量都不相同,功能也不一样,因而每款戒指都应为一个子类。那假如我有很多不同功能的戒指,岂不是需要很多子类?这样的话,就会引起类的膨胀!

5、戒指【每3秒自动回复10%的HP】、【每5秒自动回复10%的HP】这些功能如何实现?

抽象出一个功能类,然后戒指类拥有一个功能类的集合

6、面向对象原则总结(BattleHeart(战争之心)游戏实例)?

1、 谁拥有数据,则由谁来处理数据,并对外提供处理的方法。如只有道具才知道它自己的售价,因而出售的方法应由道具来提供。
2、 设计应能进行扩展,如我需要增加一个英雄种类,我只需要继承英雄类。
3、 应使用多个专门的接口,与可画和可被触摸没什么关联性,因而应把它们分开成两个接口来设计。
4、 设计应能防止出现类的膨胀,可适当地使用组合来代替继承。

7、游戏的画面是怎么画出来的?

游戏其实和电影一样,都是一帧一帧快速地切换显示(其中一帧可以理解为一幅画),以达到动态的效果

8、游戏的画面在画的时候如何让它有立体感?

背景先画

出现在最下面东西(如背景)的先画,出现在最上面的最后画(如英雄),如此按顺序地画,那么画出来的效果就是:最后画的,会覆盖前面画的。如果背景是一条路,这样看上去英雄就站在路上了!

二、面向对象设计与分析实例(转)

转自:面向对象设计与分析实例
https://www.cnblogs.com/zknublx/p/6093875.html

面向对象程序设计有5条基本设计原则,分别是:单一职责原则、开放封闭原则、依赖倒置原则、接口隔离原则和Liskov替换原则,但对于初学者来说,这5条基本设计原则可能有点难以理解。

下面我以BattleHeart(战争之心)这款角色扮演类的手机游戏(已从IOS移植到Android了)为背景,分析一下其中的类的设计(注:以下为个人的设计想法,因此可能与这款游戏真实的设计有所不同)。

这款游戏中可以操作4个英雄,英雄种类分别有:战士、法师、牧师、刺客等。每个英雄都拥有自己的技能、都能够装备武器、衣服、戒指等。

其中,无论是战士、法师或者其他种类的英雄,他们都有一些共同的属性,如:HP、ATK(攻击力)、DEF(防御力)、POS(位置)、人物形象、各种装备、各种技能等

因此,我们可以设计出一个公共的英雄类,如下图所示:

注:这里只列出部分属性,可根据需要增加或减少。

注:#代表为protected –代表private +代表public

而每种英雄,则又都有各自不同的地方。如:攻击方式不同,其中战士是近身攻击、法师是远程攻击、牧师是加血等。因此,不同种类的英雄,攻击方式的实现也就不一样。所以,我们可以给英雄增加一个抽象方法——攻击,然后由不同的子类来作对应的实现,如下图所示:

游戏中,每个英雄都可以装备一些武器之类的道具,而道具又分很多种类,一类是可以被装备的,一类是可以使用的消耗品。由于本游戏中只有可以被装备的道具种类,因此道具的设计比较简单。道具的属性有:形象(即我们看到的样子)、买入价格、卖出价格等。又因为武器是加攻击力这类伤害属性的,而衣服则是加防御力这类减伤属性的,戒指是加一些特殊属性的。所以如果把这些属性都放在道具类中,道具类的属性就会显得很庞大。再者当道具为武器时,衣服相关的属性相对来说是没有意义的。因而我们可以把武器、衣服、戒指等作为道具的子类,再加入自己需要的属性。设计如下图所示:

其中,所有道具都应有购买和出售功能,因而,可在道具类中加入购买和出售方法,如下图所示:

这里,可能有些人会觉得很奇怪,我们玩游戏时,购买道具和出售道具不是由我们来操作的么?那不是应该把购买和出售功能放到玩家类中?(注:玩家类是对我们游戏中玩家的一个抽象,这里我就不做设计了)

在前面的所有类图中,我们可以看到,每个类中的属性都不是public的,如果是父类中,使用protected,这样子类才能访问,而如果是在子类中,则使用的是private,意思为这属性是我特有的,且其他类不能直接访问。这是类设计的一个基本原则:每个对象的数据只能由自己来访问和处理,如果其他对象想修改某个对象里的状态(数据),则只能调用其提供的public方法。

而我们需要出售道具时,需要把卖出价格增加到玩家的钱包中。而玩家是不应该可以访问道具的卖出价格的,因而,出售功能应由道具来提供,因为只能道具才知道自己能卖出多少钱!同样,购买功能也是如此,应由道具来提供。

仔细的人可能会发现一个问题——出售道具时,玩家的金钱应该是会增加的,而购买道具时,玩家的钱应该会减少。而在上面的设计中,道具在出售时,只知道卖出价格,但却不知道玩家是谁,因而无法给玩家增加金钱!所以应修改上面的设计,使得道具能知道自己的拥有者是谁!如下图所示:

而由于金钱的属性是属于玩家类的,道具不应该能直接访问,所以玩家应该有一个方法提供给道具来增加金钱!这里我给出一个简单的玩家类设计(这个玩家类只满足道具类可以使用,真正的设计会更加复杂),如下图所示:

大家可能有注意到,上面的戒指类的设计有点问题。在这款游戏中,戒指的作用是属性的加成。但由于属性种类有很多(如命中率、爆击率等),而每款戒指的加成所针对的属性不一致。因而,我们可以使用一种设计——每款戒指都继承于戒指类。但这种设计有很大的缺陷,由于加成方式有很多,如一款戒指的功能为【攻击力加30%,每秒加3点血】,而另一款戒指的功能为【增加100%的爆击率】。这两款戒指的属性的数量都不相同,功能也不一样,因而每款戒指都应为一个子类。那假如我有很多不同功能的戒指,岂不是需要很多子类?这样的话,就会引起类的膨胀!这种设计显然是不合理的。

那我们应该如何设计呢?我们知道,每个英雄的属性值是有限的,而每个戒指可能拥有的【加成属性方式】有多种,但这些戒指的【加成属性方式】却是有限的。既然这样,那我们是不是可以直接让戒指类包含全部【加成属性方式】,然后如果没有这种【加成属性方式】的话,就把该【加成属性方式】置为空。这样,我们只有需要增加【加成属性方式】时,才需要修改戒指类,而不是说每增加一款新的戒指时,就需要增加一个子类!因而,新的设计应该如下所示:

现在感觉好多了吧?但这样的设计是不是就是可以的呢?如果是【每3秒自动回复10%的HP】、【每5秒自动回复10%的HP】这些功能呢?是不是发现这种设计也无法完成这些功能呢?

接下来戒指的设计我就不深谈了,这里我给一个思路:抽象出一个功能类,然后戒指类拥有一个功能类的集合。至于功能类应该有什么属性,提供什么方法,大家可以深入思考一下!

到了这里,其实类的设计有很多地方没考虑和设计(如英雄使用技能,英雄装备武器等),也有很多类也没设计出来(如技能类、怪物类等),但类的设计思想是一样的,所以我就不深入设计了,留给大家进行思考!

 下面,我们考虑一下接口的设计问题。

开发过游戏的都知道(没开发过的也不要紧),游戏其实和电影一样,都是一帧一帧快速地切换显示(其中一帧可以理解为一幅画),以达到动态的效果。而BattleHeart这款游戏,是属于一款2D的角色扮演游戏,因此,我们在画每一帧时,可以使用一种简单的方式——出现在最下面东西(如背景)的先画,出现在最上面的最后画(如英雄),如此按顺序地画,那么画出来的效果就是:最后画的,会覆盖前面画的。如果背景是一条路,这样看上去英雄就站在路上了!

我们看下这款游戏的截图,可以看到,那个英雄和怪物是站在地面(背景)上的,因而是背景先画。而英雄和怪物则是谁在下面,谁就应该显示出来,所以应该把英雄和怪物按Y轴方向从上往下按依次画出来,这样就会有一种立体感。

根据上面类的设计,我们知道,谁拥有数据,谁才能直接操作数据。而这里我们要把这游戏的每一帧画面画出来,显然只有英雄才知道自己长什么样的,只能装备(道具)才知道自己长什么样的,只有怪物才知道自己长什么样的,只有技能才知道自己长什么样的。因而,我们要把一帧画面画出来,就需要去让英雄、怪物、装备及技能等按一定的顺序把自己画出来。

既然它们都能把自己画出来,就应该拥有一个画自己的方法!由于有很多不同的类,都需要有一个画的方法,那么,我们是不是可以把这个方法抽象出来了呢?这里,我设计一个Drawable接口,意为可画,然后里面有一个画自己的方法。设计如下图所示:

接下来,我们在看一下这款游戏的操作。这款游戏是属于IOS下的游戏,且已经移植到Android平台上。由于这两个平台都是触屏的,因而这款游戏的玩法是使用触屏的方式,去操作英雄移动、攻击、使用技能等。

在这里,为了更好地说明下面的设计,我简单地说一下这款游戏的玩法:玩家点击英雄,英雄对应的技能会显示到左上角中,如果这时候再点某个技能,那么该英雄就会去释放出对应的技能。而如果玩家点击了英雄后:

1、 拖动到怪物上,该英雄就会对怪物进行攻击。

2、 拖动到地面上,该英雄就会移动到那里。

3、 拖动到英雄上(前提是该英雄是牧师,否则当作拖动到了英雄那里的地面上),该英雄就会给对应的英雄进行加血。

其他的操作,我就不一一说明了。

显然,在这款游戏中,英雄、技能、道具等都能被触摸,作为输入事件,并引起对应输出(如英雄被选中,英雄移动,技能释放等)。而怪物被触摸后,是不会产生任何效果的。因而我们可以定义一个Touchable(可触摸)的接口,接口中定义一个被触摸的方法。如下图所示:

在上面的设计中,有很多方面比较细节上的设计是没有做的,如怪物是智能攻击的,因而怪物应该有自动选择目标进行攻击的方法。同时,可以设计一个专门管理怪物的Factory(工厂)来控制怪物的自动产生等等。

或许会有人问,这样面向对象的设计有什么好处呢?下面我来以上图的设计,写一段半伪代码,给大家感受一下这样设计的好处。

由于每个平台画图的函数思想类似,但写法不同,所以下面不会出现平台相关的写法。

由于Java是一门面向对象的程序设计语言,下面我使用Java代码来写。

public class GameView {

//可以被触摸的东西的集合,如英雄、技能、道具等

List<Touchable>  touchable;

//可以被画的出来东西的集合,如英雄、怪物、技能等,都应该这里

List<Drawable>  drawables;

…其他属性和方法的实现等

public void 画界面(Graphics g) {

for(Drawable d : drawables) {

d.画自己();

}

}

public boolean 界面被触摸() {

for(Touchable t : touchables) {

boolean isDeal = t.被触摸();

if(isDeal) {

return isDeal;

}

}

return false;

}

}

英雄画自己和被触摸的功能都可以直接放到英雄类中实现,而不需要放到其子类(战士、法师等)中实现。

英雄的伪代码如下:

public abstract class 英雄 implements Touchable, Drawable {

…这里是各种各样的属性和方法

public abstract void 攻击();

public abstract boolean 识别触摸事件是否为攻击();

public boolean 被触摸() {

if(识别触摸事件是否为攻击()) {

攻击();

return true;

}

}

public void 画自己() {

//把自己画出来

}

}

文章写到这里,差不多已经要结束了。上面的设计并不完整,且已经设计的部分可能还有一些没考虑周到的地方,欢迎大家讨论并指正。

在结束之前,我对本文做个总结:

1、 谁拥有数据,则由谁来处理数据,并对外提供处理的方法。如只有道具才知道它自己的售价,因而出售的方法应由道具来提供。

2、 设计应能进行扩展,如我需要增加一个英雄种类,我只需要继承英雄类。

3、 应使用多个专门的接口,与可画和可被触摸没什么关联性,因而应把它们分开成两个接口来设计。

4、 设计应能防止出现类的膨胀,可适当地使用组合来代替继承。

最后,回到一开始所说的5条基本设计原则,具体的大家可以百度一下,会有很多说明的。大家可以对照这个实例,理解一下这5条基本设计原则的含义!

 

php开发面试题---游戏面向对象设计与分析实例的更多相关文章

  1. php开发面试题---php面向对象详解(对象的主要三个特性)

    php开发面试题---php面向对象详解(对象的主要三个特性) 一.总结 一句话总结: 对象的行为:可以对 对象施加那些操作,开灯,关灯就是行为. 对象的形态:当施加那些方法是对象如何响应,颜色,尺寸 ...

  2. python3 开发面试题(面向对象)6.6

    """ 封装.继承.多态 1. 谈谈你对面向对象的理解? 2. Python面向对象中的继承有什么特点? 3. 面向对象深度优先和广度优先是什么? 4. 面向对象中sup ...

  3. 100个iOS开发面试题汇总-王刚韧的技术博客

    100个iOS开发面试题汇总 关于iOS开发面试,不管对于招聘和应聘来说,面试都是很重要的一个环节,特别对于开发者来说,面试中的技术问题环节不仅是企业对应聘者技能和积累的考察,也是一个开发者自我检验的 ...

  4. 前端开发面试题总结之——JAVASCRIPT(一)

    ___________________________________________________________________________________ 相关知识点 数据类型.运算.对象 ...

  5. J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP

    J2EE进阶(十四)超详细的Java后台开发面试题之Spring IOC与AOP 前言   搜狐畅游笔试题中有一道问答题涉及到回答谈谈对Spring IOC与AOP的理解.特将相关内容进行整理.    ...

  6. 100个iOS开发面试题汇总

    100个iOS开发面试题汇总 关于iOS开发面试,不管对于招聘和应聘来说,面试都是很重要的一个环节,特别对于开发者来说,面试中的技术问题环节不仅是企业对应聘者技能和积累的考察,也是一个开发者自我检验的 ...

  7. 【理论面试篇】收集整理来自网络上的一些常见的 经典前端、H5面试题 Web前端开发面试题

    ##2017.10.30收集 面试技巧 5.1 面试形式 1)        一般而言,小公司做笔试题:大公司面谈项目经验:做地图的一定考算法 2)        面试官喜欢什么样的人 ü  技术好. ...

  8. [转]linux C/C++服务器后台开发面试题总结

    linux C/C++服务器后台开发面试题总结  https://www.cnblogs.com/nancymake/p/6516933.html 一.编程语言 1.根据熟悉的语言,谈谈两种语言的区别 ...

  9. php开发面试题---lavarel和tp的区别是什么(呕心整理)

    php开发面试题---lavarel和tp的区别是什么(呕心整理) 一.总结 一句话总结: 反思的回顾非常有用,因为决定了我的方向和技巧 以战养己,这是非常非常好的方式 主要从大小.功能.安全性.操作 ...

随机推荐

  1. hdu 5279 YJC plays Minecraft——生成函数

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5279 令 n 个点的树的 EGF 是 g(x) ,则 \( g(x) = \sum\limits_{i=0 ...

  2. [CSP-S模拟测试52]题解

    A.平均数 看到第K小,又确定跟平衡树/主席树没有关系,可以把问题转化为有K-1个答案比它小再考虑二分. 二分平均值x,之后将原序列统一减去x.这时序列中区间和<0的区间个数就是原序列中平均值小 ...

  3. 【Tomcat】2.配置Tomcat服务器端口和HTTPS

    1.修改XML配置文件 找到Tomcat安装目录下的conf文件夹,打开server.xml文件(可以用笔记本打开) 其中有几行代码如下 <Server port="8005" ...

  4. 【Tomcat】1.Tomcat在Windows系统的安装和使用

    1.下载与安装 安装Tomcat的[前提条件]是安装好JDK或者JRE(本文略过)Tomcat在Windows系统中可以通过[压缩包]或[安装包]来安装建议使用[安装包]来简化安装步骤登录官网http ...

  5. PAT 1036 Boys vs Girls (25 分)

    1036 Boys vs Girls (25 分)   This time you are asked to tell the difference between the lowest grade ...

  6. (10)C++ 使用类

    一.运算符重载 1. #include<iostream> using namespace std; class Sum { int add; public: Sum(int add) { ...

  7. MySQL-视图上进行增删改查

    https://dev.mysql.com/doc/refman/5.7/en/view-updatability.html https://dev.mysql.com/doc/refman/8.0/ ...

  8. 自己写一个 wsgi 服务器运行 Django 、Tornado 等框架应用

    https://blog.csdn.net/heybob/article/details/52288006

  9. QMUI android 框架 git下载项目运行报错解决 input String“”

    1.编译源码,input String“” 解决办法: 打开qmuidemo里面的gradle文件,注释掉顶部的 //def cmd = 'git rev-list HEAD --count'//de ...

  10. 2019杭电多校第六场hdu6638 Snowy Smile(线段树+枚举)

    Snowy Smile 题目传送门 解题思路 先把y离散化,然后把点按照x的大小进行排序,我们枚举每一种x作为上边界,然后再枚举其对应的每一种下边界.按照这种顺序插入点,这是一个压维的操作,即在线段树 ...