Reputation: 559
I have a class Game
with class EnemyManager
. EnemyManager
deals with spawning of enemies and the logic behind it. The problem is that EnemyManager
needs access to functions and other Game
objects in the game class. I can think of two ways to handle this.
Pass the address of the class object Game*
using this
as one of the arguments in the EnemyManager
.
Declare a global pointer to a Game object and set it when initializing the Game
class. Then extern it into the enemymanager.cpp
.
Which is the more advisable way to do this?
Upvotes: 2
Views: 1073
Reputation: 163
It is hard to say without knowing the overall architecture layout, but my 2 cents:
The way you describe as a first one is called the dependency injection and is widely used all around. You should keep an eye on what methods/fields you're making public.
I assume that Game
class has the methods that should not be accessible from the EnemyManager
class, thus is seems like it's a good idea to create the interface which has the declaration of the methods that are used by EnemyManager
and then pass the pointer to the EnemyManager
instance (instead of the Game
).
For example: The Game
class implements IGameEnemyManager
, and you're passing IGameEnemyManager
using this as one of the initialization arguments.
Upvotes: 1
Reputation: 2787
You're absolutely need to use the 1st approach, but with a few changes: you should disintegrate your Game
class to more components. For example you can create a SceneManager
class, which is responsible for all game object's creation/management. When you're instantiating the EnemyManager
- just pass a pointer to it:
// in SceneManager
EnemyManager* emgr = new EnemyManager(this);
InterfaceManager* imgr = new InterfaceManager(this);
Note that your SceneManager
class should provide a complete interface
// in EnemyManager
GameObject* spawnEnemyAt(string name, EnemyClass* eclass, Vector3 position, AIBehaviour* behaviour)
{
GameObject* myEnemy = smgr->createGameObject(name, position, etc...);
//register an enemy in the enemies list, initialize it's behaviour and do any other logic
return myEnemy
}
This approach should help you not to ruin your architecture and not to be captured in the friend
(class)-zone.
[Upd.] Note that my approach assumes that all objects on the scene are GameObject
s, there's neither Enemy
nor Player
classes. Every GameObject
may has a Renderer
, Animator
, AIBehaviour
components.
Upvotes: 0
Reputation: 2019
When dealing with object oriented designs, it is typically good to think about who will act how on what to find a first version of a design. After having written this version, one often finds the weaknesses and rewrite it for the second iteration.
So, in this case, the Game
class manages the world (I assume) and offers different ways to manipulate it. Your EnemyManager
manages one aspect of the world, enemies, but they do live inside the world.
class Enemy {
public:
Enemy(Location& location, int hitpoints);
bool Move(Direction& direction);
};
class Game {
public:
bool CreateInitialState();
bool AddEnemy(Enemy& enemy);
bool AddBullet(Location& location, Direction& direction, int speed);
void Render();
};
class EnemyManager {
public:
EnemyManager(Game& game);
void MoveEnemies();
};
In this first version, all types see each other as proper classes and manipulates things by calling the appropriate method. This offers little support for expanding on the game if you want to add new things to it.
This is where interfaces become handy and you can try to think about how the different parts will interact instead of how they should be implemented.
class Canvas {
public:
// Different graphical primitives.
};
class GameObject {
public:
virtual ~GameObject() {};
virtual void Draw(Canvas& canvas) = 0;
virtual bool Move(Direction& direction) = 0;
};
class GlobalState {
public:
virtual AddGameObject(GameObject& gameObject) = 0;
};
class Game : public Canvas, public GlobalState {
public:
bool CreateInitialState();
void Render() {
// Send itself to the Draw method in all GameObjects that have been added
}
// Other game logic
};
class Enemy : public GameObject {
// This can be specialized even more if you need to
};
class Bullet : public GameObject {
// This can also be specialized even more if you need to
};
This separates design from implementation and, as I see it, is a good way to end up with a proper first attempt.
Upvotes: 1
Reputation: 3288
If you are handling game objects
in EnemyManager
, why is it part of the class Game
? I suppose you should consider reviewing your design as there are chances of circular reference problem if you don't handle the scenarios well.
Consider segregating both the classes to ensure a single responsibility principle.
EnemyManager
Define proper interface in yourto Game object as argument and act on the functions
These are little suggestions that I can think of with limited idea about your design
Upvotes: 0
Reputation: 84
Whenever I encounter situations like this I review the overall design of the related classes. If EnemyManager is a member of a Game object and needs to call things within Game, maybe those functions in Game can be factored out into a separate component. If something you are writing is beginning to feel overly-complex or like a hack it's usually time to do some factoring.
Upvotes: 5