• Advertisement
  • Popular Tags

  • Popular Now

  • Advertisement
  • Similar Content

    • By Runemark Studio
      Dark Fantasy Environment and Props





    • By bowcox
      Hi guys! 
      I have created a Pong game that has an AI that is almost beatable, changing the speed of the AI can make it ridiculously easy or hard depending on the way you go about it. 
       
      using System.Collections; using System.Collections.Generic; using UnityEngine; public class ComputerMovement : MonoBehaviour { private float speed; private float reAdjustSpeed = 1f; private Rigidbody2D computer2d; public static bool isTwoPlayer; GameObject theBall; Rigidbody2D rb2d; void Start() { computer2d = GetComponent<Rigidbody2D> (); } void FixedUpdate() { if (isTwoPlayer == true) { speed = 5f; if (Input.GetKey (KeyCode.W)) { computer2d.position += Vector2.up * speed * Time.deltaTime; } if (Input.GetKey (KeyCode.S)) { computer2d.position += Vector2.down * speed * Time.deltaTime; } } if (isTwoPlayer == false) { speed = 3f; if (theBall == null) { theBall = GameObject.FindGameObjectWithTag ("Ball"); } rb2d = theBall.GetComponent<Rigidbody2D> (); //Is the ball going left or right if (rb2d.velocity.x > 0) { if (rb2d.velocity.y > 0) { if (rb2d.position.y > computer2d.position.y) { MoveUp (); } if (rb2d.position.y < computer2d.position.y) { MoveDown (); } } if (rb2d.velocity.y < 0) { if (rb2d.position.y > computer2d.position.y) { MoveUp (); } if (rb2d.position.y < computer2d.position.y) { MoveDown (); } } } //Whilst it's not moving at the paddle, let it gain a slight reset by moving with the ball at a slower pace. if (rb2d.velocity.x < 0) { if (computer2d.position.y < 0) { computer2d.position += Vector2.up * reAdjustSpeed * Time.deltaTime; } if (computer2d.position.y > 0) { computer2d.position += Vector2.down * reAdjustSpeed * Time.deltaTime; } } } } void MoveDown() { if (Mathf.Abs(rb2d.velocity.y) > speed) { computer2d.position += Vector2.down * speed * Time.deltaTime; } else { computer2d.position += Vector2.down * speed * Time.deltaTime; } } void MoveUp() { if (Mathf.Abs (rb2d.velocity.y) > speed) { computer2d.position += Vector2.up * speed * Time.deltaTime; } else { computer2d.position += Vector2.up * speed * Time.deltaTime; } } }  
      I have looked up several posts across many different forums in order to create a much better AI. Most of the posts recommend that I use Raycasts to find out exactly where the ball might hit the paddle. I have looked up how to use them and I'm just completely lost, do raycasts consider collisions and go on infinitely or once they hit a wall, that's where it'll end up? Would anyone be able to help me understand raycasts a little better? 
      If you have another solution that enables me to calculate exactly where the ball will end up on the opponents side, I am more than willing to hear it
      Thanks again if you read this!
    • By eldwin11929
      We're looking for a Unity (C#) Programmer for our 2D Project. We're looking for a new lead programmer to continue with an existing project.
       
      Project is an open-world RTS, and is very close to a prototyping (playable) phase. Our existing lead, unfortunately, has no more time for the project, and thus we are in search of a new one who is interested.
       
      Game is purely fantasy based, and we'll be able to give you much more detailed info about the project as we begin to work you into it.
       
      You'll be working with our junior developer, who has been here since the beginning.
       
      Primary skills needed are just being able to work within Unity. But skills within XML are also a plus.
       
      Our list of major goals we'd need you to do is minimal, yet still fairly extensive:
      -Edit our current Pathfinding system to account for a few extra features.
      -Setup our global map system. You’ll be working off an existing random node-map web generator and existing random map generation system and essentially linking the two together. This includes handling random spawns (which has already been semi-setup) unique to each node’s respective map.
      -Further implementation of an existing random spawning algorithm (used to spawn things like enemies randomly across the Map).
      -Making sure to Save and Record all respective aspects of what was mentioned above.
      -Handling our XML database- database is created, but we’ll need to be integrating it. This includes all various things from units to abilities and so forth. Will also need to handle implementing an object’s unique attributes we cannot take care of within XML.
      -Various Content Implementation (to be done once our XML has been integrated).
      -Various Saving and Recording of all respective aspects of the database info mentioned above.
      -Various Performance Enhancements.
      -Potential for various misc things, such as further UI work.
      -Setting up a Menu system.
       
      We have a considerable amount of things done already- however I must warn ahead of time we have quite a bit of unclean code, which may be fairly overwhelming for a new developer on the project.
       
      Let me know your rates per hour, and we'll see if we can work out a good deal between both of us. Royalties are also included.
       
      If interested, send an email to: eldwin11929@yahoo.com
       
      Thanks!
    • By jhocking
      My bestselling and highly recommended Unity book has been fully revised! Unity in Action, Second Edition teaches you to write and deploy games with the Unity game development platform. You'll master the Unity toolset from the ground up, adding the skills you need to go from application coder to game developer.

      Foreword by Jesse Schell, author of The Art of Game Design

      Don't take my word for it being good, look at the sky-high ratings on GoodReads.

      You can order the ebook directly from the publisher's site, or order the book on Amazon to get both the physical book and a coupon to download the ebook!
    • By ThunderTwonk
      Hello everyone, I am working on a game idea and since I am still in the process of learning C# and the features available in unity I was hoping some of you might be able to offer me a little insight on things in general for getting started.
      I guess the basic components of what I'm wanting to create would be a Multi-levels management/city builder/rpg.
      The goal is to provide a framework for players to interact with, build in and affect the world both from a 3rd person action RPG as well as a zoomed out 4x style view (This would be something unlocked through gameplay)
       
      As for my questions go I was wondering if anyone had resources that could help me learn.  I've been on youtube as well as enrolled in an online course for basic unity and C# and will continue those but if anyone has any words of advice, a place that has good information and tutorials etc.
       
      Thanks for your time.
  • Advertisement
  • Advertisement
Sign in to follow this  

Unity Unique ID per type

This topic is 825 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi,
 
I have a Scene graph of SceneNodes. Every SceneNode has a vector of Component*.
 
Component* base class of all types of components in my scene, like a CameraComponent, LightComponent, CharacterController, etc. (Like Unity.)
 
 
I am working serializing the data so I can store in something like an XML or JSON file.
 
The only issue I have right now is creating a unique ID for every type of component that is cross platform and is the same on every run.
 
I know there is the hacky way of having a big enum, in which you create an ID for every class you create. However  I don't like this at all. Is there a better way to do this, where it generates id's automatically?
 
Thanks in advance!
 
 
 
EDIT:
 
I think I have found a way :D
I simply generate a hash based on the class name. I can also replace the RTTI with a static function for every type if I really want to. (however I don't really see a point ATM.)
It also allows me to change to a different hashing algorithm, should this one fail me.
 
struct TypeHash
{
  //check if types are equal
  friend inline bool operator==(const TypeHash& l, const TypeHash& r)
  { return l.id == r.id; }
  //check if types are different
  friend inline bool operator!=(const TypeHash& l, const TypeHash& r)
  { return !operator==(l, r); }


  //for sorting
  friend inline bool operator<(const TypeHash& l, const TypeHash& r)
  { return l.id < r.id; }


  template<typename T> friend TypeHash HashType();
private:
  TypeHash(uint64_t id) : id(id) {}
  uint64_t id;
};


//create a hash based of a type name
inline uint64_t HashTypeName(const char* str)
{
  //djb2 algorithm from here:
  //http://www.cse.yorku.ca/~oz/hash.html
  uint64_t hash = 5381;
  int c;
  while((c = *str++) != 0)
    hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
  return hash;
}


template<typename T> inline TypeHash HashType()
{
  //a way of generating a hash that is cross platform
  static TypeHash hash = HashTypeName(typeid(T).raw_name());
  return hash;
}
 

Share this post


Link to post
Share on other sites
Advertisement

That should work (except there is no such thing as raw_name in std::type_info, it's just name).

 

A few notes:

  • As it stands, your approach will generally "work fine" but the program is ill-formed because you don't include <typeinfo> prior to evaluating a typeid expression (your compiler should warn about that?).
  • You are caching the hash in a static variable. Keep it that way. The temptation exists to instead make the hash function constexpr. Don't do that because it will not work on the stricter compilers as the name is not a constant expression (it sure is, how could it possibly not be... but the standard and the compiler think differently) and will be vastly inferior on the more forgiving compilers (which will compile fine, but evaluate at runtime).
  • std::type_info has a member function hash_code which just looks like what you want, only better, faster, and standard. Yeah right. Don't fall for that. The hash provided by the standard not only isn't portable (that would be quite hard to do, admittedly), but it does not even guarantee that the value stays the same between different runs of the same executable. Which, frankly, is total shit.
  • The standard also provides std::type_index, which suggests by its name and its description that it could be very useful (index? as in unique number? great!), but it is really just a wrapper around std::type_info which adds operators <= and >= in terms of std::type_info.before(). Other than for using it as key in unordered standard containers, it's pretty useless.
  • Instead of using std::type_info.name(), you could use the well-known hack with a helper class that contains a static function which evaluates some flavour of __func__ or __PRETTY_FUNCTION__ or whatever you want to use, optionally adding an offset into the string constant to strip off the ugly mangling. These string constants are not constexpr either (although I think they should be, unless the name of a type can change during a program's execution which would be a big WTF, they are pretty darn constant expressions), but it is less bloat than using std::type_info (especially with GCC which has a very poor implementation), and you save yourself from including another header. I seem to remember someone even posted a complete, usable implementation of the __func__ hack on this site not long ago.
  • From the most pedantic point of view, using the __func__ hack even makes your program a little more robust. The typeid operator does not guarantee that the same type_info object is returned for different invocations in the same program with the same type. This sounds like something you could take for granted, and this is probably what happens anyway, but in the strictest sense, that's not the case. The standard merely says that some type_info (or derived) object with static storage duration is returned (and leaving unspecified whether destructors are called), and that the objects from different typeid expressions with the same type compare equal. That doesn't mean that they are equal, or that that name() returns the same value (or even the same pointer).

Share this post


Link to post
Share on other sites


 

That should work (except there is no such thing as raw_name in std::type_info, it's just name).

 

A few notes:

  •  
  • As it stands, your approach will generally "work fine" but the program is ill-formed because you don't include <typeinfo> prior to evaluating a typeid expression (your compiler should warn about that?).
  •  
  • You are caching the hash in a static variable. Keep it that way. The temptation exists to instead make the hash function constexpr. Don't do that because it will not work on the stricter compilers as the name is not a constant expression (it sure is, how could it possibly not be... but the standard and the compiler think differently) and will be vastly inferior on the more forgiving compilers (which will compile fine, but evaluate at runtime).
  •  
  • std::type_info has a member function hash_code which just looks like what you want, only better, faster, and standard. Yeah right. Don't fall for that. The hash provided by the standard not only isn't portable (that would be quite hard to do, admittedly), but it does not even guarantee that the value stays the same between different runs of the same executable. Which, frankly, is total shit.
  •  
  • The standard also provides std::type_index, which suggests by its name and its description that it could be very useful (index? as in unique number? great!), but it is really just a wrapper around std::type_info which adds operators <= and >= in terms of std::type_info.before(). Other than for using it as key in unordered standard containers, it's pretty useless.
  •  
  • Instead of using std::type_info.name(), you could use the well-known hack with a helper class that contains a static function which evaluates some flavour of __func__ or __PRETTY_FUNCTION__ or whatever you want to use, optionally adding an offset into the string constant to strip off the ugly mangling. These string constants are not constexpr either (although I think they should be, unless the name of a type can change during a program's execution which would be a big WTF, they are pretty darn constant expressions), but it is less bloat than using std::type_info (especially with GCC which has a very poor implementation), and you save yourself from including another header. I seem to remember someone even posted a complete, usable implementation of the __func__ hack on this site not long ago.
  •  
  • From the most pedantic point of view, using the __func__ hack even makes your program a little more robust. The typeid operator does not guarantee that the same type_info object is returned for different invocations in the same program with the same type. This sounds like something you could take for granted, and this is probably what happens anyway, but in the strictest sense, that's not the case. The standard merely says that some type_info (or derived) object with static storage duration is returned (and leaving unspecified whether destructors are called), and that the objects from different typeid expressions with the same type compare equal. That doesn't mean that they are equal, or that that name() returns the same value (or even the same pointer).
  •  

 

I wouldnt use type info for this, you can do this through the preprocessor with something like:

//create a hash based of a type name
inline uint64_t HashTypeName(const char* str)
{
  //djb2 algorithm from here:
  //http://www.cse.yorku.ca/~oz/hash.html
  uint64_t hash = 5381;
  int c;
  while((c = *str++) != 0)
  {
    hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
  }
  return hash;
}
 
#define HASHTYPE(type)\
    inline TypeHash HashType()\
    {\
      //a way of generating a hash that is cross platform\
      static TypeHash hash = HashTypeName(#type);\
      return hash;\
    }
 
Class MyType
{
public:
    HASHTYPE(MyType);
 
};

This needs less template magic than your solution and is generally easier to use because typeid names contain namespaces and such which can make it hard to figure out what a hash belongs too when you are debugging the code. In my case you can just run the HashTypeName("MyType") function in the watch window to find the hash of your type when on a breakpoint.

 

Alot of game engines have stuff like Runtime type info turned off in compile settings which will make typeid not work for dynamic types.

 

If you use a constexpr hash function all of the preprocessor stuff and dynamic lookup of typeid at runtime will be change to static compile time implementations.

Edited by NightCreature83

Share this post


Link to post
Share on other sites

You could use something like this is you dont need compile time ID

template<typename T>
struct quick_type_id{
    static void functionAsID() {}
}

and use

quick_type_id<int>::functionAsID
Edited by imoogiBG

Share this post


Link to post
Share on other sites

@samoth What you are describing is kind of what I am finding on the internet. I completely agree with your points.

@NightCreature83 I had to turn RTTI on yeah, and would prefer to have it off. I might actually go with a solution like that.

@imoogiBG I can't use that since it's not guaranteed that I get the same ID for a class on every run.

Share this post


Link to post
Share on other sites
  • From the most pedantic point of view, using the __func__ hack even makes your program a little more robust. The typeid operator does not guarantee that the same type_info object is returned for different invocations in the same program with the same type. This sounds like something you could take for granted, and this is probably what happens anyway, but in the strictest sense, that's not the case. The standard merely says that some type_info (or derived) object with static storage duration is returned (and leaving unspecified whether destructors are called), and that the objects from different typeid expressions with the same type compare equal. That doesn't mean that they are equal, or that that name() returns the same value (or even the same pointer).

 

Isn't this the entire point of type_index, so that type_index's made from different typeid's to the same type do compare equal?  From my understanding the real issue with type_info's being different for different types becomes relevant when were talking same types used from different dll's.

Share this post


Link to post
Share on other sites

For type checking in my Lua bindings, I use hashes generated by parsing __FUNCTION__

template<class T>
struct TypeName
{
	static void Get(const char*& begin, const char*& end)
	{
		begin = __FUNCTION__;
		for(++begin; *begin && *(begin-1) != '<'; ++ begin);
		for(end = begin; *end; ++ end);
		for(; end > begin && *end != '>'; -- end);
	}
	static const char* Get(Scope& a)
	{
		const char* begin=0, *end=0;
		Get(begin, end);
		uint length = end-begin;
		char* buf = (char*)a.Alloc(length+1);
		memcpy(buf, begin, length);
		buf[length] = 0;
		return buf;
	}
	static void Get(char* buf, uint bufLen)
	{
		const char* begin=0, *end=0;
		Get(begin, end);
		uint length = end-begin;
		eiASSERT( length+1 <= bufLen );
		memcpy(buf, begin, length);
		buf[length] = 0;
	}
	static const char* Get()
	{
		static const char* value = 0;
		if( !value )
		{
			static char buffer[256];
			Get(buffer, 256);
			//todo - memory fence
			value = buffer;
		}
		return value;
	}
};

template<class T>
struct TypeHash
{
	static u32 Get_()
	{
		const char* begin;
		const char* end;
		TypeName<T>::Get(begin, end);
		return Fnv32a(begin, end);
	}
	static u32 Get()
	{
		static const u32 value = Get_();
		return value;
	}
};

If you're talking about file I/O and format compatibility, you absolutely want manual IDs.

^^ This. Everything based on __func__, typeid, etc, is compiler dependent. You upgrade your compiler, or port to another platform, and all your type ID's will change.

Share this post


Link to post
Share on other sites

SeanMiddleditch is 100% correct. If you want to be able to load saved game states (eg: save games), you need to define the Id's in such a way that they can never change. The only way to do this is to assign them yourself.
 
Generating a hash from the name of the type seems like a good idea, but what if you ever decide to change the name of your class? For example if you decide that "LightComponent" should be "LightingComponent"?

 

Another thing you will need to consider is hash collisions. They are rare, but they can happen. Check out the hash collision tests done in the following stackexchange post: http://programmers.stackexchange.com/questions/49550/which-hashing-algorithm-is-best-for-uniqueness-and-speed
 
They found 7 collisions in the english dictionary using the DJB2 algorithm you're considering:
 

DJB2 collisions

  • hetairas collides with mentioner
  • heliotropes collides with neurospora
  • depravement collides with serafins
  • stylist collides with subgenera
  • joyful collides with synaphea
  • redescribed collides with urites
  • dram collides with vivency

Share this post


Link to post
Share on other sites

Isn't this the entire point of type_index, so that type_index's made from different typeid's to the same type do compare equal? From my understanding the real issue with type_info's being different for different types becomes relevant when were talking same types used from different dll's

That's right, the entire point of type_index is to make it work when it "shouldn't" work but that is what is intended. Means that two thing that are the same aren't the same, but the container still sees them as equal, so it somehow "works".

DLLs are not something C++ cares about (and many argue that they're "broken" because of mangling anyway). Though of course they might be the exact reason why typeid is deliberately specified in such a needlessly obnoxious way. I wouldn't know. But even so, that would be "mostly harmless" since nobody would expect types in any haphazard DLL possibly written by someone else to be identical with the ones in your program. How should that be possible.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement