MarcusAseth

Control flow based on type in C++

Recommended Posts

Hi guys, I'm not quite sure how to achieve this :S

Here what I got so far, my GameMode class own an object of type Physics:

class Physics
{
private://variables
	GameMode* Game;

public://constructors
	Physics(GameMode* gameRef);
	~Physics();

public://methods
	bool IsColliding(Entity* current, ECollisionTest collisionTestType);

private://methods
	bool BoxCollisionTest(const Rect& current, const Rect& other);
};

And since all my entities have a pointer to the GameMode they can retrieve a pointer to the Physics object, so when they move they can query the Physics object to see if they collided with something, passing "this" as the object to control against all the Entities inside GameMode, like this:

//Collision Check
if (PhysicsManager->IsColliding(this, ECollisionTest::EBoxCollisionTest))
{
	LogConsole("Collision");
}

and IsColliding() goes like this:

bool Physics::IsColliding(Entity* current, ECollisionTest collisionTestType)
{
	for (auto& E : Game->Entities)
	{
		if (current != E.get())//avoid self testing
		{
			switch (collisionTestType)
			{
				case ECollisionTest::EBoxCollisionTest:
				{
					if (BoxCollisionTest(current->GetCollisionBox(), E->GetCollisionBox()))
					{
						return true;
					}
				}
				break;
			}
		}
	}
	return false;
}

Now, there are two things I don't like about my current setup.

1) I am testing against all the entities. The paddle of the Breakout game can only move left and right, and hit either a ball or the left/right boundary, makes no sense to test it against 50 bricks at every update.

2)From inside the Paddle class I am calling "IsColliding(this, ECollisionTest::EBoxCollisionTest)" so there is the assumption that all the entities that can collide with this one require a box test. May not be the case, maybe I have a "worm" entity running on the screen and it requires another type of collision test, so the choosen function to run shouldn't relying on me explicitly saying which one is, but it should be called at runtime trough overload, based on the type of Entity being compared. So maybe the Paddle<->Ball comparison would do a BoxCollisionTest, while Paddle<->Worm comparison would do something else.

So how do I get it to work the way I want?

This is what I want:

1)Physics object is working with Entity*, and yet I need it to being able to distinguish between a Paddle* and or a Brick* or a Boundary* or a Ball* (all of this inherit from entity), a bit kind of like Unreal Engine BlueprintEditor Cast node, which allow me to say "Cast to Door" and if the thing was a door it return success, otherwise fails. Can you show me an example of how such mechanism is built, in code(C++)?

2)Physics object should just call a generic TestCollision() function between the "this" passed (the current colliding object) and all the other entities, and then the overload resolution calls the appropriate function based on the types. And yet this shouldn't fail to compile for pairs for which I don't explicitly overload, for instance I wouldn't overload for Paddle<->Brick because such comparison will never happen, so when Paddle<->Brick comparison is performed, it should just return false even though I never declared a TestCollision(Paddle* p, Brick* b). 

How can this be achieved? :)

 

 

 

Edited by MarcusAseth

Share this post


Link to post
Share on other sites

Your question is related to multiple sources of solutions so I will do one by one:

It sounds as your system is some type too generic so that you should rework your collision and try to reduce the number of possible collision targets but to answer your question; Unreal Blueprints are working on an UObject unreal object that has capabilities to do some type loockups such as owning class/struct type, value type and so on. So what you would need is either some kind of wrapper or meta storage or some wired c++ tricks that help pointing out if it is one of your derived classes. Such a trick is

dynamic_cast<derived*>(base)

that will return a null_ptr if dosent match the derived type. A more template and not so wired version is to use an own implementation of Object that provides those information to you. This could utilize templates and inheritance for example to wrap an untyped structure arround an internal typed derived class

class Object
{
   private:
      class BaseObject
      {
         public:
            virtual const type_info& GetType() = 0;
            virtual uint32 Size() = 0;
      };
      template<typename T> class TypedObject : BaseObject
      {
         public:
            inline virtual const type_info& GetType() { return typeid(T); }
            inline virtual uint32 Size() { return sizeof(T); } 
      };
        
      template<typename T> inline BaseObject* GetTypeHandler()
      {
         static TypedObject<T> handler;
         return &handler;
      }
        
      BaseObject* handler;
      void* value;
  
   public:
      template<typename T> inline Object(T* ptr) : handler(0), value(ptr)
      {
         handler = GetTypeHandler<T>();
      }
};

Calling this via the typed constructor will do as follows: Create a static instance of a class TypedObject depending on your pointer passed that will auto evaluate the template argument for T once the function GetTypedHandler is first called and/or return the created instance's pointer as its untyped base class. This handler object instance implements the abstract declared virtual functions of its base class depending on the template argument T passed to derived class, so even if the pointer is BaseObject, it will return the derived classes function values.

This leads to having your

Object obj(MyPaddlePtr);
assert(type_trait<Paddle>::type == obj.GetType())

evaluate to true where it will evaluate to false for for example MyBrickPtr (when those prts were of different derived class type). I implemented a class like this as a toy implementation and it works so may be a solution.

 

Your second question could be easily solved by using implicite template arguments as described in the Object approach and template specialization like follows

template<typename T, typename E> bool Collides(T* ptr, E* entity);
  
template<> bool Collides<Paddle, Ball>(Paddle* ptr, Ball* entity)
{
  ...
}
template<> bool Collides<Ball, Brick>(Ball* ptr, Brick* entity)
{
  ...
}

so you could call

if(Collides(this, derivedEntityType))

and template arguments are automatically choosen from the compiling unit. The compiler will (usually) choose the most matching template function first so you could also easily change the above implementation to

template<typename T, typename E> bool Collides(T* ptr, E* entity)
{
   return false; 
}

as default choosen function so that anything you dont specialized your function for will return a failure collision

Share this post


Link to post
Share on other sites

Thank you for the answer @Shaarigan I just woke up and is already clear I need some cofee and to read it again more carefully and possibly multiple time before I fully grasp it and try :D

Quote

It sounds as your system is some type too generic so that you should rework your collision and try to reduce the number of possible collision targets

That is probably true, but I feel like I will need to learn this anyway if I want to do stuff with components in the future (even though maybe is not necessary? not sure yet...), so I thought to embed this training into this part of the breakout game :)

I already have the feeling that to makes this compile it will take me some tries, so I'll probably be back later with more questions :P

Share this post


Link to post
Share on other sites

For my engines entity component system, I made a template function for each system to query components of a certain type using a static instance of the component list class. Each entity adding/removing a component tells the list about updates for its components. A system then could grab the desired list to operate for example on each collider component continiously. There might be better fitting solutions, I choosed this approach to be memory and performance aware but also flexible

[EDIT] I forgot, the main trick big engines do is to pre-erase possible collision checks by utilizing some kind of collision tree/scene view lookup. For simple games you could spread your entities arround a quad tree instance so collision testing would lead to a query into your quad tree for certain target and result into an O(log n) lookup result list of entities at certain area to test. This leads to significant less computation

Edited by Shaarigan

Share this post


Link to post
Share on other sites

@Shaarigan I've read again your first answer but I'm still not quite sure how to implement it / how does it map into my existing code, I think I'll need to learn this more slowly/gradually, because I am confused x_x (I am a slow learner xD) 

Can you suggest me any books on the subject that will get me there if read from cover to cover? :P

 

Edited by MarcusAseth

Share this post


Link to post
Share on other sites

Sorry, no book but a stackoverflow post that describes the functionality of object/any far better than I could as same as in this blog post


https://stackoverflow.com/questions/24702235/c-stdmap-holding-any-type-of-value

https://akrzemi1.wordpress.com/2014/01/13/type-erasure-part-iv/

 

And a way more performing implementation is for example this one from codeproject

https://www.codeproject.com/Articles/11250/High-Performance-Dynamic-Typing-in-C-using-a-Repla

 

This is all about type erasure using templates and void ptr to hold a type and provide some type information about it. One thought was to solve your first question, to not pass a pointer to an entity object rather than pass a container arround that works similar to what I cross referenced here but a way simpler because

dynamic_cast<derived*>(base)

might work on most compilers but may also fail/suceed in failure so you need something more reliable to get the kind of derived class from your entity object. The idea is to implement some type of object_entity (like object in C#) that has two members, a pointer to your entity passed in it and a pointer to some sort of type-info structure so your systems are able to query type informations about your object. This might accordingly to the code project implementation look like this

class Object
{
   public:
      enum TypeFlag
      {
         Unknown,
         Paddle,
         Brick,
         Ball
      }
  
   private:
      template <typename T> TypeFlag GetTypeFlag() { return Unknown; }
      template <> TypeFlag GetTypeFlag<Paddle>() { return Paddle; }
      template <> TypeFlag GetTypeFlag<Brick>() { return Brick; }
      template <> TypeFlag GetTypeFlag<Ball>() { return Ball; }
  
      struct TypeInfoBase
      {
         virtual int Size() = 0;
         virtual TypeFlag Flag() = 0;
      }
      template <typename T> TypeInfo : TypeInfoBase
      {
         virtual int Size() { return sizeof(T); }
         virtual TypeFlag Flag() { return GetTypeFlag<T>(); }
      }
  
  	  template <typename T> TypeInfoBase* GetTypeInfo()
      {
         static TypeInfo<T> info; //static variable will be initialized once
         return info;
      }
  
      TypeInfoBase* handler;
      Entity* value;
  
      public:
         template <typename T> inline Object(T* value) : handler(0), value(value)
         {
            handler = GetTypeInfo<T>();
         }
  
         inline Enity* Value() const { return value; }
         inline TypeFlag Flag() const { return handler->Flag(); }
         inline int Size() const { return handler->Size(); }
  
         template <typename T> T* Cast() { return static_cast<T*>(value); }
};

(Note: This is untested for syntactical correctness)

You will then use this in this way

Paddle* paddle = new Paddle(); //dont complain about new and plain pointers here, it is an example ;)
Object obj(paddle);

cout << obj.Size(); //obj.Size() => handler.Size() => TypeInfo<Paddle>.Size()
cout << obj.Flag(); //obj.Flag() => handler.Flag() => TypeInfo<Paddle>.Flag() => GetTypeFlag<T>() => GetTypeFlag<Paddle>() => Paddle

 

Share this post


Link to post
Share on other sites

Thanks @Shaarigan , now is already much more clear, probably it was already clear before and the only difference is that the more examples I see the more I can wrap my head around it :P

Should I prefer enum class over enum or there are specific reasons to use plain enum instead?

Also I saw a video on youtube where the guy did it in a way that seems a lot like the one you explained, he called it "The poor man's reflection" though, why is that?! xD

Also I only use VC, but for how you talk about dynamic_cast it sounds kind of unreliable, is that really true?! How much unreliable is it? :S 

Btw, I just woke up so I'll leave those link for after cofee, but I'll probably come back later to ask about those as well :P 

Edited by MarcusAseth

Share this post


Link to post
Share on other sites

I use plain enums to keep the code VS2010 compatible without C++ 11 features, you may use whatever you like.

C++ does not has any reflection capability as for example C# has that enables to fully assemble a class definition tree only by on-board functions. C++ has RTTI but on the cost of performance and just getting a name and compare to given types thats it, so not worth to mention. dynamic_cast belongs to RTTI but may depending on compiler and runtime return false positive results for certain types depending where the base and derived types are in the argument list. Also it is damn slow due to string compare types.

This is the reason why there exists reflection frameworks using different approaches (and I currently expand mine in my engine). RTTI types are not compiler independent so bad for serialization and data exchange (you could not send a serialized type from a Windows client to Linux server for example) and performance is not best at all so bad for games

Share this post


Link to post
Share on other sites

So a "decision based on static c++ type" is not a strategy you need to be using anywhere in your code.  If it did, this would probably be better served by polymorphism via virtual functions ... but whatever.

A decision based on a logical/abstract/property representing a "type" within your game system ... makes tons of sense.  This is cases where you have a "collidable object" class or interface or whatever.  And it has a type, like "simple rect", "simple circle", or "complex polygon" as its 3 supported collision detection types.  then each object's 1 colliadable object has a "detection type" property, and an appropriate associated data info object to match.  Yes this is just like the feature of RTTI, but it is a DATA or OBJECT CONSTRUCTION truth, not a code truth.  You are free to use inheritance, containment, interface, delegation  or any and all other programming strategies to implement this feature - and interestingly, all of them would likely be clearer and/or faster than C++'s RTTI feature ... while giving you more flexibility too.

Share this post


Link to post
Share on other sites

As for optimizing out the NxN performance issue of testing every object against every object even though most can't hit each other.  This would be a case of maintaining more tightly controlled lists of objects for your business at hand. 

A universal "full game object database" collection is great for making saving/loading easy (although it isn't really suited for that, because you really want 2 lists the "static/level" objects and the dynamic/active objects ... because then a save is just a reference to a level, and then the dynamic objects.  But I digress.

For your purpose, depending on the game, you might have lists such as "map objects" and "autonomous objects" if your game rules were such that you only needed to check the list of autonomous objects vs the list of autonomous and map objects.  This way you'd check 3 vs 200, not 200 vs 200 ... or whatever.

Other optimizations exist as well, such as spatial partitions, or even simply sorted lists by each dimension (for cases where more objects move very little each frame)

Share this post


Link to post
Share on other sites

Without templates, 


typedef int WorldTransform; //typedef, should be a matrix
typedef int Rect3D;			//should be a 3d-rect, 8 poinits or w/e
typedef int MeshData;		//collection of tri or w/e

class CollisionObject {
public:
	enum class CollisionObjectID { Sphere, Cube, Mesh };

	class CollisionShape {
	public:
		CollisionObjectID mCollisionObjectID;

		CollisionShape(CollisionObjectID id)
			:mCollisionObjectID(id)
		{}
	};

	class Sphere :	public CollisionShape {
	public:
		double mRadius;

		Sphere()
			:CollisionShape(CollisionObjectID::Sphere)
		{}
	};

	class Cube :	public CollisionShape {
	public:
		Rect3D mRect;

		Cube()
			:CollisionShape(CollisionObjectID::Cube)
		{}
	};

	class Mesh :	public CollisionShape {
		MeshData mMeshData;
	
	public:
		Mesh()
			:CollisionShape(CollisionObjectID::Mesh)
		{}
	};

protected:

	CollisionShape* mCollisionShape;
	WorldTransform mWorldTransform;

	//trickle-down comparisons, you need to pass obj1/obj2 to these functions, not implemented, see collidesWith
	bool SphereVsSphere() { return true; }
	bool SphereVsCube() { return true; }
	bool SphereVsMesh() { return true; }

	bool CubeVsCube() { return true; }
	bool CubeVsMesh() { return true; }

	bool MeshVsMesh() { return true; }

public:
	CollisionObject( WorldTransform worldTransform, CollisionShape* shape)
		: mWorldTransform( worldTransform )
		, mCollisionShape( shape )
	{}

	bool collidesWith(CollisionObject* obj2) {

		//ensure that the trickle down functions work by ordering objs 1 < 2
		CollisionObject* obj1 = this;
		if (obj2->mCollisionShape->mCollisionObjectID < mCollisionShape->mCollisionObjectID)
			std::swap(obj1, obj2);

		CollisionObjectID id1= obj1->mCollisionShape->mCollisionObjectID, id2 = obj2->mCollisionShape->mCollisionObjectID;

		switch ( id1 ){
		case CollisionObjectID::Sphere:

			switch( id2 ) {
			case CollisionObjectID::Sphere:
				SphereVsSphere();
				break;
			case CollisionObjectID::Cube:
				SphereVsCube();
				break;
			case CollisionObjectID::Mesh:
				SphereVsMesh();
				break;
			}
			break;

		case CollisionObjectID::Cube:

			switch ( id2 ) {
			case CollisionObjectID::Cube:
				CubeVsCube();
				break;
			case CollisionObjectID::Mesh:
				CubeVsMesh();
				break;
			}
			break;

		case CollisionObjectID::Mesh:
			MeshVsMesh();
			break;
		}
	}
};

class PhysicalObject {
protected:
	std::vector< CollisionObject > mCollisionObjects;
public:

	bool collidesWith(PhysicalObject* obj2) {

		for (auto child1 : mCollisionObjects) {
			for( auto child2 : obj2->mCollisionObjects )
				if (child1.collidesWith( &child2 )) return true;
		}
		return false;
	}
};

class Paddle : public PhysicalObject {

	CollisionObject::Cube mCollisionShapeCube; // can also store all shapes in a repository and have a ptr here
public:
	Paddle() {
		//can push back as many objects as want, worm could have several cubes or spheres or w/e
		mCollisionObjects.push_back(CollisionObject(WorldTransform(), &mCollisionShapeCube));
	}
};

You'd run down all physical objects that potentially intersect, and call colldiesWith. In a game like breakout I don't think you'd have enough objects to worry about comparing to all of them.

Share this post


Link to post
Share on other sites

Sorry if I'm not answering to this topic for a while guys, I dont want you get the wrong idea that I am not interested or something, is just that I've paused my project few days ago because I am getting lost and I need to do more reading (of basic stuff as well) in order to be able to proceed, so currently I am going trough some books and online material, but I'll be back and resume this and read again the whole topic once I am done and ready to proceed :)  Thanks for all the answers, which apparently are helping other people as well :) 

 

Edited by MarcusAseth

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Forum Statistics

    • Total Topics
      628290
    • Total Posts
      2981858
  • Similar Content

    • By reders
      Hi, everyone!
      I "finished" building my first game. Obviously Pong.
      It's written in C++ on Visual Studio with SFML.
      Pong.cpp
      What do you think? What should I consider doing to improve the code?
      Thank you very much.
       
      EDIT: added some screenshot and .zip file of the playable game
       
      Pong.zip


    • By noodleBowl
      I was wondering if anyone could explain the depth buffer and the depth stencil state comparison function to me as I'm a little confused
      So I have set up a depth stencil state where the DepthFunc is set to D3D11_COMPARISON_LESS, but what am I actually comparing here? What is actually written to the buffer, the pixel that should show up in the front?
      I have these 2 quad faces, a Red Face and a Blue Face. The Blue Face is further away from the Viewer with a Z index value of -100.0f. Where the Red Face is close to the Viewer with a Z index value of 0.0f.
      When DepthFunc is set to D3D11_COMPARISON_LESS the Red Face shows up in front of the Blue Face like it should based on the Z index values. BUT if I change the DepthFunc to D3D11_COMPARISON_LESS_EQUAL the Blue Face shows in front of the Red Face. Which does not make sense to me, I would think that when the function is set to D3D11_COMPARISON_LESS_EQUAL the Red Face would still show up in front of the Blue Face as the Z index for the Red Face is still closer to the viewer
      Am I thinking of this comparison function all wrong?
      Vertex data just in case
      //Vertex date that make up the 2 faces Vertex verts[] = { //Red face Vertex(Vector4(0.0f, 0.0f, 0.0f), Color(1.0f, 0.0f, 0.0f)), Vertex(Vector4(100.0f, 100.0f, 0.0f), Color(1.0f, 0.0f, 0.0f)), Vertex(Vector4(100.0f, 0.0f, 0.0f), Color(1.0f, 0.0f, 0.0f)), Vertex(Vector4(0.0f, 0.0f, 0.0f), Color(1.0f, 0.0f, 0.0f)), Vertex(Vector4(0.0f, 100.0f, 0.0f), Color(1.0f, 0.0f, 0.0f)), Vertex(Vector4(100.0f, 100.0f, 0.0f), Color(1.0f, 0.0f, 0.0f)), //Blue face Vertex(Vector4(0.0f, 0.0f, -100.0f), Color(0.0f, 0.0f, 1.0f)), Vertex(Vector4(100.0f, 100.0f, -100.0f), Color(0.0f, 0.0f, 1.0f)), Vertex(Vector4(100.0f, 0.0f, -100.0f), Color(0.0f, 0.0f, 1.0f)), Vertex(Vector4(0.0f, 0.0f, -100.0f), Color(0.0f, 0.0f, 1.0f)), Vertex(Vector4(0.0f, 100.0f, -100.0f), Color(0.0f, 0.0f, 1.0f)), Vertex(Vector4(100.0f, 100.0f, -100.0f), Color(0.0f, 0.0f, 1.0f)), };  
    • By Rannion
      Hi,
      I'm trying to fill a win64 Console with ASCII char.
      At the moment I have 2 solutions: one using std::cout for each line, let's say 30 lines at once using std::endl at the end of each one.
      The second solution is using FillConsoleOutputCharacter. This method seems a lot more robust and with less flickering. But I'm guessing, internally it's using a different table than the one used by std::cout. I'm trying to fill the console with the unsigned char 0xB0 which is a sort of grey square when I use std::cout but when using FillConsoleOutputCharacter it is outputted as the UTF8 char '°'.
      I tried using SetConsoleOutputCP before but could not find a proper way to force it to only use the non-extended ASCII code page...
      Has anyone a hint on this one?
      Cheers!
    • By Vortez
      Hi guys, i know this is stupid but i've been trying to convert this block of asm code in c++ for an hour or two and im stuck
      ////////////////////////////////////////////////////////////////////////////////////////////// /////// This routine write the value returned by GetProcAddress() at the address p /////////// ////////////////////////////////////////////////////////////////////////////////////////////// bool SetProcAddress(HINSTANCE dll, void *p, char *name) { UINT *res = (UINT*)ptr; void *f = GetProcAddress(dll, name); if(!f) return false; _asm { push ebx push edx mov ebx, f mov edx, p mov [ebx], edx // <--- put edx at the address pointed by ebx pop edx pop ebx } return res != 0; } ... // ie: SetProcAddress(hDll, &some_function, "function_name"); I tried:
      memcmp(p, f, sizeof(p)); and UINT *i1 = (*UINT)p; UINT *i2 = (*UINT)f; *f = *p; The first one dosent seem to give the right retult, and the second one won't compile.
      Any idea?
    • By adapelin
      I am a computer engineering student and i have the assignment below. İ only can write the 2D maze array and have no idea about creating car and time as well. Could anyone write and explain hot to do???
      Minimum Criteria: You are expected to design the game by using C ++ . Below are the minimal criteria: • You must create game board with 2 - Dimensional Matrix • Bonuses create with randomly in the game board • All bonuses have got the same value but different effect for car and score . These effects may be positive or negative . • You must use pointer for creating and using car . Some bonuses may be change car type. • When the game finish, you must show high - score. • For moving car , you need to create coordinate s randomly and you need to write proper control statements. • You must use functions for drawing game board and changing car type . If you need extra functions, you can use it. • If you cannot get out the maze when the time is up , the game is over and you need to show high score. In this project, you must do all minimum criteria. In the end, your program must be work without any errors. Bonus: • Save and load high score information to/from disk • Each bonus has got different random values. • You can create cheat codes for the game. • You can create alternative control for car . • Car can jump over the wall but may lose the score . When car exit the maze , game is over and you need to show high score.    
  • Popular Now