Jump to content
  • Advertisement

noizex

GDNet+
  • Content Count

    181
  • Joined

  • Last visited

  • Days Won

    1

noizex last won the day on September 30

noizex had the most liked content!

Community Reputation

1442 Excellent

About noizex

  • Rank
    Member

Personal Information

  • Role
    Creative Director
    Producer
    Programmer
  • Interests
    Art
    Education
    Production
    Programming

Social

  • Twitter
    no1zex

Recent Profile Visitors

10647 profile views
  1. noizex

    Problem with value type & opAssign

    Thanks! To be honest I'm not sure why I didn't make it asOBJ_POD - I'm pretty sure that would be the first thing to try for me.. I tried changing it and it now compiles and seems to work fine.
  2. Hi, I try to wrap my head around operator behaviour, documentation does not say much for the C++ side, so I guess it should be probably simple but I can't get this to work: # this works vec3 a(1.0f); vec3 b(0.0f); vec3 c = a - b; # this doesn't Transform@ transform = Transform(); vec3 a(1.0f); vec3 c = a - transform.position; (70): No appropriate opAssign method found in 'vec3' for value assignment (70): Previous error occurred while attempting to create a temporary copy of object Transform register: asCHECK(engine->RegisterObjectType("Transform", 0, asOBJ_REF)); asCHECK(engine->RegisterObjectBehaviour("Transform", asBEHAVE_FACTORY, "Transform@ f()", asMETHOD(SpatialWorld, makeTransform), asCALL_THISCALL_ASGLOBAL, this)); asCHECK(engine->RegisterObjectBehaviour("Transform", asBEHAVE_ADDREF, "void f()", asMETHOD(TransformScriptProxy, addRef), asCALL_THISCALL)); asCHECK(engine->RegisterObjectBehaviour("Transform", asBEHAVE_RELEASE, "void f()", asMETHOD(TransformScriptProxy, release), asCALL_THISCALL)); asCHECK(engine->RegisterObjectMethod("Transform", "vec3 get_forward() const", asMETHOD(TransformScriptProxy, getForward), asCALL_THISCALL)); asCHECK(engine->RegisterObjectMethod("Transform", "vec3 get_position() const", asMETHOD(TransformScriptProxy, getPosition), asCALL_THISCALL)); asCHECK(engine->RegisterObjectMethod("Transform", "void set_position(const vec3 &in)", asMETHOD(TransformScriptProxy, setPosition), asCALL_THISCALL)); vec3 register: // Type & behaviours asCHECK(m_engine->RegisterObjectType("vec3", sizeof(glm::vec3), asOBJ_VALUE | asGetTypeTraits<glm::vec3>())); asCHECK(m_engine->RegisterObjectBehaviour("vec3", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(vec3_ConstructorEmpty), asCALL_CDECL_OBJLAST)); asCHECK(m_engine->RegisterObjectBehaviour("vec3", asBEHAVE_CONSTRUCT, "void f(float, float, float)", asFUNCTION(vec3_Constructor), asCALL_CDECL_OBJFIRST)); asCHECK(m_engine->RegisterObjectBehaviour("vec3", asBEHAVE_CONSTRUCT, "void f(float)", asFUNCTION(vec3_ConstructorScalar), asCALL_CDECL_OBJFIRST)); asCHECK(m_engine->RegisterObjectBehaviour("vec3", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(vec3_Destructor), asCALL_CDECL_OBJFIRST)); // Properties asCHECK(m_engine->RegisterObjectProperty("vec3", "float x", asOFFSET(glm::vec3, x))); asCHECK(m_engine->RegisterObjectProperty("vec3", "float y", asOFFSET(glm::vec3, y))); asCHECK(m_engine->RegisterObjectProperty("vec3", "float z", asOFFSET(glm::vec3, z))); // Operators asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3& opAddAssign(const vec3 &in) const", asMETHODPR(glm::vec3, operator+=, (const glm::vec3&), glm::vec3&), asCALL_THISCALL)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3& opMulAssign(const vec3 &in) const", asMETHODPR(glm::vec3, operator*=, (const glm::vec3&), glm::vec3&), asCALL_THISCALL)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3& opAssign(const vec3 &in) const", asMETHODPR(glm::vec3, operator=, (const glm::vec3&), glm::vec3&), asCALL_THISCALL)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 opAdd(const vec3 &in) const", asFUNCTIONPR(glm::operator+, (const glm::vec3&, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJLAST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 opSub(const vec3 &in) const", asFUNCTIONPR(glm::operator-, (const glm::vec3&, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJLAST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 opMul(const vec3 &in) const", asFUNCTIONPR(glm::operator*, (const glm::vec3&, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJLAST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 opMul_r(float) const", asFUNCTIONPR(glm::operator*, (float, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJLAST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 opDiv(const vec3 &in) const", asFUNCTIONPR(glm::operator/, (const glm::vec3&, const glm::vec3&), glm::vec3), asCALL_CDECL_OBJLAST)); // Methods asCHECK(m_engine->RegisterObjectMethod("vec3", "float length() const", asFUNCTIONPR(glm::length, (const glm::vec3&), float), asCALL_CDECL_OBJFIRST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "float dot(const vec3& in) const", asFUNCTIONPR(glm::dot, (const glm::vec3&, const glm::vec3&), float), asCALL_CDECL_OBJFIRST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "vec3 normalize() const", asFUNCTIONPR(glm::normalize, (const glm::vec3&), glm::vec3), asCALL_CDECL_OBJFIRST)); asCHECK(m_engine->RegisterObjectMethod("vec3", "string str()", asFUNCTIONPR(glm::to_string, (const glm::vec3&), std::string), asCALL_CDECL_OBJLAST)); Anyone knows what might be wrong here? Also if you spot some obvious inefficiencies please let me know - vec3 is small class (it's glm::vec3) that can be copied and used by value - maybe the problem is that I return a value from Transform::get_position() instead of reference? Or that I registered vec3::opAssign as returning reference, but without it I was having errors with registers and overall breakage...
  3. Hmm that sounds like a good idea! I'd have some way to identify these. One could be just having a list of the classes that are registered like this (there is limited set of those) and finding all occurences of such class in a object, then releasing it. Or more generic approach with some metainfo like [autoclean] - but first solution may be better considering there won't be a lot of these classes. Thanks, for some reason I haven't thought to use built-in script reflection for this kind of cleanup!
  4. After a bit of thinking I found some way, similar to what you mention. This will require some more care on script programmer's side. I added a "cleanup" interface which gets called when I want the object to be destroyed (both C++ & script side, but I can only guarantee C++ side goes away, and script side may be kept alive a little longer). This means I can release all references there instead of counting on destructor or scoped release. So I just do: void cleanup() { @transform = null; @mesh = null; } and because both Transform and Mesh are C++ registered classes, they're released as soon as their refcount reaches 0 and no GC is involved. This is more demanding than just relying on destructor but as you pointed out, there is no way to force destruction of object without risking dangerous side effects. So this is probably the only way I can do this, when the destruction of used resources matters (and it does, I want them gone when I say "this object is destroyed from world").
  5. Sorry, but I'm looking for an answer from someone who uses and appreciates Angelscript. Not sure how you ended up on this forum, but question about scripting language I'm using is rather weird.
  6. I already maintain 2-way slot_map to keep the objects in question (transform, mesh etc). I'd like to avoid this on script side, as each of those is already behind a proxy. My problem is proper clean-up of objects, because with Garbage Collection and deferred destruction destructors do not make sense really, as the object is already considered destroyed if unreferenced, yet it's kept alive like a real object. This is my problem - I'd like the object to go away as soon as the refcount from script/C++ side reaches 0, but I know that GC will keep one reference and then cleanup and try to resolve circular dependencies. Even if I use weak_ptr there will still be this step where GC runs, so my main question is: is there a way to make the object immediately destroyed without waiting for GC pass? My another cocnept, I think close to your 2-way check, is to implement in my proxy (do TransformProxy, MeshProxy) a way to cut the link and destroy the C++ object (so Transform, Mesh), while still being referenced in scripts due to deferred destruction. I'd then throw exception if accessing such reference where the C++ object has been destroyed, making it easier to spot obvious programming errors. But it seems like a lot of work and checking, while just destroying game object as soon as references are gone (assuming I won't ever keep reference to it outside for longer than using it when obtained from weakPtr) should work fine.
  7. Hello, I've run into weird ownership / object lifetime problem. My classes look as follow: shared abstract class Object: IScriptObjectInterface { // common "game object" functionality proxied to C++ side object } class Item: Object { Transform@ transform; Mesh@ mesh; } class Monster: Object { Transform@ transform; SkinnedMesh@ skinnedMesh; } Now, I'd like to be able to force destroy my game object. This poses several problems, one of them being - script objects are naturally reference counted, so destruction of object happens a) When no other objects reference that object b) Garbage Collector runs and destroys the object Now, composable objects like Transform, Mesh, SkinnedMesh are created on C++ side in a very optimized structure and are as much decoupled from game object as possible - to a point where game object is not needed to render Mesh instances, just mere presence in a container holding all meshes is enough. This means that object which has a reference to Mesh@ will keep that Mesh alive, and that object which I want to destroy does not have a deterministic destruction time because it may be destroyed sometime later. This means that object may be "destoyed" and unreferenced from world object list, but it will hold references to Mesh, SkinnedMesh, Physics etc. which will still exist (as they're refcounted too) meaning they'll be simulated, rendered etc. I have no idea how to solve this problem, every time I try some approach I run into some deadly reference dependency. One idea I had is to let these objects stay in the container, so Mesh will be in all_meshes on C++ side, but it will be `mesh.render = false` which can be sorted and processed probably fast enough. But ideal solution would be to be able to destroy object as soon as no references point to it without waiting for Garbage Collector run - I tried searching the docs and I see no way to make the object instantly call it's destructor once refcount reaches 1 (means GC is the only reference keeper). I don't intend on holding onto references in other objects, and if so I'll be using weak_ptr, so this means there should be no circular references and object should be safely destroyed ASAP, not sometime in the future. Any idea how to achieve this scenario and/or how to solve above problem of object lifecycle?
  8. Hello, For performance reasons, I'm using slot map container on C++ side to store instances of some particular object Foo. This means I'm not actually storing pointers to elements of that container directly because the whole access goes through special slot tables that map a key to an exact object instance - so instead of having Foo* registered for scripting as a usual refcounted reference there is one layer of indirection - I hold a "handle" that can be used to retrieve the pointer which will be valid for the time of the call. In C++ I would overload -> operator to hide this indirection, and still be able to use foo_handle->foo_method(): Foo* operator->() { return slotmap.get(handle); } How can I register such handle on Angelscript side so I don't have to proxy all the methods to the actual retrieved Foo* instance? So instead of having this: class FooScriptProxy { FooHandle h; void addRef(); // refcounting the proxy void release(); void fooMethodA() { Foo* f = slot_map.get(h); if (f) f->fooMethodA(); else ?? } void fooMethodB() { Foo* f = slot_map.get(h); if (f) f->fooMethodB(); else ?? } } I'd like to just be able to register the handle without delegating all the method calls manually while retrieving the pointer thru handle - so dynamically retrieved like through -> operator: So whenever I do something like this in script: # C++ side: class FooHandle { SlotMapKey k; Foo* retrieve() { return slotmap.get(k); // returns Foo* if exists in a map or nullptr if it wasn't found } void AddRef(); void Release(); } engine->RegisterObjectType("Foo", 0, asOBJ_REF) engine->RegisterObjectBehaviour("Foo", asBEHAVE_ADDREF, "void f()", asMETHOD(FooHandle,AddRef), asCALL_THISCALL); assert( r >= 0 ); engine->RegisterObjectBehaviour("Foo", asBEHAVE_RELEASE, "void f()", asMETHOD(FooHandle,Release), asCALL_THISCALL); assert( r >= 0 ); -> here do some magic so it registers method "retrieve" in a way similar to arrow op? # AS side: Foo @foo = createFoo(); foo.fooMethodB(); # <---- when foo.method happens, it would mean Foo* f = FooHandle::retrieve; f.method() it would actually dynamically retrieve the pointer, and then call method "fooMethodB" on it. Umm, hope it makes sense
  9. noizex

    Entity Component Systems and Data Oriented Design

    Ah, thanks for reminding me. I've got the book and I learned a lot from it (my whole animation system is based on ideas from this book). For some reason I never checked the chapter on game objects as I had my own idea settled already back then... which didn't really age that well
  10. noizex

    Entity Component Systems and Data Oriented Design

    Well, that's true and, for he most part, this will involve rather limited set of components, because if they were to cover a gameplay needs it seems like a job for scripting (where we have more dynamic situation), not C++ -. So not having the whole "crust" of generic component that can be anything would not be a problem. Robert Nystrom in his book mentions the version which is just normal composition (http://gameprogrammingpatterns.com/component.html), and then he shows other approaches, getting more close to what usual person thinks of component-based approach (the "terrible one"). By the way, Bob's way of going through the topic is insanely useful, even if he doesn't dig very deep into the subjects and keep them "appraochable", I love how he starts small, with a rather simple example and builds on top of it, while mentioning all pros and cons - no religious warfare, no opinionated stuff (or if any, he does it as some side-notes) - I wish more people would write books or articles on such topics in that manner. Anyway, what I would like to learn myself is how to make a system that: doesn't need to be overly generic (I'll have limited set of "modules" building the low level game object that I may need - transform, appearance, physics, skeleton, animation controller etc) allow me to not have some of the "component" on a given object - if half of the objects in the world are static I don't want them to have skeleton or animation controller needlessly allocated good on performance side (would rather avoid paying costs of magnitude 10x or more...) have a good interface to access given functionality (though as I mentioned previously this would be alleviated by a scripting layer where I can hide certain design decisions - I'm a strong believer that game logic should not be so low level to make people think of performance all the time, something they're pushing in Unity now, I'd like the low level layer to be able to cope with whatever high level game logic throws at it) (nice to have) would be ability to substitute certain functions, like being able to add different kind of beaviour in place, like Physics and WeirdPhysics - but this gets us into virtual land, and requires some common interface to be shared by classes implementing this behaviour (not so common as Component, but something like IPhysicsController etc.) And about your suggestion of I'm missing something here... components may communicate with each other to perform their functions, but there has to be some entry point to what they do, which will be used in game logic? Say we want to move our gameobject forward and start walking animation, what you mean to do? We're at game logic level, we're thinking "objects", not "some transform component" because that would be too abstract... I want to obj->setAnimation("walking"), obj->setVelocity(123) and have it perform what I need, and on the low level this can be whatever, separate systems made of components stored as SoA or AoS or ASUS even... If that makes sense? So the Entity/Object will have to be somehow there because we need some entry point to use the whole thing in a convenient manner - without the entry point you have components thrown around into various places and a bunch of them refer to an object - but how do you actually USE it? PS. Am I the only one who's missing Slack's or other communicators way of formatting inline code (single backtick ``) inside the text? Whenever I try to use preformatted it adds a paragraph and destroys the whole thing Unless there is some other way to pre-format only part of an inline text?
  11. noizex

    Entity Component Systems and Data Oriented Design

    Please, please write that blog post! I'd really like to read about why "dynamic composition system" is terrible, what are the alternatives (I can think of some but most of them will not be as dynamic - is any dynamic one terrible or just the one presented in the video?). I, personally, am looking into a system for lower level functionality - physics, rendering, interest management, collision, animation - and not slapping it all into a single GameObject bag. I plan to have scripting for anything regarding in-game logic, hell, I can even hide hideous interface from C++ side under neat script interface so people can use it conveniently for higher-level code, but beneath the surface is neatly engineered C++ code. Isn't it often the problem? That the code which performs horribly and follows bad patterns is usually easier to use for higher-level programming (so game logic etc) rather than having it well-engineered but requiring totally different way of looking at things? Less object-with-all-the-stuff-centric? I have no problem designing (I think) pretty good systems, following good practices, but where my skills fail me is designing a system for game objects that will work well - and not end up with inheritance crap, or forced everything-as-components, or any other religious crap. I'm just genuinely having a problem, because after all such object, built of all the bricks, IS EVERYTHING. It doesn't have a single responsibility, it's an object, which will become a freaking monster, player or a tree. So either there is something that totally turns it upside down, or we end up with systems we know are terrible, but they have the advantage of getting the job done, vs. ideal? To me, it's important that this system has a usable interface for end-user writing game logic, and not only follows all principles but is virtually unusable to write a logic code, which just has to do some job, and not be engineering masterpiece...
  12. noizex

    Entity Component Systems and Data Oriented Design

    Actually as far as I know we're talking about generic game engine support here, so it's not about my particular project, it's about generic enough solution to fit more uses than single one...
  13. noizex

    Entity Component Systems and Data Oriented Design

    I'm well aware there are no silver bullets, I just don't know if bashing one solution because it skews OO without showing the actual solutions which work or show the OO as it should be helps much. Most of discussions about ECS turn into argument how bad one or another side is, so there must be some practices that are in "the middle" and that could form a good toolbox for engineering solutions for our needs - I'd love to hear what are these. And funny thing you mention Ruby on Rails, that's what my team is doing in my day job, but I think you kinda drifted with that analogy... And of course there are arguments over which framework or solution works better - I just suggest to make this more... productive? so we could share the good practices and solutions? Not expecting silver bullet here, what Oberon accused me for. "Take ideas from something and something and use it to your whatever" says nothing really. We have a real problem here - management of entities and their logic in a game world. Of course this will be different for RTS strategy vs. race game vs. open world RPG. But if that's not good, then what is? Most of 3D games nowdays require some kind of 3D world filled with objects that are processed by some logic - lets discuss this and ditch all racers, platformers etc. which may require something slightly different, and talk what is better than ECS, data-driven or badly-OO-based one...
  14. noizex

    Entity Component Systems and Data Oriented Design

    And I'd gladly hear about the "right way" to do this, because if ECS is bad, bad OO is bad, then what's good? Links, blog posts, articles, code samples please. I'm a bit tired of hearing one side advertising some ultimate solution to everything and more (which looks kinda ugly and is probably just as unmaintainable as anything else as soon as it grew to something bigger than some bazzilion of sprintes rotating at once on the screen), and another side bashing this, and mentioning some proper OO code which I obviously had never an honour to see.
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!