设为首页 加入收藏

TOP

《游戏编程模式》(5)(二)
2017-10-13 10:40:12 】 浏览:4687
Tags:《游戏编程模式》
14 int intValue; 15 double doubleva lue; 16 char* stringValue; 17 }; 18 };

 

Chatper Twelve 子类沙盒

使用基类提供的操作集合来定义子类中的行为。

扁平的继承树比起长纵深的继承树更易用。 

使用情境:

  1. 有一个带有大量子类的基类;
  2. 基类能够提供所有子类可能需要的操作集合;
  3. 希望更简便地共享子类之间重复的代码;
  4. 使子类和程序其他模块的耦合最小化。 

基类:

 1 class Superpower
 2 {
 3 
 4 public:
 5   virtual ~Superpower() {}
 6  
 7 protected:
 8   virtual void activate() = 0;
 9  
10   double getHeroX()
11   {
12     // Code here...
13   }
14 
15   double getHeroY()
16   {
17     // Code here...
18   }
19 
20   double getHeroZ()
21   {
22     // Code here...
23   }
24  
25   void move(double x, double y, double z)
26   {
27     // Code here...
28   } 
29 
30   void playSound(SoundId sound, double volume)
31   {
32     // Code here...
33   } 
34 
35   void spawnParticles(ParticleType type, int count)
36   {
37     // Code here...
38   }
39 
40 };

Activate()就是沙盒函数,子类必须重写这个抽象虚函数。Move()或许和物理引擎有关,playSound()或许和声音模块有关,在基类中实现使得所有的耦合都有SuperPower这个基类来承担。

子类:

 1 class SkyLaunch : public Superpower
 2 {
 3 
 4 protected:
 5   virtual void activate()
 6   {
 7     if (getHeroZ() == 0)
 8     {
 9       // On the ground, so spring into the air.
10       playSound(SOUND_SPROING, 1.0f);
11       spawnParticles(PARTICLE_DUST, 10);
12       move(0, 0, 20);
13     }
14     else if (getHeroZ() < 10.0f)
15     {
16       // Near the ground, so do a double jump.
17       playSound(SOUND_SWOOP, 1.0f);
18       move(0, 0, getHeroZ() - 20);
19     }
20     else
21     {
22       // Way up in the air, so do a dive attack.
23       playSound(SOUND_DIVE, 0.7f);
24       spawnParticles(PARTICLE_SPARKLES, 1);
25       move(0, 0, -getHeroZ());
26     }
27   }
28 
29 };

 

设计决策:

需要提供什么操作(多少操作)

  1. 仅被少数子类使用的操作不必加入基类;
  2. 不修改任何状态的方法调用,不具备侵入性,是个安全的耦合;

避免臃肿的基类:

把相关操作分流到辅助类

 1 class SoundPlayer
 2 {
 3   void playSound(SoundId sound, double volume)
 4   {
 5     // Code here...
 6   }
 7  
 8   void stopSound(SoundId sound)
 9   {
10     // Code here...
11   } 
12 
13   void setVolume(SoundId sound)
14   {
15     // Code here...
16   }
17 };
18 
19 class Superpower
20 {
21 
22 protected:
23   SoundPlayer& getSoundPlayer()
24   {
25     return soundPlayer_;
26   } 
27 
28   // Sandbox method and other operations...
29  
30 private:
31   SoundPlayer soundPlayer_;
32 
33 };

 

基类如何获取所需状态

分段初始化:

构造函数不传参,在第二步传递所需参数

1 Superpower* createSkyLaunch(ParticleSystem* particles)
2 {
3   Superpower* power = new SkyLaunch();
4   power->init(particles);
5   return power;
6 }

 

状态静态化

 1 class Superpower
 2 {
 3 
 4 public:
 5   static void init(ParticleSystem* particles)
 6   {
 7     particles_ = particles;
 8   } 
 9 
10   // Sandbox method and other operations...
11  
12 private:
13   static ParticleSystem* particles_;
14 
15 };

静态变量Particle_不必为每个SuperPower实例所存储,可以减少内存占用。

  

Chatper 13 类型对象

通过创建一个类来支持新类型的灵活创建,其每个实例都代表一个不同的类型对象。

 

类型对象:

 1 class Breed
 2 {
 3 
 4 public:
 5   Breed(int health, const char* attack)
 6   : health_(health),
 7     attack_(attack)
 8   {}
 9 
10   Monster* newMonster() { return new Monster(*this); } 
11 
12   int getHealth() { return health_; }
13   const char* getAttack() { return attack_; } 
14 
15 private:
16   int health_; // Starting health.
17   const char* attack_;
18 
19 };

使用类型对象的类:

 1 class Monster
 2 {
 3   friend class Breed; 
 4 
 5 public:
 6   const char* getAttack() { return breed_.getAttack(); }
 7  
 8 private:
 9   Monster(Breed& breed)
10   : health_(breed.getHealth()),
11     breed_(breed)
12   {}
13  
14   int health_; // Current health.
15   Breed& breed_;
16 
17 };

这样创建一个怪物:

1 Monster* monster = someBreed.newMonster();

Monster的构造函数是private,不能直接调用。友元类Breed绕开了这个限制,可以直接访问

首页 上一页 1 2 3 下一页 尾页 2/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Restful与webService区别 下一篇ASP.NET Zero--4.不使用谷歌字体..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目