Circular inclusion problem

Started by
14 comments, last by Yxjmir 6 years, 6 months ago

Entity.h

Update Paddle.h the same way, by removing include "GameMode.h", and other things related to GameMode


#pragma once
#include "SDL2\SDL.h"
#include "Utility.h"
using namespace util;

enum class PivotMode: Uint8 {CENTER,TOP_LEFT};

class Entity
{
protected://variables
	float XCenter;
	float YCenter;
	SDL_Rect CollisionBox;
	SDL_Texture* Sprite;
	SDL_Renderer* Renderer;	// This can also be moved outside of this class if needed

public://constructors
	Entity(PivotMode inputMode, int x, int y, std::string path);
	virtual ~Entity();
	Entity(const Entity&) = delete;
	Entity& operator=(const Entity&) = delete;
	Entity(Entity&&) = delete;
	Entity& operator=(Entity&&) = delete;

public://methods
	virtual void Update(float deltaTime) = 0;
	virtual void Draw(float interpolation) = 0;

private://methods
	void SetTexture(SDL_Texture* texture)const; // Call this from the new class below to set the enitity's texture
	void SetCollisionBox(int x, int y, PivotMode InputMode);
};

GameMode.h

Removed #include "Entity.h" and #include "Paddle.h", also removed class declarations:

class Entity;

class Paddle;


#pragma once
#include "SDL2\SDL.h"
#include <string>
#include <vector>
#include <memory>
#include "App.h"

class GameMode
{
	friend class App;
private://variables
	bool Running;
	SDL_Window* Window;
	SDL_Renderer* Renderer;
	App* AppRef;

public://constructors
	GameMode(SDL_Window* Window, SDL_Renderer* Renderer, App* App);
	~GameMode();

	GameMode(const GameMode&) = delete;
	GameMode& operator=(const GameMode&) = delete;	
	GameMode(GameMode&&) = delete;
	GameMode& operator=(GameMode&&) = delete;

public://methods
	SDL_Texture* RequestTexture(std::string path)const;
	bool IsRunning()const;
	SDL_Renderer* GetRenderer()const;

private://methods
	void Update(float deltaTime);
	void Draw(float interpolation);
};

ClassName.h


#include "Paddle.h"
#include "GameMode.h"

class ClassName
{
	GameMode* m_pGameMode;
	std::list<Entity*> m_pEntities; // List of all entities, does not have to include paddle if you include the following line
	// but you have make sure you update and render the paddle and this list.
	
	Paddle* m_pPaddle;	// I've only included this for easier access to the paddle

	// Other class variables/functions
}

ClassName.cpp


ClassName::ClassName(GameMode* gameRef) : m_pGameMode{ gameRef }
{
	if (m_pGameMode) { Renderer = m_pGameMode->GetRenderer(); }
	// You can comment this out, and create and initialize m_pGameMode here, but its not necessary
}

ClassName::~ClassName()
{
}

SDL_Texture* ClassName::RequestTexture(std::string path)const
{
	if (m_pGameMode->IsRunning())
	{
		return m_pGameMode->RequestTexture(path);
	}
	return nullptr;
}

// Other Funtions

You probably won't have to worry about the last part of my previous post, but if you started using shared_ptr or something similar, then you'd have a potential memory leak. Basically, two classes would not let go of their references to each other until the other one did, so they never would, I don't know how to put it simpler than that, so if you still don't understand, then look it up.

Advertisement

So the benefit of doing that would be that I store only 1 pointer to GameMode (as opposed to 1 per entity) and I pass 1 less argument at Entity construction, right?

I don't know, doesn't seems worth adding another layer of complexity, currently GameMode is holding the vector<unique_ptr<Entity>> so I could instead assign the GameMode "this" to a global GameMode* during GameMode construction so that every Entity can see and use it.

Unless I am missing some other benefit, doesn't seems worth adding one more layer :/

I didn't see that vector<unique_ptr<Entity>> in GameMode.h, which means the class isn't actually holding onto it, unless you left it out in your post.

You can just use GameMode the same way as my "class ClassName" example. This will require you to include Paddle.h in GameMode.h or GameMode.cpp if the entity list is stored there. You still won't need the forward declarations for those Entity or Paddle in GameMode.h regardless. And Neither Paddle.h or Entity.h (or their cpp files) should include GameMode.h.

32 minutes ago, MarcusAseth said:

so I could instead assign the GameMode "this" to a global GameMode* during GameMode construction so that every Entity can see and use it.

Yes you could, but Entity/Paddle don't need to have access to GameMode or use data from it. GameMode already has access to them, and should be able to manipulate/set their data as it needs to.

I was actually going to suggest this first, but a lot of people don't like having even one global variable at all, so I figured I'd offer another solution. There's nothing wrong with this, as long as you don't start doing it for all of you classes.

I hope this makes sense.

44 minutes ago, Yxjmir said:

I didn't see that vector<unique_ptr<Entity>> in GameMode.h, which means the class isn't actually holding onto it, unless you left it out in your post.

My bad, is a modify I made after this topic was posted. Though I don't think I can remove #include GameMode.h from the cpp files of the entities because they need more than a forward declare in order to call methods on GameMode :\

13 hours ago, MarcusAseth said:

I don't think I can remove #include GameMode.h from the cpp files of the entities because they need more than a forward declare in order to call methods on GameMode :\

I think you're missing the point. GameMode can send the texture, and whatever else it needs to, to the Entity when the Entity or unique_ptr<Entity> is created. All you have to do is make "SDL_Texture* Sprite;" a public variable in the Entity class so GameMode can access it, or create a "SetTexture(SDL_Texture* sprite)" function that GameMode calls and supplies with the texture as a parameter.

The only other thing that I saw that might require GameMode.h to be included in Entity.cpp is SDL_Renderer* Renderer; but you already have it in the GameMode class, so Entity doesn't need to store it.


class GameMode
{
	friend class App;
private://variables
	bool Running;
	SDL_Window* Window;
	SDL_Renderer* Renderer;	// <-- Just send this to each Entity during Entity::Draw if needed
	App* AppRef;

public://constructors
	GameMode(SDL_Window* Window, SDL_Renderer* Renderer, App* App);
	~GameMode();

Its up to you whether or not to do this, I'm just trying to explain it so you can see how its possible.

This topic is closed to new replies.

Advertisement